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,50 +1,50 @@
|
|
|
1
|
-
import { render, screen, waitFor } from '@testing-library/react';
|
|
2
|
-
import userEvent from '@testing-library/user-event';
|
|
3
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
4
|
-
import { Tabs, TabsList, TabsTrigger, TabsContent } from './tabs';
|
|
5
|
-
import React from 'react';
|
|
6
|
-
|
|
7
|
-
describe('Tabs', () => {
|
|
8
|
-
it('renders correctly', () => {
|
|
9
|
-
render(
|
|
10
|
-
<Tabs defaultValue="tab1">
|
|
11
|
-
<TabsList>
|
|
12
|
-
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
|
|
13
|
-
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
|
|
14
|
-
</TabsList>
|
|
15
|
-
<TabsContent value="tab1">Content 1</TabsContent>
|
|
16
|
-
<TabsContent value="tab2">Content 2</TabsContent>
|
|
17
|
-
</Tabs>
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
expect(screen.getByText('Tab 1')).toBeInTheDocument();
|
|
21
|
-
expect(screen.getByText('Content 1')).toBeInTheDocument();
|
|
22
|
-
expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('switches content when trigger is clicked', async () => {
|
|
26
|
-
const user = userEvent.setup();
|
|
27
|
-
const onValueChange = vi.fn();
|
|
28
|
-
render(
|
|
29
|
-
<Tabs defaultValue="tab1" onValueChange={onValueChange}>
|
|
30
|
-
<TabsList>
|
|
31
|
-
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
|
|
32
|
-
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
|
|
33
|
-
</TabsList>
|
|
34
|
-
<TabsContent value="tab1">Content 1</TabsContent>
|
|
35
|
-
<TabsContent value="tab2">Content 2</TabsContent>
|
|
36
|
-
</Tabs>
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
const trigger2 = screen.getByRole('tab', { name: 'Tab 2' });
|
|
40
|
-
await user.click(trigger2);
|
|
41
|
-
|
|
42
|
-
await waitFor(() => {
|
|
43
|
-
expect(onValueChange).toHaveBeenCalledWith('tab2');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
await waitFor(() => {
|
|
47
|
-
expect(screen.getByText('Content 2')).toBeInTheDocument();
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
});
|
|
1
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
4
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from './tabs';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
describe('Tabs', () => {
|
|
8
|
+
it('renders correctly', () => {
|
|
9
|
+
render(
|
|
10
|
+
<Tabs defaultValue="tab1">
|
|
11
|
+
<TabsList>
|
|
12
|
+
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
|
|
13
|
+
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
|
|
14
|
+
</TabsList>
|
|
15
|
+
<TabsContent value="tab1">Content 1</TabsContent>
|
|
16
|
+
<TabsContent value="tab2">Content 2</TabsContent>
|
|
17
|
+
</Tabs>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
expect(screen.getByText('Tab 1')).toBeInTheDocument();
|
|
21
|
+
expect(screen.getByText('Content 1')).toBeInTheDocument();
|
|
22
|
+
expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('switches content when trigger is clicked', async () => {
|
|
26
|
+
const user = userEvent.setup();
|
|
27
|
+
const onValueChange = vi.fn();
|
|
28
|
+
render(
|
|
29
|
+
<Tabs defaultValue="tab1" onValueChange={onValueChange}>
|
|
30
|
+
<TabsList>
|
|
31
|
+
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
|
|
32
|
+
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
|
|
33
|
+
</TabsList>
|
|
34
|
+
<TabsContent value="tab1">Content 1</TabsContent>
|
|
35
|
+
<TabsContent value="tab2">Content 2</TabsContent>
|
|
36
|
+
</Tabs>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const trigger2 = screen.getByRole('tab', { name: 'Tab 2' });
|
|
40
|
+
await user.click(trigger2);
|
|
41
|
+
|
|
42
|
+
await waitFor(() => {
|
|
43
|
+
expect(onValueChange).toHaveBeenCalledWith('tab2');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
await waitFor(() => {
|
|
47
|
+
expect(screen.getByText('Content 2')).toBeInTheDocument();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
|
5
|
-
|
|
6
|
-
import { cn } from '../../shared/utils';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Intra-page navigation tabs (section switcher).
|
|
10
|
-
*
|
|
11
|
-
* @description
|
|
12
|
-
* Segments large content areas into mutually exclusive clickable categories,
|
|
13
|
-
* rendering each panel in-place without a URL reload.
|
|
14
|
-
*
|
|
15
|
-
* @ai-rules
|
|
16
|
-
* 1. Compose strictly: `Tabs > TabsList > TabsTrigger` with panels in matching `TabsContent`.
|
|
17
|
-
* 2. In long forms split by tabs, ensure inactive inputs retain values by correctly registering them with React Hook Form.
|
|
18
|
-
* 3. NEVER simulate tabs with raw buttons + `useState` — use this Radix base for proper keyboard navigation (left/right arrows).
|
|
19
|
-
*/
|
|
20
|
-
function Tabs({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
|
21
|
-
return (
|
|
22
|
-
<TabsPrimitive.Root
|
|
23
|
-
data-slot="tabs"
|
|
24
|
-
className={cn('flex flex-col gap-2', className)}
|
|
25
|
-
{...props}
|
|
26
|
-
/>
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function TabsList({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.List>) {
|
|
31
|
-
return (
|
|
32
|
-
<TabsPrimitive.List
|
|
33
|
-
data-slot="tabs-list"
|
|
34
|
-
className={cn(
|
|
35
|
-
'relative inline-flex h-12 w-fit items-end justify-start border-b border-border bg-transparent',
|
|
36
|
-
className
|
|
37
|
-
)}
|
|
38
|
-
{...props}
|
|
39
|
-
/>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
|
44
|
-
return (
|
|
45
|
-
<TabsPrimitive.Trigger
|
|
46
|
-
data-slot="tabs-trigger"
|
|
47
|
-
className={cn(
|
|
48
|
-
"relative inline-flex h-12 items-center justify-center gap-1.5 bg-transparent px-4 py-3 text-sm font-medium whitespace-nowrap transition-all duration-200 ease-in-out border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-accent/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 data-[state=active]:text-primary data-[state=active]:border-primary data-[state=active]:bg-transparent [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
49
|
-
className
|
|
50
|
-
)}
|
|
51
|
-
{...props}
|
|
52
|
-
/>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
|
57
|
-
return (
|
|
58
|
-
<TabsPrimitive.Content
|
|
59
|
-
data-slot="tabs-content"
|
|
60
|
-
className={cn('flex-1 outline-none', className)}
|
|
61
|
-
{...props}
|
|
62
|
-
/>
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
|
5
|
+
|
|
6
|
+
import { cn } from '../../shared/utils';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Intra-page navigation tabs (section switcher).
|
|
10
|
+
*
|
|
11
|
+
* @description
|
|
12
|
+
* Segments large content areas into mutually exclusive clickable categories,
|
|
13
|
+
* rendering each panel in-place without a URL reload.
|
|
14
|
+
*
|
|
15
|
+
* @ai-rules
|
|
16
|
+
* 1. Compose strictly: `Tabs > TabsList > TabsTrigger` with panels in matching `TabsContent`.
|
|
17
|
+
* 2. In long forms split by tabs, ensure inactive inputs retain values by correctly registering them with React Hook Form.
|
|
18
|
+
* 3. NEVER simulate tabs with raw buttons + `useState` — use this Radix base for proper keyboard navigation (left/right arrows).
|
|
19
|
+
*/
|
|
20
|
+
function Tabs({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
|
21
|
+
return (
|
|
22
|
+
<TabsPrimitive.Root
|
|
23
|
+
data-slot="tabs"
|
|
24
|
+
className={cn('flex flex-col gap-2', className)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function TabsList({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.List>) {
|
|
31
|
+
return (
|
|
32
|
+
<TabsPrimitive.List
|
|
33
|
+
data-slot="tabs-list"
|
|
34
|
+
className={cn(
|
|
35
|
+
'relative inline-flex h-12 w-fit items-end justify-start border-b border-border bg-transparent',
|
|
36
|
+
className
|
|
37
|
+
)}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
|
44
|
+
return (
|
|
45
|
+
<TabsPrimitive.Trigger
|
|
46
|
+
data-slot="tabs-trigger"
|
|
47
|
+
className={cn(
|
|
48
|
+
"relative inline-flex h-12 items-center justify-center gap-1.5 bg-transparent px-4 py-3 text-sm font-medium whitespace-nowrap transition-all duration-200 ease-in-out border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-accent/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 data-[state=active]:text-primary data-[state=active]:border-primary data-[state=active]:bg-transparent [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
49
|
+
className
|
|
50
|
+
)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
|
57
|
+
return (
|
|
58
|
+
<TabsPrimitive.Content
|
|
59
|
+
data-slot="tabs-content"
|
|
60
|
+
className={cn('flex-1 outline-none', className)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './textarea';
|
|
1
|
+
export * from './textarea';
|
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import { Textarea } from './textarea';
|
|
3
|
-
import { Label } from '../label';
|
|
4
|
-
import React from 'react';
|
|
5
|
-
|
|
6
|
-
const meta: Meta<typeof Textarea> = {
|
|
7
|
-
title: 'UI/Textarea',
|
|
8
|
-
component: Textarea,
|
|
9
|
-
render: args => <Textarea {...args} />,
|
|
10
|
-
argTypes: {
|
|
11
|
-
size: {
|
|
12
|
-
control: 'select',
|
|
13
|
-
options: ['sm', 'md', 'lg'],
|
|
14
|
-
description: 'Size variant — controls padding and font size.',
|
|
15
|
-
},
|
|
16
|
-
disabled: {
|
|
17
|
-
control: 'boolean',
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export default meta;
|
|
23
|
-
type Story = StoryObj<typeof Textarea>;
|
|
24
|
-
|
|
25
|
-
export const Default: Story = {
|
|
26
|
-
args: {
|
|
27
|
-
placeholder: 'Type your message here.',
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const WithLabel: Story = {
|
|
32
|
-
render: args => (
|
|
33
|
-
<div className="grid w-full gap-1.5">
|
|
34
|
-
<Label htmlFor="message" size={args.size}>
|
|
35
|
-
Your message
|
|
36
|
-
</Label>
|
|
37
|
-
<Textarea {...args} placeholder="Type your message here." id="message" />
|
|
38
|
-
</div>
|
|
39
|
-
),
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const Disabled: Story = {
|
|
43
|
-
args: {
|
|
44
|
-
disabled: true,
|
|
45
|
-
placeholder: 'Textarea is disabled.',
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Size comparison: sm, md (default), lg.
|
|
51
|
-
*/
|
|
52
|
-
export const Sizes: Story = {
|
|
53
|
-
render: () => (
|
|
54
|
-
<div className="flex flex-col gap-4 max-w-sm">
|
|
55
|
-
<div className="grid gap-1.5">
|
|
56
|
-
<Label size="sm">Small (sm)</Label>
|
|
57
|
-
<Textarea size="sm" placeholder="Small textarea" />
|
|
58
|
-
</div>
|
|
59
|
-
<div className="grid gap-1.5">
|
|
60
|
-
<Label size="md">Medium (md — default)</Label>
|
|
61
|
-
<Textarea size="md" placeholder="Medium textarea" />
|
|
62
|
-
</div>
|
|
63
|
-
<div className="grid gap-1.5">
|
|
64
|
-
<Label size="lg">Large (lg)</Label>
|
|
65
|
-
<Textarea size="lg" placeholder="Large textarea" />
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
),
|
|
69
|
-
};
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Textarea } from './textarea';
|
|
3
|
+
import { Label } from '../label';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Textarea> = {
|
|
7
|
+
title: 'UI/Textarea',
|
|
8
|
+
component: Textarea,
|
|
9
|
+
render: args => <Textarea {...args} />,
|
|
10
|
+
argTypes: {
|
|
11
|
+
size: {
|
|
12
|
+
control: 'select',
|
|
13
|
+
options: ['sm', 'md', 'lg'],
|
|
14
|
+
description: 'Size variant — controls padding and font size.',
|
|
15
|
+
},
|
|
16
|
+
disabled: {
|
|
17
|
+
control: 'boolean',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
type Story = StoryObj<typeof Textarea>;
|
|
24
|
+
|
|
25
|
+
export const Default: Story = {
|
|
26
|
+
args: {
|
|
27
|
+
placeholder: 'Type your message here.',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const WithLabel: Story = {
|
|
32
|
+
render: args => (
|
|
33
|
+
<div className="grid w-full gap-1.5">
|
|
34
|
+
<Label htmlFor="message" size={args.size}>
|
|
35
|
+
Your message
|
|
36
|
+
</Label>
|
|
37
|
+
<Textarea {...args} placeholder="Type your message here." id="message" />
|
|
38
|
+
</div>
|
|
39
|
+
),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const Disabled: Story = {
|
|
43
|
+
args: {
|
|
44
|
+
disabled: true,
|
|
45
|
+
placeholder: 'Textarea is disabled.',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Size comparison: sm, md (default), lg.
|
|
51
|
+
*/
|
|
52
|
+
export const Sizes: Story = {
|
|
53
|
+
render: () => (
|
|
54
|
+
<div className="flex flex-col gap-4 max-w-sm">
|
|
55
|
+
<div className="grid gap-1.5">
|
|
56
|
+
<Label size="sm">Small (sm)</Label>
|
|
57
|
+
<Textarea size="sm" placeholder="Small textarea" />
|
|
58
|
+
</div>
|
|
59
|
+
<div className="grid gap-1.5">
|
|
60
|
+
<Label size="md">Medium (md — default)</Label>
|
|
61
|
+
<Textarea size="md" placeholder="Medium textarea" />
|
|
62
|
+
</div>
|
|
63
|
+
<div className="grid gap-1.5">
|
|
64
|
+
<Label size="lg">Large (lg)</Label>
|
|
65
|
+
<Textarea size="lg" placeholder="Large textarea" />
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
),
|
|
69
|
+
};
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
3
|
-
import { Textarea } from './textarea';
|
|
4
|
-
import React from 'react';
|
|
5
|
-
|
|
6
|
-
describe('Textarea', () => {
|
|
7
|
-
it('renders correctly with default props', () => {
|
|
8
|
-
render(<Textarea placeholder="Enter description" />);
|
|
9
|
-
const textarea = screen.getByPlaceholderText('Enter description');
|
|
10
|
-
expect(textarea).toBeInTheDocument();
|
|
11
|
-
expect(textarea).toHaveClass('text-base'); // md size
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('renders correctly with different sizes', () => {
|
|
15
|
-
const { rerender } = render(<Textarea size="sm" placeholder="Small" />);
|
|
16
|
-
expect(screen.getByPlaceholderText('Small')).toHaveClass('text-sm');
|
|
17
|
-
|
|
18
|
-
rerender(<Textarea size="md" placeholder="Medium" />);
|
|
19
|
-
expect(screen.getByPlaceholderText('Medium')).toHaveClass('text-base');
|
|
20
|
-
|
|
21
|
-
rerender(<Textarea size="lg" placeholder="Large" />);
|
|
22
|
-
expect(screen.getByPlaceholderText('Large')).toHaveClass('text-base');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('updates value on change', () => {
|
|
26
|
-
const onChange = vi.fn();
|
|
27
|
-
render(<Textarea onChange={onChange} />);
|
|
28
|
-
const textarea = screen.getByRole('textbox');
|
|
29
|
-
|
|
30
|
-
fireEvent.change(textarea, { target: { value: 'New text' } });
|
|
31
|
-
|
|
32
|
-
expect(textarea).toHaveValue('New text');
|
|
33
|
-
expect(onChange).toHaveBeenCalled();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('is disabled when disabled prop is true', () => {
|
|
37
|
-
render(<Textarea disabled placeholder="Disabled" />);
|
|
38
|
-
const textarea = screen.getByPlaceholderText('Disabled');
|
|
39
|
-
expect(textarea).toBeDisabled();
|
|
40
|
-
});
|
|
41
|
-
});
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
3
|
+
import { Textarea } from './textarea';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
|
|
6
|
+
describe('Textarea', () => {
|
|
7
|
+
it('renders correctly with default props', () => {
|
|
8
|
+
render(<Textarea placeholder="Enter description" />);
|
|
9
|
+
const textarea = screen.getByPlaceholderText('Enter description');
|
|
10
|
+
expect(textarea).toBeInTheDocument();
|
|
11
|
+
expect(textarea).toHaveClass('text-base'); // md size
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('renders correctly with different sizes', () => {
|
|
15
|
+
const { rerender } = render(<Textarea size="sm" placeholder="Small" />);
|
|
16
|
+
expect(screen.getByPlaceholderText('Small')).toHaveClass('text-sm');
|
|
17
|
+
|
|
18
|
+
rerender(<Textarea size="md" placeholder="Medium" />);
|
|
19
|
+
expect(screen.getByPlaceholderText('Medium')).toHaveClass('text-base');
|
|
20
|
+
|
|
21
|
+
rerender(<Textarea size="lg" placeholder="Large" />);
|
|
22
|
+
expect(screen.getByPlaceholderText('Large')).toHaveClass('text-base');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('updates value on change', () => {
|
|
26
|
+
const onChange = vi.fn();
|
|
27
|
+
render(<Textarea onChange={onChange} />);
|
|
28
|
+
const textarea = screen.getByRole('textbox');
|
|
29
|
+
|
|
30
|
+
fireEvent.change(textarea, { target: { value: 'New text' } });
|
|
31
|
+
|
|
32
|
+
expect(textarea).toHaveValue('New text');
|
|
33
|
+
expect(onChange).toHaveBeenCalled();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('is disabled when disabled prop is true', () => {
|
|
37
|
+
render(<Textarea disabled placeholder="Disabled" />);
|
|
38
|
+
const textarea = screen.getByPlaceholderText('Disabled');
|
|
39
|
+
expect(textarea).toBeDisabled();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
|
|
3
|
-
import { cn } from '../../shared/utils';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Props para o componente Textarea.
|
|
7
|
-
*
|
|
8
|
-
* @interface TextareaProps
|
|
9
|
-
*/
|
|
10
|
-
export interface TextareaProps extends React.ComponentProps<'textarea'> {
|
|
11
|
-
/**
|
|
12
|
-
* Size variant — matches the Input component sizing scale.
|
|
13
|
-
* Controls padding and font size (height is determined by `rows` prop or content).
|
|
14
|
-
* - `sm`: px-2 py-1, text-sm
|
|
15
|
-
* - `md`: px-3 py-2, text-base — **default**, aligned with Input default
|
|
16
|
-
* - `lg`: px-4 py-3, text-base
|
|
17
|
-
*/
|
|
18
|
-
size?: 'sm' | 'md' | 'lg';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Multi-line text input for extended content.
|
|
23
|
-
*
|
|
24
|
-
* @description
|
|
25
|
-
* Styled replacement for the native HTML `<textarea>` element.
|
|
26
|
-
* Supports the same size scale as Input (`sm`, `md`, `lg`) for consistent form alignment.
|
|
27
|
-
*
|
|
28
|
-
* @ai-rules
|
|
29
|
-
* 1. Use when capturing large text blocks: descriptions, bios, notes, comments.
|
|
30
|
-
* 2. Inside React Hook Form, wrap in `<FormControl>` and pass `{...field}`.
|
|
31
|
-
* 3. Do NOT use `<Input>` for multi-line text — always use `<Textarea>`.
|
|
32
|
-
* 4. The `size` prop controls padding and font — not height. Use `rows` to control height.
|
|
33
|
-
*/
|
|
34
|
-
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
35
|
-
({ className, size = 'md', ...props }, ref) => {
|
|
36
|
-
const sizeClasses = {
|
|
37
|
-
sm: 'px-2 py-1 text-sm',
|
|
38
|
-
md: 'px-3 py-2 text-base',
|
|
39
|
-
lg: 'px-4 py-3 text-base',
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<textarea
|
|
44
|
-
data-slot="textarea"
|
|
45
|
-
className={cn(
|
|
46
|
-
'flex min-h-16 w-full bg-background rounded-[var(--radius)] border border-border transition-colors outline-none resize-none text-foreground',
|
|
47
|
-
'placeholder:text-muted-foreground',
|
|
48
|
-
'focus:ring-2 focus:ring-primary focus:border-transparent',
|
|
49
|
-
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
50
|
-
sizeClasses[size],
|
|
51
|
-
className
|
|
52
|
-
)}
|
|
53
|
-
ref={ref}
|
|
54
|
-
{...props}
|
|
55
|
-
/>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
);
|
|
59
|
-
Textarea.displayName = 'Textarea';
|
|
60
|
-
|
|
61
|
-
export { Textarea };
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../shared/utils';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Props para o componente Textarea.
|
|
7
|
+
*
|
|
8
|
+
* @interface TextareaProps
|
|
9
|
+
*/
|
|
10
|
+
export interface TextareaProps extends React.ComponentProps<'textarea'> {
|
|
11
|
+
/**
|
|
12
|
+
* Size variant — matches the Input component sizing scale.
|
|
13
|
+
* Controls padding and font size (height is determined by `rows` prop or content).
|
|
14
|
+
* - `sm`: px-2 py-1, text-sm
|
|
15
|
+
* - `md`: px-3 py-2, text-base — **default**, aligned with Input default
|
|
16
|
+
* - `lg`: px-4 py-3, text-base
|
|
17
|
+
*/
|
|
18
|
+
size?: 'sm' | 'md' | 'lg';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Multi-line text input for extended content.
|
|
23
|
+
*
|
|
24
|
+
* @description
|
|
25
|
+
* Styled replacement for the native HTML `<textarea>` element.
|
|
26
|
+
* Supports the same size scale as Input (`sm`, `md`, `lg`) for consistent form alignment.
|
|
27
|
+
*
|
|
28
|
+
* @ai-rules
|
|
29
|
+
* 1. Use when capturing large text blocks: descriptions, bios, notes, comments.
|
|
30
|
+
* 2. Inside React Hook Form, wrap in `<FormControl>` and pass `{...field}`.
|
|
31
|
+
* 3. Do NOT use `<Input>` for multi-line text — always use `<Textarea>`.
|
|
32
|
+
* 4. The `size` prop controls padding and font — not height. Use `rows` to control height.
|
|
33
|
+
*/
|
|
34
|
+
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
35
|
+
({ className, size = 'md', ...props }, ref) => {
|
|
36
|
+
const sizeClasses = {
|
|
37
|
+
sm: 'px-2 py-1 text-sm',
|
|
38
|
+
md: 'px-3 py-2 text-base',
|
|
39
|
+
lg: 'px-4 py-3 text-base',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<textarea
|
|
44
|
+
data-slot="textarea"
|
|
45
|
+
className={cn(
|
|
46
|
+
'flex min-h-16 w-full bg-background rounded-[var(--radius)] border border-border transition-colors outline-none resize-none text-foreground',
|
|
47
|
+
'placeholder:text-muted-foreground',
|
|
48
|
+
'focus:ring-2 focus:ring-primary focus:border-transparent',
|
|
49
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
50
|
+
sizeClasses[size],
|
|
51
|
+
className
|
|
52
|
+
)}
|
|
53
|
+
ref={ref}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
Textarea.displayName = 'Textarea';
|
|
60
|
+
|
|
61
|
+
export { Textarea };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './timeline';
|
|
1
|
+
export * from './timeline';
|