@neynar/ui 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/dist/components/ui/accordion.d.ts +229 -0
- package/dist/components/ui/accordion.d.ts.map +1 -0
- package/dist/components/ui/alert-dialog.d.ts +247 -0
- package/dist/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/components/ui/alert.d.ts +187 -0
- package/dist/components/ui/alert.d.ts.map +1 -0
- package/dist/components/ui/aspect-ratio.d.ts +94 -0
- package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
- package/dist/components/ui/avatar.d.ts +244 -0
- package/dist/components/ui/avatar.d.ts.map +1 -0
- package/dist/components/ui/badge.d.ts +163 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/breadcrumb.d.ts +281 -0
- package/dist/components/ui/breadcrumb.d.ts.map +1 -0
- package/dist/components/ui/button.d.ts +129 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/calendar.d.ts +169 -0
- package/dist/components/ui/calendar.d.ts.map +1 -0
- package/dist/components/ui/card.d.ts +365 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/carousel.d.ts +369 -0
- package/dist/components/ui/carousel.d.ts.map +1 -0
- package/dist/components/ui/chart.d.ts +442 -0
- package/dist/components/ui/chart.d.ts.map +1 -0
- package/dist/components/ui/checkbox.d.ts +88 -0
- package/dist/components/ui/checkbox.d.ts.map +1 -0
- package/dist/components/ui/collapsible.d.ts +182 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/combobox.d.ts +270 -0
- package/dist/components/ui/combobox.d.ts.map +1 -0
- package/dist/components/ui/command.d.ts +355 -0
- package/dist/components/ui/command.d.ts.map +1 -0
- package/dist/components/ui/container.d.ts +102 -0
- package/dist/components/ui/container.d.ts.map +1 -0
- package/dist/components/ui/context-menu.d.ts +339 -0
- package/dist/components/ui/context-menu.d.ts.map +1 -0
- package/dist/components/ui/date-picker.d.ts +145 -0
- package/dist/components/ui/date-picker.d.ts.map +1 -0
- package/dist/components/ui/dialog.d.ts +322 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/drawer.d.ts +154 -0
- package/dist/components/ui/drawer.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.d.ts +349 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/components/ui/empty-state.d.ts +133 -0
- package/dist/components/ui/empty-state.d.ts.map +1 -0
- package/dist/components/ui/hover-card.d.ts +109 -0
- package/dist/components/ui/hover-card.d.ts.map +1 -0
- package/dist/components/ui/input.d.ts +89 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/label.d.ts +93 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/menubar.d.ts +306 -0
- package/dist/components/ui/menubar.d.ts.map +1 -0
- package/dist/components/ui/navigation-menu.d.ts +318 -0
- package/dist/components/ui/navigation-menu.d.ts.map +1 -0
- package/dist/components/ui/pagination.d.ts +343 -0
- package/dist/components/ui/pagination.d.ts.map +1 -0
- package/dist/components/ui/popover.d.ts +178 -0
- package/dist/components/ui/popover.d.ts.map +1 -0
- package/dist/components/ui/progress.d.ts +64 -0
- package/dist/components/ui/progress.d.ts.map +1 -0
- package/dist/components/ui/radio-group.d.ts +144 -0
- package/dist/components/ui/radio-group.d.ts.map +1 -0
- package/dist/components/ui/resizable.d.ts +164 -0
- package/dist/components/ui/resizable.d.ts.map +1 -0
- package/dist/components/ui/scroll-area.d.ts +82 -0
- package/dist/components/ui/scroll-area.d.ts.map +1 -0
- package/dist/components/ui/select.d.ts +316 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/separator.d.ts +80 -0
- package/dist/components/ui/separator.d.ts.map +1 -0
- package/dist/components/ui/sheet.d.ts +346 -0
- package/dist/components/ui/sheet.d.ts.map +1 -0
- package/dist/components/ui/sidebar.d.ts +1561 -0
- package/dist/components/ui/sidebar.d.ts.map +1 -0
- package/dist/components/ui/skeleton.d.ts +66 -0
- package/dist/components/ui/skeleton.d.ts.map +1 -0
- package/dist/components/ui/slider.d.ts +95 -0
- package/dist/components/ui/slider.d.ts.map +1 -0
- package/dist/components/ui/sonner.d.ts +101 -0
- package/dist/components/ui/sonner.d.ts.map +1 -0
- package/dist/components/ui/stack.d.ts +192 -0
- package/dist/components/ui/stack.d.ts.map +1 -0
- package/dist/components/ui/stories/accordion.stories.d.ts +71 -0
- package/dist/components/ui/stories/accordion.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/alert-dialog.stories.d.ts +39 -0
- package/dist/components/ui/stories/alert-dialog.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/alert.stories.d.ts +48 -0
- package/dist/components/ui/stories/alert.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/aspect-ratio.stories.d.ts +53 -0
- package/dist/components/ui/stories/aspect-ratio.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/avatar.stories.d.ts +49 -0
- package/dist/components/ui/stories/avatar.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/badge.stories.d.ts +64 -0
- package/dist/components/ui/stories/badge.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/breadcrumb.stories.d.ts +27 -0
- package/dist/components/ui/stories/breadcrumb.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/button.stories.d.ts +92 -0
- package/dist/components/ui/stories/button.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/calendar.stories.d.ts +94 -0
- package/dist/components/ui/stories/calendar.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/card.stories.d.ts +29 -0
- package/dist/components/ui/stories/card.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/carousel.stories.d.ts +42 -0
- package/dist/components/ui/stories/carousel.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/chart.stories.d.ts +51 -0
- package/dist/components/ui/stories/chart.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/checkbox.stories.d.ts +72 -0
- package/dist/components/ui/stories/checkbox.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/cn.stories.d.ts +19 -0
- package/dist/components/ui/stories/cn.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/collapsible.stories.d.ts +51 -0
- package/dist/components/ui/stories/collapsible.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/colors.stories.d.ts +31 -0
- package/dist/components/ui/stories/colors.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/combobox.stories.d.ts +89 -0
- package/dist/components/ui/stories/combobox.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/command.stories.d.ts +69 -0
- package/dist/components/ui/stories/command.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/container.stories.d.ts +42 -0
- package/dist/components/ui/stories/container.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/context-menu.stories.d.ts +32 -0
- package/dist/components/ui/stories/context-menu.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/date-picker.stories.d.ts +67 -0
- package/dist/components/ui/stories/date-picker.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/dialog.stories.d.ts +48 -0
- package/dist/components/ui/stories/dialog.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/drawer.stories.d.ts +33 -0
- package/dist/components/ui/stories/drawer.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/dropdown-menu.stories.d.ts +31 -0
- package/dist/components/ui/stories/dropdown-menu.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/empty-state.stories.d.ts +74 -0
- package/dist/components/ui/stories/empty-state.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/hover-card.stories.d.ts +35 -0
- package/dist/components/ui/stories/hover-card.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/input.stories.d.ts +69 -0
- package/dist/components/ui/stories/input.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/label.stories.d.ts +47 -0
- package/dist/components/ui/stories/label.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/menubar.stories.d.ts +39 -0
- package/dist/components/ui/stories/menubar.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/navigation-menu.stories.d.ts +44 -0
- package/dist/components/ui/stories/navigation-menu.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/pagination.stories.d.ts +33 -0
- package/dist/components/ui/stories/pagination.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/popover.stories.d.ts +36 -0
- package/dist/components/ui/stories/popover.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/progress.stories.d.ts +38 -0
- package/dist/components/ui/stories/progress.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/radio-group.stories.d.ts +76 -0
- package/dist/components/ui/stories/radio-group.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/resizable.stories.d.ts +49 -0
- package/dist/components/ui/stories/resizable.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/scroll-area.stories.d.ts +35 -0
- package/dist/components/ui/stories/scroll-area.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/select.stories.d.ts +51 -0
- package/dist/components/ui/stories/select.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/separator.stories.d.ts +58 -0
- package/dist/components/ui/stories/separator.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/sheet.stories.d.ts +43 -0
- package/dist/components/ui/stories/sheet.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/sidebar.stories.d.ts +60 -0
- package/dist/components/ui/stories/sidebar.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/skeleton.stories.d.ts +42 -0
- package/dist/components/ui/stories/skeleton.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/slider.stories.d.ts +99 -0
- package/dist/components/ui/stories/slider.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/sonner.stories.d.ts +9 -0
- package/dist/components/ui/stories/sonner.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/stack.stories.d.ts +39 -0
- package/dist/components/ui/stories/stack.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/switch.stories.d.ts +71 -0
- package/dist/components/ui/stories/switch.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/table.stories.d.ts +40 -0
- package/dist/components/ui/stories/table.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/tabs.stories.d.ts +62 -0
- package/dist/components/ui/stories/tabs.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/text-field.stories.d.ts +78 -0
- package/dist/components/ui/stories/text-field.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/textarea.stories.d.ts +57 -0
- package/dist/components/ui/stories/textarea.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/theme-toggle.stories.d.ts +71 -0
- package/dist/components/ui/stories/theme-toggle.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/theme.stories.d.ts +51 -0
- package/dist/components/ui/stories/theme.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/toggle-group.stories.d.ts +71 -0
- package/dist/components/ui/stories/toggle-group.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/toggle.stories.d.ts +78 -0
- package/dist/components/ui/stories/toggle.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/tooltip.stories.d.ts +37 -0
- package/dist/components/ui/stories/tooltip.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/typography.stories.d.ts +137 -0
- package/dist/components/ui/stories/typography.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/use-mobile.stories.d.ts +20 -0
- package/dist/components/ui/stories/use-mobile.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/use-theme.stories.d.ts +23 -0
- package/dist/components/ui/stories/use-theme.stories.d.ts.map +1 -0
- package/dist/components/ui/switch.d.ts +84 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/components/ui/table.d.ts +321 -0
- package/dist/components/ui/table.d.ts.map +1 -0
- package/dist/components/ui/tabs.d.ts +260 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/components/ui/text-field.d.ts +157 -0
- package/dist/components/ui/text-field.d.ts.map +1 -0
- package/dist/components/ui/textarea.d.ts +84 -0
- package/dist/components/ui/textarea.d.ts.map +1 -0
- package/dist/components/ui/theme-toggle.d.ts +105 -0
- package/dist/components/ui/theme-toggle.d.ts.map +1 -0
- package/dist/components/ui/theme.d.ts +110 -0
- package/dist/components/ui/theme.d.ts.map +1 -0
- package/dist/components/ui/toggle-group.d.ts +133 -0
- package/dist/components/ui/toggle-group.d.ts.map +1 -0
- package/dist/components/ui/toggle.d.ts +84 -0
- package/dist/components/ui/toggle.d.ts.map +1 -0
- package/dist/components/ui/tooltip.d.ts +202 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/typography.d.ts +287 -0
- package/dist/components/ui/typography.d.ts.map +1 -0
- package/dist/hooks/use-mobile.d.ts +74 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-theme.d.ts +142 -0
- package/dist/hooks/use-theme.d.ts.map +1 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27498 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/utils.d.ts +43 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/llm/colors.md +273 -0
- package/docs/llm/components/buttons.md +68 -0
- package/docs/llm/components/cards.md +53 -0
- package/docs/llm/components/display.md +134 -0
- package/docs/llm/components/feedback.md +96 -0
- package/docs/llm/components/forms.md +90 -0
- package/docs/llm/components/layout.md +59 -0
- package/docs/llm/components/menus.md +70 -0
- package/docs/llm/components/navigation.md +80 -0
- package/docs/llm/components/overlays.md +83 -0
- package/docs/llm/components/tables.md +73 -0
- package/docs/llm/components/typography.md +199 -0
- package/docs/llm/components/utilities.md +114 -0
- package/docs/llm/guide.md +165 -0
- package/llms.txt +122 -0
- package/package.json +104 -0
- package/src/components/ui/accordion.tsx +285 -0
- package/src/components/ui/alert-dialog.tsx +387 -0
- package/src/components/ui/alert.tsx +243 -0
- package/src/components/ui/aspect-ratio.tsx +99 -0
- package/src/components/ui/avatar.tsx +288 -0
- package/src/components/ui/badge.tsx +205 -0
- package/src/components/ui/breadcrumb.tsx +378 -0
- package/src/components/ui/button.tsx +195 -0
- package/src/components/ui/calendar.tsx +371 -0
- package/src/components/ui/card.tsx +447 -0
- package/src/components/ui/carousel.tsx +624 -0
- package/src/components/ui/chart.tsx +802 -0
- package/src/components/ui/checkbox.tsx +113 -0
- package/src/components/ui/collapsible.tsx +207 -0
- package/src/components/ui/combobox.tsx +373 -0
- package/src/components/ui/command.tsx +518 -0
- package/src/components/ui/container.tsx +114 -0
- package/src/components/ui/context-menu.tsx +563 -0
- package/src/components/ui/date-picker.tsx +213 -0
- package/src/components/ui/dialog.tsx +447 -0
- package/src/components/ui/drawer.tsx +273 -0
- package/src/components/ui/dropdown-menu.tsx +578 -0
- package/src/components/ui/empty-state.tsx +145 -0
- package/src/components/ui/hover-card.tsx +144 -0
- package/src/components/ui/input.tsx +106 -0
- package/src/components/ui/label.tsx +110 -0
- package/src/components/ui/menubar.tsx +553 -0
- package/src/components/ui/navigation-menu.tsx +471 -0
- package/src/components/ui/pagination.tsx +456 -0
- package/src/components/ui/popover.tsx +216 -0
- package/src/components/ui/progress.tsx +88 -0
- package/src/components/ui/radio-group.tsx +183 -0
- package/src/components/ui/resizable.tsx +209 -0
- package/src/components/ui/scroll-area.tsx +132 -0
- package/src/components/ui/select.tsx +485 -0
- package/src/components/ui/separator.tsx +101 -0
- package/src/components/ui/sheet.tsx +495 -0
- package/src/components/ui/sidebar.tsx +2211 -0
- package/src/components/ui/skeleton.tsx +76 -0
- package/src/components/ui/slider.tsx +147 -0
- package/src/components/ui/sonner.tsx +120 -0
- package/src/components/ui/stack.tsx +180 -0
- package/src/components/ui/stories/accordion.stories.tsx +429 -0
- package/src/components/ui/stories/alert-dialog.stories.tsx +519 -0
- package/src/components/ui/stories/alert.stories.tsx +228 -0
- package/src/components/ui/stories/aspect-ratio.stories.tsx +200 -0
- package/src/components/ui/stories/avatar.stories.tsx +317 -0
- package/src/components/ui/stories/badge.stories.tsx +260 -0
- package/src/components/ui/stories/breadcrumb.stories.tsx +482 -0
- package/src/components/ui/stories/button.stories.tsx +266 -0
- package/src/components/ui/stories/calendar.stories.tsx +375 -0
- package/src/components/ui/stories/card.stories.tsx +308 -0
- package/src/components/ui/stories/carousel.stories.tsx +328 -0
- package/src/components/ui/stories/chart.stories.tsx +430 -0
- package/src/components/ui/stories/checkbox.stories.tsx +297 -0
- package/src/components/ui/stories/cn.stories.tsx +433 -0
- package/src/components/ui/stories/collapsible.stories.tsx +256 -0
- package/src/components/ui/stories/colors.stories.tsx +502 -0
- package/src/components/ui/stories/combobox.stories.tsx +301 -0
- package/src/components/ui/stories/command.stories.tsx +632 -0
- package/src/components/ui/stories/container.stories.tsx +250 -0
- package/src/components/ui/stories/context-menu.stories.tsx +446 -0
- package/src/components/ui/stories/date-picker.stories.tsx +378 -0
- package/src/components/ui/stories/dialog.stories.tsx +535 -0
- package/src/components/ui/stories/drawer.stories.tsx +364 -0
- package/src/components/ui/stories/dropdown-menu.stories.tsx +374 -0
- package/src/components/ui/stories/empty-state.stories.tsx +244 -0
- package/src/components/ui/stories/hover-card.stories.tsx +355 -0
- package/src/components/ui/stories/input.stories.tsx +289 -0
- package/src/components/ui/stories/label.stories.tsx +294 -0
- package/src/components/ui/stories/menubar.stories.tsx +764 -0
- package/src/components/ui/stories/navigation-menu.stories.tsx +539 -0
- package/src/components/ui/stories/pagination.stories.tsx +604 -0
- package/src/components/ui/stories/popover.stories.tsx +392 -0
- package/src/components/ui/stories/progress.stories.tsx +218 -0
- package/src/components/ui/stories/radio-group.stories.tsx +400 -0
- package/src/components/ui/stories/resizable.stories.tsx +417 -0
- package/src/components/ui/stories/scroll-area.stories.tsx +180 -0
- package/src/components/ui/stories/select.stories.tsx +389 -0
- package/src/components/ui/stories/separator.stories.tsx +192 -0
- package/src/components/ui/stories/sheet.stories.tsx +468 -0
- package/src/components/ui/stories/sidebar.stories.tsx +731 -0
- package/src/components/ui/stories/skeleton.stories.tsx +216 -0
- package/src/components/ui/stories/slider.stories.tsx +321 -0
- package/src/components/ui/stories/sonner.stories.tsx +373 -0
- package/src/components/ui/stories/stack.stories.tsx +222 -0
- package/src/components/ui/stories/switch.stories.tsx +202 -0
- package/src/components/ui/stories/table.stories.tsx +541 -0
- package/src/components/ui/stories/tabs.stories.tsx +544 -0
- package/src/components/ui/stories/text-field.stories.tsx +280 -0
- package/src/components/ui/stories/textarea.stories.tsx +245 -0
- package/src/components/ui/stories/theme-toggle.stories.tsx +275 -0
- package/src/components/ui/stories/theme.stories.tsx +412 -0
- package/src/components/ui/stories/toggle-group.stories.tsx +337 -0
- package/src/components/ui/stories/toggle.stories.tsx +325 -0
- package/src/components/ui/stories/tooltip.stories.tsx +444 -0
- package/src/components/ui/stories/typography.stories.tsx +1586 -0
- package/src/components/ui/stories/use-mobile.stories.tsx +420 -0
- package/src/components/ui/stories/use-theme.stories.tsx +531 -0
- package/src/components/ui/switch.tsx +106 -0
- package/src/components/ui/table.tsx +424 -0
- package/src/components/ui/tabs.tsx +316 -0
- package/src/components/ui/text-field.tsx +206 -0
- package/src/components/ui/textarea.tsx +98 -0
- package/src/components/ui/theme-toggle.tsx +185 -0
- package/src/components/ui/theme.tsx +148 -0
- package/src/components/ui/toggle-group.tsx +196 -0
- package/src/components/ui/toggle.tsx +115 -0
- package/src/components/ui/tooltip.tsx +253 -0
- package/src/components/ui/typography.tsx +468 -0
- package/src/hooks/use-mobile.ts +91 -0
- package/src/hooks/use-theme.ts +319 -0
- package/src/index.ts +77 -0
- package/src/lib/utils.ts +57 -0
- package/src/styles/globals.css +160 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChevronLeftIcon,
|
|
3
|
+
ChevronRightIcon,
|
|
4
|
+
MoreHorizontalIcon,
|
|
5
|
+
} from "lucide-react";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
|
|
8
|
+
import { cn } from "@/lib/utils";
|
|
9
|
+
import { Button, buttonVariants } from "@/components/ui/button";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Pagination navigation component for large datasets
|
|
13
|
+
*
|
|
14
|
+
* A comprehensive pagination component built on shadcn/ui standards that provides
|
|
15
|
+
* intuitive navigation through pages of content. Features responsive design,
|
|
16
|
+
* accessibility compliance, and flexible composition patterns for different use cases.
|
|
17
|
+
*
|
|
18
|
+
* Ideal for data tables, search results, product listings, and any paginated content.
|
|
19
|
+
* Integrates seamlessly with React frameworks like Next.js through customizable link components.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* // Basic pagination with numbered pages
|
|
24
|
+
* <Pagination>
|
|
25
|
+
* <PaginationContent>
|
|
26
|
+
* <PaginationItem>
|
|
27
|
+
* <PaginationPrevious href="/page/1" />
|
|
28
|
+
* </PaginationItem>
|
|
29
|
+
* <PaginationItem>
|
|
30
|
+
* <PaginationLink href="/page/1">1</PaginationLink>
|
|
31
|
+
* </PaginationItem>
|
|
32
|
+
* <PaginationItem>
|
|
33
|
+
* <PaginationLink href="/page/2" isActive>2</PaginationLink>
|
|
34
|
+
* </PaginationItem>
|
|
35
|
+
* <PaginationItem>
|
|
36
|
+
* <PaginationLink href="/page/3">3</PaginationLink>
|
|
37
|
+
* </PaginationItem>
|
|
38
|
+
* <PaginationItem>
|
|
39
|
+
* <PaginationNext href="/page/3" />
|
|
40
|
+
* </PaginationItem>
|
|
41
|
+
* </PaginationContent>
|
|
42
|
+
* </Pagination>
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* // With ellipsis for large page ranges
|
|
48
|
+
* <Pagination>
|
|
49
|
+
* <PaginationContent>
|
|
50
|
+
* <PaginationItem>
|
|
51
|
+
* <PaginationPrevious href="/page/4" />
|
|
52
|
+
* </PaginationItem>
|
|
53
|
+
* <PaginationItem>
|
|
54
|
+
* <PaginationLink href="/page/1">1</PaginationLink>
|
|
55
|
+
* </PaginationItem>
|
|
56
|
+
* <PaginationItem>
|
|
57
|
+
* <PaginationEllipsis />
|
|
58
|
+
* </PaginationItem>
|
|
59
|
+
* <PaginationItem>
|
|
60
|
+
* <PaginationLink href="/page/5" isActive>5</PaginationLink>
|
|
61
|
+
* </PaginationItem>
|
|
62
|
+
* <PaginationItem>
|
|
63
|
+
* <PaginationEllipsis />
|
|
64
|
+
* </PaginationItem>
|
|
65
|
+
* <PaginationItem>
|
|
66
|
+
* <PaginationLink href="/page/50">50</PaginationLink>
|
|
67
|
+
* </PaginationItem>
|
|
68
|
+
* <PaginationItem>
|
|
69
|
+
* <PaginationNext href="/page/6" />
|
|
70
|
+
* </PaginationItem>
|
|
71
|
+
* </PaginationContent>
|
|
72
|
+
* </Pagination>
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```tsx
|
|
77
|
+
* // With Next.js Link integration
|
|
78
|
+
* <Pagination>
|
|
79
|
+
* <PaginationContent>
|
|
80
|
+
* <PaginationItem>
|
|
81
|
+
* <PaginationLink asChild>
|
|
82
|
+
* <Link href="/products?page=1">1</Link>
|
|
83
|
+
* </PaginationLink>
|
|
84
|
+
* </PaginationItem>
|
|
85
|
+
* </PaginationContent>
|
|
86
|
+
* </Pagination>
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @accessibility
|
|
90
|
+
* - Semantic nav element with role="navigation" and aria-label="pagination"
|
|
91
|
+
* - aria-current="page" automatically applied to active page links
|
|
92
|
+
* - Descriptive aria-labels on Previous/Next buttons for screen readers
|
|
93
|
+
* - Full keyboard navigation support with Tab and Enter keys
|
|
94
|
+
* - High contrast focus indicators and proper color contrast ratios
|
|
95
|
+
* - Screen reader friendly ellipsis with "More pages" hidden text
|
|
96
|
+
*
|
|
97
|
+
* @see {@link https://ui.shadcn.com/docs/components/pagination} shadcn/ui Pagination
|
|
98
|
+
* @see {@link PaginationContent} Container for pagination items
|
|
99
|
+
* @see {@link PaginationLink} Individual page number links
|
|
100
|
+
* @see {@link PaginationPrevious} Previous page navigation button
|
|
101
|
+
* @see {@link PaginationNext} Next page navigation button
|
|
102
|
+
* @see {@link PaginationEllipsis} Ellipsis indicator for omitted pages
|
|
103
|
+
* @since 1.0.0
|
|
104
|
+
*/
|
|
105
|
+
function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
|
|
106
|
+
return (
|
|
107
|
+
<nav
|
|
108
|
+
role="navigation"
|
|
109
|
+
aria-label="pagination"
|
|
110
|
+
data-slot="pagination"
|
|
111
|
+
className={cn("mx-auto flex w-full justify-center", className)}
|
|
112
|
+
{...props}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Container for pagination navigation items
|
|
119
|
+
*
|
|
120
|
+
* A semantic unordered list that houses all pagination controls in a
|
|
121
|
+
* responsive horizontal layout. Provides proper spacing and alignment
|
|
122
|
+
* for pagination items while maintaining accessibility standards.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```tsx
|
|
126
|
+
* <PaginationContent>
|
|
127
|
+
* <PaginationItem>
|
|
128
|
+
* <PaginationPrevious href="/prev" />
|
|
129
|
+
* </PaginationItem>
|
|
130
|
+
* <PaginationItem>
|
|
131
|
+
* <PaginationLink href="/page/1">1</PaginationLink>
|
|
132
|
+
* </PaginationItem>
|
|
133
|
+
* </PaginationContent>
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* @accessibility
|
|
137
|
+
* - Semantic ul element for proper list structure
|
|
138
|
+
* - Flexible gap spacing for touch-friendly interaction
|
|
139
|
+
* - Horizontal scrolling support on narrow viewports
|
|
140
|
+
*/
|
|
141
|
+
function PaginationContent({
|
|
142
|
+
className,
|
|
143
|
+
...props
|
|
144
|
+
}: React.ComponentProps<"ul">) {
|
|
145
|
+
return (
|
|
146
|
+
<ul
|
|
147
|
+
data-slot="pagination-content"
|
|
148
|
+
className={cn("flex flex-row items-center gap-1", className)}
|
|
149
|
+
{...props}
|
|
150
|
+
/>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Individual list item wrapper for pagination controls
|
|
156
|
+
*
|
|
157
|
+
* A semantic list item that wraps pagination links, buttons, or ellipsis elements.
|
|
158
|
+
* Provides consistent structure and enables proper keyboard navigation between
|
|
159
|
+
* pagination controls.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```tsx
|
|
163
|
+
* <PaginationItem>
|
|
164
|
+
* <PaginationLink href="/page/1">1</PaginationLink>
|
|
165
|
+
* </PaginationItem>
|
|
166
|
+
*
|
|
167
|
+
* <PaginationItem>
|
|
168
|
+
* <PaginationEllipsis />
|
|
169
|
+
* </PaginationItem>
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
function PaginationItem({ ...props }: React.ComponentProps<"li">) {
|
|
173
|
+
return <li data-slot="pagination-item" {...props} />;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Props for pagination link components
|
|
178
|
+
*/
|
|
179
|
+
type PaginationLinkProps = {
|
|
180
|
+
/**
|
|
181
|
+
* Whether this link represents the currently active page
|
|
182
|
+
*
|
|
183
|
+
* When true, applies active styling and adds aria-current="page"
|
|
184
|
+
* for screen reader accessibility.
|
|
185
|
+
*
|
|
186
|
+
* @default false
|
|
187
|
+
*/
|
|
188
|
+
isActive?: boolean;
|
|
189
|
+
} & Pick<React.ComponentProps<typeof Button>, "size"> &
|
|
190
|
+
React.ComponentProps<"a">;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Clickable link for individual page numbers
|
|
194
|
+
*
|
|
195
|
+
* Interactive link component that navigates to specific pages within
|
|
196
|
+
* paginated content. Features automatic active state styling and
|
|
197
|
+
* accessibility attributes. Can be used with framework routers like
|
|
198
|
+
* Next.js Link or React Router through the asChild pattern.
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```tsx
|
|
202
|
+
* // Basic page links
|
|
203
|
+
* <PaginationLink href="/products?page=1">1</PaginationLink>
|
|
204
|
+
* <PaginationLink href="/products?page=2" isActive>2</PaginationLink>
|
|
205
|
+
* <PaginationLink href="/products?page=3">3</PaginationLink>
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```tsx
|
|
210
|
+
* // With Next.js Link
|
|
211
|
+
* <PaginationLink asChild>
|
|
212
|
+
* <Link href="/search?q=react&page=1">1</Link>
|
|
213
|
+
* </PaginationLink>
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```tsx
|
|
218
|
+
* // With onClick handlers for client-side pagination
|
|
219
|
+
* <PaginationLink
|
|
220
|
+
* href="#"
|
|
221
|
+
* onClick={(e) => {
|
|
222
|
+
* e.preventDefault();
|
|
223
|
+
* onPageChange(1);
|
|
224
|
+
* }}
|
|
225
|
+
* >
|
|
226
|
+
* 1
|
|
227
|
+
* </PaginationLink>
|
|
228
|
+
* ```
|
|
229
|
+
*
|
|
230
|
+
* @accessibility
|
|
231
|
+
* - Automatically applies aria-current="page" when isActive is true
|
|
232
|
+
* - Button-style focus indicators for keyboard navigation
|
|
233
|
+
* - Sufficient color contrast for active/inactive states
|
|
234
|
+
* - Touch-friendly minimum 44px target size
|
|
235
|
+
*/
|
|
236
|
+
function PaginationLink({
|
|
237
|
+
className,
|
|
238
|
+
isActive,
|
|
239
|
+
size = "icon",
|
|
240
|
+
...props
|
|
241
|
+
}: PaginationLinkProps) {
|
|
242
|
+
return (
|
|
243
|
+
<a
|
|
244
|
+
aria-current={isActive ? "page" : undefined}
|
|
245
|
+
data-slot="pagination-link"
|
|
246
|
+
data-active={isActive}
|
|
247
|
+
className={cn(
|
|
248
|
+
buttonVariants({
|
|
249
|
+
variant: isActive ? "outline" : "ghost",
|
|
250
|
+
size,
|
|
251
|
+
}),
|
|
252
|
+
className,
|
|
253
|
+
)}
|
|
254
|
+
{...props}
|
|
255
|
+
/>
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Previous page navigation button
|
|
261
|
+
*
|
|
262
|
+
* Navigates to the previous page in the pagination sequence. Features
|
|
263
|
+
* responsive design that shows only an icon on mobile devices and
|
|
264
|
+
* icon with text on larger screens for optimal user experience.
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```tsx
|
|
268
|
+
* // Basic previous button
|
|
269
|
+
* <PaginationPrevious href="/products?page=1" />
|
|
270
|
+
* ```
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```tsx
|
|
274
|
+
* // With disabled state (typically for first page)
|
|
275
|
+
* <PaginationPrevious
|
|
276
|
+
* href="#"
|
|
277
|
+
* className="pointer-events-none opacity-50"
|
|
278
|
+
* aria-disabled="true"
|
|
279
|
+
* />
|
|
280
|
+
* ```
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```tsx
|
|
284
|
+
* // With click handler for client-side navigation
|
|
285
|
+
* <PaginationPrevious
|
|
286
|
+
* href="#"
|
|
287
|
+
* onClick={(e) => {
|
|
288
|
+
* e.preventDefault();
|
|
289
|
+
* if (currentPage > 1) {
|
|
290
|
+
* onPageChange(currentPage - 1);
|
|
291
|
+
* }
|
|
292
|
+
* }}
|
|
293
|
+
* />
|
|
294
|
+
* ```
|
|
295
|
+
*
|
|
296
|
+
* @accessibility
|
|
297
|
+
* - Built-in aria-label="Go to previous page" for screen readers
|
|
298
|
+
* - Chevron icon provides visual direction context
|
|
299
|
+
* - Responsive text label appears on larger screens
|
|
300
|
+
* - Keyboard accessible through Tab navigation
|
|
301
|
+
* - Should be disabled on first page to prevent confusion
|
|
302
|
+
*/
|
|
303
|
+
function PaginationPrevious({
|
|
304
|
+
className,
|
|
305
|
+
...props
|
|
306
|
+
}: React.ComponentProps<typeof PaginationLink>) {
|
|
307
|
+
return (
|
|
308
|
+
<PaginationLink
|
|
309
|
+
aria-label="Go to previous page"
|
|
310
|
+
size="default"
|
|
311
|
+
className={cn("gap-1 px-2.5 sm:pl-2.5", className)}
|
|
312
|
+
{...props}
|
|
313
|
+
>
|
|
314
|
+
<ChevronLeftIcon />
|
|
315
|
+
<span className="hidden sm:block">Previous</span>
|
|
316
|
+
</PaginationLink>
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Next page navigation button
|
|
322
|
+
*
|
|
323
|
+
* Navigates to the next page in the pagination sequence. Features
|
|
324
|
+
* responsive design that shows only an icon on mobile devices and
|
|
325
|
+
* text with icon on larger screens for optimal user experience.
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```tsx
|
|
329
|
+
* // Basic next button
|
|
330
|
+
* <PaginationNext href="/products?page=3" />
|
|
331
|
+
* ```
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```tsx
|
|
335
|
+
* // With disabled state (typically for last page)
|
|
336
|
+
* <PaginationNext
|
|
337
|
+
* href="#"
|
|
338
|
+
* className="pointer-events-none opacity-50"
|
|
339
|
+
* aria-disabled="true"
|
|
340
|
+
* />
|
|
341
|
+
* ```
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```tsx
|
|
345
|
+
* // With click handler for client-side navigation
|
|
346
|
+
* <PaginationNext
|
|
347
|
+
* href="#"
|
|
348
|
+
* onClick={(e) => {
|
|
349
|
+
* e.preventDefault();
|
|
350
|
+
* if (currentPage < totalPages) {
|
|
351
|
+
* onPageChange(currentPage + 1);
|
|
352
|
+
* }
|
|
353
|
+
* }}
|
|
354
|
+
* />
|
|
355
|
+
* ```
|
|
356
|
+
*
|
|
357
|
+
* @accessibility
|
|
358
|
+
* - Built-in aria-label="Go to next page" for screen readers
|
|
359
|
+
* - Chevron icon provides visual direction context
|
|
360
|
+
* - Responsive text label appears on larger screens
|
|
361
|
+
* - Keyboard accessible through Tab navigation
|
|
362
|
+
* - Should be disabled on last page to prevent confusion
|
|
363
|
+
*/
|
|
364
|
+
function PaginationNext({
|
|
365
|
+
className,
|
|
366
|
+
...props
|
|
367
|
+
}: React.ComponentProps<typeof PaginationLink>) {
|
|
368
|
+
return (
|
|
369
|
+
<PaginationLink
|
|
370
|
+
aria-label="Go to next page"
|
|
371
|
+
size="default"
|
|
372
|
+
className={cn("gap-1 px-2.5 sm:pr-2.5", className)}
|
|
373
|
+
{...props}
|
|
374
|
+
>
|
|
375
|
+
<span className="hidden sm:block">Next</span>
|
|
376
|
+
<ChevronRightIcon />
|
|
377
|
+
</PaginationLink>
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Visual indicator for omitted page numbers
|
|
383
|
+
*
|
|
384
|
+
* Displays a horizontal ellipsis (three dots) to indicate that
|
|
385
|
+
* page numbers have been omitted from the pagination display.
|
|
386
|
+
* Used to maintain clean UI when dealing with large page ranges.
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```tsx
|
|
390
|
+
* // Between page ranges
|
|
391
|
+
* <PaginationItem>
|
|
392
|
+
* <PaginationLink href="/page/1">1</PaginationLink>
|
|
393
|
+
* </PaginationItem>
|
|
394
|
+
* <PaginationItem>
|
|
395
|
+
* <PaginationEllipsis />
|
|
396
|
+
* </PaginationItem>
|
|
397
|
+
* <PaginationItem>
|
|
398
|
+
* <PaginationLink href="/page/25" isActive>25</PaginationLink>
|
|
399
|
+
* </PaginationItem>
|
|
400
|
+
* ```
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* ```tsx
|
|
404
|
+
* // Common pagination pattern with ellipsis
|
|
405
|
+
* // 1 ... 23 24 [25] 26 27 ... 100
|
|
406
|
+
* <PaginationContent>
|
|
407
|
+
* <PaginationItem>
|
|
408
|
+
* <PaginationLink href="/page/1">1</PaginationLink>
|
|
409
|
+
* </PaginationItem>
|
|
410
|
+
* <PaginationItem>
|
|
411
|
+
* <PaginationEllipsis />
|
|
412
|
+
* </PaginationItem>
|
|
413
|
+
* <PaginationItem>
|
|
414
|
+
* <PaginationLink href="/page/25" isActive>25</PaginationLink>
|
|
415
|
+
* </PaginationItem>
|
|
416
|
+
* <PaginationItem>
|
|
417
|
+
* <PaginationEllipsis />
|
|
418
|
+
* </PaginationItem>
|
|
419
|
+
* <PaginationItem>
|
|
420
|
+
* <PaginationLink href="/page/100">100</PaginationLink>
|
|
421
|
+
* </PaginationItem>
|
|
422
|
+
* </PaginationContent>
|
|
423
|
+
* ```
|
|
424
|
+
*
|
|
425
|
+
* @accessibility
|
|
426
|
+
* - Visual element is aria-hidden from screen readers
|
|
427
|
+
* - Hidden "More pages" text provides context for assistive technology
|
|
428
|
+
* - Non-interactive, purely decorative indicator
|
|
429
|
+
* - Consistent sizing with pagination links for visual harmony
|
|
430
|
+
*/
|
|
431
|
+
function PaginationEllipsis({
|
|
432
|
+
className,
|
|
433
|
+
...props
|
|
434
|
+
}: React.ComponentProps<"span">) {
|
|
435
|
+
return (
|
|
436
|
+
<span
|
|
437
|
+
aria-hidden
|
|
438
|
+
data-slot="pagination-ellipsis"
|
|
439
|
+
className={cn("flex size-9 items-center justify-center", className)}
|
|
440
|
+
{...props}
|
|
441
|
+
>
|
|
442
|
+
<MoreHorizontalIcon className="size-4" />
|
|
443
|
+
<span className="sr-only">More pages</span>
|
|
444
|
+
</span>
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export {
|
|
449
|
+
Pagination,
|
|
450
|
+
PaginationContent,
|
|
451
|
+
PaginationEllipsis,
|
|
452
|
+
PaginationItem,
|
|
453
|
+
PaginationLink,
|
|
454
|
+
PaginationNext,
|
|
455
|
+
PaginationPrevious,
|
|
456
|
+
};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Popover displays rich content in a portal, triggered by a button
|
|
8
|
+
*
|
|
9
|
+
* A versatile floating panel component built on Radix UI primitives that displays
|
|
10
|
+
* interactive content without navigating away from the current context. Unlike tooltips,
|
|
11
|
+
* popovers support complex layouts, forms, and user interactions while maintaining
|
|
12
|
+
* proper focus management and accessibility standards.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* // Basic popover with information
|
|
17
|
+
* <Popover>
|
|
18
|
+
* <PopoverTrigger asChild>
|
|
19
|
+
* <Button variant="outline">Open popover</Button>
|
|
20
|
+
* </PopoverTrigger>
|
|
21
|
+
* <PopoverContent>
|
|
22
|
+
* <div className="grid gap-4">
|
|
23
|
+
* <h4 className="font-medium leading-none">Dimensions</h4>
|
|
24
|
+
* <p className="text-sm text-muted-foreground">
|
|
25
|
+
* Set the dimensions for the layer.
|
|
26
|
+
* </p>
|
|
27
|
+
* </div>
|
|
28
|
+
* </PopoverContent>
|
|
29
|
+
* </Popover>
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* // Controlled popover with form interactions
|
|
35
|
+
* const [open, setOpen] = useState(false);
|
|
36
|
+
*
|
|
37
|
+
* <Popover open={open} onOpenChange={setOpen}>
|
|
38
|
+
* <PopoverTrigger asChild>
|
|
39
|
+
* <Button>Settings</Button>
|
|
40
|
+
* </PopoverTrigger>
|
|
41
|
+
* <PopoverContent className="w-80">
|
|
42
|
+
* <div className="grid gap-4">
|
|
43
|
+
* <div className="space-y-2">
|
|
44
|
+
* <h4 className="font-medium leading-none">Settings</h4>
|
|
45
|
+
* <p className="text-sm text-muted-foreground">
|
|
46
|
+
* Configure your preferences
|
|
47
|
+
* </p>
|
|
48
|
+
* </div>
|
|
49
|
+
* <div className="grid gap-2">
|
|
50
|
+
* <Label htmlFor="width">Width</Label>
|
|
51
|
+
* <Input id="width" defaultValue="100%" />
|
|
52
|
+
* </div>
|
|
53
|
+
* </div>
|
|
54
|
+
* </PopoverContent>
|
|
55
|
+
* </Popover>
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* // Positioned popover with custom alignment
|
|
61
|
+
* <Popover>
|
|
62
|
+
* <PopoverTrigger asChild>
|
|
63
|
+
* <Button variant="ghost" size="icon">
|
|
64
|
+
* <HelpCircle className="h-4 w-4" />
|
|
65
|
+
* </Button>
|
|
66
|
+
* </PopoverTrigger>
|
|
67
|
+
* <PopoverContent side="top" align="start" className="w-80">
|
|
68
|
+
* <div className="space-y-2">
|
|
69
|
+
* <h4 className="font-medium">Help Information</h4>
|
|
70
|
+
* <p className="text-sm text-muted-foreground">
|
|
71
|
+
* Additional context and helpful tips for this feature.
|
|
72
|
+
* </p>
|
|
73
|
+
* </div>
|
|
74
|
+
* </PopoverContent>
|
|
75
|
+
* </Popover>
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @accessibility
|
|
79
|
+
* - **Keyboard Navigation**: Tab to focus, Enter/Space to open, Escape to close
|
|
80
|
+
* - **Focus Management**: Focus trapped within popover when open, returns to trigger on close
|
|
81
|
+
* - **Screen Reader Support**: Proper ARIA attributes and announcements
|
|
82
|
+
* - **Auto-positioning**: Automatically repositions to stay within viewport bounds
|
|
83
|
+
* - **Dismissible**: Closes on outside click or focus loss
|
|
84
|
+
*
|
|
85
|
+
* @see {@link https://ui.shadcn.com/docs/components/popover} shadcn/ui Popover
|
|
86
|
+
* @see {@link https://www.radix-ui.com/primitives/docs/components/popover} Radix Popover Primitive
|
|
87
|
+
* @since 1.0.0
|
|
88
|
+
*/
|
|
89
|
+
/**
|
|
90
|
+
* Root popover component that manages open/closed state
|
|
91
|
+
*
|
|
92
|
+
* @param open - Controls the open state of the popover
|
|
93
|
+
* @param onOpenChange - Event handler called when the open state changes
|
|
94
|
+
* @param defaultOpen - The initial open state for uncontrolled usage
|
|
95
|
+
* @param modal - Whether the popover should be modal (default: false)
|
|
96
|
+
*/
|
|
97
|
+
function Popover({
|
|
98
|
+
...props
|
|
99
|
+
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
|
100
|
+
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* PopoverTrigger - The element that triggers the popover
|
|
105
|
+
*
|
|
106
|
+
* @param asChild - Changes the default rendered element to the one passed as a child,
|
|
107
|
+
* merging their props and behavior. Recommended for custom triggers.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```tsx
|
|
111
|
+
* // Using asChild with custom button
|
|
112
|
+
* <PopoverTrigger asChild>
|
|
113
|
+
* <Button variant="outline">Open Settings</Button>
|
|
114
|
+
* </PopoverTrigger>
|
|
115
|
+
*
|
|
116
|
+
* // Direct usage (renders as button)
|
|
117
|
+
* <PopoverTrigger className="custom-trigger">
|
|
118
|
+
* Click me
|
|
119
|
+
* </PopoverTrigger>
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* @since 1.0.0
|
|
123
|
+
*/
|
|
124
|
+
function PopoverTrigger({
|
|
125
|
+
...props
|
|
126
|
+
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
|
127
|
+
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* PopoverContent - The content container for the popover
|
|
132
|
+
*
|
|
133
|
+
* @param side - The preferred side of the trigger to render against ("top" | "right" | "bottom" | "left")
|
|
134
|
+
* @param align - How to align the popover relative to the trigger ("start" | "center" | "end")
|
|
135
|
+
* @param sideOffset - Distance in pixels from the trigger (default: 4)
|
|
136
|
+
* @param alignOffset - Offset in pixels along the align axis
|
|
137
|
+
* @param avoidCollisions - Whether to automatically avoid collisions with viewport edges (default: true)
|
|
138
|
+
* @param collisionBoundary - Boundary element(s) to consider for collision detection
|
|
139
|
+
* @param sticky - Whether to stick to the boundary edges when colliding ("partial" | "always")
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```tsx
|
|
143
|
+
* // Basic content with default positioning
|
|
144
|
+
* <PopoverContent>
|
|
145
|
+
* <div className="grid gap-4">
|
|
146
|
+
* <h4 className="font-medium">Title</h4>
|
|
147
|
+
* <p className="text-sm text-muted-foreground">Description</p>
|
|
148
|
+
* </div>
|
|
149
|
+
* </PopoverContent>
|
|
150
|
+
*
|
|
151
|
+
* // Positioned content with custom width
|
|
152
|
+
* <PopoverContent side="top" align="start" className="w-80">
|
|
153
|
+
* <form className="grid gap-4">
|
|
154
|
+
* <Input placeholder="Enter value" />
|
|
155
|
+
* <Button type="submit">Save</Button>
|
|
156
|
+
* </form>
|
|
157
|
+
* </PopoverContent>
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @since 1.0.0
|
|
161
|
+
*/
|
|
162
|
+
function PopoverContent({
|
|
163
|
+
className,
|
|
164
|
+
align = "center",
|
|
165
|
+
sideOffset = 4,
|
|
166
|
+
...props
|
|
167
|
+
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
|
168
|
+
return (
|
|
169
|
+
<PopoverPrimitive.Portal>
|
|
170
|
+
<PopoverPrimitive.Content
|
|
171
|
+
data-slot="popover-content"
|
|
172
|
+
align={align}
|
|
173
|
+
sideOffset={sideOffset}
|
|
174
|
+
className={cn(
|
|
175
|
+
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
|
176
|
+
className,
|
|
177
|
+
)}
|
|
178
|
+
{...props}
|
|
179
|
+
/>
|
|
180
|
+
</PopoverPrimitive.Portal>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* PopoverAnchor - Optional anchor element for custom positioning
|
|
186
|
+
*
|
|
187
|
+
* Use PopoverAnchor when you need the popover to position relative to an element
|
|
188
|
+
* other than the trigger. This is useful for complex layouts where the visual
|
|
189
|
+
* trigger and positioning reference should be different elements.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```tsx
|
|
193
|
+
* <Popover>
|
|
194
|
+
* <PopoverAnchor asChild>
|
|
195
|
+
* <div className="relative">
|
|
196
|
+
* <span>Reference element for positioning</span>
|
|
197
|
+
* </div>
|
|
198
|
+
* </PopoverAnchor>
|
|
199
|
+
* <PopoverTrigger asChild>
|
|
200
|
+
* <Button>Open (positioned relative to anchor)</Button>
|
|
201
|
+
* </PopoverTrigger>
|
|
202
|
+
* <PopoverContent>
|
|
203
|
+
* <p>This popover positions relative to the anchor, not the trigger</p>
|
|
204
|
+
* </PopoverContent>
|
|
205
|
+
* </Popover>
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* @since 1.0.0
|
|
209
|
+
*/
|
|
210
|
+
function PopoverAnchor({
|
|
211
|
+
...props
|
|
212
|
+
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
|
213
|
+
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
|