xertica-ui 2.2.1 → 2.4.0
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/CHANGELOG.md +564 -525
- package/README.md +417 -382
- package/bin/cli.ts +1244 -748
- package/bin/generate-tokens.ts +262 -262
- package/bin/language-config.ts +5 -8
- package/components/assets/xertica-orbe-animation.ts +1162 -1162
- package/components/assistant/code-block/CodeBlock.tsx +268 -268
- package/components/assistant/code-block/code-block.stories.tsx +57 -57
- package/components/assistant/code-block/code-block.test.tsx +44 -44
- package/components/assistant/code-block/index.ts +1 -1
- package/components/assistant/formatted-document/FormattedDocument.tsx +147 -147
- package/components/assistant/formatted-document/formatted-document.stories.tsx +51 -51
- package/components/assistant/formatted-document/formatted-document.test.tsx +42 -42
- package/components/assistant/formatted-document/index.ts +1 -1
- package/components/assistant/index.ts +6 -6
- package/components/assistant/markdown-message/MarkdownMessage.tsx +152 -152
- package/components/assistant/markdown-message/index.ts +1 -1
- package/components/assistant/markdown-message/markdown-message.stories.tsx +50 -50
- package/components/assistant/markdown-message/markdown-message.test.tsx +33 -33
- package/components/assistant/modern-chat-input/ModernChatInput.tsx +17 -7
- package/components/assistant/modern-chat-input/index.ts +1 -1
- package/components/assistant/modern-chat-input/modern-chat-input.stories.tsx +131 -131
- package/components/assistant/modern-chat-input/modern-chat-input.test.tsx +79 -79
- package/components/assistant/xertica-assistant/index.ts +3 -3
- package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +99 -99
- package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -106
- package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -81
- package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +88 -78
- package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +75 -75
- package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +564 -560
- package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +67 -67
- package/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.tsx +41 -41
- package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +103 -103
- package/components/assistant/xertica-assistant/parts/index.ts +16 -16
- package/components/assistant/xertica-assistant/types.ts +134 -134
- package/components/assistant/xertica-assistant/use-assistant.ts +615 -615
- package/components/assistant/xertica-assistant/xertica-assistant.stories.tsx +407 -407
- package/components/assistant/xertica-assistant/xertica-assistant.test.tsx +65 -65
- package/components/assistant/xertica-assistant/xertica-assistant.tsx +611 -613
- package/components/blocks/card-patterns/ActivityCard.tsx +100 -100
- package/components/blocks/card-patterns/FeatureCard.tsx +109 -109
- package/components/blocks/card-patterns/FeatureCardSkeleton.tsx +1 -6
- package/components/blocks/card-patterns/NotificationCard.tsx +140 -140
- package/components/blocks/card-patterns/ProfileCard.tsx +112 -114
- package/components/blocks/card-patterns/ProjectCard.tsx +123 -123
- package/components/blocks/card-patterns/ProjectCardSkeleton.tsx +1 -6
- package/components/blocks/card-patterns/QuickActionCard.tsx +68 -68
- package/components/blocks/card-patterns/card-patterns.mdx +123 -123
- package/components/blocks/card-patterns/card-patterns.stories.tsx +594 -594
- package/components/blocks/card-patterns/index.ts +29 -29
- package/components/blocks/index.ts +1 -1
- package/components/brand/branding/branding.stories.tsx +57 -57
- package/components/brand/index.ts +6 -6
- package/components/brand/language-selector/index.ts +1 -1
- package/components/brand/language-selector/language-selector.mdx +126 -126
- package/components/brand/language-selector/language-selector.stories.tsx +1 -4
- package/components/brand/theme-toggle/ThemeToggle.tsx +74 -70
- package/components/brand/theme-toggle/index.ts +1 -1
- package/components/brand/theme-toggle/theme-toggle.stories.tsx +34 -34
- package/components/brand/theme-toggle/theme-toggle.test.tsx +34 -34
- package/components/brand/xertica-logo/XerticaLogo.stories.tsx +82 -82
- package/components/brand/xertica-logo/XerticaLogo.tsx +104 -104
- package/components/brand/xertica-logo/index.ts +1 -1
- package/components/brand/xertica-logo/xertica-logo.test.tsx +26 -26
- package/components/brand/xertica-orbe/XerticaOrbe.tsx +1927 -1927
- package/components/brand/xertica-orbe/index.ts +1 -1
- package/components/brand/xertica-orbe/xertica-orbe.stories.tsx +40 -40
- package/components/brand/xertica-orbe/xertica-orbe.test.tsx +19 -19
- package/components/brand/xertica-provider/XerticaProvider.tsx +1 -4
- package/components/brand/xertica-provider/index.ts +1 -1
- package/components/brand/xertica-provider/xertica-provider.test.tsx +74 -74
- package/components/brand/xertica-xlogo/XerticaXLogo.stories.tsx +79 -79
- package/components/brand/xertica-xlogo/XerticaXLogo.tsx +65 -65
- package/components/brand/xertica-xlogo/index.ts +1 -1
- package/components/brand/xertica-xlogo/xertica-xlogo.test.tsx +16 -16
- package/components/examples/ApiKeyMapExample.tsx +71 -71
- package/components/examples/DrawingMapExample.tsx +565 -565
- package/components/examples/FilterableMapExample.tsx +393 -393
- package/components/examples/LocationPickerExample.tsx +348 -348
- package/components/examples/MapExamples.tsx +268 -268
- package/components/examples/MapGmpExample.tsx +169 -169
- package/components/examples/MapShowcase.tsx +471 -471
- package/components/examples/RouteMapExamples.tsx +329 -329
- package/components/examples/SidebarLogoExample.tsx +65 -65
- package/components/examples/SimpleFilterableMap.tsx +219 -219
- package/components/examples/index.ts +45 -45
- package/components/figma/ImageWithFallback.tsx +27 -27
- package/components/hooks/index.ts +13 -13
- package/components/hooks/use-layout-shortcuts.ts +43 -43
- package/components/index.ts +86 -90
- package/components/layout/header/header.stories.tsx +204 -204
- package/components/layout/header/header.test.tsx +75 -75
- package/components/layout/header/header.tsx +349 -349
- package/components/layout/header/index.ts +1 -1
- package/components/layout/index.ts +2 -2
- package/components/layout/sidebar/index.ts +3 -3
- package/components/layout/sidebar/sidebar.stories.tsx +586 -586
- package/components/layout/sidebar/sidebar.test.tsx +76 -76
- package/components/layout/sidebar/sidebar.tsx +1079 -1073
- package/components/layout/sidebar/use-sidebar.ts +104 -104
- package/components/media/FloatingMediaWrapper.tsx +371 -371
- package/components/media/audio-player/AudioPlayer.stories.tsx +124 -124
- package/components/media/audio-player/AudioPlayer.test.tsx +106 -106
- package/components/media/audio-player/AudioPlayer.tsx +767 -765
- package/components/media/audio-player/index.ts +1 -1
- package/components/media/audio-player/use-audio-player.ts +312 -312
- package/components/media/index.ts +3 -3
- package/components/media/video-player/VideoPlayer.stories.tsx +98 -98
- package/components/media/video-player/VideoPlayer.test.tsx +73 -73
- package/components/media/video-player/VideoPlayer.tsx +310 -310
- package/components/media/video-player/index.ts +1 -1
- package/components/pages/forgot-password-page/ForgotPasswordPage.stories.tsx +24 -24
- package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +188 -188
- package/components/pages/forgot-password-page/forgot-password-page.test.tsx +45 -45
- package/components/pages/forgot-password-page/index.ts +1 -1
- package/components/pages/home-content/HomeContent.stories.tsx +43 -43
- package/components/pages/home-content/HomeContent.tsx +120 -120
- package/components/pages/home-content/index.ts +1 -1
- package/components/pages/home-page/HomePage.stories.tsx +39 -39
- package/components/pages/home-page/HomePage.tsx +78 -74
- package/components/pages/home-page/home-page.test.tsx +53 -53
- package/components/pages/home-page/index.ts +1 -1
- package/components/pages/index.ts +8 -8
- package/components/pages/login-page/LoginPage.stories.tsx +39 -39
- package/components/pages/login-page/LoginPage.tsx +218 -216
- package/components/pages/login-page/index.ts +1 -1
- package/components/pages/login-page/login-page.test.tsx +63 -63
- package/components/pages/reset-password-page/ResetPasswordPage.stories.tsx +24 -24
- package/components/pages/reset-password-page/ResetPasswordPage.tsx +243 -239
- package/components/pages/reset-password-page/index.ts +1 -1
- package/components/pages/template-content/TemplateContent.stories.tsx +43 -43
- package/components/pages/template-content/TemplateContent.tsx +1354 -1235
- package/components/pages/template-content/index.ts +1 -1
- package/components/pages/template-page/TemplatePage.stories.tsx +39 -39
- package/components/pages/template-page/TemplatePage.tsx +62 -62
- package/components/pages/template-page/index.ts +1 -1
- package/components/pages/template-page/template-page.test.tsx +52 -52
- package/components/pages/verify-email-page/VerifyEmailPage.stories.tsx +41 -41
- package/components/pages/verify-email-page/VerifyEmailPage.tsx +206 -206
- package/components/pages/verify-email-page/index.ts +1 -1
- package/components/public-api-smoke.test.tsx +52 -52
- package/components/shared/CustomTooltipContent.tsx +48 -48
- package/components/shared/assistant-utils.test.ts +16 -16
- package/components/shared/assistant-utils.ts +225 -225
- package/components/shared/error-boundary.stories.tsx +114 -132
- package/components/shared/error-boundary.tsx +150 -154
- package/components/shared/error-fallbacks.tsx +222 -226
- package/components/shared/layout-constants.ts +8 -8
- package/components/shared/navigation.ts +35 -35
- package/components/shared/use-mobile.test.ts +16 -16
- package/components/shared/use-mobile.ts +36 -36
- package/components/shared/utils.test.ts +14 -14
- package/components/shared/utils.ts +6 -6
- package/components/ui/accordion/accordion.stories.tsx +105 -105
- package/components/ui/accordion/accordion.test.tsx +59 -59
- package/components/ui/accordion/accordion.tsx +77 -77
- package/components/ui/accordion/index.ts +1 -1
- package/components/ui/alert/alert.stories.tsx +86 -86
- package/components/ui/alert/alert.test.tsx +53 -53
- package/components/ui/alert/alert.tsx +93 -93
- package/components/ui/alert/index.ts +1 -1
- package/components/ui/alert-dialog/alert-dialog.stories.tsx +84 -84
- package/components/ui/alert-dialog/alert-dialog.test.tsx +70 -70
- package/components/ui/alert-dialog/alert-dialog.tsx +149 -149
- package/components/ui/alert-dialog/index.ts +1 -1
- package/components/ui/aspect-ratio/aspect-ratio.stories.tsx +46 -46
- package/components/ui/aspect-ratio/aspect-ratio.test.tsx +28 -28
- package/components/ui/aspect-ratio/aspect-ratio.tsx +20 -20
- package/components/ui/aspect-ratio/index.ts +1 -1
- package/components/ui/assistant-chart/AssistantChart.tsx +64 -64
- package/components/ui/assistant-chart/assistant-chart.stories.tsx +44 -44
- package/components/ui/assistant-chart/assistant-chart.test.tsx +46 -46
- package/components/ui/assistant-chart/index.ts +1 -1
- package/components/ui/avatar/avatar.stories.tsx +86 -86
- package/components/ui/avatar/avatar.test.tsx +55 -55
- package/components/ui/avatar/avatar.tsx +71 -71
- package/components/ui/avatar/index.ts +1 -1
- package/components/ui/badge/badge.stories.tsx +72 -72
- package/components/ui/badge/badge.test.tsx +40 -40
- package/components/ui/badge/badge.tsx +58 -58
- package/components/ui/badge/index.ts +1 -1
- package/components/ui/breadcrumb/breadcrumb.stories.tsx +123 -123
- package/components/ui/breadcrumb/breadcrumb.test.tsx +70 -70
- package/components/ui/breadcrumb/breadcrumb.tsx +114 -114
- package/components/ui/breadcrumb/index.ts +1 -1
- package/components/ui/button/button.stories.tsx +183 -183
- package/components/ui/button/button.test.tsx +64 -64
- package/components/ui/button/button.tsx +98 -98
- package/components/ui/button/index.ts +1 -1
- package/components/ui/calendar/calendar.stories.tsx +108 -108
- package/components/ui/calendar/calendar.test.tsx +53 -53
- package/components/ui/calendar/calendar.tsx +230 -230
- package/components/ui/calendar/index.ts +1 -1
- package/components/ui/card/card.stories.tsx +301 -301
- package/components/ui/card/card.test.tsx +55 -55
- package/components/ui/card/card.tsx +83 -83
- package/components/ui/card/index.ts +1 -1
- package/components/ui/carousel/carousel.stories.tsx +80 -80
- package/components/ui/carousel/carousel.test.tsx +75 -75
- package/components/ui/carousel/carousel.tsx +242 -242
- package/components/ui/carousel/index.ts +1 -1
- package/components/ui/chart/chart.stories.tsx +1328 -1328
- package/components/ui/chart/chart.test.tsx +178 -178
- package/components/ui/chart/chart.tsx +2232 -2232
- package/components/ui/chart/index.ts +1 -1
- package/components/ui/checkbox/checkbox.stories.tsx +109 -109
- package/components/ui/checkbox/checkbox.test.tsx +49 -49
- package/components/ui/checkbox/checkbox.tsx +68 -68
- package/components/ui/checkbox/index.ts +1 -1
- package/components/ui/collapsible/collapsible.stories.tsx +45 -45
- package/components/ui/collapsible/collapsible.test.tsx +51 -51
- package/components/ui/collapsible/collapsible.tsx +32 -32
- package/components/ui/collapsible/index.ts +1 -1
- package/components/ui/command/command.stories.tsx +134 -134
- package/components/ui/command/command.test.tsx +48 -48
- package/components/ui/command/command.tsx +163 -163
- package/components/ui/command/index.ts +1 -1
- package/components/ui/context-menu/context-menu.stories.tsx +76 -76
- package/components/ui/context-menu/context-menu.test.tsx +61 -61
- package/components/ui/context-menu/context-menu.tsx +236 -236
- package/components/ui/context-menu/index.ts +1 -1
- package/components/ui/dialog/dialog.stories.tsx +174 -174
- package/components/ui/dialog/dialog.test.tsx +78 -78
- package/components/ui/dialog/dialog.tsx +189 -189
- package/components/ui/dialog/index.ts +1 -1
- package/components/ui/drawer/drawer.stories.tsx +71 -71
- package/components/ui/drawer/drawer.test.tsx +67 -67
- package/components/ui/drawer/drawer.tsx +146 -146
- package/components/ui/drawer/index.ts +1 -1
- package/components/ui/dropdown-menu/dropdown-menu.stories.tsx +156 -156
- package/components/ui/dropdown-menu/dropdown-menu.test.tsx +62 -62
- package/components/ui/dropdown-menu/dropdown-menu.tsx +240 -240
- package/components/ui/dropdown-menu/index.ts +1 -1
- package/components/ui/empty/empty.stories.tsx +85 -85
- package/components/ui/empty/empty.test.tsx +31 -31
- package/components/ui/empty/empty.tsx +88 -88
- package/components/ui/empty/index.ts +1 -1
- package/components/ui/file-upload/file-upload.stories.tsx +144 -144
- package/components/ui/file-upload/file-upload.test.tsx +65 -65
- package/components/ui/file-upload/file-upload.tsx +142 -142
- package/components/ui/file-upload/index.ts +2 -2
- package/components/ui/file-upload/use-file-upload.ts +177 -177
- package/components/ui/form/form.stories.tsx +85 -85
- package/components/ui/form/form.test.tsx +75 -75
- package/components/ui/form/form.tsx +163 -163
- package/components/ui/form/index.ts +1 -1
- package/components/ui/google-maps-loader/google-maps-loader.test.tsx +35 -35
- package/components/ui/google-maps-loader/google-maps-loader.tsx +465 -465
- package/components/ui/google-maps-loader/index.ts +1 -1
- package/components/ui/hover-card/hover-card.stories.tsx +61 -61
- package/components/ui/hover-card/hover-card.test.tsx +48 -48
- package/components/ui/hover-card/hover-card.tsx +50 -50
- package/components/ui/hover-card/index.ts +1 -1
- package/components/ui/index.ts +400 -400
- package/components/ui/input/index.ts +1 -1
- package/components/ui/input/input.stories.tsx +153 -153
- package/components/ui/input/input.test.tsx +47 -47
- package/components/ui/input/input.tsx +57 -57
- package/components/ui/input-otp/index.ts +1 -1
- package/components/ui/input-otp/input-otp.stories.tsx +120 -120
- package/components/ui/input-otp/input-otp.test.tsx +74 -74
- package/components/ui/input-otp/input-otp.tsx +101 -101
- package/components/ui/label/index.ts +1 -1
- package/components/ui/label/label.stories.tsx +74 -74
- package/components/ui/label/label.test.tsx +45 -45
- package/components/ui/label/label.tsx +53 -53
- package/components/ui/map/index.ts +1 -1
- package/components/ui/map/map.stories.tsx +86 -86
- package/components/ui/map/map.test.tsx +82 -82
- package/components/ui/map/map.tsx +506 -506
- package/components/ui/map/mock.test.tsx +13 -13
- package/components/ui/map-config/index.ts +1 -1
- package/components/ui/map-config/map-config.ts +18 -18
- package/components/ui/map-layers/index.ts +1 -1
- package/components/ui/map-layers/map-layers.test.tsx +48 -48
- package/components/ui/map-layers/map-layers.tsx +126 -126
- package/components/ui/map.exports/index.ts +1 -1
- package/components/ui/map.exports/map.exports.ts +31 -31
- package/components/ui/menubar/index.ts +1 -1
- package/components/ui/menubar/menubar.stories.tsx +130 -130
- package/components/ui/menubar/menubar.test.tsx +53 -53
- package/components/ui/menubar/menubar.tsx +265 -265
- package/components/ui/navigation-menu/index.ts +1 -1
- package/components/ui/navigation-menu/navigation-menu.stories.tsx +126 -126
- package/components/ui/navigation-menu/navigation-menu.test.tsx +47 -47
- package/components/ui/navigation-menu/navigation-menu.tsx +165 -165
- package/components/ui/notification-badge/index.ts +1 -1
- package/components/ui/notification-badge/notification-badge.stories.tsx +66 -66
- package/components/ui/notification-badge/notification-badge.test.tsx +61 -61
- package/components/ui/notification-badge/notification-badge.tsx +91 -91
- package/components/ui/page-header/index.ts +1 -1
- package/components/ui/page-header/page-header.stories.tsx +69 -69
- package/components/ui/page-header/page-header.test.tsx +37 -37
- package/components/ui/page-header/page-header.tsx +124 -124
- package/components/ui/pagination/index.ts +3 -3
- package/components/ui/pagination/pagination.stories.tsx +210 -210
- package/components/ui/pagination/pagination.test.tsx +63 -63
- package/components/ui/pagination/pagination.tsx +140 -140
- package/components/ui/pagination/use-pagination.ts +173 -173
- package/components/ui/popover/index.ts +1 -1
- package/components/ui/popover/popover.stories.tsx +73 -73
- package/components/ui/popover/popover.test.tsx +48 -48
- package/components/ui/popover/popover.tsx +54 -54
- package/components/ui/progress/index.ts +1 -1
- package/components/ui/progress/progress.stories.tsx +55 -55
- package/components/ui/progress/progress.test.tsx +23 -23
- package/components/ui/progress/progress.tsx +68 -68
- package/components/ui/radio-group/index.ts +1 -1
- package/components/ui/radio-group/radio-group.stories.tsx +114 -114
- package/components/ui/radio-group/radio-group.test.tsx +78 -78
- package/components/ui/radio-group/radio-group.tsx +93 -93
- package/components/ui/rating/index.ts +1 -1
- package/components/ui/rating/rating.stories.tsx +50 -50
- package/components/ui/rating/rating.test.tsx +48 -48
- package/components/ui/rating/rating.tsx +145 -145
- package/components/ui/resizable/index.ts +1 -1
- package/components/ui/resizable/resizable.stories.tsx +88 -88
- package/components/ui/resizable/resizable.test.tsx +61 -61
- package/components/ui/resizable/resizable.tsx +452 -452
- package/components/ui/rich-text-editor/index.ts +7 -7
- package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +290 -290
- package/components/ui/rich-text-editor/rich-text-editor.test.tsx +86 -86
- package/components/ui/rich-text-editor/rich-text-editor.tsx +634 -634
- package/components/ui/rich-text-editor/use-rich-text-editor.ts +453 -453
- package/components/ui/route-map/index.ts +1 -1
- package/components/ui/route-map/route-map.stories.tsx +48 -48
- package/components/ui/route-map/route-map.test.tsx +108 -108
- package/components/ui/route-map/route-map.tsx +349 -349
- package/components/ui/scroll-area/index.ts +1 -1
- package/components/ui/scroll-area/scroll-area.stories.tsx +31 -31
- package/components/ui/scroll-area/scroll-area.test.tsx +27 -27
- package/components/ui/scroll-area/scroll-area.tsx +70 -70
- package/components/ui/search/index.ts +1 -1
- package/components/ui/search/search.stories.tsx +107 -107
- package/components/ui/search/search.test.tsx +67 -67
- package/components/ui/search/search.tsx +141 -141
- package/components/ui/select/index.ts +1 -1
- package/components/ui/select/select.stories.tsx +163 -163
- package/components/ui/select/select.test.tsx +99 -99
- package/components/ui/select/select.tsx +195 -195
- package/components/ui/separator/index.ts +1 -1
- package/components/ui/separator/separator.stories.tsx +55 -55
- package/components/ui/separator/separator.test.tsx +23 -23
- package/components/ui/separator/separator.tsx +39 -39
- package/components/ui/sheet/index.ts +1 -1
- package/components/ui/sheet/sheet.stories.tsx +93 -93
- package/components/ui/sheet/sheet.test.tsx +62 -62
- package/components/ui/sheet/sheet.tsx +149 -149
- package/components/ui/simple-map/index.ts +1 -1
- package/components/ui/simple-map/simple-map.stories.tsx +44 -44
- package/components/ui/simple-map/simple-map.test.tsx +36 -36
- package/components/ui/simple-map/simple-map.tsx +92 -92
- package/components/ui/skeleton/index.ts +1 -1
- package/components/ui/skeleton/skeleton.stories.tsx +36 -36
- package/components/ui/skeleton/skeleton.test.tsx +19 -19
- package/components/ui/skeleton/skeleton.tsx +25 -25
- package/components/ui/slider/index.ts +1 -1
- package/components/ui/slider/slider.stories.tsx +44 -44
- package/components/ui/slider/slider.test.tsx +25 -25
- package/components/ui/slider/slider.tsx +66 -66
- package/components/ui/sonner/index.ts +1 -1
- package/components/ui/sonner/sonner.stories.tsx +41 -41
- package/components/ui/sonner/sonner.test.tsx +24 -24
- package/components/ui/sonner/sonner.tsx +74 -74
- package/components/ui/stats-card/index.ts +2 -2
- package/components/ui/stats-card/stats-card-skeleton.tsx +1 -3
- package/components/ui/stats-card/stats-card.stories.tsx +99 -99
- package/components/ui/stats-card/stats-card.test.tsx +34 -34
- package/components/ui/stats-card/stats-card.tsx +93 -93
- package/components/ui/stepper/index.ts +3 -3
- package/components/ui/stepper/stepper.stories.tsx +171 -171
- package/components/ui/stepper/stepper.test.tsx +47 -47
- package/components/ui/stepper/stepper.tsx +190 -190
- package/components/ui/stepper/use-stepper.ts +139 -139
- package/components/ui/switch/index.ts +1 -1
- package/components/ui/switch/switch.stories.tsx +93 -93
- package/components/ui/switch/switch.test.tsx +44 -44
- package/components/ui/switch/switch.tsx +70 -70
- package/components/ui/table/index.ts +1 -1
- package/components/ui/table/table.stories.tsx +114 -114
- package/components/ui/table/table.test.tsx +43 -43
- package/components/ui/table/table.tsx +104 -104
- package/components/ui/tabs/index.ts +1 -1
- package/components/ui/tabs/tabs.stories.tsx +140 -140
- package/components/ui/tabs/tabs.test.tsx +50 -50
- package/components/ui/tabs/tabs.tsx +66 -66
- package/components/ui/textarea/index.ts +1 -1
- package/components/ui/textarea/textarea.stories.tsx +69 -69
- package/components/ui/textarea/textarea.test.tsx +41 -41
- package/components/ui/textarea/textarea.tsx +61 -61
- package/components/ui/timeline/index.ts +1 -1
- package/components/ui/timeline/timeline.stories.tsx +97 -97
- package/components/ui/timeline/timeline.test.tsx +53 -53
- package/components/ui/timeline/timeline.tsx +124 -124
- package/components/ui/toggle/index.ts +1 -1
- package/components/ui/toggle/toggle.stories.tsx +56 -56
- package/components/ui/toggle/toggle.test.tsx +32 -32
- package/components/ui/toggle/toggle.tsx +55 -55
- package/components/ui/toggle-group/index.ts +1 -1
- package/components/ui/toggle-group/toggle-group.stories.tsx +66 -66
- package/components/ui/toggle-group/toggle-group.test.tsx +47 -47
- package/components/ui/toggle-group/toggle-group.tsx +79 -79
- package/components/ui/tooltip/index.ts +1 -1
- package/components/ui/tooltip/tooltip.stories.tsx +83 -83
- package/components/ui/tooltip/tooltip.test.tsx +39 -39
- package/components/ui/tooltip/tooltip.tsx +69 -69
- package/components/ui/tree-view/index.ts +4 -4
- package/components/ui/tree-view/tree-view.stories.tsx +154 -154
- package/components/ui/tree-view/tree-view.test.tsx +58 -58
- package/components/ui/tree-view/tree-view.tsx +171 -171
- package/components/ui/tree-view/use-tree-view.ts +237 -237
- package/components.json +892 -892
- package/contexts/ApiKeyContext.test.tsx +26 -26
- package/contexts/ApiKeyContext.tsx +196 -196
- package/contexts/AssistenteContext.test.tsx +17 -17
- package/contexts/AssistenteContext.tsx +113 -113
- package/contexts/AuthContext.tsx +121 -118
- package/contexts/BrandColorsContext.test.tsx +21 -21
- package/contexts/BrandColorsContext.tsx +251 -251
- package/contexts/LanguageContext.tsx +1 -2
- package/contexts/LayoutContext.test.tsx +29 -29
- package/contexts/LayoutContext.tsx +140 -140
- package/contexts/ThemeContext.test.tsx +38 -38
- package/contexts/ThemeContext.tsx +111 -111
- package/contexts/index.ts +8 -8
- package/contexts/theme-data.ts +340 -340
- package/dist/AssistantChart-COGiOV-g.cjs +3541 -0
- package/dist/AssistantChart-CWX1OWNM.js +3373 -0
- package/dist/AudioPlayer-9psiEucT.cjs +1282 -0
- package/dist/AudioPlayer-Dp2bD1Gk.js +1278 -0
- package/dist/BrandColorsContext-DZT7JjeD.js +659 -0
- package/dist/BrandColorsContext-awnBCmC4.cjs +666 -0
- package/dist/CodeBlock-DYkTfR0f.js +221 -0
- package/dist/CodeBlock-EOvp9cVu.cjs +223 -0
- package/dist/CustomTooltipContent-BhdIeBEg.cjs +54 -0
- package/dist/CustomTooltipContent-CNbVB2NS.js +33 -0
- package/dist/FeatureCard-BZ4CYxFf.cjs +497 -0
- package/dist/FeatureCard-DNycVGwT.js +485 -0
- package/dist/FeatureCardSkeleton-DZqc96mt.js +27 -0
- package/dist/FeatureCardSkeleton-pTa0YNKP.cjs +29 -0
- package/dist/LayoutContext-BEq_-n98.cjs +96 -0
- package/dist/LayoutContext-DNl1xSoX.js +92 -0
- package/dist/ThemeContext-CMD3z2Dz.cjs +1930 -0
- package/dist/ThemeContext-x_F2zsnv.js +1923 -0
- package/dist/VerifyEmailPage-BJjAMUTW.js +3223 -0
- package/dist/VerifyEmailPage-Bv8Ah_TK.cjs +3235 -0
- package/dist/VerifyEmailPage-CkBYfsNy.cjs +3232 -0
- package/dist/VerifyEmailPage-Cyl55sJb.js +3226 -0
- package/dist/VerifyEmailPage-X14vhdyl.js +3296 -0
- package/dist/VerifyEmailPage-u_Dn7t1U.cjs +3305 -0
- package/dist/XerticaOrbe-Uk2JML1-.cjs +1927 -0
- package/dist/XerticaOrbe-jA5T2iOk.js +1925 -0
- package/dist/XerticaProvider-BErr83Bg.js +42 -0
- package/dist/XerticaProvider-CwOkHxiT.cjs +44 -0
- package/dist/XerticaProvider-DUOJg9iX.js +49 -0
- package/dist/XerticaProvider-Dl_b72_l.cjs +51 -0
- package/dist/XerticaXLogo-BX3ueACh.js +255 -0
- package/dist/XerticaXLogo-mqjoBiLI.js +252 -0
- package/dist/XerticaXLogo-qBPhwK3g.cjs +260 -0
- package/dist/XerticaXLogo-uQgwns_E.cjs +257 -0
- package/dist/alert-dialog-DhwPioBa.cjs +885 -0
- package/dist/alert-dialog-DqlRW_An.js +831 -0
- package/dist/assistant.cjs.js +8 -4
- package/dist/assistant.es.js +5 -11
- package/dist/avatar-3kO2Anrp.js +54 -0
- package/dist/avatar-BCM7YQRC.cjs +77 -0
- package/dist/blocks.cjs.js +9 -4
- package/dist/blocks.es.js +2 -16
- package/dist/brand.cjs.js +10 -5
- package/dist/brand.es.js +3 -11
- package/dist/breadcrumb-BKtHF4gk.cjs +98 -0
- package/dist/breadcrumb-ifNsA7Zl.js +90 -0
- package/dist/button-0BlA47It.cjs +85 -0
- package/dist/button-DZHzN1Gd.js +62 -0
- package/dist/cli.js +471 -93
- package/dist/components/brand/theme-toggle/ThemeToggle.d.ts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/dropdown-menu-BMcykFDf.cjs +225 -0
- package/dist/dropdown-menu-Dn_eV2Xb.js +190 -0
- package/dist/google-maps-loader-BCe58h9D.js +308 -0
- package/dist/google-maps-loader-casMyxlo.cjs +316 -0
- package/dist/hooks.cjs.js +12 -8
- package/dist/hooks.es.js +10 -27
- package/dist/index-9GWd0qxq.cjs +12 -0
- package/dist/index-BabBx2pa.js +6 -0
- package/dist/index.cjs.js +37 -32
- package/dist/index.es.js +30 -363
- package/dist/input-C_UiS2Py.cjs +152 -0
- package/dist/input-cc-PTD4R.js +123 -0
- package/dist/layout.cjs.js +10 -6
- package/dist/layout.es.js +7 -9
- package/dist/media.cjs.js +8 -3
- package/dist/media.es.js +1 -6
- package/dist/pages.cjs.js +8 -3
- package/dist/pages.es.js +1 -11
- package/dist/progress-C7Lti5wo.js +80 -0
- package/dist/progress-Cqwxbqs1.cjs +103 -0
- package/dist/rich-text-editor-DqLICivI.js +2832 -0
- package/dist/rich-text-editor-DxO1Hz3a.cjs +2903 -0
- package/dist/select-CH6v_KcQ.cjs +161 -0
- package/dist/select-D-xvCZK2.js +130 -0
- package/dist/sidebar-3XyzjVBw.js +792 -0
- package/dist/sidebar-B4ZWaMrE.js +792 -0
- package/dist/sidebar-BS1p2V7t.cjs +795 -0
- package/dist/sidebar-DyYvgyBj.cjs +795 -0
- package/dist/skeleton-DjiHerJn.cjs +87 -0
- package/dist/skeleton-DtR5tkYe.js +78 -0
- package/dist/slider-B00b9SVK.cjs +78 -0
- package/dist/slider-DQCNUUMj.js +56 -0
- package/dist/sonner-B-jWlik1.cjs +68 -0
- package/dist/sonner-C9tiqj4f.js +47 -0
- package/dist/tooltip-D8n9UYoU.cjs +72 -0
- package/dist/tooltip-RtbSmPYJ.js +48 -0
- package/dist/ui.cjs.js +23 -18
- package/dist/ui.es.js +16 -303
- package/dist/use-audio-player-B78fd2ct.js +188 -0
- package/dist/use-audio-player-DGvhPrgR.cjs +190 -0
- package/dist/use-mobile-BdXTRb0Z.cjs +51 -0
- package/dist/use-mobile-Ce2cBAQe.js +29 -0
- package/dist/xertica-assistant-B1NaSFFj.js +2173 -0
- package/dist/xertica-assistant-B687qEPU.js +2165 -0
- package/dist/xertica-assistant-CIaUlbIt.cjs +2180 -0
- package/dist/xertica-assistant-sOHwTgIP.cjs +2172 -0
- package/dist/xertica-ui.css +1 -1
- package/docs/ai-usage.md +195 -195
- package/docs/architecture-improvements.md +456 -456
- package/docs/architecture.md +312 -306
- package/docs/components/accordion.md +109 -109
- package/docs/components/alert-dialog.md +127 -127
- package/docs/components/alert.md +106 -106
- package/docs/components/aspect-ratio.md +58 -58
- package/docs/components/assistant-chart.md +47 -47
- package/docs/components/assistant.md +428 -426
- package/docs/components/audio-player.md +167 -167
- package/docs/components/avatar.md +101 -101
- package/docs/components/badge.md +84 -84
- package/docs/components/branding.md +252 -252
- package/docs/components/breadcrumb.md +104 -104
- package/docs/components/button.md +156 -156
- package/docs/components/calendar.md +141 -141
- package/docs/components/card-patterns.md +447 -445
- package/docs/components/card.md +245 -245
- package/docs/components/carousel.md +100 -100
- package/docs/components/chart.md +638 -638
- package/docs/components/checkbox.md +88 -88
- package/docs/components/code-block.md +105 -105
- package/docs/components/collapsible.md +86 -86
- package/docs/components/command.md +113 -113
- package/docs/components/context-menu.md +81 -81
- package/docs/components/dialog.md +198 -198
- package/docs/components/drawer.md +105 -105
- package/docs/components/dropdown-menu.md +127 -127
- package/docs/components/empty.md +127 -127
- package/docs/components/error-boundary.md +201 -191
- package/docs/components/file-upload.md +189 -189
- package/docs/components/floating-media-wrapper.md +63 -63
- package/docs/components/form.md +177 -177
- package/docs/components/formatted-document.md +105 -105
- package/docs/components/google-maps-loader.md +44 -44
- package/docs/components/header.md +177 -177
- package/docs/components/hooks.md +432 -430
- package/docs/components/hover-card.md +86 -86
- package/docs/components/image-with-fallback.md +107 -107
- package/docs/components/input-otp.md +95 -95
- package/docs/components/input.md +130 -130
- package/docs/components/label.md +69 -69
- package/docs/components/language-selector.md +20 -16
- package/docs/components/map-layers.md +138 -138
- package/docs/components/map.md +84 -84
- package/docs/components/markdown-message.md +47 -47
- package/docs/components/menubar.md +89 -89
- package/docs/components/modern-chat-input.md +164 -164
- package/docs/components/navigation-menu.md +83 -83
- package/docs/components/notification-badge.md +78 -78
- package/docs/components/page-header.md +93 -93
- package/docs/components/pages.md +323 -309
- package/docs/components/pagination.md +334 -334
- package/docs/components/popover.md +116 -116
- package/docs/components/progress.md +103 -103
- package/docs/components/radio-group.md +133 -133
- package/docs/components/rating.md +77 -77
- package/docs/components/resizable.md +84 -84
- package/docs/components/rich-text-editor.md +255 -255
- package/docs/components/route-map.md +124 -124
- package/docs/components/scroll-area.md +58 -58
- package/docs/components/search.md +87 -87
- package/docs/components/select.md +144 -144
- package/docs/components/separator.md +58 -58
- package/docs/components/sheet.md +122 -122
- package/docs/components/sidebar.md +314 -314
- package/docs/components/simple-map.md +51 -51
- package/docs/components/skeleton.md +99 -99
- package/docs/components/slider.md +84 -84
- package/docs/components/sonner.md +115 -115
- package/docs/components/stats-card.md +120 -120
- package/docs/components/stepper.md +268 -268
- package/docs/components/switch.md +106 -106
- package/docs/components/table.md +138 -138
- package/docs/components/tabs.md +117 -117
- package/docs/components/textarea.md +86 -86
- package/docs/components/theme-toggle.md +73 -73
- package/docs/components/timeline.md +121 -121
- package/docs/components/toggle-group.md +68 -68
- package/docs/components/toggle.md +62 -62
- package/docs/components/tooltip.md +116 -116
- package/docs/components/tree-view.md +238 -238
- package/docs/components/use-mobile.md +96 -96
- package/docs/components/video-player.md +68 -68
- package/docs/components/xertica-logo.md +36 -36
- package/docs/components/xertica-orbe.md +35 -35
- package/docs/components/xertica-provider.md +65 -65
- package/docs/components/xertica-xlogo.md +35 -35
- package/docs/decision-tree.md +293 -293
- package/docs/doc-audit.md +244 -243
- package/docs/form-sizing.md +162 -162
- package/docs/getting-started.md +616 -591
- package/docs/guidelines.md +330 -328
- package/docs/i18n.md +61 -57
- package/docs/installation.md +268 -267
- package/docs/layout.md +143 -143
- package/docs/llms.md +295 -295
- package/docs/patterns/analytics.md +194 -194
- package/docs/patterns/crud.md +149 -149
- package/docs/patterns/dashboard.md +138 -138
- package/docs/patterns/detail-page.md +296 -296
- package/docs/patterns/form.md +241 -241
- package/docs/patterns/login.md +156 -156
- package/docs/patterns/settings.md +368 -368
- package/docs/patterns/wizard.md +213 -213
- package/docs/state-management.md +289 -289
- package/guidelines/Guidelines.md +409 -406
- package/hooks/useTheme.test.tsx +16 -16
- package/hooks/useTheme.ts +4 -4
- package/imports/Podcast.tsx +540 -540
- package/imports/XerticaAi.tsx +46 -46
- package/imports/XerticaX.tsx +15 -15
- package/imports/svg-aueiaqngck.ts +20 -20
- package/imports/svg-v9krss1ozd.ts +23 -23
- package/imports/svg-vhrdofe3qe.ts +6 -6
- package/llms-compact.txt +2 -1
- package/llms.txt +2 -1
- package/mcp/resources.json +22 -22
- package/mcp/tools.json +35 -35
- package/package.json +219 -213
- package/scripts/ai-validator.ts +91 -91
- package/scripts/cleanup-case-dupes.ts +62 -62
- package/scripts/generate-ai-manifests.ts +107 -107
- package/styles/globals.css +13 -13
- package/styles/xertica/app-overrides/chat.css +61 -61
- package/styles/xertica/app-overrides/scrollbar.css +33 -33
- package/styles/xertica/base.css +90 -71
- package/styles/xertica/integrations/google-maps.css +76 -76
- package/styles/xertica/integrations/sonner.css +73 -73
- package/styles/xertica/theme-map.css +102 -99
- package/styles/xertica/tokens.css +240 -236
- package/templates/CLAUDE.md +16 -1
- package/templates/eslint.config.js +26 -26
- package/templates/guidelines/Guidelines.md +577 -553
- package/templates/package.json +69 -69
- package/templates/postcss.config.js +6 -6
- package/templates/src/app/App.tsx +46 -46
- package/templates/src/app/components/AppLayout.tsx +55 -55
- package/templates/src/app/components/AuthGuard.tsx +131 -82
- package/templates/src/app/context/AuthContext.tsx +108 -108
- package/templates/src/features/assistant/index.ts +5 -5
- package/templates/src/features/auth/index.ts +4 -4
- package/templates/src/features/auth/ui/AuthPageShell.tsx +32 -32
- package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +70 -72
- package/templates/src/features/auth/ui/LoginContent.tsx +92 -92
- package/templates/src/features/auth/ui/ResetPasswordContent.tsx +6 -2
- package/templates/src/features/auth/ui/SocialLoginButtons.tsx +78 -78
- package/templates/src/features/auth/ui/VerifyEmailContent.tsx +2 -6
- package/templates/src/features/home/data/mock.ts +41 -35
- package/templates/src/features/home/index.ts +11 -11
- package/templates/src/features/home/store/dashboardStore.ts +25 -25
- package/templates/src/features/home/ui/HomeContent.tsx +117 -119
- package/templates/src/features/template/index.ts +5 -5
- package/templates/src/features/template/ui/CrudTemplate.tsx +1 -4
- package/templates/src/features/template/ui/LoginTemplate.tsx +1 -1
- package/templates/src/features/template/ui/TemplateContent.tsx +29 -21
- package/templates/src/locales/en/pages/templates.json +17 -17
- package/templates/src/locales/es/pages/templates.json +17 -17
- package/templates/src/locales/pt-BR/pages/templates.json +17 -17
- package/templates/src/main.tsx +11 -11
- package/templates/src/pages/AssistantPage.tsx +26 -20
- package/templates/src/pages/ForgotPasswordPage.tsx +6 -6
- package/templates/src/pages/HomePage.tsx +53 -49
- package/templates/src/pages/LoginPage.tsx +10 -10
- package/templates/src/pages/ResetPasswordPage.tsx +6 -6
- package/templates/src/pages/TemplatePage.tsx +28 -28
- package/templates/src/pages/VerifyEmailPage.tsx +6 -6
- package/templates/src/shared/config/navigation.ts +19 -19
- package/templates/src/shared/error-boundary.tsx +150 -154
- package/templates/src/shared/error-fallbacks.tsx +222 -226
- package/templates/src/shared/lib/auth.ts +20 -20
- package/templates/src/shared/types/auth.ts +3 -3
- package/templates/src/styles/index.css +95 -95
- package/templates/src/styles/xertica/tokens.css +240 -236
- package/templates/tsconfig.json +25 -25
- package/templates/tsconfig.node.json +12 -12
- package/templates/vite-env.d.ts +1 -1
- package/templates/vite.config.js +20 -20
- package/templates/vite.config.ts +54 -51
- package/utils/color-utils.ts +72 -72
- package/utils/demo-responses.test.ts +10 -10
- package/utils/demo-responses.ts +151 -151
- package/utils/gemini.test.ts +25 -25
- package/utils/gemini.ts +155 -155
|
@@ -1,334 +1,334 @@
|
|
|
1
|
-
# Pagination
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
A navigation control for moving through pages of a large dataset. Renders Previous/Next buttons, numbered page buttons, and ellipsis for large page counts. Use it below data tables to control which page of records is displayed.
|
|
6
|
-
|
|
7
|
-
The package also exports a **headless `usePagination` hook** that computes the full page item list (numbers + ellipsis) and exposes navigation helpers — use it when you need full control over the pagination UI.
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Exports
|
|
12
|
-
|
|
13
|
-
| Export | Description |
|
|
14
|
-
| --------------------- | ---------------------------------------------- |
|
|
15
|
-
| `Pagination` | Root nav wrapper |
|
|
16
|
-
| `PaginationContent` | Flex container for all items |
|
|
17
|
-
| `PaginationItem` | Individual item wrapper |
|
|
18
|
-
| `PaginationLink` | Numbered page button |
|
|
19
|
-
| `PaginationPrevious` | "Previous" button with left arrow |
|
|
20
|
-
| `PaginationNext` | "Next" button with right arrow |
|
|
21
|
-
| `PaginationEllipsis` | "..." indicator for skipped pages |
|
|
22
|
-
| `usePagination` | Headless hook — all logic, no UI |
|
|
23
|
-
| `UsePaginationProps` | TypeScript props type for the hook |
|
|
24
|
-
| `UsePaginationReturn` | TypeScript return type for the hook |
|
|
25
|
-
| `PaginationPageItem` | Union type for page items returned by the hook |
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## When to Use
|
|
30
|
-
|
|
31
|
-
- Below tables with more records than fit on one page
|
|
32
|
-
- Any paginated list or grid of content
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Anatomy
|
|
37
|
-
|
|
38
|
-
```
|
|
39
|
-
<Pagination>
|
|
40
|
-
<PaginationContent>
|
|
41
|
-
<PaginationItem><PaginationPrevious href="#" /></PaginationItem>
|
|
42
|
-
<PaginationItem><PaginationLink href="#">1</PaginationLink></PaginationItem>
|
|
43
|
-
<PaginationItem><PaginationEllipsis /></PaginationItem>
|
|
44
|
-
<PaginationItem><PaginationLink href="#" isActive>5</PaginationLink></PaginationItem>
|
|
45
|
-
<PaginationItem><PaginationNext href="#" /></PaginationItem>
|
|
46
|
-
</PaginationContent>
|
|
47
|
-
</Pagination>
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## Sub-Components
|
|
53
|
-
|
|
54
|
-
| Component | Description |
|
|
55
|
-
| -------------------- | --------------------------------- |
|
|
56
|
-
| `Pagination` | Root nav wrapper |
|
|
57
|
-
| `PaginationContent` | Flex container for all items |
|
|
58
|
-
| `PaginationItem` | Individual item wrapper |
|
|
59
|
-
| `PaginationLink` | Numbered page button |
|
|
60
|
-
| `PaginationPrevious` | "Previous" button with left arrow |
|
|
61
|
-
| `PaginationNext` | "Next" button with right arrow |
|
|
62
|
-
| `PaginationEllipsis` | "..." indicator for skipped pages |
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Props
|
|
67
|
-
|
|
68
|
-
### PaginationLink
|
|
69
|
-
|
|
70
|
-
| Prop | Type | Description |
|
|
71
|
-
| ---------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
72
|
-
| `href` | `string` | URL for the page |
|
|
73
|
-
| `isActive` | `boolean` | When `true`, renders as the active page |
|
|
74
|
-
| `disabled` | `boolean` | When `true`, renders as non-interactive: removes `href`, sets `aria-disabled`, `tabIndex={-1}`, and `pointer-events-none opacity-50` |
|
|
75
|
-
| `onClick` | `() => void` | Click handler (for controlled pagination) |
|
|
76
|
-
|
|
77
|
-
### PaginationPrevious / PaginationNext
|
|
78
|
-
|
|
79
|
-
Both components accept and forward a `disabled` prop to `PaginationLink`. Pass `disabled={!canGoPrev}` / `disabled={!canGoNext}` to disable the controls when at the first or last page — this is the preferred pattern over `aria-disabled` alone.
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Examples
|
|
84
|
-
|
|
85
|
-
### Controlled Pagination
|
|
86
|
-
|
|
87
|
-
```tsx
|
|
88
|
-
import {
|
|
89
|
-
Pagination,
|
|
90
|
-
PaginationContent,
|
|
91
|
-
PaginationItem,
|
|
92
|
-
PaginationLink,
|
|
93
|
-
PaginationNext,
|
|
94
|
-
PaginationPrevious,
|
|
95
|
-
PaginationEllipsis,
|
|
96
|
-
} from 'xertica-ui/ui';
|
|
97
|
-
import { useState } from 'react';
|
|
98
|
-
|
|
99
|
-
const [currentPage, setCurrentPage] = useState(1);
|
|
100
|
-
const totalPages = 10;
|
|
101
|
-
|
|
102
|
-
<Pagination>
|
|
103
|
-
<PaginationContent>
|
|
104
|
-
<PaginationItem>
|
|
105
|
-
<PaginationPrevious onClick={() => setCurrentPage(p => Math.max(1, p - 1))} />
|
|
106
|
-
</PaginationItem>
|
|
107
|
-
{[1, 2, 3].map(page => (
|
|
108
|
-
<PaginationItem key={page}>
|
|
109
|
-
<PaginationLink isActive={currentPage === page} onClick={() => setCurrentPage(page)}>
|
|
110
|
-
{page}
|
|
111
|
-
</PaginationLink>
|
|
112
|
-
</PaginationItem>
|
|
113
|
-
))}
|
|
114
|
-
<PaginationItem>
|
|
115
|
-
<PaginationEllipsis />
|
|
116
|
-
</PaginationItem>
|
|
117
|
-
<PaginationItem>
|
|
118
|
-
<PaginationLink onClick={() => setCurrentPage(totalPages)}>{totalPages}</PaginationLink>
|
|
119
|
-
</PaginationItem>
|
|
120
|
-
<PaginationItem>
|
|
121
|
-
<PaginationNext onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))} />
|
|
122
|
-
</PaginationItem>
|
|
123
|
-
</PaginationContent>
|
|
124
|
-
</Pagination>;
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## `usePagination` Hook
|
|
130
|
-
|
|
131
|
-
A headless hook that computes the full page item list (page numbers + ellipsis markers) and exposes navigation helpers. Supports both **uncontrolled** (internal state) and **controlled** (external `page` prop) modes.
|
|
132
|
-
|
|
133
|
-
### Props
|
|
134
|
-
|
|
135
|
-
| Prop | Type | Default | Description |
|
|
136
|
-
| -------------- | ------------------------ | ------- | ------------------------------------------------------------------------------------------- |
|
|
137
|
-
| `totalItems` | `number` | — | **Required.** Total number of items across all pages |
|
|
138
|
-
| `pageSize` | `number` | `10` | Number of items per page |
|
|
139
|
-
| `initialPage` | `number` | `1` | Initial page (uncontrolled mode only) |
|
|
140
|
-
| `page` | `number` | — | Controlled current page — when provided, the hook uses this value instead of internal state |
|
|
141
|
-
| `onPageChange` | `(page: number) => void` | — | Called whenever the page changes |
|
|
142
|
-
| `siblingCount` | `number` | `1` | Number of page buttons to show on each side of the current page |
|
|
143
|
-
|
|
144
|
-
### Return Value
|
|
145
|
-
|
|
146
|
-
| Property | Type | Description |
|
|
147
|
-
| ------------- | ------------------------ | ----------------------------------------------------------------- |
|
|
148
|
-
| `currentPage` | `number` | The currently active page (1-indexed) |
|
|
149
|
-
| `totalPages` | `number` | Total number of pages |
|
|
150
|
-
| `startIndex` | `number` | Zero-based index of the first item on the current page |
|
|
151
|
-
| `endIndex` | `number` | Zero-based index of the last item on the current page (exclusive) |
|
|
152
|
-
| `canGoPrev` | `boolean` | Whether navigating to the previous page is possible |
|
|
153
|
-
| `canGoNext` | `boolean` | Whether navigating to the next page is possible |
|
|
154
|
-
| `isFirstPage` | `boolean` | Whether the current page is the first page |
|
|
155
|
-
| `isLastPage` | `boolean` | Whether the current page is the last page |
|
|
156
|
-
| `items` | `PaginationPageItem[]` | Ordered list of page items to render (see below) |
|
|
157
|
-
| `goTo` | `(page: number) => void` | Navigate to a specific page number |
|
|
158
|
-
| `next` | `() => void` | Navigate to the next page |
|
|
159
|
-
| `prev` | `() => void` | Navigate to the previous page |
|
|
160
|
-
| `first` | `() => void` | Navigate to the first page |
|
|
161
|
-
| `last` | `() => void` | Navigate to the last page |
|
|
162
|
-
|
|
163
|
-
### `PaginationPageItem` Type
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
type PaginationPageItem = { type: 'page'; page: number } | { type: 'ellipsis'; key: string };
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
The `items` array is ready to render directly — map over it and render `<PaginationLink>` for `type: 'page'` items and `<PaginationEllipsis>` for `type: 'ellipsis'` items.
|
|
170
|
-
|
|
171
|
-
### Uncontrolled Example
|
|
172
|
-
|
|
173
|
-
```tsx
|
|
174
|
-
import {
|
|
175
|
-
usePagination,
|
|
176
|
-
Pagination,
|
|
177
|
-
PaginationContent,
|
|
178
|
-
PaginationItem,
|
|
179
|
-
PaginationLink,
|
|
180
|
-
PaginationPrevious,
|
|
181
|
-
PaginationNext,
|
|
182
|
-
PaginationEllipsis,
|
|
183
|
-
} from 'xertica-ui/ui';
|
|
184
|
-
|
|
185
|
-
function MyTable({ data }: { data: Record<string, unknown>[] }) {
|
|
186
|
-
const { currentPage, startIndex, endIndex, canGoPrev, canGoNext, items, next, prev, goTo } =
|
|
187
|
-
usePagination({ totalItems: data.length, pageSize: 10 });
|
|
188
|
-
|
|
189
|
-
const pageData = data.slice(startIndex, endIndex);
|
|
190
|
-
|
|
191
|
-
return (
|
|
192
|
-
<div className="space-y-4">
|
|
193
|
-
<table>{/* render pageData rows */}</table>
|
|
194
|
-
|
|
195
|
-
<Pagination>
|
|
196
|
-
<PaginationContent>
|
|
197
|
-
<PaginationItem>
|
|
198
|
-
{/* Use disabled prop — not aria-disabled — for full a11y (removes href, tabIndex, pointer-events) */}
|
|
199
|
-
<PaginationPrevious
|
|
200
|
-
href="#"
|
|
201
|
-
onClick={e => {
|
|
202
|
-
e.preventDefault();
|
|
203
|
-
prev();
|
|
204
|
-
}}
|
|
205
|
-
disabled={!canGoPrev}
|
|
206
|
-
/>
|
|
207
|
-
</PaginationItem>
|
|
208
|
-
|
|
209
|
-
{items.map(item =>
|
|
210
|
-
item.type === 'ellipsis' ? (
|
|
211
|
-
<PaginationItem key={item.key}>
|
|
212
|
-
<PaginationEllipsis />
|
|
213
|
-
</PaginationItem>
|
|
214
|
-
) : (
|
|
215
|
-
<PaginationItem key={item.page}>
|
|
216
|
-
<PaginationLink
|
|
217
|
-
href="#"
|
|
218
|
-
isActive={item.page === currentPage}
|
|
219
|
-
onClick={e => {
|
|
220
|
-
e.preventDefault();
|
|
221
|
-
goTo(item.page);
|
|
222
|
-
}}
|
|
223
|
-
>
|
|
224
|
-
{item.page}
|
|
225
|
-
</PaginationLink>
|
|
226
|
-
</PaginationItem>
|
|
227
|
-
)
|
|
228
|
-
)}
|
|
229
|
-
|
|
230
|
-
<PaginationItem>
|
|
231
|
-
<PaginationNext
|
|
232
|
-
href="#"
|
|
233
|
-
onClick={e => {
|
|
234
|
-
e.preventDefault();
|
|
235
|
-
next();
|
|
236
|
-
}}
|
|
237
|
-
disabled={!canGoNext}
|
|
238
|
-
/>
|
|
239
|
-
</PaginationItem>
|
|
240
|
-
</PaginationContent>
|
|
241
|
-
</Pagination>
|
|
242
|
-
</div>
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
> **Page item algorithm (v2.1.9+)**: The `items` array is computed with a `Set`-based deduplication algorithm. Each page number appears exactly once regardless of `siblingCount` and total pages. Ellipsis keys are unique (`ellipsis-{page}`).
|
|
248
|
-
|
|
249
|
-
### Controlled Example (API-driven pagination)
|
|
250
|
-
|
|
251
|
-
```tsx
|
|
252
|
-
import { usePagination } from 'xertica-ui/ui';
|
|
253
|
-
import { useState } from 'react';
|
|
254
|
-
|
|
255
|
-
function ServerPaginatedTable({ totalItems }: { totalItems: number }) {
|
|
256
|
-
const [page, setPage] = useState(1);
|
|
257
|
-
|
|
258
|
-
const { items, canGoPrev, canGoNext, next, prev, goTo, currentPage } = usePagination({
|
|
259
|
-
totalItems,
|
|
260
|
-
pageSize: 20,
|
|
261
|
-
page, // controlled
|
|
262
|
-
onPageChange: setPage,
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
// fetch data for `page` from your API...
|
|
266
|
-
|
|
267
|
-
return (
|
|
268
|
-
<Pagination>
|
|
269
|
-
<PaginationContent>
|
|
270
|
-
<PaginationItem>
|
|
271
|
-
<PaginationPrevious
|
|
272
|
-
href="#"
|
|
273
|
-
onClick={e => {
|
|
274
|
-
e.preventDefault();
|
|
275
|
-
prev();
|
|
276
|
-
}}
|
|
277
|
-
disabled={!canGoPrev}
|
|
278
|
-
/>
|
|
279
|
-
</PaginationItem>
|
|
280
|
-
{items.map(item =>
|
|
281
|
-
item.type === 'ellipsis' ? (
|
|
282
|
-
<PaginationItem key={item.key}>
|
|
283
|
-
<PaginationEllipsis />
|
|
284
|
-
</PaginationItem>
|
|
285
|
-
) : (
|
|
286
|
-
<PaginationItem key={item.page}>
|
|
287
|
-
<PaginationLink
|
|
288
|
-
href="#"
|
|
289
|
-
isActive={item.page === currentPage}
|
|
290
|
-
onClick={e => {
|
|
291
|
-
e.preventDefault();
|
|
292
|
-
goTo(item.page);
|
|
293
|
-
}}
|
|
294
|
-
>
|
|
295
|
-
{item.page}
|
|
296
|
-
</PaginationLink>
|
|
297
|
-
</PaginationItem>
|
|
298
|
-
)
|
|
299
|
-
)}
|
|
300
|
-
<PaginationItem>
|
|
301
|
-
<PaginationNext
|
|
302
|
-
href="#"
|
|
303
|
-
onClick={e => {
|
|
304
|
-
e.preventDefault();
|
|
305
|
-
next();
|
|
306
|
-
}}
|
|
307
|
-
disabled={!canGoNext}
|
|
308
|
-
/>
|
|
309
|
-
</PaginationItem>
|
|
310
|
-
</PaginationContent>
|
|
311
|
-
</Pagination>
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
---
|
|
317
|
-
|
|
318
|
-
## AI Rules
|
|
319
|
-
|
|
320
|
-
- Place Pagination below the `<Table>` inside the same `<Card>` wrapping both.
|
|
321
|
-
- Use `isActive` on the currently selected page link.
|
|
322
|
-
- **Use `disabled` prop (not `aria-disabled` alone)** on `PaginationPrevious` and `PaginationNext` — `disabled={!canGoPrev}` / `disabled={!canGoNext}`. The `disabled` prop removes `href`, sets `tabIndex={-1}`, `aria-disabled`, and `pointer-events-none opacity-50` simultaneously for full accessibility.
|
|
323
|
-
- For controlled pagination (API-driven), use `onClick` with `e.preventDefault()` on `PaginationLink` instead of letting `href="#"` cause a scroll-to-top.
|
|
324
|
-
- When using `usePagination`, use `startIndex` and `endIndex` to slice client-side data arrays: `data.slice(startIndex, endIndex)`.
|
|
325
|
-
- For server-side pagination, pass `page` and `onPageChange` to `usePagination` to use controlled mode — the hook will not manage internal state.
|
|
326
|
-
- Always render `PaginationEllipsis` for `item.type === 'ellipsis'` items from the `items` array — never skip them. Ellipsis keys are unique strings in the form `ellipsis-{page}`.
|
|
327
|
-
- `totalItems` is the count of **all** records, not just the current page.
|
|
328
|
-
- Pages are **1-indexed** — the first page is `1`, not `0`.
|
|
329
|
-
|
|
330
|
-
---
|
|
331
|
-
|
|
332
|
-
## Related Components
|
|
333
|
-
|
|
334
|
-
- [`Table`](./table.md) — Primary context where Pagination is used
|
|
1
|
+
# Pagination
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
A navigation control for moving through pages of a large dataset. Renders Previous/Next buttons, numbered page buttons, and ellipsis for large page counts. Use it below data tables to control which page of records is displayed.
|
|
6
|
+
|
|
7
|
+
The package also exports a **headless `usePagination` hook** that computes the full page item list (numbers + ellipsis) and exposes navigation helpers — use it when you need full control over the pagination UI.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Exports
|
|
12
|
+
|
|
13
|
+
| Export | Description |
|
|
14
|
+
| --------------------- | ---------------------------------------------- |
|
|
15
|
+
| `Pagination` | Root nav wrapper |
|
|
16
|
+
| `PaginationContent` | Flex container for all items |
|
|
17
|
+
| `PaginationItem` | Individual item wrapper |
|
|
18
|
+
| `PaginationLink` | Numbered page button |
|
|
19
|
+
| `PaginationPrevious` | "Previous" button with left arrow |
|
|
20
|
+
| `PaginationNext` | "Next" button with right arrow |
|
|
21
|
+
| `PaginationEllipsis` | "..." indicator for skipped pages |
|
|
22
|
+
| `usePagination` | Headless hook — all logic, no UI |
|
|
23
|
+
| `UsePaginationProps` | TypeScript props type for the hook |
|
|
24
|
+
| `UsePaginationReturn` | TypeScript return type for the hook |
|
|
25
|
+
| `PaginationPageItem` | Union type for page items returned by the hook |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## When to Use
|
|
30
|
+
|
|
31
|
+
- Below tables with more records than fit on one page
|
|
32
|
+
- Any paginated list or grid of content
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Anatomy
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
<Pagination>
|
|
40
|
+
<PaginationContent>
|
|
41
|
+
<PaginationItem><PaginationPrevious href="#" /></PaginationItem>
|
|
42
|
+
<PaginationItem><PaginationLink href="#">1</PaginationLink></PaginationItem>
|
|
43
|
+
<PaginationItem><PaginationEllipsis /></PaginationItem>
|
|
44
|
+
<PaginationItem><PaginationLink href="#" isActive>5</PaginationLink></PaginationItem>
|
|
45
|
+
<PaginationItem><PaginationNext href="#" /></PaginationItem>
|
|
46
|
+
</PaginationContent>
|
|
47
|
+
</Pagination>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Sub-Components
|
|
53
|
+
|
|
54
|
+
| Component | Description |
|
|
55
|
+
| -------------------- | --------------------------------- |
|
|
56
|
+
| `Pagination` | Root nav wrapper |
|
|
57
|
+
| `PaginationContent` | Flex container for all items |
|
|
58
|
+
| `PaginationItem` | Individual item wrapper |
|
|
59
|
+
| `PaginationLink` | Numbered page button |
|
|
60
|
+
| `PaginationPrevious` | "Previous" button with left arrow |
|
|
61
|
+
| `PaginationNext` | "Next" button with right arrow |
|
|
62
|
+
| `PaginationEllipsis` | "..." indicator for skipped pages |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Props
|
|
67
|
+
|
|
68
|
+
### PaginationLink
|
|
69
|
+
|
|
70
|
+
| Prop | Type | Description |
|
|
71
|
+
| ---------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
72
|
+
| `href` | `string` | URL for the page |
|
|
73
|
+
| `isActive` | `boolean` | When `true`, renders as the active page |
|
|
74
|
+
| `disabled` | `boolean` | When `true`, renders as non-interactive: removes `href`, sets `aria-disabled`, `tabIndex={-1}`, and `pointer-events-none opacity-50` |
|
|
75
|
+
| `onClick` | `() => void` | Click handler (for controlled pagination) |
|
|
76
|
+
|
|
77
|
+
### PaginationPrevious / PaginationNext
|
|
78
|
+
|
|
79
|
+
Both components accept and forward a `disabled` prop to `PaginationLink`. Pass `disabled={!canGoPrev}` / `disabled={!canGoNext}` to disable the controls when at the first or last page — this is the preferred pattern over `aria-disabled` alone.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Examples
|
|
84
|
+
|
|
85
|
+
### Controlled Pagination
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import {
|
|
89
|
+
Pagination,
|
|
90
|
+
PaginationContent,
|
|
91
|
+
PaginationItem,
|
|
92
|
+
PaginationLink,
|
|
93
|
+
PaginationNext,
|
|
94
|
+
PaginationPrevious,
|
|
95
|
+
PaginationEllipsis,
|
|
96
|
+
} from 'xertica-ui/ui';
|
|
97
|
+
import { useState } from 'react';
|
|
98
|
+
|
|
99
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
100
|
+
const totalPages = 10;
|
|
101
|
+
|
|
102
|
+
<Pagination>
|
|
103
|
+
<PaginationContent>
|
|
104
|
+
<PaginationItem>
|
|
105
|
+
<PaginationPrevious onClick={() => setCurrentPage(p => Math.max(1, p - 1))} />
|
|
106
|
+
</PaginationItem>
|
|
107
|
+
{[1, 2, 3].map(page => (
|
|
108
|
+
<PaginationItem key={page}>
|
|
109
|
+
<PaginationLink isActive={currentPage === page} onClick={() => setCurrentPage(page)}>
|
|
110
|
+
{page}
|
|
111
|
+
</PaginationLink>
|
|
112
|
+
</PaginationItem>
|
|
113
|
+
))}
|
|
114
|
+
<PaginationItem>
|
|
115
|
+
<PaginationEllipsis />
|
|
116
|
+
</PaginationItem>
|
|
117
|
+
<PaginationItem>
|
|
118
|
+
<PaginationLink onClick={() => setCurrentPage(totalPages)}>{totalPages}</PaginationLink>
|
|
119
|
+
</PaginationItem>
|
|
120
|
+
<PaginationItem>
|
|
121
|
+
<PaginationNext onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))} />
|
|
122
|
+
</PaginationItem>
|
|
123
|
+
</PaginationContent>
|
|
124
|
+
</Pagination>;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## `usePagination` Hook
|
|
130
|
+
|
|
131
|
+
A headless hook that computes the full page item list (page numbers + ellipsis markers) and exposes navigation helpers. Supports both **uncontrolled** (internal state) and **controlled** (external `page` prop) modes.
|
|
132
|
+
|
|
133
|
+
### Props
|
|
134
|
+
|
|
135
|
+
| Prop | Type | Default | Description |
|
|
136
|
+
| -------------- | ------------------------ | ------- | ------------------------------------------------------------------------------------------- |
|
|
137
|
+
| `totalItems` | `number` | — | **Required.** Total number of items across all pages |
|
|
138
|
+
| `pageSize` | `number` | `10` | Number of items per page |
|
|
139
|
+
| `initialPage` | `number` | `1` | Initial page (uncontrolled mode only) |
|
|
140
|
+
| `page` | `number` | — | Controlled current page — when provided, the hook uses this value instead of internal state |
|
|
141
|
+
| `onPageChange` | `(page: number) => void` | — | Called whenever the page changes |
|
|
142
|
+
| `siblingCount` | `number` | `1` | Number of page buttons to show on each side of the current page |
|
|
143
|
+
|
|
144
|
+
### Return Value
|
|
145
|
+
|
|
146
|
+
| Property | Type | Description |
|
|
147
|
+
| ------------- | ------------------------ | ----------------------------------------------------------------- |
|
|
148
|
+
| `currentPage` | `number` | The currently active page (1-indexed) |
|
|
149
|
+
| `totalPages` | `number` | Total number of pages |
|
|
150
|
+
| `startIndex` | `number` | Zero-based index of the first item on the current page |
|
|
151
|
+
| `endIndex` | `number` | Zero-based index of the last item on the current page (exclusive) |
|
|
152
|
+
| `canGoPrev` | `boolean` | Whether navigating to the previous page is possible |
|
|
153
|
+
| `canGoNext` | `boolean` | Whether navigating to the next page is possible |
|
|
154
|
+
| `isFirstPage` | `boolean` | Whether the current page is the first page |
|
|
155
|
+
| `isLastPage` | `boolean` | Whether the current page is the last page |
|
|
156
|
+
| `items` | `PaginationPageItem[]` | Ordered list of page items to render (see below) |
|
|
157
|
+
| `goTo` | `(page: number) => void` | Navigate to a specific page number |
|
|
158
|
+
| `next` | `() => void` | Navigate to the next page |
|
|
159
|
+
| `prev` | `() => void` | Navigate to the previous page |
|
|
160
|
+
| `first` | `() => void` | Navigate to the first page |
|
|
161
|
+
| `last` | `() => void` | Navigate to the last page |
|
|
162
|
+
|
|
163
|
+
### `PaginationPageItem` Type
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
type PaginationPageItem = { type: 'page'; page: number } | { type: 'ellipsis'; key: string };
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The `items` array is ready to render directly — map over it and render `<PaginationLink>` for `type: 'page'` items and `<PaginationEllipsis>` for `type: 'ellipsis'` items.
|
|
170
|
+
|
|
171
|
+
### Uncontrolled Example
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
import {
|
|
175
|
+
usePagination,
|
|
176
|
+
Pagination,
|
|
177
|
+
PaginationContent,
|
|
178
|
+
PaginationItem,
|
|
179
|
+
PaginationLink,
|
|
180
|
+
PaginationPrevious,
|
|
181
|
+
PaginationNext,
|
|
182
|
+
PaginationEllipsis,
|
|
183
|
+
} from 'xertica-ui/ui';
|
|
184
|
+
|
|
185
|
+
function MyTable({ data }: { data: Record<string, unknown>[] }) {
|
|
186
|
+
const { currentPage, startIndex, endIndex, canGoPrev, canGoNext, items, next, prev, goTo } =
|
|
187
|
+
usePagination({ totalItems: data.length, pageSize: 10 });
|
|
188
|
+
|
|
189
|
+
const pageData = data.slice(startIndex, endIndex);
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
<div className="space-y-4">
|
|
193
|
+
<table>{/* render pageData rows */}</table>
|
|
194
|
+
|
|
195
|
+
<Pagination>
|
|
196
|
+
<PaginationContent>
|
|
197
|
+
<PaginationItem>
|
|
198
|
+
{/* Use disabled prop — not aria-disabled — for full a11y (removes href, tabIndex, pointer-events) */}
|
|
199
|
+
<PaginationPrevious
|
|
200
|
+
href="#"
|
|
201
|
+
onClick={e => {
|
|
202
|
+
e.preventDefault();
|
|
203
|
+
prev();
|
|
204
|
+
}}
|
|
205
|
+
disabled={!canGoPrev}
|
|
206
|
+
/>
|
|
207
|
+
</PaginationItem>
|
|
208
|
+
|
|
209
|
+
{items.map(item =>
|
|
210
|
+
item.type === 'ellipsis' ? (
|
|
211
|
+
<PaginationItem key={item.key}>
|
|
212
|
+
<PaginationEllipsis />
|
|
213
|
+
</PaginationItem>
|
|
214
|
+
) : (
|
|
215
|
+
<PaginationItem key={item.page}>
|
|
216
|
+
<PaginationLink
|
|
217
|
+
href="#"
|
|
218
|
+
isActive={item.page === currentPage}
|
|
219
|
+
onClick={e => {
|
|
220
|
+
e.preventDefault();
|
|
221
|
+
goTo(item.page);
|
|
222
|
+
}}
|
|
223
|
+
>
|
|
224
|
+
{item.page}
|
|
225
|
+
</PaginationLink>
|
|
226
|
+
</PaginationItem>
|
|
227
|
+
)
|
|
228
|
+
)}
|
|
229
|
+
|
|
230
|
+
<PaginationItem>
|
|
231
|
+
<PaginationNext
|
|
232
|
+
href="#"
|
|
233
|
+
onClick={e => {
|
|
234
|
+
e.preventDefault();
|
|
235
|
+
next();
|
|
236
|
+
}}
|
|
237
|
+
disabled={!canGoNext}
|
|
238
|
+
/>
|
|
239
|
+
</PaginationItem>
|
|
240
|
+
</PaginationContent>
|
|
241
|
+
</Pagination>
|
|
242
|
+
</div>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
> **Page item algorithm (v2.1.9+)**: The `items` array is computed with a `Set`-based deduplication algorithm. Each page number appears exactly once regardless of `siblingCount` and total pages. Ellipsis keys are unique (`ellipsis-{page}`).
|
|
248
|
+
|
|
249
|
+
### Controlled Example (API-driven pagination)
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
import { usePagination } from 'xertica-ui/ui';
|
|
253
|
+
import { useState } from 'react';
|
|
254
|
+
|
|
255
|
+
function ServerPaginatedTable({ totalItems }: { totalItems: number }) {
|
|
256
|
+
const [page, setPage] = useState(1);
|
|
257
|
+
|
|
258
|
+
const { items, canGoPrev, canGoNext, next, prev, goTo, currentPage } = usePagination({
|
|
259
|
+
totalItems,
|
|
260
|
+
pageSize: 20,
|
|
261
|
+
page, // controlled
|
|
262
|
+
onPageChange: setPage,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// fetch data for `page` from your API...
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<Pagination>
|
|
269
|
+
<PaginationContent>
|
|
270
|
+
<PaginationItem>
|
|
271
|
+
<PaginationPrevious
|
|
272
|
+
href="#"
|
|
273
|
+
onClick={e => {
|
|
274
|
+
e.preventDefault();
|
|
275
|
+
prev();
|
|
276
|
+
}}
|
|
277
|
+
disabled={!canGoPrev}
|
|
278
|
+
/>
|
|
279
|
+
</PaginationItem>
|
|
280
|
+
{items.map(item =>
|
|
281
|
+
item.type === 'ellipsis' ? (
|
|
282
|
+
<PaginationItem key={item.key}>
|
|
283
|
+
<PaginationEllipsis />
|
|
284
|
+
</PaginationItem>
|
|
285
|
+
) : (
|
|
286
|
+
<PaginationItem key={item.page}>
|
|
287
|
+
<PaginationLink
|
|
288
|
+
href="#"
|
|
289
|
+
isActive={item.page === currentPage}
|
|
290
|
+
onClick={e => {
|
|
291
|
+
e.preventDefault();
|
|
292
|
+
goTo(item.page);
|
|
293
|
+
}}
|
|
294
|
+
>
|
|
295
|
+
{item.page}
|
|
296
|
+
</PaginationLink>
|
|
297
|
+
</PaginationItem>
|
|
298
|
+
)
|
|
299
|
+
)}
|
|
300
|
+
<PaginationItem>
|
|
301
|
+
<PaginationNext
|
|
302
|
+
href="#"
|
|
303
|
+
onClick={e => {
|
|
304
|
+
e.preventDefault();
|
|
305
|
+
next();
|
|
306
|
+
}}
|
|
307
|
+
disabled={!canGoNext}
|
|
308
|
+
/>
|
|
309
|
+
</PaginationItem>
|
|
310
|
+
</PaginationContent>
|
|
311
|
+
</Pagination>
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## AI Rules
|
|
319
|
+
|
|
320
|
+
- Place Pagination below the `<Table>` inside the same `<Card>` wrapping both.
|
|
321
|
+
- Use `isActive` on the currently selected page link.
|
|
322
|
+
- **Use `disabled` prop (not `aria-disabled` alone)** on `PaginationPrevious` and `PaginationNext` — `disabled={!canGoPrev}` / `disabled={!canGoNext}`. The `disabled` prop removes `href`, sets `tabIndex={-1}`, `aria-disabled`, and `pointer-events-none opacity-50` simultaneously for full accessibility.
|
|
323
|
+
- For controlled pagination (API-driven), use `onClick` with `e.preventDefault()` on `PaginationLink` instead of letting `href="#"` cause a scroll-to-top.
|
|
324
|
+
- When using `usePagination`, use `startIndex` and `endIndex` to slice client-side data arrays: `data.slice(startIndex, endIndex)`.
|
|
325
|
+
- For server-side pagination, pass `page` and `onPageChange` to `usePagination` to use controlled mode — the hook will not manage internal state.
|
|
326
|
+
- Always render `PaginationEllipsis` for `item.type === 'ellipsis'` items from the `items` array — never skip them. Ellipsis keys are unique strings in the form `ellipsis-{page}`.
|
|
327
|
+
- `totalItems` is the count of **all** records, not just the current page.
|
|
328
|
+
- Pages are **1-indexed** — the first page is `1`, not `0`.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Related Components
|
|
333
|
+
|
|
334
|
+
- [`Table`](./table.md) — Primary context where Pagination is used
|