xertica-ui 2.5.0 → 2.5.2
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 +35 -0
- package/README.md +56 -17
- package/assets/xertica-logo.svg +37 -37
- package/assets/xertica-x-logo.svg +20 -20
- package/bin/cli.ts +14 -2
- package/bin/generate-tokens.ts +262 -262
- package/bin/language-config.ts +359 -358
- package/components/assistant/code-block/CodeBlock.tsx +268 -268
- package/components/assistant/formatted-document/FormattedDocument.tsx +147 -147
- package/components/assistant/modern-chat-input/ModernChatInput.tsx +564 -564
- package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +99 -99
- package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -104
- package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -81
- package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +88 -88
- package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +75 -75
- package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +564 -564
- package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +67 -67
- package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +103 -103
- package/components/assistant/xertica-assistant/use-assistant.ts +615 -615
- package/components/assistant/xertica-assistant/xertica-assistant.tsx +611 -611
- package/components/blocks/card-patterns/ActivityCard.tsx +100 -100
- package/components/blocks/card-patterns/ActivityCardSkeleton.tsx +56 -56
- package/components/blocks/card-patterns/FeatureCardSkeleton.tsx +58 -58
- package/components/blocks/card-patterns/NotificationCard.tsx +140 -140
- package/components/blocks/card-patterns/NotificationCardSkeleton.tsx +81 -81
- package/components/blocks/card-patterns/ProfileCard.tsx +112 -112
- package/components/blocks/card-patterns/ProfileCardSkeleton.tsx +69 -69
- package/components/blocks/card-patterns/ProjectCard.tsx +123 -123
- package/components/blocks/card-patterns/ProjectCardSkeleton.tsx +67 -67
- package/components/blocks/card-patterns/QuickActionCardSkeleton.tsx +44 -44
- package/components/blocks/card-patterns/card-patterns.stories.tsx +594 -594
- package/components/blocks/card-patterns/index.ts +29 -29
- package/components/brand/language-selector/LanguageSelector.tsx +102 -102
- package/components/brand/language-selector/language-selector.stories.tsx +111 -111
- package/components/brand/language-selector/language-selector.test.tsx +101 -101
- package/components/brand/theme-toggle/ThemeToggle.tsx +74 -74
- package/components/brand/xertica-provider/xertica-provider.mdx +61 -61
- package/components/index.ts +86 -86
- package/components/layout/sidebar/sidebar.mdx +1 -1
- package/components/layout/sidebar/sidebar.stories.tsx +1033 -787
- package/components/layout/sidebar/sidebar.tsx +338 -1
- package/components/media/FloatingMediaWrapper.tsx +371 -371
- package/components/media/audio-player/AudioPlayer.tsx +768 -768
- package/components/media/video-player/VideoPlayer.tsx +310 -310
- package/components/pages/home-content/HomeContent.tsx +120 -120
- package/components/pages/home-content/home-content.mdx +62 -62
- package/components/pages/home-page/HomePage.tsx +78 -78
- package/components/pages/home-page/home-page.mdx +53 -53
- package/components/pages/template-content/TemplateContent.tsx +1354 -1354
- package/components/pages/template-content/template-content.mdx +61 -61
- package/components/pages/template-page/TemplatePage.stories.tsx +32 -32
- package/components/pages/template-page/template-page.mdx +53 -53
- package/components/shared/error-boundary.stories.tsx +114 -114
- package/components/shared/error-boundary.tsx +150 -150
- package/components/shared/error-fallbacks.tsx +222 -222
- package/components/ui/accordion/accordion.mdx +8 -8
- package/components/ui/alert/alert.mdx +8 -8
- package/components/ui/alert-dialog/alert-dialog.mdx +8 -8
- package/components/ui/aspect-ratio/aspect-ratio.mdx +8 -8
- package/components/ui/assistant-chart/assistant-chart.mdx +8 -8
- package/components/ui/avatar/avatar.mdx +8 -8
- package/components/ui/badge/badge.mdx +8 -8
- package/components/ui/breadcrumb/breadcrumb.mdx +8 -8
- package/components/ui/button/button.mdx +8 -8
- package/components/ui/calendar/calendar.mdx +8 -8
- package/components/ui/card/card.mdx +8 -8
- package/components/ui/carousel/carousel.mdx +8 -8
- package/components/ui/chart/chart.mdx +8 -8
- package/components/ui/chart/chart.test.tsx +178 -178
- package/components/ui/chart/chart.tsx +2245 -2239
- package/components/ui/checkbox/checkbox.mdx +8 -8
- package/components/ui/collapsible/collapsible.mdx +8 -8
- package/components/ui/command/command.mdx +8 -8
- package/components/ui/context-menu/context-menu.mdx +8 -8
- package/components/ui/dialog/dialog.mdx +8 -8
- package/components/ui/drawer/drawer.mdx +8 -8
- package/components/ui/dropdown-menu/dropdown-menu.mdx +8 -8
- package/components/ui/empty/empty.mdx +8 -8
- package/components/ui/file-upload/file-upload.mdx +8 -8
- package/components/ui/hover-card/hover-card.mdx +8 -8
- package/components/ui/input/input.mdx +8 -8
- package/components/ui/input-otp/input-otp.mdx +8 -8
- package/components/ui/label/label.mdx +8 -8
- package/components/ui/map/map.mdx +8 -8
- package/components/ui/menubar/menubar.mdx +8 -8
- package/components/ui/navigation-menu/navigation-menu.mdx +8 -8
- package/components/ui/notification-badge/notification-badge.mdx +8 -8
- package/components/ui/pagination/pagination.mdx +8 -8
- package/components/ui/popover/popover.mdx +8 -8
- package/components/ui/progress/progress.mdx +8 -8
- package/components/ui/radio-group/radio-group.mdx +8 -8
- package/components/ui/rating/rating.mdx +8 -8
- package/components/ui/resizable/resizable.mdx +8 -8
- package/components/ui/route-map/route-map.mdx +8 -8
- package/components/ui/scroll-area/scroll-area.mdx +8 -8
- package/components/ui/search/search.mdx +8 -8
- package/components/ui/select/select.mdx +8 -8
- package/components/ui/separator/separator.mdx +8 -8
- package/components/ui/sheet/sheet.mdx +8 -8
- package/components/ui/simple-map/simple-map.mdx +8 -8
- package/components/ui/skeleton/skeleton.mdx +8 -8
- package/components/ui/slider/slider.mdx +8 -8
- package/components/ui/sonner/sonner.mdx +8 -8
- package/components/ui/stats-card/index.ts +2 -2
- package/components/ui/stats-card/stats-card-skeleton.tsx +60 -60
- package/components/ui/stats-card/stats-card.mdx +8 -8
- package/components/ui/stats-card/stats-card.tsx +109 -109
- package/components/ui/stepper/stepper.mdx +8 -8
- package/components/ui/switch/switch.mdx +8 -8
- package/components/ui/table/table.mdx +8 -8
- package/components/ui/tabs/tabs.mdx +8 -8
- package/components/ui/textarea/textarea.mdx +8 -8
- package/components/ui/timeline/timeline.mdx +8 -8
- package/components/ui/toggle/toggle.mdx +8 -8
- package/components/ui/toggle-group/toggle-group.mdx +8 -8
- package/components/ui/tooltip/tooltip.mdx +8 -8
- package/components/ui/tree-view/tree-view.mdx +8 -8
- package/components.json +511 -511
- package/contexts/AuthContext.tsx +121 -121
- package/contexts/BrandColorsContext.tsx +282 -282
- package/contexts/LanguageContext.test.tsx +121 -121
- package/contexts/LanguageContext.tsx +250 -250
- package/contexts/theme-data.ts +391 -391
- package/dist/{AssistantChart-DoZCyS5r.cjs → AssistantChart-9w31gdAb.cjs} +4 -4
- package/dist/{AssistantChart-CldVCVDe.cjs → AssistantChart-BAudAfne.cjs} +5 -5
- package/dist/{AssistantChart-Bdd44uBn.cjs → AssistantChart-BAx9VQvb.cjs} +127 -388
- package/dist/{AssistantChart-Cu3m7RBo.js → AssistantChart-BP8upjMk.js} +5 -5
- package/dist/{AssistantChart-CFhDdGyU.js → AssistantChart-CVko2A1W.js} +130 -391
- package/dist/{AssistantChart-C_hwFRRr.js → AssistantChart-CVzmmhx4.js} +4 -4
- package/dist/{AudioPlayer-IAU5q5T1.cjs → AudioPlayer-1ypwE2Wh.cjs} +1 -1
- package/dist/{AudioPlayer-CGRUtUdN.js → AudioPlayer-DuKXrCfy.js} +1 -1
- package/dist/{LanguageContext-CS14yCpi.js → LanguageContext-BwhwC3G2.js} +2 -2
- package/dist/{LanguageContext-B_KFTCzT.cjs → LanguageContext-DvUt5jBg.cjs} +2 -2
- package/dist/{ThemeContext-C2EwAPDt.js → ThemeContext-BbBNoFTG.js} +2 -2
- package/dist/{ThemeContext-Bmod0Cg2.cjs → ThemeContext-BblcjQup.cjs} +13 -8
- package/dist/{ThemeContext-BWq9ACPo.js → ThemeContext-Bo-W2WZH.js} +13 -8
- package/dist/{ThemeContext-j5aGtPky.cjs → ThemeContext-CP3a0jxy.cjs} +193 -262
- package/dist/{ThemeContext-vTjumZeM.cjs → ThemeContext-Cmr8Ex8H.cjs} +2 -2
- package/dist/ThemeContext-CpqYShLq.cjs +324 -0
- package/dist/{ThemeContext-CQSo4Iwc.js → ThemeContext-D3LzacmG.js} +8 -1
- package/dist/ThemeContext-Du2nE1PL.js +325 -0
- package/dist/ThemeContext-GeEBTJ3q.cjs +1621 -0
- package/dist/ThemeContext-JyLK9B1o.js +1622 -0
- package/dist/{ThemeContext-CGk3KK0k.cjs → ThemeContext-U4dEYc6C.cjs} +8 -1
- package/dist/{ThemeContext-BXjrgUjW.js → ThemeContext-ept8jhXI.js} +200 -261
- package/dist/{VerifyEmailPage-CGIwmWrm.js → VerifyEmailPage-B31mCrMc.js} +1 -1
- package/dist/{VerifyEmailPage-C0c2e5n0.js → VerifyEmailPage-BE-L9mB7.js} +7 -7
- package/dist/{VerifyEmailPage-DSBMRHtl.js → VerifyEmailPage-BIBOKV7Z.js} +41 -36
- package/dist/{VerifyEmailPage-DgIid028.js → VerifyEmailPage-BJjAMUTW.js} +4 -4
- package/dist/{VerifyEmailPage--1Vurewl.cjs → VerifyEmailPage-BRSP-Pwt.cjs} +3 -3
- package/dist/{VerifyEmailPage-Cwi3kbol.cjs → VerifyEmailPage-Bae2cBXT.cjs} +7 -7
- package/dist/{VerifyEmailPage-De6bQjrz.cjs → VerifyEmailPage-BiRm7Nh4.cjs} +41 -36
- package/dist/{VerifyEmailPage-ByerOcm4.cjs → VerifyEmailPage-Bv8Ah_TK.cjs} +23 -20
- package/dist/VerifyEmailPage-Bvfv8HVQ.js +3214 -0
- package/dist/{VerifyEmailPage-BComraR7.cjs → VerifyEmailPage-CR7kb5df.cjs} +22 -12
- package/dist/{VerifyEmailPage-CpqqpLpo.cjs → VerifyEmailPage-C_Zk6Gen.cjs} +1 -1
- package/dist/{VerifyEmailPage-MTD7AG1Z.js → VerifyEmailPage-C_ihbcth.js} +4 -4
- package/dist/{VerifyEmailPage-1WwWczAn.js → VerifyEmailPage-CbgjOF0v.js} +22 -12
- package/dist/{VerifyEmailPage-DvMLZgFt.js → VerifyEmailPage-CdYPSJoO.js} +1 -1
- package/dist/{VerifyEmailPage-By3Jf__L.cjs → VerifyEmailPage-CkBYfsNy.cjs} +4 -4
- package/dist/{VerifyEmailPage-CJLz3jrn.js → VerifyEmailPage-Cyl55sJb.js} +23 -20
- package/dist/VerifyEmailPage-D-FRj5TU.cjs +3213 -0
- package/dist/{VerifyEmailPage-B4peJjAT.cjs → VerifyEmailPage-DF2ilhum.cjs} +334 -356
- package/dist/{VerifyEmailPage-CYXtbKi3.cjs → VerifyEmailPage-DMBh4NM9.cjs} +1 -1
- package/dist/{VerifyEmailPage-CgMxRb4z.js → VerifyEmailPage-DTtFfC-J.js} +3 -3
- package/dist/{VerifyEmailPage-CFLMls1p.cjs → VerifyEmailPage-Dt7zgA4w.cjs} +4 -4
- package/dist/{VerifyEmailPage-C5TNQTBa.js → VerifyEmailPage-EhudUdqF.js} +343 -355
- package/dist/{VerifyEmailPage-DGhuIqkb.js → VerifyEmailPage-X14vhdyl.js} +4 -4
- package/dist/VerifyEmailPage-hdB8JQGv.cjs +3213 -0
- package/dist/{VerifyEmailPage-Bp1XXl3H.cjs → VerifyEmailPage-u_Dn7t1U.cjs} +4 -4
- package/dist/VerifyEmailPage-vYHbYK3q.js +3214 -0
- package/dist/{XerticaProvider-CBGc4EMA.cjs → XerticaProvider-AChwphCO.cjs} +4 -4
- package/dist/{XerticaProvider-BIrqfZ-i.cjs → XerticaProvider-AbWlr7Af.cjs} +8 -11
- package/dist/{XerticaProvider-D-yNhF94.cjs → XerticaProvider-B8CaV7xu.cjs} +1 -1
- package/dist/{XerticaProvider-CEoWMTxu.js → XerticaProvider-BITjgC5p.js} +2 -2
- package/dist/{XerticaProvider-CllrbMEJ.cjs → XerticaProvider-By8q3Roe.cjs} +2 -2
- package/dist/{XerticaProvider-C1DKnvLh.js → XerticaProvider-CUYJZc32.js} +4 -4
- package/dist/{XerticaProvider-ET0ihewn.cjs → XerticaProvider-CW9hpCdF.cjs} +2 -2
- package/dist/{XerticaProvider-Dt5HEzbQ.js → XerticaProvider-CWgby5mY.js} +10 -10
- package/dist/XerticaProvider-CWs6EwNa.js +49 -0
- package/dist/XerticaProvider-CjQAQPcn.cjs +48 -0
- package/dist/XerticaProvider-D5lLumH-.js +49 -0
- package/dist/{XerticaProvider-DYq4JWtg.js → XerticaProvider-DQtvJU7m.js} +1 -1
- package/dist/XerticaProvider-qQUDop71.cjs +48 -0
- package/dist/{XerticaProvider-B7EVH-NF.js → XerticaProvider-siSt9uG2.js} +2 -2
- package/dist/{XerticaXLogo-Zw2B276b.cjs → XerticaXLogo-8TTzBjHw.cjs} +1 -1
- package/dist/{XerticaXLogo-B7xQ5dhi.js → XerticaXLogo-BWaag64t.js} +1 -1
- package/dist/{XerticaXLogo-DZbo4vOE.js → XerticaXLogo-CFuIlYFH.js} +12 -12
- package/dist/{XerticaXLogo-bvZSgwGF.cjs → XerticaXLogo-CU-U-GP4.cjs} +7 -13
- package/dist/XerticaXLogo-ChryA6xj.js +252 -0
- package/dist/{XerticaXLogo-CQUUjXoH.cjs → XerticaXLogo-CziKMQil.cjs} +8 -8
- package/dist/XerticaXLogo-DHz5SugF.js +252 -0
- package/dist/XerticaXLogo-DTee_y8X.cjs +251 -0
- package/dist/{XerticaXLogo-Cmsp-Eey.js → XerticaXLogo-DfUvz-lD.js} +9 -9
- package/dist/XerticaXLogo-kslQ8Tk_.cjs +251 -0
- package/dist/{alert-dialog-s-vmNkJ_.js → alert-dialog-iDe5VE5o.js} +3 -3
- package/dist/{alert-dialog-DSKByiKZ.cjs → alert-dialog-yckpaOpy.cjs} +3 -3
- package/dist/cli.js +16 -6
- package/dist/components/ui/chart/chart.d.ts +7 -5
- package/dist/{google-maps-loader-Y-QkD-Li.cjs → google-maps-loader-BqsYL48U.cjs} +0 -5
- package/dist/{google-maps-loader-CTYySAun.js → google-maps-loader-t2IlYBzw.js} +0 -4
- package/dist/index-CkTUgOwX.js +8 -0
- package/dist/{index-COtD8bRW.cjs → index-D3RLKRAs.cjs} +1 -1
- package/dist/index.cjs.js +2 -2
- package/dist/index.es.js +2 -2
- package/dist/index.umd.js +454 -1027
- package/dist/layout.cjs.js +1 -1
- package/dist/layout.es.js +1 -1
- package/dist/pages.cjs.js +1 -1
- package/dist/pages.es.js +1 -1
- package/dist/{sidebar-DAaY8bRU.cjs → sidebar-B3EYhli0.cjs} +33 -24
- package/dist/{sidebar-nzPoVHBQ.cjs → sidebar-B9NR0lCe.cjs} +46 -41
- package/dist/{sidebar-CeTMuzOx.cjs → sidebar-BvF5I2Ue.cjs} +47 -128
- package/dist/{sidebar-q7P2Godd.cjs → sidebar-C5B_LHek.cjs} +1 -1
- package/dist/{sidebar-CrQDDdcz.js → sidebar-CA6_ek3f.js} +33 -24
- package/dist/sidebar-CLmIjgNd.cjs +1136 -0
- package/dist/{sidebar-BxGXsDAd.cjs → sidebar-CVUGHOS_.cjs} +8 -16
- package/dist/{sidebar-BViy8Eeu.js → sidebar-CmvwjnVb.js} +9 -17
- package/dist/{sidebar-B6SlKZYN.js → sidebar-CplprZpM.js} +49 -40
- package/dist/sidebar-Duermn32.js +1133 -0
- package/dist/{sidebar-BbVIQvlP.js → sidebar-Dz7bd3zP.js} +1 -1
- package/dist/{sidebar-0ocFLSks.js → sidebar-KIS0C2JH.js} +50 -127
- package/dist/sidebar-OTO_up7Z.js +801 -0
- package/dist/sidebar-zowjejT2.cjs +800 -0
- package/dist/{use-audio-player-nv8ZSGa1.js → use-audio-player-Bkh23vQ3.js} +3 -7
- package/dist/{use-audio-player-NKsWyjWu.cjs → use-audio-player-Dn1NR9xN.cjs} +3 -7
- package/dist/{xertica-assistant-dyP7KHM5.cjs → xertica-assistant-B1IaHXnB.cjs} +388 -529
- package/dist/{xertica-assistant-ciJaWqm1.js → xertica-assistant-BMqdyRVi.js} +10 -28
- package/dist/{xertica-assistant-V_IdW4WF.cjs → xertica-assistant-Bj3vBCq_.cjs} +9 -27
- package/dist/{xertica-assistant-yX1CFBBo.js → xertica-assistant-DPsESB6t.js} +390 -531
- package/dist/{CodeBlock-7TTgmdGG.cjs → xertica-assistant-Qp3ydksa.cjs} +51 -263
- package/dist/{CodeBlock-BeSt1h5P.js → xertica-assistant-gnCJdcZY.js} +7 -219
- package/dist/xertica-ui.css +2 -2
- package/docs/architecture-improvements.md +456 -456
- package/docs/architecture.md +312 -312
- package/docs/components/assistant.md +428 -428
- package/docs/components/branding.md +252 -252
- package/docs/components/card-patterns.md +447 -447
- package/docs/components/error-boundary.md +201 -201
- package/docs/components/hooks.md +432 -432
- package/docs/components/language-selector.md +176 -176
- package/docs/components/pages.md +323 -323
- package/docs/components/sidebar.md +331 -331
- package/docs/components/stats-card.md +138 -138
- package/docs/doc-audit.md +244 -244
- package/docs/getting-started.md +616 -616
- package/docs/guidelines.md +330 -330
- package/docs/i18n.md +480 -480
- package/docs/installation.md +268 -268
- package/docs/llms.md +295 -295
- package/docs/state-management.md +289 -289
- package/guidelines/Guidelines.md +409 -409
- package/llms-compact.txt +1 -1
- package/llms-full.txt +10688 -10688
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/styles/xertica/base.css +90 -90
- package/styles/xertica/tokens.css +240 -240
- package/templates/.prettierignore +4 -4
- package/templates/.prettierrc +10 -10
- package/templates/CLAUDE.md +180 -180
- package/templates/package.json +2 -2
- package/templates/src/app/App.tsx +46 -46
- package/templates/src/app/components/AuthGuard.tsx +131 -131
- package/templates/src/features/assistant/data/mock.ts +75 -75
- package/templates/src/features/assistant/hooks/useAssistantConfig.ts +20 -20
- package/templates/src/features/assistant/index.ts +5 -5
- package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +70 -70
- package/templates/src/features/auth/ui/LoginContent.tsx +92 -92
- package/templates/src/features/auth/ui/ResetPasswordContent.tsx +183 -183
- package/templates/src/features/auth/ui/SocialLoginButtons.tsx +78 -78
- package/templates/src/features/auth/ui/VerifyEmailContent.tsx +80 -80
- package/templates/src/features/home/data/mock.ts +41 -41
- package/templates/src/features/home/hooks/useFeatureCards.ts +20 -20
- package/templates/src/features/home/index.ts +11 -11
- package/templates/src/features/home/ui/HomeContent.tsx +117 -117
- package/templates/src/features/template/ui/CrudTemplate.tsx +112 -112
- package/templates/src/features/template/ui/DashboardTemplate.tsx +110 -110
- package/templates/src/features/template/ui/FormTemplate.tsx +117 -117
- package/templates/src/features/template/ui/LoginTemplate.tsx +59 -59
- package/templates/src/features/template/ui/TemplateContent.tsx +1322 -1322
- package/templates/src/i18n.ts +124 -124
- package/templates/src/locales/en/common.json +21 -21
- package/templates/src/locales/en/components/activityCard.json +10 -10
- package/templates/src/locales/en/components/assistant.json +119 -119
- package/templates/src/locales/en/components/media.json +29 -29
- package/templates/src/locales/en/components/notificationCard.json +5 -5
- package/templates/src/locales/en/components/profileCard.json +8 -8
- package/templates/src/locales/en/components/projectCard.json +10 -10
- package/templates/src/locales/en/components/sidebar.json +14 -14
- package/templates/src/locales/en/components/stats.json +8 -8
- package/templates/src/locales/en/components/team.json +14 -14
- package/templates/src/locales/en/errors.json +9 -9
- package/templates/src/locales/en/languageSelector.json +7 -7
- package/templates/src/locales/en/nav.json +6 -6
- package/templates/src/locales/en/pages/crudTemplate.json +25 -25
- package/templates/src/locales/en/pages/dashboardTemplate.json +20 -20
- package/templates/src/locales/en/pages/forgotPassword.json +10 -10
- package/templates/src/locales/en/pages/formTemplate.json +16 -16
- package/templates/src/locales/en/pages/home.json +7 -7
- package/templates/src/locales/en/pages/login.json +15 -15
- package/templates/src/locales/en/pages/loginTemplate.json +9 -9
- package/templates/src/locales/en/pages/resetPassword.json +18 -18
- package/templates/src/locales/en/pages/templates.json +317 -317
- package/templates/src/locales/en/pages/verifyEmail.json +12 -12
- package/templates/src/locales/en/themeToggle.json +6 -6
- package/templates/src/locales/es/common.json +21 -21
- package/templates/src/locales/es/components/activityCard.json +10 -10
- package/templates/src/locales/es/components/assistant.json +119 -119
- package/templates/src/locales/es/components/media.json +29 -29
- package/templates/src/locales/es/components/notificationCard.json +5 -5
- package/templates/src/locales/es/components/profileCard.json +8 -8
- package/templates/src/locales/es/components/projectCard.json +10 -10
- package/templates/src/locales/es/components/sidebar.json +14 -14
- package/templates/src/locales/es/components/stats.json +8 -8
- package/templates/src/locales/es/components/team.json +14 -14
- package/templates/src/locales/es/errors.json +9 -9
- package/templates/src/locales/es/languageSelector.json +7 -7
- package/templates/src/locales/es/nav.json +6 -6
- package/templates/src/locales/es/pages/crudTemplate.json +25 -25
- package/templates/src/locales/es/pages/dashboardTemplate.json +20 -20
- package/templates/src/locales/es/pages/forgotPassword.json +10 -10
- package/templates/src/locales/es/pages/formTemplate.json +16 -16
- package/templates/src/locales/es/pages/home.json +7 -7
- package/templates/src/locales/es/pages/login.json +15 -15
- package/templates/src/locales/es/pages/loginTemplate.json +9 -9
- package/templates/src/locales/es/pages/resetPassword.json +18 -18
- package/templates/src/locales/es/pages/templates.json +317 -317
- package/templates/src/locales/es/pages/verifyEmail.json +12 -12
- package/templates/src/locales/es/themeToggle.json +6 -6
- package/templates/src/locales/pt-BR/common.json +21 -21
- package/templates/src/locales/pt-BR/components/activityCard.json +10 -10
- package/templates/src/locales/pt-BR/components/assistant.json +119 -119
- package/templates/src/locales/pt-BR/components/media.json +29 -29
- package/templates/src/locales/pt-BR/components/notificationCard.json +5 -5
- package/templates/src/locales/pt-BR/components/profileCard.json +8 -8
- package/templates/src/locales/pt-BR/components/projectCard.json +10 -10
- package/templates/src/locales/pt-BR/components/sidebar.json +14 -14
- package/templates/src/locales/pt-BR/components/stats.json +8 -8
- package/templates/src/locales/pt-BR/components/team.json +14 -14
- package/templates/src/locales/pt-BR/errors.json +9 -9
- package/templates/src/locales/pt-BR/languageSelector.json +7 -7
- package/templates/src/locales/pt-BR/nav.json +6 -6
- package/templates/src/locales/pt-BR/pages/crudTemplate.json +25 -25
- package/templates/src/locales/pt-BR/pages/dashboardTemplate.json +20 -20
- package/templates/src/locales/pt-BR/pages/forgotPassword.json +10 -10
- package/templates/src/locales/pt-BR/pages/formTemplate.json +16 -16
- package/templates/src/locales/pt-BR/pages/home.json +7 -7
- package/templates/src/locales/pt-BR/pages/login.json +15 -15
- package/templates/src/locales/pt-BR/pages/loginTemplate.json +9 -9
- package/templates/src/locales/pt-BR/pages/resetPassword.json +18 -18
- package/templates/src/locales/pt-BR/pages/templates.json +317 -317
- package/templates/src/locales/pt-BR/pages/verifyEmail.json +12 -12
- package/templates/src/locales/pt-BR/themeToggle.json +6 -6
- package/templates/src/pages/AssistantPage.tsx +470 -470
- package/templates/src/pages/HomePage.tsx +53 -53
- package/templates/src/shared/error-boundary.tsx +150 -150
- package/templates/src/shared/error-fallbacks.tsx +222 -222
- package/templates/src/styles/xertica/tokens.css +240 -240
- package/templates/vite.config.js +20 -20
- package/templates/vite.config.ts +55 -55
- package/dist/AssistantChart-BKVtGUKF.js +0 -3383
- package/dist/AssistantChart-CxGjH7Qk.js +0 -3477
- package/dist/AssistantChart-DIpshm3i.js +0 -4784
- package/dist/AssistantChart-D_PTeu8P.cjs +0 -3503
- package/dist/AssistantChart-WeycT5Pd.cjs +0 -3551
- package/dist/AssistantChart-zjsy2GaZ.cjs +0 -4810
- package/dist/AudioPlayer-B1lt5cPl.cjs +0 -989
- package/dist/AudioPlayer-BZ7bibzU.cjs +0 -982
- package/dist/AudioPlayer-BpRPS4-1.cjs +0 -1277
- package/dist/AudioPlayer-C12BjQBV.cjs +0 -997
- package/dist/AudioPlayer-CFeV8t-5.cjs +0 -936
- package/dist/AudioPlayer-Coly3q5R.js +0 -1278
- package/dist/AudioPlayer-CySJIyvL.js +0 -937
- package/dist/AudioPlayer-DMcG_c7L.js +0 -990
- package/dist/AudioPlayer-DcFKRJE_.js +0 -998
- package/dist/AudioPlayer-e8LfNoqO.js +0 -983
- package/dist/BrandColorsContext-565dDHd5.js +0 -660
- package/dist/BrandColorsContext-BcJbtkqn.cjs +0 -659
- package/dist/CodeBlock-BgfYL_rD.cjs +0 -2094
- package/dist/CodeBlock-BlcqlA9M.cjs +0 -2094
- package/dist/CodeBlock-Bnmeu5ez.cjs +0 -2094
- package/dist/CodeBlock-BtfPlbAI.js +0 -2078
- package/dist/CodeBlock-CIySIuYr.js +0 -2078
- package/dist/CodeBlock-CuPtUM-7.cjs +0 -2094
- package/dist/CodeBlock-D6ffWXgc.js +0 -2078
- package/dist/CodeBlock-D8dcwbit.cjs +0 -2094
- package/dist/CodeBlock-DMZrFnlw.cjs +0 -2094
- package/dist/CodeBlock-DlBehYN8.js +0 -2078
- package/dist/CodeBlock-DnYNI8rQ.js +0 -2078
- package/dist/CodeBlock-DvKWbSnE.cjs +0 -2094
- package/dist/CodeBlock-DwMCfkFY.js +0 -2078
- package/dist/CodeBlock-Dy6CNYyj.js +0 -2078
- package/dist/CodeBlock-U1pPOQI7.cjs +0 -2094
- package/dist/CodeBlock-f_GpNhEB.js +0 -2078
- package/dist/CodeBlock-oB6u8nI1.js +0 -2078
- package/dist/CodeBlock-tZC31B73.cjs +0 -2094
- package/dist/FeatureCard-CxC-7C-C.cjs +0 -300
- package/dist/FeatureCard-DbHWCb4E.js +0 -301
- package/dist/ImageWithFallback-CGtidP6B.cjs +0 -4542
- package/dist/ImageWithFallback-lsg3pdFg.js +0 -4508
- package/dist/LanguageSelector-B5YfbHra.js +0 -231
- package/dist/LanguageSelector-D6uacAIM.cjs +0 -230
- package/dist/LayoutContext-B45-e9DI.cjs +0 -93
- package/dist/LayoutContext-BAql6ZRY.js +0 -97
- package/dist/LayoutContext-Bav3UMEA.js +0 -94
- package/dist/LayoutContext-BvK-ggDa.cjs +0 -96
- package/dist/ThemeContext-BoH4NLfN.js +0 -734
- package/dist/ThemeContext-r69W20Xg.cjs +0 -733
- package/dist/VerifyEmailPage-COiyNl1y.js +0 -2825
- package/dist/VerifyEmailPage-CqKsR2v8.js +0 -2827
- package/dist/VerifyEmailPage-DjQKRlUS.cjs +0 -2824
- package/dist/VerifyEmailPage-s-1X3LDJ.cjs +0 -2826
- package/dist/XerticaOrbe-KL1RBHzw.cjs +0 -1354
- package/dist/XerticaOrbe-zwS1p2a8.js +0 -1355
- package/dist/XerticaProvider-6btlAlzc.js +0 -17
- package/dist/XerticaProvider-BNoNOxQ5.cjs +0 -16
- package/dist/XerticaProvider-BlY2limY.cjs +0 -38
- package/dist/XerticaProvider-DDuiIcKo.js +0 -39
- package/dist/XerticaProvider-cI9hSs27.cjs +0 -38
- package/dist/XerticaProvider-hSwhNQex.js +0 -39
- package/dist/alert-dialog-BOje--vD.js +0 -847
- package/dist/alert-dialog-BtEuQqrg.cjs +0 -870
- package/dist/breadcrumb-CqJ7bHY5.js +0 -161
- package/dist/breadcrumb-m9Hb2_XN.cjs +0 -177
- package/dist/components/assistant/xertica-assistant/hooks/index.d.ts +0 -6
- package/dist/components/assistant/xertica-assistant/hooks/use-assistant-conversations.d.ts +0 -21
- package/dist/components/assistant/xertica-assistant/hooks/use-assistant-messages.d.ts +0 -49
- package/dist/components/assistant/xertica-assistant/hooks/use-assistant-suggestions.d.ts +0 -16
- package/dist/components/blocks/audio-player/AudioPlayer.d.ts +0 -35
- package/dist/components/blocks/audio-player/index.d.ts +0 -1
- package/dist/components/blocks/document-editor/DocumentEditor.d.ts +0 -26
- package/dist/components/blocks/document-editor/index.d.ts +0 -1
- package/dist/components/blocks/podcast-player/PodcastPlayer.d.ts +0 -41
- package/dist/components/blocks/podcast-player/index.d.ts +0 -1
- package/dist/components/ui/chart/parts/chart-dashboard.d.ts +0 -113
- package/dist/components/ui/chart/parts/chart-metric.d.ts +0 -118
- package/dist/components/ui/chart/parts/chart-primitives.d.ts +0 -101
- package/dist/components/ui/chart/parts/chart-shared.d.ts +0 -20
- package/dist/components/ui/chart/parts/chart-utils.d.ts +0 -12
- package/dist/components/ui/chart/parts/index.d.ts +0 -5
- package/dist/dropdown-menu-BDB5CmQs.cjs +0 -247
- package/dist/dropdown-menu-DQidbKBD.js +0 -231
- package/dist/google-maps-loader-BFWp6VPd.js +0 -287
- package/dist/google-maps-loader-BKcdgFbu.cjs +0 -312
- package/dist/google-maps-loader-CumCNXeG.js +0 -312
- package/dist/google-maps-loader-eS3uQ5TA.cjs +0 -287
- package/dist/header-Cgy6vYPk.cjs +0 -731
- package/dist/header-DRlT4jgI.js +0 -715
- package/dist/header-Dux00SI4.cjs +0 -731
- package/dist/header-EkGKXPsD.js +0 -715
- package/dist/header-WfEywpyc.cjs +0 -731
- package/dist/header-tifNQn2U.js +0 -715
- package/dist/index-BhapVLVj.js +0 -8
- package/dist/index-D6fxYEY8.cjs +0 -7
- package/dist/index-DAIp0_HK.js +0 -8
- package/dist/index-DW5tYe26.js +0 -8
- package/dist/index-GA__GvnG.cjs +0 -7
- package/dist/input-2R4loU86.js +0 -127
- package/dist/input-DWANSKGb.cjs +0 -145
- package/dist/progress-DPtzoVV8.js +0 -175
- package/dist/progress-EeaoqqUs.cjs +0 -191
- package/dist/rich-text-editor-0mraWT5y.cjs +0 -2376
- package/dist/rich-text-editor-B-IkcPD0.js +0 -2874
- package/dist/rich-text-editor-B6jMRLzk.cjs +0 -1939
- package/dist/rich-text-editor-B8_oYcIR.js +0 -1730
- package/dist/rich-text-editor-B9UbSXNb.js +0 -1203
- package/dist/rich-text-editor-BYuRBNBU.js +0 -2373
- package/dist/rich-text-editor-Bb9pySTs.cjs +0 -2374
- package/dist/rich-text-editor-BcL6L3cm.cjs +0 -2374
- package/dist/rich-text-editor-BoVZYtTs.cjs +0 -2391
- package/dist/rich-text-editor-Bp3zQqMC.js +0 -2954
- package/dist/rich-text-editor-CMgSN_w2.js +0 -1189
- package/dist/rich-text-editor-CPV1lEPH.cjs +0 -1748
- package/dist/rich-text-editor-CeucBdIv.cjs +0 -2971
- package/dist/rich-text-editor-CoKqbCtu.cjs +0 -1799
- package/dist/rich-text-editor-Cw56T_mB.js +0 -2356
- package/dist/rich-text-editor-Cyt8qs2b.js +0 -1921
- package/dist/rich-text-editor-D6H84OcX.cjs +0 -1220
- package/dist/rich-text-editor-D76gD-QI.js +0 -2328
- package/dist/rich-text-editor-DKkokOnA.js +0 -1781
- package/dist/rich-text-editor-DNsdpN64.cjs +0 -2359
- package/dist/rich-text-editor-DfG8bCyY.js +0 -2358
- package/dist/rich-text-editor-Dxjw31Z4.js +0 -2341
- package/dist/rich-text-editor-DzP0Epmb.js +0 -2356
- package/dist/rich-text-editor-bRkNoeZY.cjs +0 -2891
- package/dist/rich-text-editor-lyYE2ZG5.cjs +0 -1207
- package/dist/rich-text-editor-skplNlBM.cjs +0 -2345
- package/dist/select-Bkbr0f-Z.cjs +0 -162
- package/dist/select-CvIVdX2n.js +0 -145
- package/dist/sidebar-CK_0ZQHj.cjs +0 -803
- package/dist/sidebar-CUuOvYhK.js +0 -787
- package/dist/sidebar-DQj1z3jG.cjs +0 -758
- package/dist/sidebar-Djn5syhi.cjs +0 -786
- package/dist/sidebar-LluMXfam.js +0 -759
- package/dist/sidebar-_rT7rBMk.js +0 -787
- package/dist/slider-Bc5Hd0y1.js +0 -56
- package/dist/slider-N7hFFj6X.cjs +0 -73
- package/dist/tooltip-Ded96neP.cjs +0 -137
- package/dist/tooltip-HDOoD2-0.js +0 -120
- package/dist/use-audio-player-B31J-aqh.cjs +0 -187
- package/dist/use-audio-player-BkmEmj8Q.js +0 -185
- package/dist/use-audio-player-CLFTWFW1.cjs +0 -184
- package/dist/use-audio-player-CLLn00I6.js +0 -188
- package/dist/use-file-upload-BcjEo2S5.js +0 -404
- package/dist/use-file-upload-CRJR68Tj.cjs +0 -403
- package/dist/use-mobile-B0hNy_Y6.cjs +0 -4303
- package/dist/use-mobile-BXuYROXM.js +0 -4202
- package/dist/use-mobile-Bbd51ASU.cjs +0 -4392
- package/dist/use-mobile-Bk6CX-TC.js +0 -4359
- package/dist/use-mobile-BvYdisLP.js +0 -4202
- package/dist/use-mobile-BzuxjzNX.cjs +0 -4392
- package/dist/use-mobile-CG2-SdXV.cjs +0 -4235
- package/dist/use-mobile-CKb5pqTs.js +0 -4269
- package/dist/use-mobile-CYuAuGDl.js +0 -4202
- package/dist/use-mobile-CaENcqm-.js +0 -4508
- package/dist/use-mobile-CbrYgJGJ.js +0 -4203
- package/dist/use-mobile-Cd4xPrKq.cjs +0 -46
- package/dist/use-mobile-DMOvImGQ.cjs +0 -4542
- package/dist/use-mobile-DRB3BQgD.cjs +0 -4235
- package/dist/use-mobile-DZvv7QMR.js +0 -4359
- package/dist/use-mobile-DdI_TXam.cjs +0 -4235
- package/dist/use-mobile-DlceKf8a.js +0 -4359
- package/dist/use-mobile-DsOnow1o.cjs +0 -4236
- package/dist/use-mobile-Kcj6jSnK.cjs +0 -4392
- package/dist/use-mobile-bnKcua_i.js +0 -4202
- package/dist/use-mobile-j4w2Jrf1.js +0 -30
- package/dist/use-mobile-ncXBeE2z.cjs +0 -4235
- package/dist/use-rich-text-editor-DjiddBGv.js +0 -282
- package/dist/use-rich-text-editor-lpeswbCs.cjs +0 -281
- package/dist/xertica-assistant-BdiZag0h.js +0 -2187
- package/dist/xertica-assistant-CrgTb6Hs.cjs +0 -2155
- package/dist/xertica-assistant-DCsnQyi5.js +0 -2156
- package/dist/xertica-assistant-DUBpmEgo.cjs +0 -2186
- package/dist/{rich-text-editor-DgF8s7xW.js → rich-text-editor-BmsjY03B.js} +26 -26
- package/dist/{rich-text-editor-mWoaSCE4.cjs → rich-text-editor-GS2kpTAK.cjs} +26 -26
|
@@ -1,250 +1,250 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
createContext,
|
|
3
|
-
useCallback,
|
|
4
|
-
useContext,
|
|
5
|
-
useEffect,
|
|
6
|
-
useMemo,
|
|
7
|
-
useState,
|
|
8
|
-
type ReactNode,
|
|
9
|
-
} from 'react';
|
|
10
|
-
import i18n from '../i18n';
|
|
11
|
-
import { useQueryClient } from '@tanstack/react-query';
|
|
12
|
-
|
|
13
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
14
|
-
// Types
|
|
15
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Language code — any string is allowed so consumers can extend with their own
|
|
19
|
-
* locales (e.g. `'fr'`, `'de'`, `'ja'`). The library ships with built-in
|
|
20
|
-
* support for `'pt-BR'`, `'en'`, and `'es'`, but those are recommendations not
|
|
21
|
-
* restrictions.
|
|
22
|
-
*/
|
|
23
|
-
export type Language = string;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Descriptor for a single language available in the picker.
|
|
27
|
-
*/
|
|
28
|
-
export interface LanguageDefinition {
|
|
29
|
-
/** ISO/BCP-47 code stored in localStorage and passed to i18n.changeLanguage() */
|
|
30
|
-
code: Language;
|
|
31
|
-
/** Full display label shown in the LanguageSelector dropdown */
|
|
32
|
-
label: string;
|
|
33
|
-
/** Short label shown in `variant="minimal"` (e.g. "PT", "EN") */
|
|
34
|
-
shortLabel?: string;
|
|
35
|
-
/** Optional translation JSON. When provided, it is registered with i18next
|
|
36
|
-
* on mount so dynamically added locales are loaded automatically.
|
|
37
|
-
* Use a plain object matching your `pt-BR.json` shape. */
|
|
38
|
-
resources?: Record<string, unknown>;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface LanguageContextType {
|
|
42
|
-
/** Currently active language code */
|
|
43
|
-
language: Language;
|
|
44
|
-
/** Change the active language (persists + updates i18n + invalidates queries) */
|
|
45
|
-
setLanguage: (language: Language) => void;
|
|
46
|
-
/** All languages registered for this app */
|
|
47
|
-
availableLanguages: LanguageDefinition[];
|
|
48
|
-
/** True when only a single language is configured — UI can hide selectors */
|
|
49
|
-
isMonolingual: boolean;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
53
|
-
// Defaults
|
|
54
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Default language set when no `availableLanguages` prop is provided.
|
|
58
|
-
* These are the locales the library ships with out-of-the-box.
|
|
59
|
-
*/
|
|
60
|
-
export const DEFAULT_LANGUAGES: LanguageDefinition[] = [
|
|
61
|
-
{ code: 'pt-BR', label: 'Português (BR)', shortLabel: 'PT' },
|
|
62
|
-
{ code: 'en', label: 'English', shortLabel: 'EN' },
|
|
63
|
-
{ code: 'es', label: 'Español', shortLabel: 'ES' },
|
|
64
|
-
];
|
|
65
|
-
|
|
66
|
-
const STORAGE_KEY = 'xertica_language';
|
|
67
|
-
|
|
68
|
-
// Maps legacy localStorage values (from older versions) to canonical codes.
|
|
69
|
-
const LEGACY_LANGUAGE_MAP: Record<string, string> = {
|
|
70
|
-
PT: 'pt-BR',
|
|
71
|
-
pt: 'pt-BR',
|
|
72
|
-
EN: 'en',
|
|
73
|
-
'en-US': 'en',
|
|
74
|
-
ES: 'es',
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
78
|
-
// Context
|
|
79
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
80
|
-
|
|
81
|
-
const LanguageContext = createContext<LanguageContextType | undefined>(undefined);
|
|
82
|
-
|
|
83
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
84
|
-
// Provider
|
|
85
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
86
|
-
|
|
87
|
-
export interface LanguageProviderProps {
|
|
88
|
-
children: ReactNode;
|
|
89
|
-
/**
|
|
90
|
-
* List of languages available to this app. The first item is the default
|
|
91
|
-
* when no saved preference exists. Pass a single-item array to lock the
|
|
92
|
-
* app to one language (the LanguageSelector will hide itself automatically).
|
|
93
|
-
* Defaults to `DEFAULT_LANGUAGES` (pt-BR, en, es) when omitted.
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* ```tsx
|
|
97
|
-
* // Monolingual English app
|
|
98
|
-
* <LanguageProvider availableLanguages={[{ code: 'en', label: 'English' }]}>
|
|
99
|
-
* ```
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* ```tsx
|
|
103
|
-
* // Add French alongside the built-in languages
|
|
104
|
-
* import fr from './locales/fr.json';
|
|
105
|
-
*
|
|
106
|
-
* <LanguageProvider availableLanguages={[
|
|
107
|
-
* ...DEFAULT_LANGUAGES,
|
|
108
|
-
* { code: 'fr', label: 'Français', shortLabel: 'FR', resources: fr },
|
|
109
|
-
* ]}>
|
|
110
|
-
* ```
|
|
111
|
-
*/
|
|
112
|
-
availableLanguages?: LanguageDefinition[];
|
|
113
|
-
/**
|
|
114
|
-
* Override the default language. Falls back to the first item in
|
|
115
|
-
* `availableLanguages` when omitted.
|
|
116
|
-
*/
|
|
117
|
-
defaultLanguage?: Language;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function LanguageProvider({
|
|
121
|
-
children,
|
|
122
|
-
availableLanguages = DEFAULT_LANGUAGES,
|
|
123
|
-
defaultLanguage,
|
|
124
|
-
}: LanguageProviderProps) {
|
|
125
|
-
// Hard guard: empty array is almost always a consumer mistake. Throwing here
|
|
126
|
-
// surfaces the bug at provider mount instead of letting the app silently fall
|
|
127
|
-
// back to DEFAULT_LANGUAGES (which would, in turn, surprise monolingual apps
|
|
128
|
-
// that meant to pass `[{code:'en',...}]` but accidentally passed `[]`).
|
|
129
|
-
if (availableLanguages.length === 0) {
|
|
130
|
-
throw new Error(
|
|
131
|
-
'LanguageProvider: `availableLanguages` cannot be empty. Pass at least one ' +
|
|
132
|
-
'LanguageDefinition or omit the prop to use DEFAULT_LANGUAGES.'
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
const languages = availableLanguages;
|
|
136
|
-
|
|
137
|
-
// useQueryClient() works because LanguageProvider is always rendered inside
|
|
138
|
-
// <QueryClientProvider> (both in App.tsx and via XerticaProvider in templates).
|
|
139
|
-
const queryClient = useQueryClient();
|
|
140
|
-
|
|
141
|
-
// Stable "signature" of the configured languages — string of comma-joined
|
|
142
|
-
// codes. This prevents the effect below (and downstream `useMemo`) from
|
|
143
|
-
// firing every render when a consumer passes `availableLanguages={[...]}`
|
|
144
|
-
// inline (a fresh array reference on every render).
|
|
145
|
-
const languageCodesKey = useMemo(() => languages.map(l => l.code).join(','), [languages]);
|
|
146
|
-
|
|
147
|
-
// Register any locale `resources` carried by language definitions. This
|
|
148
|
-
// allows consumers to ship new locales without editing `i18n.ts`.
|
|
149
|
-
useEffect(() => {
|
|
150
|
-
for (const lang of languages) {
|
|
151
|
-
if (lang.resources && !i18n.hasResourceBundle(lang.code, 'translation')) {
|
|
152
|
-
i18n.addResourceBundle(lang.code, 'translation', lang.resources, true, true);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
// `languageCodesKey` is a stable string signature; only re-runs when the
|
|
156
|
-
// set of configured language codes actually changes.
|
|
157
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
158
|
-
}, [languageCodesKey]);
|
|
159
|
-
|
|
160
|
-
const resolvedDefault = defaultLanguage ?? languages[0].code;
|
|
161
|
-
|
|
162
|
-
const [language, setLanguageState] = useState<Language>(() => {
|
|
163
|
-
const saved = typeof window !== 'undefined' ? window.localStorage?.getItem(STORAGE_KEY) : null;
|
|
164
|
-
|
|
165
|
-
// Direct match against configured languages
|
|
166
|
-
if (saved && languages.some(l => l.code === saved)) {
|
|
167
|
-
return saved;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Legacy migration
|
|
171
|
-
if (saved && LEGACY_LANGUAGE_MAP[saved]) {
|
|
172
|
-
const migrated = LEGACY_LANGUAGE_MAP[saved];
|
|
173
|
-
if (languages.some(l => l.code === migrated)) {
|
|
174
|
-
return migrated;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return resolvedDefault;
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
/** Change language: persists to localStorage, updates i18next, and invalidates
|
|
182
|
-
* the React Query cache so any query whose result contains translated strings
|
|
183
|
-
* is refetched in the new language on next render.
|
|
184
|
-
*
|
|
185
|
-
* Components using `useTranslation()` already update instantly (i18next notifies
|
|
186
|
-
* them). Queries using `useFeatureCards()` / `useAssistantConfig()` etc. also
|
|
187
|
-
* update instantly because language is included in their queryKey — switching
|
|
188
|
-
* language means a new key → cache miss → immediate refetch.
|
|
189
|
-
*
|
|
190
|
-
* Wrapped in `useCallback` so that consumers destructuring `setLanguage` and
|
|
191
|
-
* passing it into effect dependency arrays get a stable reference. */
|
|
192
|
-
const setLanguage = useCallback(
|
|
193
|
-
(lang: Language) => {
|
|
194
|
-
// Silently no-op if the requested language is not registered.
|
|
195
|
-
if (!languages.some(l => l.code === lang)) {
|
|
196
|
-
if (typeof console !== 'undefined') {
|
|
197
|
-
console.warn(
|
|
198
|
-
`[LanguageProvider] Language "${lang}" is not in availableLanguages — ignoring.`
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
setLanguageState(lang);
|
|
204
|
-
window.localStorage?.setItem(STORAGE_KEY, lang);
|
|
205
|
-
i18n.changeLanguage(lang);
|
|
206
|
-
// Defensive invalidation: refetches any query that didn't include language
|
|
207
|
-
// in its queryKey and would otherwise serve stale translated strings.
|
|
208
|
-
queryClient.invalidateQueries();
|
|
209
|
-
},
|
|
210
|
-
// Depend on the stable codes signature instead of the `languages` array
|
|
211
|
-
// reference so the callback identity remains stable across inline-prop renders.
|
|
212
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
213
|
-
[languageCodesKey, queryClient]
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
// Sync i18next on mount in case the page refreshed with a saved language
|
|
217
|
-
useEffect(() => {
|
|
218
|
-
if (i18n.language !== language) {
|
|
219
|
-
i18n.changeLanguage(language);
|
|
220
|
-
}
|
|
221
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
222
|
-
}, []); // mount-only — i18n.ts already reads localStorage for the initial lng
|
|
223
|
-
|
|
224
|
-
const value = useMemo<LanguageContextType>(
|
|
225
|
-
() => ({
|
|
226
|
-
language,
|
|
227
|
-
setLanguage,
|
|
228
|
-
availableLanguages: languages,
|
|
229
|
-
isMonolingual: languages.length <= 1,
|
|
230
|
-
}),
|
|
231
|
-
// `setLanguage` is stable thanks to useCallback above; `languages` is gated
|
|
232
|
-
// by `languageCodesKey` so that inline-array consumers don't thrash the memo.
|
|
233
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
234
|
-
[language, setLanguage, languageCodesKey]
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
return <LanguageContext.Provider value={value}>{children}</LanguageContext.Provider>;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
241
|
-
// Hook
|
|
242
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
243
|
-
|
|
244
|
-
export function useLanguage() {
|
|
245
|
-
const context = useContext(LanguageContext);
|
|
246
|
-
if (context === undefined) {
|
|
247
|
-
throw new Error('useLanguage must be used within a LanguageProvider');
|
|
248
|
-
}
|
|
249
|
-
return context;
|
|
250
|
-
}
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useCallback,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useState,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import i18n from '../i18n';
|
|
11
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
12
|
+
|
|
13
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
// Types
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Language code — any string is allowed so consumers can extend with their own
|
|
19
|
+
* locales (e.g. `'fr'`, `'de'`, `'ja'`). The library ships with built-in
|
|
20
|
+
* support for `'pt-BR'`, `'en'`, and `'es'`, but those are recommendations not
|
|
21
|
+
* restrictions.
|
|
22
|
+
*/
|
|
23
|
+
export type Language = string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Descriptor for a single language available in the picker.
|
|
27
|
+
*/
|
|
28
|
+
export interface LanguageDefinition {
|
|
29
|
+
/** ISO/BCP-47 code stored in localStorage and passed to i18n.changeLanguage() */
|
|
30
|
+
code: Language;
|
|
31
|
+
/** Full display label shown in the LanguageSelector dropdown */
|
|
32
|
+
label: string;
|
|
33
|
+
/** Short label shown in `variant="minimal"` (e.g. "PT", "EN") */
|
|
34
|
+
shortLabel?: string;
|
|
35
|
+
/** Optional translation JSON. When provided, it is registered with i18next
|
|
36
|
+
* on mount so dynamically added locales are loaded automatically.
|
|
37
|
+
* Use a plain object matching your `pt-BR.json` shape. */
|
|
38
|
+
resources?: Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface LanguageContextType {
|
|
42
|
+
/** Currently active language code */
|
|
43
|
+
language: Language;
|
|
44
|
+
/** Change the active language (persists + updates i18n + invalidates queries) */
|
|
45
|
+
setLanguage: (language: Language) => void;
|
|
46
|
+
/** All languages registered for this app */
|
|
47
|
+
availableLanguages: LanguageDefinition[];
|
|
48
|
+
/** True when only a single language is configured — UI can hide selectors */
|
|
49
|
+
isMonolingual: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
53
|
+
// Defaults
|
|
54
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Default language set when no `availableLanguages` prop is provided.
|
|
58
|
+
* These are the locales the library ships with out-of-the-box.
|
|
59
|
+
*/
|
|
60
|
+
export const DEFAULT_LANGUAGES: LanguageDefinition[] = [
|
|
61
|
+
{ code: 'pt-BR', label: 'Português (BR)', shortLabel: 'PT' },
|
|
62
|
+
{ code: 'en', label: 'English', shortLabel: 'EN' },
|
|
63
|
+
{ code: 'es', label: 'Español', shortLabel: 'ES' },
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
const STORAGE_KEY = 'xertica_language';
|
|
67
|
+
|
|
68
|
+
// Maps legacy localStorage values (from older versions) to canonical codes.
|
|
69
|
+
const LEGACY_LANGUAGE_MAP: Record<string, string> = {
|
|
70
|
+
PT: 'pt-BR',
|
|
71
|
+
pt: 'pt-BR',
|
|
72
|
+
EN: 'en',
|
|
73
|
+
'en-US': 'en',
|
|
74
|
+
ES: 'es',
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
78
|
+
// Context
|
|
79
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
const LanguageContext = createContext<LanguageContextType | undefined>(undefined);
|
|
82
|
+
|
|
83
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
84
|
+
// Provider
|
|
85
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
export interface LanguageProviderProps {
|
|
88
|
+
children: ReactNode;
|
|
89
|
+
/**
|
|
90
|
+
* List of languages available to this app. The first item is the default
|
|
91
|
+
* when no saved preference exists. Pass a single-item array to lock the
|
|
92
|
+
* app to one language (the LanguageSelector will hide itself automatically).
|
|
93
|
+
* Defaults to `DEFAULT_LANGUAGES` (pt-BR, en, es) when omitted.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```tsx
|
|
97
|
+
* // Monolingual English app
|
|
98
|
+
* <LanguageProvider availableLanguages={[{ code: 'en', label: 'English' }]}>
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```tsx
|
|
103
|
+
* // Add French alongside the built-in languages
|
|
104
|
+
* import fr from './locales/fr.json';
|
|
105
|
+
*
|
|
106
|
+
* <LanguageProvider availableLanguages={[
|
|
107
|
+
* ...DEFAULT_LANGUAGES,
|
|
108
|
+
* { code: 'fr', label: 'Français', shortLabel: 'FR', resources: fr },
|
|
109
|
+
* ]}>
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
availableLanguages?: LanguageDefinition[];
|
|
113
|
+
/**
|
|
114
|
+
* Override the default language. Falls back to the first item in
|
|
115
|
+
* `availableLanguages` when omitted.
|
|
116
|
+
*/
|
|
117
|
+
defaultLanguage?: Language;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function LanguageProvider({
|
|
121
|
+
children,
|
|
122
|
+
availableLanguages = DEFAULT_LANGUAGES,
|
|
123
|
+
defaultLanguage,
|
|
124
|
+
}: LanguageProviderProps) {
|
|
125
|
+
// Hard guard: empty array is almost always a consumer mistake. Throwing here
|
|
126
|
+
// surfaces the bug at provider mount instead of letting the app silently fall
|
|
127
|
+
// back to DEFAULT_LANGUAGES (which would, in turn, surprise monolingual apps
|
|
128
|
+
// that meant to pass `[{code:'en',...}]` but accidentally passed `[]`).
|
|
129
|
+
if (availableLanguages.length === 0) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
'LanguageProvider: `availableLanguages` cannot be empty. Pass at least one ' +
|
|
132
|
+
'LanguageDefinition or omit the prop to use DEFAULT_LANGUAGES.'
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
const languages = availableLanguages;
|
|
136
|
+
|
|
137
|
+
// useQueryClient() works because LanguageProvider is always rendered inside
|
|
138
|
+
// <QueryClientProvider> (both in App.tsx and via XerticaProvider in templates).
|
|
139
|
+
const queryClient = useQueryClient();
|
|
140
|
+
|
|
141
|
+
// Stable "signature" of the configured languages — string of comma-joined
|
|
142
|
+
// codes. This prevents the effect below (and downstream `useMemo`) from
|
|
143
|
+
// firing every render when a consumer passes `availableLanguages={[...]}`
|
|
144
|
+
// inline (a fresh array reference on every render).
|
|
145
|
+
const languageCodesKey = useMemo(() => languages.map(l => l.code).join(','), [languages]);
|
|
146
|
+
|
|
147
|
+
// Register any locale `resources` carried by language definitions. This
|
|
148
|
+
// allows consumers to ship new locales without editing `i18n.ts`.
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
for (const lang of languages) {
|
|
151
|
+
if (lang.resources && !i18n.hasResourceBundle(lang.code, 'translation')) {
|
|
152
|
+
i18n.addResourceBundle(lang.code, 'translation', lang.resources, true, true);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// `languageCodesKey` is a stable string signature; only re-runs when the
|
|
156
|
+
// set of configured language codes actually changes.
|
|
157
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
158
|
+
}, [languageCodesKey]);
|
|
159
|
+
|
|
160
|
+
const resolvedDefault = defaultLanguage ?? languages[0].code;
|
|
161
|
+
|
|
162
|
+
const [language, setLanguageState] = useState<Language>(() => {
|
|
163
|
+
const saved = typeof window !== 'undefined' ? window.localStorage?.getItem(STORAGE_KEY) : null;
|
|
164
|
+
|
|
165
|
+
// Direct match against configured languages
|
|
166
|
+
if (saved && languages.some(l => l.code === saved)) {
|
|
167
|
+
return saved;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Legacy migration
|
|
171
|
+
if (saved && LEGACY_LANGUAGE_MAP[saved]) {
|
|
172
|
+
const migrated = LEGACY_LANGUAGE_MAP[saved];
|
|
173
|
+
if (languages.some(l => l.code === migrated)) {
|
|
174
|
+
return migrated;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return resolvedDefault;
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
/** Change language: persists to localStorage, updates i18next, and invalidates
|
|
182
|
+
* the React Query cache so any query whose result contains translated strings
|
|
183
|
+
* is refetched in the new language on next render.
|
|
184
|
+
*
|
|
185
|
+
* Components using `useTranslation()` already update instantly (i18next notifies
|
|
186
|
+
* them). Queries using `useFeatureCards()` / `useAssistantConfig()` etc. also
|
|
187
|
+
* update instantly because language is included in their queryKey — switching
|
|
188
|
+
* language means a new key → cache miss → immediate refetch.
|
|
189
|
+
*
|
|
190
|
+
* Wrapped in `useCallback` so that consumers destructuring `setLanguage` and
|
|
191
|
+
* passing it into effect dependency arrays get a stable reference. */
|
|
192
|
+
const setLanguage = useCallback(
|
|
193
|
+
(lang: Language) => {
|
|
194
|
+
// Silently no-op if the requested language is not registered.
|
|
195
|
+
if (!languages.some(l => l.code === lang)) {
|
|
196
|
+
if (typeof console !== 'undefined') {
|
|
197
|
+
console.warn(
|
|
198
|
+
`[LanguageProvider] Language "${lang}" is not in availableLanguages — ignoring.`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
setLanguageState(lang);
|
|
204
|
+
window.localStorage?.setItem(STORAGE_KEY, lang);
|
|
205
|
+
i18n.changeLanguage(lang);
|
|
206
|
+
// Defensive invalidation: refetches any query that didn't include language
|
|
207
|
+
// in its queryKey and would otherwise serve stale translated strings.
|
|
208
|
+
queryClient.invalidateQueries();
|
|
209
|
+
},
|
|
210
|
+
// Depend on the stable codes signature instead of the `languages` array
|
|
211
|
+
// reference so the callback identity remains stable across inline-prop renders.
|
|
212
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
213
|
+
[languageCodesKey, queryClient]
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
// Sync i18next on mount in case the page refreshed with a saved language
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
if (i18n.language !== language) {
|
|
219
|
+
i18n.changeLanguage(language);
|
|
220
|
+
}
|
|
221
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
222
|
+
}, []); // mount-only — i18n.ts already reads localStorage for the initial lng
|
|
223
|
+
|
|
224
|
+
const value = useMemo<LanguageContextType>(
|
|
225
|
+
() => ({
|
|
226
|
+
language,
|
|
227
|
+
setLanguage,
|
|
228
|
+
availableLanguages: languages,
|
|
229
|
+
isMonolingual: languages.length <= 1,
|
|
230
|
+
}),
|
|
231
|
+
// `setLanguage` is stable thanks to useCallback above; `languages` is gated
|
|
232
|
+
// by `languageCodesKey` so that inline-array consumers don't thrash the memo.
|
|
233
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
234
|
+
[language, setLanguage, languageCodesKey]
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
return <LanguageContext.Provider value={value}>{children}</LanguageContext.Provider>;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
241
|
+
// Hook
|
|
242
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
243
|
+
|
|
244
|
+
export function useLanguage() {
|
|
245
|
+
const context = useContext(LanguageContext);
|
|
246
|
+
if (context === undefined) {
|
|
247
|
+
throw new Error('useLanguage must be used within a LanguageProvider');
|
|
248
|
+
}
|
|
249
|
+
return context;
|
|
250
|
+
}
|