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.
Files changed (708) hide show
  1. package/CHANGELOG.md +564 -525
  2. package/README.md +417 -382
  3. package/bin/cli.ts +1244 -748
  4. package/bin/generate-tokens.ts +262 -262
  5. package/bin/language-config.ts +5 -8
  6. package/components/assets/xertica-orbe-animation.ts +1162 -1162
  7. package/components/assistant/code-block/CodeBlock.tsx +268 -268
  8. package/components/assistant/code-block/code-block.stories.tsx +57 -57
  9. package/components/assistant/code-block/code-block.test.tsx +44 -44
  10. package/components/assistant/code-block/index.ts +1 -1
  11. package/components/assistant/formatted-document/FormattedDocument.tsx +147 -147
  12. package/components/assistant/formatted-document/formatted-document.stories.tsx +51 -51
  13. package/components/assistant/formatted-document/formatted-document.test.tsx +42 -42
  14. package/components/assistant/formatted-document/index.ts +1 -1
  15. package/components/assistant/index.ts +6 -6
  16. package/components/assistant/markdown-message/MarkdownMessage.tsx +152 -152
  17. package/components/assistant/markdown-message/index.ts +1 -1
  18. package/components/assistant/markdown-message/markdown-message.stories.tsx +50 -50
  19. package/components/assistant/markdown-message/markdown-message.test.tsx +33 -33
  20. package/components/assistant/modern-chat-input/ModernChatInput.tsx +17 -7
  21. package/components/assistant/modern-chat-input/index.ts +1 -1
  22. package/components/assistant/modern-chat-input/modern-chat-input.stories.tsx +131 -131
  23. package/components/assistant/modern-chat-input/modern-chat-input.test.tsx +79 -79
  24. package/components/assistant/xertica-assistant/index.ts +3 -3
  25. package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +99 -99
  26. package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -106
  27. package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -81
  28. package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +88 -78
  29. package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +75 -75
  30. package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +564 -560
  31. package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +67 -67
  32. package/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.tsx +41 -41
  33. package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +103 -103
  34. package/components/assistant/xertica-assistant/parts/index.ts +16 -16
  35. package/components/assistant/xertica-assistant/types.ts +134 -134
  36. package/components/assistant/xertica-assistant/use-assistant.ts +615 -615
  37. package/components/assistant/xertica-assistant/xertica-assistant.stories.tsx +407 -407
  38. package/components/assistant/xertica-assistant/xertica-assistant.test.tsx +65 -65
  39. package/components/assistant/xertica-assistant/xertica-assistant.tsx +611 -613
  40. package/components/blocks/card-patterns/ActivityCard.tsx +100 -100
  41. package/components/blocks/card-patterns/FeatureCard.tsx +109 -109
  42. package/components/blocks/card-patterns/FeatureCardSkeleton.tsx +1 -6
  43. package/components/blocks/card-patterns/NotificationCard.tsx +140 -140
  44. package/components/blocks/card-patterns/ProfileCard.tsx +112 -114
  45. package/components/blocks/card-patterns/ProjectCard.tsx +123 -123
  46. package/components/blocks/card-patterns/ProjectCardSkeleton.tsx +1 -6
  47. package/components/blocks/card-patterns/QuickActionCard.tsx +68 -68
  48. package/components/blocks/card-patterns/card-patterns.mdx +123 -123
  49. package/components/blocks/card-patterns/card-patterns.stories.tsx +594 -594
  50. package/components/blocks/card-patterns/index.ts +29 -29
  51. package/components/blocks/index.ts +1 -1
  52. package/components/brand/branding/branding.stories.tsx +57 -57
  53. package/components/brand/index.ts +6 -6
  54. package/components/brand/language-selector/index.ts +1 -1
  55. package/components/brand/language-selector/language-selector.mdx +126 -126
  56. package/components/brand/language-selector/language-selector.stories.tsx +1 -4
  57. package/components/brand/theme-toggle/ThemeToggle.tsx +74 -70
  58. package/components/brand/theme-toggle/index.ts +1 -1
  59. package/components/brand/theme-toggle/theme-toggle.stories.tsx +34 -34
  60. package/components/brand/theme-toggle/theme-toggle.test.tsx +34 -34
  61. package/components/brand/xertica-logo/XerticaLogo.stories.tsx +82 -82
  62. package/components/brand/xertica-logo/XerticaLogo.tsx +104 -104
  63. package/components/brand/xertica-logo/index.ts +1 -1
  64. package/components/brand/xertica-logo/xertica-logo.test.tsx +26 -26
  65. package/components/brand/xertica-orbe/XerticaOrbe.tsx +1927 -1927
  66. package/components/brand/xertica-orbe/index.ts +1 -1
  67. package/components/brand/xertica-orbe/xertica-orbe.stories.tsx +40 -40
  68. package/components/brand/xertica-orbe/xertica-orbe.test.tsx +19 -19
  69. package/components/brand/xertica-provider/XerticaProvider.tsx +1 -4
  70. package/components/brand/xertica-provider/index.ts +1 -1
  71. package/components/brand/xertica-provider/xertica-provider.test.tsx +74 -74
  72. package/components/brand/xertica-xlogo/XerticaXLogo.stories.tsx +79 -79
  73. package/components/brand/xertica-xlogo/XerticaXLogo.tsx +65 -65
  74. package/components/brand/xertica-xlogo/index.ts +1 -1
  75. package/components/brand/xertica-xlogo/xertica-xlogo.test.tsx +16 -16
  76. package/components/examples/ApiKeyMapExample.tsx +71 -71
  77. package/components/examples/DrawingMapExample.tsx +565 -565
  78. package/components/examples/FilterableMapExample.tsx +393 -393
  79. package/components/examples/LocationPickerExample.tsx +348 -348
  80. package/components/examples/MapExamples.tsx +268 -268
  81. package/components/examples/MapGmpExample.tsx +169 -169
  82. package/components/examples/MapShowcase.tsx +471 -471
  83. package/components/examples/RouteMapExamples.tsx +329 -329
  84. package/components/examples/SidebarLogoExample.tsx +65 -65
  85. package/components/examples/SimpleFilterableMap.tsx +219 -219
  86. package/components/examples/index.ts +45 -45
  87. package/components/figma/ImageWithFallback.tsx +27 -27
  88. package/components/hooks/index.ts +13 -13
  89. package/components/hooks/use-layout-shortcuts.ts +43 -43
  90. package/components/index.ts +86 -90
  91. package/components/layout/header/header.stories.tsx +204 -204
  92. package/components/layout/header/header.test.tsx +75 -75
  93. package/components/layout/header/header.tsx +349 -349
  94. package/components/layout/header/index.ts +1 -1
  95. package/components/layout/index.ts +2 -2
  96. package/components/layout/sidebar/index.ts +3 -3
  97. package/components/layout/sidebar/sidebar.stories.tsx +586 -586
  98. package/components/layout/sidebar/sidebar.test.tsx +76 -76
  99. package/components/layout/sidebar/sidebar.tsx +1079 -1073
  100. package/components/layout/sidebar/use-sidebar.ts +104 -104
  101. package/components/media/FloatingMediaWrapper.tsx +371 -371
  102. package/components/media/audio-player/AudioPlayer.stories.tsx +124 -124
  103. package/components/media/audio-player/AudioPlayer.test.tsx +106 -106
  104. package/components/media/audio-player/AudioPlayer.tsx +767 -765
  105. package/components/media/audio-player/index.ts +1 -1
  106. package/components/media/audio-player/use-audio-player.ts +312 -312
  107. package/components/media/index.ts +3 -3
  108. package/components/media/video-player/VideoPlayer.stories.tsx +98 -98
  109. package/components/media/video-player/VideoPlayer.test.tsx +73 -73
  110. package/components/media/video-player/VideoPlayer.tsx +310 -310
  111. package/components/media/video-player/index.ts +1 -1
  112. package/components/pages/forgot-password-page/ForgotPasswordPage.stories.tsx +24 -24
  113. package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +188 -188
  114. package/components/pages/forgot-password-page/forgot-password-page.test.tsx +45 -45
  115. package/components/pages/forgot-password-page/index.ts +1 -1
  116. package/components/pages/home-content/HomeContent.stories.tsx +43 -43
  117. package/components/pages/home-content/HomeContent.tsx +120 -120
  118. package/components/pages/home-content/index.ts +1 -1
  119. package/components/pages/home-page/HomePage.stories.tsx +39 -39
  120. package/components/pages/home-page/HomePage.tsx +78 -74
  121. package/components/pages/home-page/home-page.test.tsx +53 -53
  122. package/components/pages/home-page/index.ts +1 -1
  123. package/components/pages/index.ts +8 -8
  124. package/components/pages/login-page/LoginPage.stories.tsx +39 -39
  125. package/components/pages/login-page/LoginPage.tsx +218 -216
  126. package/components/pages/login-page/index.ts +1 -1
  127. package/components/pages/login-page/login-page.test.tsx +63 -63
  128. package/components/pages/reset-password-page/ResetPasswordPage.stories.tsx +24 -24
  129. package/components/pages/reset-password-page/ResetPasswordPage.tsx +243 -239
  130. package/components/pages/reset-password-page/index.ts +1 -1
  131. package/components/pages/template-content/TemplateContent.stories.tsx +43 -43
  132. package/components/pages/template-content/TemplateContent.tsx +1354 -1235
  133. package/components/pages/template-content/index.ts +1 -1
  134. package/components/pages/template-page/TemplatePage.stories.tsx +39 -39
  135. package/components/pages/template-page/TemplatePage.tsx +62 -62
  136. package/components/pages/template-page/index.ts +1 -1
  137. package/components/pages/template-page/template-page.test.tsx +52 -52
  138. package/components/pages/verify-email-page/VerifyEmailPage.stories.tsx +41 -41
  139. package/components/pages/verify-email-page/VerifyEmailPage.tsx +206 -206
  140. package/components/pages/verify-email-page/index.ts +1 -1
  141. package/components/public-api-smoke.test.tsx +52 -52
  142. package/components/shared/CustomTooltipContent.tsx +48 -48
  143. package/components/shared/assistant-utils.test.ts +16 -16
  144. package/components/shared/assistant-utils.ts +225 -225
  145. package/components/shared/error-boundary.stories.tsx +114 -132
  146. package/components/shared/error-boundary.tsx +150 -154
  147. package/components/shared/error-fallbacks.tsx +222 -226
  148. package/components/shared/layout-constants.ts +8 -8
  149. package/components/shared/navigation.ts +35 -35
  150. package/components/shared/use-mobile.test.ts +16 -16
  151. package/components/shared/use-mobile.ts +36 -36
  152. package/components/shared/utils.test.ts +14 -14
  153. package/components/shared/utils.ts +6 -6
  154. package/components/ui/accordion/accordion.stories.tsx +105 -105
  155. package/components/ui/accordion/accordion.test.tsx +59 -59
  156. package/components/ui/accordion/accordion.tsx +77 -77
  157. package/components/ui/accordion/index.ts +1 -1
  158. package/components/ui/alert/alert.stories.tsx +86 -86
  159. package/components/ui/alert/alert.test.tsx +53 -53
  160. package/components/ui/alert/alert.tsx +93 -93
  161. package/components/ui/alert/index.ts +1 -1
  162. package/components/ui/alert-dialog/alert-dialog.stories.tsx +84 -84
  163. package/components/ui/alert-dialog/alert-dialog.test.tsx +70 -70
  164. package/components/ui/alert-dialog/alert-dialog.tsx +149 -149
  165. package/components/ui/alert-dialog/index.ts +1 -1
  166. package/components/ui/aspect-ratio/aspect-ratio.stories.tsx +46 -46
  167. package/components/ui/aspect-ratio/aspect-ratio.test.tsx +28 -28
  168. package/components/ui/aspect-ratio/aspect-ratio.tsx +20 -20
  169. package/components/ui/aspect-ratio/index.ts +1 -1
  170. package/components/ui/assistant-chart/AssistantChart.tsx +64 -64
  171. package/components/ui/assistant-chart/assistant-chart.stories.tsx +44 -44
  172. package/components/ui/assistant-chart/assistant-chart.test.tsx +46 -46
  173. package/components/ui/assistant-chart/index.ts +1 -1
  174. package/components/ui/avatar/avatar.stories.tsx +86 -86
  175. package/components/ui/avatar/avatar.test.tsx +55 -55
  176. package/components/ui/avatar/avatar.tsx +71 -71
  177. package/components/ui/avatar/index.ts +1 -1
  178. package/components/ui/badge/badge.stories.tsx +72 -72
  179. package/components/ui/badge/badge.test.tsx +40 -40
  180. package/components/ui/badge/badge.tsx +58 -58
  181. package/components/ui/badge/index.ts +1 -1
  182. package/components/ui/breadcrumb/breadcrumb.stories.tsx +123 -123
  183. package/components/ui/breadcrumb/breadcrumb.test.tsx +70 -70
  184. package/components/ui/breadcrumb/breadcrumb.tsx +114 -114
  185. package/components/ui/breadcrumb/index.ts +1 -1
  186. package/components/ui/button/button.stories.tsx +183 -183
  187. package/components/ui/button/button.test.tsx +64 -64
  188. package/components/ui/button/button.tsx +98 -98
  189. package/components/ui/button/index.ts +1 -1
  190. package/components/ui/calendar/calendar.stories.tsx +108 -108
  191. package/components/ui/calendar/calendar.test.tsx +53 -53
  192. package/components/ui/calendar/calendar.tsx +230 -230
  193. package/components/ui/calendar/index.ts +1 -1
  194. package/components/ui/card/card.stories.tsx +301 -301
  195. package/components/ui/card/card.test.tsx +55 -55
  196. package/components/ui/card/card.tsx +83 -83
  197. package/components/ui/card/index.ts +1 -1
  198. package/components/ui/carousel/carousel.stories.tsx +80 -80
  199. package/components/ui/carousel/carousel.test.tsx +75 -75
  200. package/components/ui/carousel/carousel.tsx +242 -242
  201. package/components/ui/carousel/index.ts +1 -1
  202. package/components/ui/chart/chart.stories.tsx +1328 -1328
  203. package/components/ui/chart/chart.test.tsx +178 -178
  204. package/components/ui/chart/chart.tsx +2232 -2232
  205. package/components/ui/chart/index.ts +1 -1
  206. package/components/ui/checkbox/checkbox.stories.tsx +109 -109
  207. package/components/ui/checkbox/checkbox.test.tsx +49 -49
  208. package/components/ui/checkbox/checkbox.tsx +68 -68
  209. package/components/ui/checkbox/index.ts +1 -1
  210. package/components/ui/collapsible/collapsible.stories.tsx +45 -45
  211. package/components/ui/collapsible/collapsible.test.tsx +51 -51
  212. package/components/ui/collapsible/collapsible.tsx +32 -32
  213. package/components/ui/collapsible/index.ts +1 -1
  214. package/components/ui/command/command.stories.tsx +134 -134
  215. package/components/ui/command/command.test.tsx +48 -48
  216. package/components/ui/command/command.tsx +163 -163
  217. package/components/ui/command/index.ts +1 -1
  218. package/components/ui/context-menu/context-menu.stories.tsx +76 -76
  219. package/components/ui/context-menu/context-menu.test.tsx +61 -61
  220. package/components/ui/context-menu/context-menu.tsx +236 -236
  221. package/components/ui/context-menu/index.ts +1 -1
  222. package/components/ui/dialog/dialog.stories.tsx +174 -174
  223. package/components/ui/dialog/dialog.test.tsx +78 -78
  224. package/components/ui/dialog/dialog.tsx +189 -189
  225. package/components/ui/dialog/index.ts +1 -1
  226. package/components/ui/drawer/drawer.stories.tsx +71 -71
  227. package/components/ui/drawer/drawer.test.tsx +67 -67
  228. package/components/ui/drawer/drawer.tsx +146 -146
  229. package/components/ui/drawer/index.ts +1 -1
  230. package/components/ui/dropdown-menu/dropdown-menu.stories.tsx +156 -156
  231. package/components/ui/dropdown-menu/dropdown-menu.test.tsx +62 -62
  232. package/components/ui/dropdown-menu/dropdown-menu.tsx +240 -240
  233. package/components/ui/dropdown-menu/index.ts +1 -1
  234. package/components/ui/empty/empty.stories.tsx +85 -85
  235. package/components/ui/empty/empty.test.tsx +31 -31
  236. package/components/ui/empty/empty.tsx +88 -88
  237. package/components/ui/empty/index.ts +1 -1
  238. package/components/ui/file-upload/file-upload.stories.tsx +144 -144
  239. package/components/ui/file-upload/file-upload.test.tsx +65 -65
  240. package/components/ui/file-upload/file-upload.tsx +142 -142
  241. package/components/ui/file-upload/index.ts +2 -2
  242. package/components/ui/file-upload/use-file-upload.ts +177 -177
  243. package/components/ui/form/form.stories.tsx +85 -85
  244. package/components/ui/form/form.test.tsx +75 -75
  245. package/components/ui/form/form.tsx +163 -163
  246. package/components/ui/form/index.ts +1 -1
  247. package/components/ui/google-maps-loader/google-maps-loader.test.tsx +35 -35
  248. package/components/ui/google-maps-loader/google-maps-loader.tsx +465 -465
  249. package/components/ui/google-maps-loader/index.ts +1 -1
  250. package/components/ui/hover-card/hover-card.stories.tsx +61 -61
  251. package/components/ui/hover-card/hover-card.test.tsx +48 -48
  252. package/components/ui/hover-card/hover-card.tsx +50 -50
  253. package/components/ui/hover-card/index.ts +1 -1
  254. package/components/ui/index.ts +400 -400
  255. package/components/ui/input/index.ts +1 -1
  256. package/components/ui/input/input.stories.tsx +153 -153
  257. package/components/ui/input/input.test.tsx +47 -47
  258. package/components/ui/input/input.tsx +57 -57
  259. package/components/ui/input-otp/index.ts +1 -1
  260. package/components/ui/input-otp/input-otp.stories.tsx +120 -120
  261. package/components/ui/input-otp/input-otp.test.tsx +74 -74
  262. package/components/ui/input-otp/input-otp.tsx +101 -101
  263. package/components/ui/label/index.ts +1 -1
  264. package/components/ui/label/label.stories.tsx +74 -74
  265. package/components/ui/label/label.test.tsx +45 -45
  266. package/components/ui/label/label.tsx +53 -53
  267. package/components/ui/map/index.ts +1 -1
  268. package/components/ui/map/map.stories.tsx +86 -86
  269. package/components/ui/map/map.test.tsx +82 -82
  270. package/components/ui/map/map.tsx +506 -506
  271. package/components/ui/map/mock.test.tsx +13 -13
  272. package/components/ui/map-config/index.ts +1 -1
  273. package/components/ui/map-config/map-config.ts +18 -18
  274. package/components/ui/map-layers/index.ts +1 -1
  275. package/components/ui/map-layers/map-layers.test.tsx +48 -48
  276. package/components/ui/map-layers/map-layers.tsx +126 -126
  277. package/components/ui/map.exports/index.ts +1 -1
  278. package/components/ui/map.exports/map.exports.ts +31 -31
  279. package/components/ui/menubar/index.ts +1 -1
  280. package/components/ui/menubar/menubar.stories.tsx +130 -130
  281. package/components/ui/menubar/menubar.test.tsx +53 -53
  282. package/components/ui/menubar/menubar.tsx +265 -265
  283. package/components/ui/navigation-menu/index.ts +1 -1
  284. package/components/ui/navigation-menu/navigation-menu.stories.tsx +126 -126
  285. package/components/ui/navigation-menu/navigation-menu.test.tsx +47 -47
  286. package/components/ui/navigation-menu/navigation-menu.tsx +165 -165
  287. package/components/ui/notification-badge/index.ts +1 -1
  288. package/components/ui/notification-badge/notification-badge.stories.tsx +66 -66
  289. package/components/ui/notification-badge/notification-badge.test.tsx +61 -61
  290. package/components/ui/notification-badge/notification-badge.tsx +91 -91
  291. package/components/ui/page-header/index.ts +1 -1
  292. package/components/ui/page-header/page-header.stories.tsx +69 -69
  293. package/components/ui/page-header/page-header.test.tsx +37 -37
  294. package/components/ui/page-header/page-header.tsx +124 -124
  295. package/components/ui/pagination/index.ts +3 -3
  296. package/components/ui/pagination/pagination.stories.tsx +210 -210
  297. package/components/ui/pagination/pagination.test.tsx +63 -63
  298. package/components/ui/pagination/pagination.tsx +140 -140
  299. package/components/ui/pagination/use-pagination.ts +173 -173
  300. package/components/ui/popover/index.ts +1 -1
  301. package/components/ui/popover/popover.stories.tsx +73 -73
  302. package/components/ui/popover/popover.test.tsx +48 -48
  303. package/components/ui/popover/popover.tsx +54 -54
  304. package/components/ui/progress/index.ts +1 -1
  305. package/components/ui/progress/progress.stories.tsx +55 -55
  306. package/components/ui/progress/progress.test.tsx +23 -23
  307. package/components/ui/progress/progress.tsx +68 -68
  308. package/components/ui/radio-group/index.ts +1 -1
  309. package/components/ui/radio-group/radio-group.stories.tsx +114 -114
  310. package/components/ui/radio-group/radio-group.test.tsx +78 -78
  311. package/components/ui/radio-group/radio-group.tsx +93 -93
  312. package/components/ui/rating/index.ts +1 -1
  313. package/components/ui/rating/rating.stories.tsx +50 -50
  314. package/components/ui/rating/rating.test.tsx +48 -48
  315. package/components/ui/rating/rating.tsx +145 -145
  316. package/components/ui/resizable/index.ts +1 -1
  317. package/components/ui/resizable/resizable.stories.tsx +88 -88
  318. package/components/ui/resizable/resizable.test.tsx +61 -61
  319. package/components/ui/resizable/resizable.tsx +452 -452
  320. package/components/ui/rich-text-editor/index.ts +7 -7
  321. package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +290 -290
  322. package/components/ui/rich-text-editor/rich-text-editor.test.tsx +86 -86
  323. package/components/ui/rich-text-editor/rich-text-editor.tsx +634 -634
  324. package/components/ui/rich-text-editor/use-rich-text-editor.ts +453 -453
  325. package/components/ui/route-map/index.ts +1 -1
  326. package/components/ui/route-map/route-map.stories.tsx +48 -48
  327. package/components/ui/route-map/route-map.test.tsx +108 -108
  328. package/components/ui/route-map/route-map.tsx +349 -349
  329. package/components/ui/scroll-area/index.ts +1 -1
  330. package/components/ui/scroll-area/scroll-area.stories.tsx +31 -31
  331. package/components/ui/scroll-area/scroll-area.test.tsx +27 -27
  332. package/components/ui/scroll-area/scroll-area.tsx +70 -70
  333. package/components/ui/search/index.ts +1 -1
  334. package/components/ui/search/search.stories.tsx +107 -107
  335. package/components/ui/search/search.test.tsx +67 -67
  336. package/components/ui/search/search.tsx +141 -141
  337. package/components/ui/select/index.ts +1 -1
  338. package/components/ui/select/select.stories.tsx +163 -163
  339. package/components/ui/select/select.test.tsx +99 -99
  340. package/components/ui/select/select.tsx +195 -195
  341. package/components/ui/separator/index.ts +1 -1
  342. package/components/ui/separator/separator.stories.tsx +55 -55
  343. package/components/ui/separator/separator.test.tsx +23 -23
  344. package/components/ui/separator/separator.tsx +39 -39
  345. package/components/ui/sheet/index.ts +1 -1
  346. package/components/ui/sheet/sheet.stories.tsx +93 -93
  347. package/components/ui/sheet/sheet.test.tsx +62 -62
  348. package/components/ui/sheet/sheet.tsx +149 -149
  349. package/components/ui/simple-map/index.ts +1 -1
  350. package/components/ui/simple-map/simple-map.stories.tsx +44 -44
  351. package/components/ui/simple-map/simple-map.test.tsx +36 -36
  352. package/components/ui/simple-map/simple-map.tsx +92 -92
  353. package/components/ui/skeleton/index.ts +1 -1
  354. package/components/ui/skeleton/skeleton.stories.tsx +36 -36
  355. package/components/ui/skeleton/skeleton.test.tsx +19 -19
  356. package/components/ui/skeleton/skeleton.tsx +25 -25
  357. package/components/ui/slider/index.ts +1 -1
  358. package/components/ui/slider/slider.stories.tsx +44 -44
  359. package/components/ui/slider/slider.test.tsx +25 -25
  360. package/components/ui/slider/slider.tsx +66 -66
  361. package/components/ui/sonner/index.ts +1 -1
  362. package/components/ui/sonner/sonner.stories.tsx +41 -41
  363. package/components/ui/sonner/sonner.test.tsx +24 -24
  364. package/components/ui/sonner/sonner.tsx +74 -74
  365. package/components/ui/stats-card/index.ts +2 -2
  366. package/components/ui/stats-card/stats-card-skeleton.tsx +1 -3
  367. package/components/ui/stats-card/stats-card.stories.tsx +99 -99
  368. package/components/ui/stats-card/stats-card.test.tsx +34 -34
  369. package/components/ui/stats-card/stats-card.tsx +93 -93
  370. package/components/ui/stepper/index.ts +3 -3
  371. package/components/ui/stepper/stepper.stories.tsx +171 -171
  372. package/components/ui/stepper/stepper.test.tsx +47 -47
  373. package/components/ui/stepper/stepper.tsx +190 -190
  374. package/components/ui/stepper/use-stepper.ts +139 -139
  375. package/components/ui/switch/index.ts +1 -1
  376. package/components/ui/switch/switch.stories.tsx +93 -93
  377. package/components/ui/switch/switch.test.tsx +44 -44
  378. package/components/ui/switch/switch.tsx +70 -70
  379. package/components/ui/table/index.ts +1 -1
  380. package/components/ui/table/table.stories.tsx +114 -114
  381. package/components/ui/table/table.test.tsx +43 -43
  382. package/components/ui/table/table.tsx +104 -104
  383. package/components/ui/tabs/index.ts +1 -1
  384. package/components/ui/tabs/tabs.stories.tsx +140 -140
  385. package/components/ui/tabs/tabs.test.tsx +50 -50
  386. package/components/ui/tabs/tabs.tsx +66 -66
  387. package/components/ui/textarea/index.ts +1 -1
  388. package/components/ui/textarea/textarea.stories.tsx +69 -69
  389. package/components/ui/textarea/textarea.test.tsx +41 -41
  390. package/components/ui/textarea/textarea.tsx +61 -61
  391. package/components/ui/timeline/index.ts +1 -1
  392. package/components/ui/timeline/timeline.stories.tsx +97 -97
  393. package/components/ui/timeline/timeline.test.tsx +53 -53
  394. package/components/ui/timeline/timeline.tsx +124 -124
  395. package/components/ui/toggle/index.ts +1 -1
  396. package/components/ui/toggle/toggle.stories.tsx +56 -56
  397. package/components/ui/toggle/toggle.test.tsx +32 -32
  398. package/components/ui/toggle/toggle.tsx +55 -55
  399. package/components/ui/toggle-group/index.ts +1 -1
  400. package/components/ui/toggle-group/toggle-group.stories.tsx +66 -66
  401. package/components/ui/toggle-group/toggle-group.test.tsx +47 -47
  402. package/components/ui/toggle-group/toggle-group.tsx +79 -79
  403. package/components/ui/tooltip/index.ts +1 -1
  404. package/components/ui/tooltip/tooltip.stories.tsx +83 -83
  405. package/components/ui/tooltip/tooltip.test.tsx +39 -39
  406. package/components/ui/tooltip/tooltip.tsx +69 -69
  407. package/components/ui/tree-view/index.ts +4 -4
  408. package/components/ui/tree-view/tree-view.stories.tsx +154 -154
  409. package/components/ui/tree-view/tree-view.test.tsx +58 -58
  410. package/components/ui/tree-view/tree-view.tsx +171 -171
  411. package/components/ui/tree-view/use-tree-view.ts +237 -237
  412. package/components.json +892 -892
  413. package/contexts/ApiKeyContext.test.tsx +26 -26
  414. package/contexts/ApiKeyContext.tsx +196 -196
  415. package/contexts/AssistenteContext.test.tsx +17 -17
  416. package/contexts/AssistenteContext.tsx +113 -113
  417. package/contexts/AuthContext.tsx +121 -118
  418. package/contexts/BrandColorsContext.test.tsx +21 -21
  419. package/contexts/BrandColorsContext.tsx +251 -251
  420. package/contexts/LanguageContext.tsx +1 -2
  421. package/contexts/LayoutContext.test.tsx +29 -29
  422. package/contexts/LayoutContext.tsx +140 -140
  423. package/contexts/ThemeContext.test.tsx +38 -38
  424. package/contexts/ThemeContext.tsx +111 -111
  425. package/contexts/index.ts +8 -8
  426. package/contexts/theme-data.ts +340 -340
  427. package/dist/AssistantChart-COGiOV-g.cjs +3541 -0
  428. package/dist/AssistantChart-CWX1OWNM.js +3373 -0
  429. package/dist/AudioPlayer-9psiEucT.cjs +1282 -0
  430. package/dist/AudioPlayer-Dp2bD1Gk.js +1278 -0
  431. package/dist/BrandColorsContext-DZT7JjeD.js +659 -0
  432. package/dist/BrandColorsContext-awnBCmC4.cjs +666 -0
  433. package/dist/CodeBlock-DYkTfR0f.js +221 -0
  434. package/dist/CodeBlock-EOvp9cVu.cjs +223 -0
  435. package/dist/CustomTooltipContent-BhdIeBEg.cjs +54 -0
  436. package/dist/CustomTooltipContent-CNbVB2NS.js +33 -0
  437. package/dist/FeatureCard-BZ4CYxFf.cjs +497 -0
  438. package/dist/FeatureCard-DNycVGwT.js +485 -0
  439. package/dist/FeatureCardSkeleton-DZqc96mt.js +27 -0
  440. package/dist/FeatureCardSkeleton-pTa0YNKP.cjs +29 -0
  441. package/dist/LayoutContext-BEq_-n98.cjs +96 -0
  442. package/dist/LayoutContext-DNl1xSoX.js +92 -0
  443. package/dist/ThemeContext-CMD3z2Dz.cjs +1930 -0
  444. package/dist/ThemeContext-x_F2zsnv.js +1923 -0
  445. package/dist/VerifyEmailPage-BJjAMUTW.js +3223 -0
  446. package/dist/VerifyEmailPage-Bv8Ah_TK.cjs +3235 -0
  447. package/dist/VerifyEmailPage-CkBYfsNy.cjs +3232 -0
  448. package/dist/VerifyEmailPage-Cyl55sJb.js +3226 -0
  449. package/dist/VerifyEmailPage-X14vhdyl.js +3296 -0
  450. package/dist/VerifyEmailPage-u_Dn7t1U.cjs +3305 -0
  451. package/dist/XerticaOrbe-Uk2JML1-.cjs +1927 -0
  452. package/dist/XerticaOrbe-jA5T2iOk.js +1925 -0
  453. package/dist/XerticaProvider-BErr83Bg.js +42 -0
  454. package/dist/XerticaProvider-CwOkHxiT.cjs +44 -0
  455. package/dist/XerticaProvider-DUOJg9iX.js +49 -0
  456. package/dist/XerticaProvider-Dl_b72_l.cjs +51 -0
  457. package/dist/XerticaXLogo-BX3ueACh.js +255 -0
  458. package/dist/XerticaXLogo-mqjoBiLI.js +252 -0
  459. package/dist/XerticaXLogo-qBPhwK3g.cjs +260 -0
  460. package/dist/XerticaXLogo-uQgwns_E.cjs +257 -0
  461. package/dist/alert-dialog-DhwPioBa.cjs +885 -0
  462. package/dist/alert-dialog-DqlRW_An.js +831 -0
  463. package/dist/assistant.cjs.js +8 -4
  464. package/dist/assistant.es.js +5 -11
  465. package/dist/avatar-3kO2Anrp.js +54 -0
  466. package/dist/avatar-BCM7YQRC.cjs +77 -0
  467. package/dist/blocks.cjs.js +9 -4
  468. package/dist/blocks.es.js +2 -16
  469. package/dist/brand.cjs.js +10 -5
  470. package/dist/brand.es.js +3 -11
  471. package/dist/breadcrumb-BKtHF4gk.cjs +98 -0
  472. package/dist/breadcrumb-ifNsA7Zl.js +90 -0
  473. package/dist/button-0BlA47It.cjs +85 -0
  474. package/dist/button-DZHzN1Gd.js +62 -0
  475. package/dist/cli.js +471 -93
  476. package/dist/components/brand/theme-toggle/ThemeToggle.d.ts +1 -1
  477. package/dist/components/index.d.ts +1 -1
  478. package/dist/dropdown-menu-BMcykFDf.cjs +225 -0
  479. package/dist/dropdown-menu-Dn_eV2Xb.js +190 -0
  480. package/dist/google-maps-loader-BCe58h9D.js +308 -0
  481. package/dist/google-maps-loader-casMyxlo.cjs +316 -0
  482. package/dist/hooks.cjs.js +12 -8
  483. package/dist/hooks.es.js +10 -27
  484. package/dist/index-9GWd0qxq.cjs +12 -0
  485. package/dist/index-BabBx2pa.js +6 -0
  486. package/dist/index.cjs.js +37 -32
  487. package/dist/index.es.js +30 -363
  488. package/dist/input-C_UiS2Py.cjs +152 -0
  489. package/dist/input-cc-PTD4R.js +123 -0
  490. package/dist/layout.cjs.js +10 -6
  491. package/dist/layout.es.js +7 -9
  492. package/dist/media.cjs.js +8 -3
  493. package/dist/media.es.js +1 -6
  494. package/dist/pages.cjs.js +8 -3
  495. package/dist/pages.es.js +1 -11
  496. package/dist/progress-C7Lti5wo.js +80 -0
  497. package/dist/progress-Cqwxbqs1.cjs +103 -0
  498. package/dist/rich-text-editor-DqLICivI.js +2832 -0
  499. package/dist/rich-text-editor-DxO1Hz3a.cjs +2903 -0
  500. package/dist/select-CH6v_KcQ.cjs +161 -0
  501. package/dist/select-D-xvCZK2.js +130 -0
  502. package/dist/sidebar-3XyzjVBw.js +792 -0
  503. package/dist/sidebar-B4ZWaMrE.js +792 -0
  504. package/dist/sidebar-BS1p2V7t.cjs +795 -0
  505. package/dist/sidebar-DyYvgyBj.cjs +795 -0
  506. package/dist/skeleton-DjiHerJn.cjs +87 -0
  507. package/dist/skeleton-DtR5tkYe.js +78 -0
  508. package/dist/slider-B00b9SVK.cjs +78 -0
  509. package/dist/slider-DQCNUUMj.js +56 -0
  510. package/dist/sonner-B-jWlik1.cjs +68 -0
  511. package/dist/sonner-C9tiqj4f.js +47 -0
  512. package/dist/tooltip-D8n9UYoU.cjs +72 -0
  513. package/dist/tooltip-RtbSmPYJ.js +48 -0
  514. package/dist/ui.cjs.js +23 -18
  515. package/dist/ui.es.js +16 -303
  516. package/dist/use-audio-player-B78fd2ct.js +188 -0
  517. package/dist/use-audio-player-DGvhPrgR.cjs +190 -0
  518. package/dist/use-mobile-BdXTRb0Z.cjs +51 -0
  519. package/dist/use-mobile-Ce2cBAQe.js +29 -0
  520. package/dist/xertica-assistant-B1NaSFFj.js +2173 -0
  521. package/dist/xertica-assistant-B687qEPU.js +2165 -0
  522. package/dist/xertica-assistant-CIaUlbIt.cjs +2180 -0
  523. package/dist/xertica-assistant-sOHwTgIP.cjs +2172 -0
  524. package/dist/xertica-ui.css +1 -1
  525. package/docs/ai-usage.md +195 -195
  526. package/docs/architecture-improvements.md +456 -456
  527. package/docs/architecture.md +312 -306
  528. package/docs/components/accordion.md +109 -109
  529. package/docs/components/alert-dialog.md +127 -127
  530. package/docs/components/alert.md +106 -106
  531. package/docs/components/aspect-ratio.md +58 -58
  532. package/docs/components/assistant-chart.md +47 -47
  533. package/docs/components/assistant.md +428 -426
  534. package/docs/components/audio-player.md +167 -167
  535. package/docs/components/avatar.md +101 -101
  536. package/docs/components/badge.md +84 -84
  537. package/docs/components/branding.md +252 -252
  538. package/docs/components/breadcrumb.md +104 -104
  539. package/docs/components/button.md +156 -156
  540. package/docs/components/calendar.md +141 -141
  541. package/docs/components/card-patterns.md +447 -445
  542. package/docs/components/card.md +245 -245
  543. package/docs/components/carousel.md +100 -100
  544. package/docs/components/chart.md +638 -638
  545. package/docs/components/checkbox.md +88 -88
  546. package/docs/components/code-block.md +105 -105
  547. package/docs/components/collapsible.md +86 -86
  548. package/docs/components/command.md +113 -113
  549. package/docs/components/context-menu.md +81 -81
  550. package/docs/components/dialog.md +198 -198
  551. package/docs/components/drawer.md +105 -105
  552. package/docs/components/dropdown-menu.md +127 -127
  553. package/docs/components/empty.md +127 -127
  554. package/docs/components/error-boundary.md +201 -191
  555. package/docs/components/file-upload.md +189 -189
  556. package/docs/components/floating-media-wrapper.md +63 -63
  557. package/docs/components/form.md +177 -177
  558. package/docs/components/formatted-document.md +105 -105
  559. package/docs/components/google-maps-loader.md +44 -44
  560. package/docs/components/header.md +177 -177
  561. package/docs/components/hooks.md +432 -430
  562. package/docs/components/hover-card.md +86 -86
  563. package/docs/components/image-with-fallback.md +107 -107
  564. package/docs/components/input-otp.md +95 -95
  565. package/docs/components/input.md +130 -130
  566. package/docs/components/label.md +69 -69
  567. package/docs/components/language-selector.md +20 -16
  568. package/docs/components/map-layers.md +138 -138
  569. package/docs/components/map.md +84 -84
  570. package/docs/components/markdown-message.md +47 -47
  571. package/docs/components/menubar.md +89 -89
  572. package/docs/components/modern-chat-input.md +164 -164
  573. package/docs/components/navigation-menu.md +83 -83
  574. package/docs/components/notification-badge.md +78 -78
  575. package/docs/components/page-header.md +93 -93
  576. package/docs/components/pages.md +323 -309
  577. package/docs/components/pagination.md +334 -334
  578. package/docs/components/popover.md +116 -116
  579. package/docs/components/progress.md +103 -103
  580. package/docs/components/radio-group.md +133 -133
  581. package/docs/components/rating.md +77 -77
  582. package/docs/components/resizable.md +84 -84
  583. package/docs/components/rich-text-editor.md +255 -255
  584. package/docs/components/route-map.md +124 -124
  585. package/docs/components/scroll-area.md +58 -58
  586. package/docs/components/search.md +87 -87
  587. package/docs/components/select.md +144 -144
  588. package/docs/components/separator.md +58 -58
  589. package/docs/components/sheet.md +122 -122
  590. package/docs/components/sidebar.md +314 -314
  591. package/docs/components/simple-map.md +51 -51
  592. package/docs/components/skeleton.md +99 -99
  593. package/docs/components/slider.md +84 -84
  594. package/docs/components/sonner.md +115 -115
  595. package/docs/components/stats-card.md +120 -120
  596. package/docs/components/stepper.md +268 -268
  597. package/docs/components/switch.md +106 -106
  598. package/docs/components/table.md +138 -138
  599. package/docs/components/tabs.md +117 -117
  600. package/docs/components/textarea.md +86 -86
  601. package/docs/components/theme-toggle.md +73 -73
  602. package/docs/components/timeline.md +121 -121
  603. package/docs/components/toggle-group.md +68 -68
  604. package/docs/components/toggle.md +62 -62
  605. package/docs/components/tooltip.md +116 -116
  606. package/docs/components/tree-view.md +238 -238
  607. package/docs/components/use-mobile.md +96 -96
  608. package/docs/components/video-player.md +68 -68
  609. package/docs/components/xertica-logo.md +36 -36
  610. package/docs/components/xertica-orbe.md +35 -35
  611. package/docs/components/xertica-provider.md +65 -65
  612. package/docs/components/xertica-xlogo.md +35 -35
  613. package/docs/decision-tree.md +293 -293
  614. package/docs/doc-audit.md +244 -243
  615. package/docs/form-sizing.md +162 -162
  616. package/docs/getting-started.md +616 -591
  617. package/docs/guidelines.md +330 -328
  618. package/docs/i18n.md +61 -57
  619. package/docs/installation.md +268 -267
  620. package/docs/layout.md +143 -143
  621. package/docs/llms.md +295 -295
  622. package/docs/patterns/analytics.md +194 -194
  623. package/docs/patterns/crud.md +149 -149
  624. package/docs/patterns/dashboard.md +138 -138
  625. package/docs/patterns/detail-page.md +296 -296
  626. package/docs/patterns/form.md +241 -241
  627. package/docs/patterns/login.md +156 -156
  628. package/docs/patterns/settings.md +368 -368
  629. package/docs/patterns/wizard.md +213 -213
  630. package/docs/state-management.md +289 -289
  631. package/guidelines/Guidelines.md +409 -406
  632. package/hooks/useTheme.test.tsx +16 -16
  633. package/hooks/useTheme.ts +4 -4
  634. package/imports/Podcast.tsx +540 -540
  635. package/imports/XerticaAi.tsx +46 -46
  636. package/imports/XerticaX.tsx +15 -15
  637. package/imports/svg-aueiaqngck.ts +20 -20
  638. package/imports/svg-v9krss1ozd.ts +23 -23
  639. package/imports/svg-vhrdofe3qe.ts +6 -6
  640. package/llms-compact.txt +2 -1
  641. package/llms.txt +2 -1
  642. package/mcp/resources.json +22 -22
  643. package/mcp/tools.json +35 -35
  644. package/package.json +219 -213
  645. package/scripts/ai-validator.ts +91 -91
  646. package/scripts/cleanup-case-dupes.ts +62 -62
  647. package/scripts/generate-ai-manifests.ts +107 -107
  648. package/styles/globals.css +13 -13
  649. package/styles/xertica/app-overrides/chat.css +61 -61
  650. package/styles/xertica/app-overrides/scrollbar.css +33 -33
  651. package/styles/xertica/base.css +90 -71
  652. package/styles/xertica/integrations/google-maps.css +76 -76
  653. package/styles/xertica/integrations/sonner.css +73 -73
  654. package/styles/xertica/theme-map.css +102 -99
  655. package/styles/xertica/tokens.css +240 -236
  656. package/templates/CLAUDE.md +16 -1
  657. package/templates/eslint.config.js +26 -26
  658. package/templates/guidelines/Guidelines.md +577 -553
  659. package/templates/package.json +69 -69
  660. package/templates/postcss.config.js +6 -6
  661. package/templates/src/app/App.tsx +46 -46
  662. package/templates/src/app/components/AppLayout.tsx +55 -55
  663. package/templates/src/app/components/AuthGuard.tsx +131 -82
  664. package/templates/src/app/context/AuthContext.tsx +108 -108
  665. package/templates/src/features/assistant/index.ts +5 -5
  666. package/templates/src/features/auth/index.ts +4 -4
  667. package/templates/src/features/auth/ui/AuthPageShell.tsx +32 -32
  668. package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +70 -72
  669. package/templates/src/features/auth/ui/LoginContent.tsx +92 -92
  670. package/templates/src/features/auth/ui/ResetPasswordContent.tsx +6 -2
  671. package/templates/src/features/auth/ui/SocialLoginButtons.tsx +78 -78
  672. package/templates/src/features/auth/ui/VerifyEmailContent.tsx +2 -6
  673. package/templates/src/features/home/data/mock.ts +41 -35
  674. package/templates/src/features/home/index.ts +11 -11
  675. package/templates/src/features/home/store/dashboardStore.ts +25 -25
  676. package/templates/src/features/home/ui/HomeContent.tsx +117 -119
  677. package/templates/src/features/template/index.ts +5 -5
  678. package/templates/src/features/template/ui/CrudTemplate.tsx +1 -4
  679. package/templates/src/features/template/ui/LoginTemplate.tsx +1 -1
  680. package/templates/src/features/template/ui/TemplateContent.tsx +29 -21
  681. package/templates/src/locales/en/pages/templates.json +17 -17
  682. package/templates/src/locales/es/pages/templates.json +17 -17
  683. package/templates/src/locales/pt-BR/pages/templates.json +17 -17
  684. package/templates/src/main.tsx +11 -11
  685. package/templates/src/pages/AssistantPage.tsx +26 -20
  686. package/templates/src/pages/ForgotPasswordPage.tsx +6 -6
  687. package/templates/src/pages/HomePage.tsx +53 -49
  688. package/templates/src/pages/LoginPage.tsx +10 -10
  689. package/templates/src/pages/ResetPasswordPage.tsx +6 -6
  690. package/templates/src/pages/TemplatePage.tsx +28 -28
  691. package/templates/src/pages/VerifyEmailPage.tsx +6 -6
  692. package/templates/src/shared/config/navigation.ts +19 -19
  693. package/templates/src/shared/error-boundary.tsx +150 -154
  694. package/templates/src/shared/error-fallbacks.tsx +222 -226
  695. package/templates/src/shared/lib/auth.ts +20 -20
  696. package/templates/src/shared/types/auth.ts +3 -3
  697. package/templates/src/styles/index.css +95 -95
  698. package/templates/src/styles/xertica/tokens.css +240 -236
  699. package/templates/tsconfig.json +25 -25
  700. package/templates/tsconfig.node.json +12 -12
  701. package/templates/vite-env.d.ts +1 -1
  702. package/templates/vite.config.js +20 -20
  703. package/templates/vite.config.ts +54 -51
  704. package/utils/color-utils.ts +72 -72
  705. package/utils/demo-responses.test.ts +10 -10
  706. package/utils/demo-responses.ts +151 -151
  707. package/utils/gemini.test.ts +25 -25
  708. package/utils/gemini.ts +155 -155
@@ -1,638 +1,638 @@
1
- # Chart
2
-
3
- ## Overview
4
-
5
- Xertica UI provides a `ChartContainer` wrapper and related components built on top of **Recharts** for theme-aware, token-driven chart rendering. The chart system uses a `ChartConfig` object to define series labels and colors via CSS variables, ensuring full dark-mode support without hard-coded hex values.
6
-
7
- The library ships **11 dashboard-ready chart wrappers** that handle loading, empty, and error states automatically, so feature layers only need to pass `data`, `isLoading`, `error`, and `onRetry`.
8
-
9
- ---
10
-
11
- ## Exports
12
-
13
- | Export | Description |
14
- | ---------------------------- | ------------------------------------------------------------------------------- |
15
- | `ChartContainer` | Root container that injects CSS color variables and wraps `ResponsiveContainer` |
16
- | `ChartTooltip` | Re-exported `recharts` `Tooltip` component |
17
- | `ChartTooltipContent` | Styled tooltip content using the design system |
18
- | `ChartLegend` | Re-exported `recharts` `Legend` component |
19
- | `ChartLegendContent` | Styled legend content using the design system |
20
- | `ChartStyle` | Internal style injector (used by `ChartContainer`, not used directly) |
21
- | `ChartCard` | Card-based shell for dashboard chart panels |
22
- | `DashboardBarChart` | Ready-to-use grouped or stacked bar chart |
23
- | `DashboardLineChart` | Ready-to-use multi-series line chart |
24
- | `HorizontalBarChart` | Ranking/comparison bar chart with horizontal layout |
25
- | `InteractiveTimeSeriesChart` | Area time-series chart with metric tabs and period select |
26
- | `ComboMetricChart` | Composed bar, line, and area chart for mixed metrics |
27
- | `DonutBreakdownChart` | Donut/pie breakdown chart with interactive segment focus |
28
- | `SparklineChart` | Compact inline area/line chart for KPI cards |
29
- | `RadarMetricChart` | Multi-dimensional radar/spider chart |
30
- | `PieMetricChart` | Proportional pie chart with optional donut, labels, and exploded slice |
31
- | `RadialBarMetricChart` | Circular progress rings (radial bar chart) |
32
- | `GaugeChart` | Semicircle gauge with needle, thresholds, and color zones |
33
- | `ChartConfig` | TypeScript type for chart configuration |
34
- | `GaugeChartThreshold` | TypeScript type for gauge color zone thresholds |
35
-
36
- ---
37
-
38
- ## Required Dependencies
39
-
40
- ```bash
41
- npm install recharts
42
- ```
43
-
44
- ---
45
-
46
- ## How It Works
47
-
48
- 1. Define a `ChartConfig` mapping each data key to a label and color.
49
- 2. Wrap your Recharts chart in `<ChartContainer config={config}>`.
50
- 3. Reference colors in chart elements using `fill="var(--color-yourKey)"`.
51
- 4. The container automatically injects CSS variables for light and dark themes.
52
-
53
- Dashboard-ready wrappers (`DashboardBarChart`, `RadarMetricChart`, etc.) build the config internally — you only need to pass `data` and `series`/`nameKey`/`valueKey`.
54
-
55
- ---
56
-
57
- ## ChartConfig Type
58
-
59
- ```typescript
60
- type ChartConfig = {
61
- [key: string]: {
62
- label?: string;
63
- icon?: React.ComponentType;
64
- color?: string; // CSS color or hsl() value
65
- theme?: { light: string; dark: string }; // Per-theme colors
66
- };
67
- };
68
- ```
69
-
70
- ---
71
-
72
- ## Color Tokens
73
-
74
- Chart colors use `--chart-1` through `--chart-8` CSS tokens. These are theme-aware and automatically switch between light and dark mode.
75
-
76
- ```tsx
77
- // In ChartConfig
78
- { revenue: { label: 'Revenue', color: 'var(--chart-1)' } }
79
-
80
- // In dashboard-ready wrappers — pass as array or per-key map
81
- colors={['var(--chart-1)', 'var(--chart-2)']}
82
- colors={{ revenue: 'var(--chart-1)', expenses: 'var(--chart-5)' }}
83
- ```
84
-
85
- ---
86
-
87
- ## Examples
88
-
89
- ### Bar Chart (low-level)
90
-
91
- ```tsx
92
- import {
93
- ChartContainer,
94
- ChartTooltip,
95
- ChartTooltipContent,
96
- ChartLegend,
97
- ChartLegendContent,
98
- type ChartConfig,
99
- } from 'xertica-ui/ui';
100
- import { BarChart, Bar, XAxis, YAxis, CartesianGrid } from 'recharts';
101
- import { Card, CardHeader, CardTitle, CardContent } from 'xertica-ui/ui';
102
-
103
- const chartConfig: ChartConfig = {
104
- revenue: { label: 'Revenue', color: 'var(--chart-1)' },
105
- expenses: { label: 'Expenses', color: 'var(--chart-5)' },
106
- };
107
-
108
- const data = [
109
- { month: 'Jan', revenue: 4000, expenses: 2400 },
110
- { month: 'Feb', revenue: 3000, expenses: 1398 },
111
- { month: 'Mar', revenue: 6000, expenses: 3200 },
112
- ];
113
-
114
- <Card>
115
- <CardHeader>
116
- <CardTitle>Revenue vs Expenses</CardTitle>
117
- </CardHeader>
118
- <CardContent>
119
- <ChartContainer config={chartConfig} className="h-[300px]">
120
- <BarChart data={data}>
121
- <CartesianGrid vertical={false} />
122
- <XAxis dataKey="month" tickLine={false} axisLine={false} />
123
- <YAxis tickLine={false} axisLine={false} />
124
- <ChartTooltip content={<ChartTooltipContent />} />
125
- <ChartLegend content={<ChartLegendContent />} />
126
- <Bar dataKey="revenue" fill="var(--color-revenue)" radius={4} />
127
- <Bar dataKey="expenses" fill="var(--color-expenses)" radius={4} />
128
- </BarChart>
129
- </ChartContainer>
130
- </CardContent>
131
- </Card>;
132
- ```
133
-
134
- ### Line Chart (low-level)
135
-
136
- ```tsx
137
- const chartConfig: ChartConfig = {
138
- users: { label: 'Active Users', color: 'var(--chart-1)' },
139
- };
140
-
141
- <ChartContainer config={chartConfig} className="h-[250px]">
142
- <LineChart data={data}>
143
- <CartesianGrid vertical={false} />
144
- <XAxis dataKey="month" />
145
- <YAxis />
146
- <ChartTooltip content={<ChartTooltipContent />} />
147
- <Line type="monotone" dataKey="users" stroke="var(--color-users)" strokeWidth={2} dot={false} />
148
- </LineChart>
149
- </ChartContainer>;
150
- ```
151
-
152
- ---
153
-
154
- ### Dashboard-Ready Charts
155
-
156
- ```tsx
157
- import {
158
- ChartCard,
159
- DashboardBarChart,
160
- DashboardLineChart,
161
- HorizontalBarChart,
162
- InteractiveTimeSeriesChart,
163
- ComboMetricChart,
164
- DonutBreakdownChart,
165
- type ChartConfig,
166
- } from 'xertica-ui/ui';
167
-
168
- const config: ChartConfig = {
169
- revenue: { label: 'Revenue', color: 'var(--chart-1)' },
170
- pipeline: { label: 'Pipeline', color: 'var(--chart-4)' },
171
- conversion: { label: 'Conversion', color: 'var(--chart-2)' },
172
- };
173
-
174
- const data = [
175
- { date: 'Apr 01', revenue: 4200, pipeline: 2600, conversion: 32 },
176
- { date: 'Apr 08', revenue: 5200, pipeline: 3200, conversion: 38 },
177
- ];
178
-
179
- <ChartCard title="Executive Trend" description="Metric and period controls">
180
- <InteractiveTimeSeriesChart
181
- data={data}
182
- indexKey="date"
183
- config={config}
184
- series={[
185
- { key: 'revenue', label: 'Revenue' },
186
- { key: 'pipeline', label: 'Pipeline' },
187
- ]}
188
- />
189
- </ChartCard>
190
-
191
- <ChartCard title="Customer Mix">
192
- <DonutBreakdownChart data={segments} config={segmentConfig} />
193
- </ChartCard>
194
-
195
- <DashboardBarChart data={data} indexKey="date" config={config} stacked />
196
-
197
- <HorizontalBarChart
198
- data={[
199
- { segment: 'Enterprise', revenue: 7600 },
200
- { segment: 'Mid-market', revenue: 5400 },
201
- ]}
202
- indexKey="segment"
203
- config={{
204
- revenue: { label: 'Revenue', color: 'var(--chart-1)' },
205
- }}
206
- showLegend={false}
207
- />
208
-
209
- <ComboMetricChart
210
- data={data}
211
- indexKey="date"
212
- config={config}
213
- series={[
214
- { key: 'pipeline', type: 'bar' },
215
- { key: 'conversion', type: 'line' },
216
- ]}
217
- />
218
- ```
219
-
220
- ---
221
-
222
- ### Radar Chart
223
-
224
- Multi-dimensional comparison across categorical axes. Use a single series for a simple spider chart, or multiple series for side-by-side comparison.
225
-
226
- ```tsx
227
- import { RadarMetricChart, ChartCard } from 'xertica-ui/ui';
228
-
229
- const data = [
230
- { skill: 'Speed', frontend: 80, backend: 60 },
231
- { skill: 'Quality', frontend: 90, backend: 85 },
232
- { skill: 'Coverage', frontend: 70, backend: 95 },
233
- { skill: 'Security', frontend: 65, backend: 88 },
234
- { skill: 'Perf', frontend: 75, backend: 72 },
235
- ];
236
-
237
- // Single series — filled polygon
238
- <ChartCard title="Frontend Skills">
239
- <RadarMetricChart
240
- data={data}
241
- labelKey="skill"
242
- series={[{ key: 'frontend', label: 'Frontend' }]}
243
- filled
244
- fillOpacity={0.3}
245
- />
246
- </ChartCard>
247
-
248
- // Multi-series comparison
249
- <ChartCard title="Team Comparison">
250
- <RadarMetricChart
251
- data={data}
252
- labelKey="skill"
253
- series={[
254
- { key: 'frontend', label: 'Frontend' },
255
- { key: 'backend', label: 'Backend' },
256
- ]}
257
- filled={false}
258
- showDots
259
- showLegend
260
- />
261
- </ChartCard>
262
- ```
263
-
264
- **Props:**
265
-
266
- | Prop | Type | Default | Description |
267
- | ---------------- | ------------------------ | ------- | --------------------------------------------- |
268
- | `data` | `DashboardChartDatum[]` | — | Data array; each item is one axis point |
269
- | `labelKey` | `string` | — | Key used as the axis label |
270
- | `series` | `DashboardChartSeries[]` | — | Series to render (one `<Radar>` per entry) |
271
- | `colors` | `DashboardChartColors` | auto | Override colors per key or as ordered array |
272
- | `filled` | `boolean` | `true` | Fill the radar polygon |
273
- | `fillOpacity` | `number` | `0.25` | Fill opacity when `filled` is true |
274
- | `showDots` | `boolean` | `false` | Show dots on each axis point |
275
- | `showGrid` | `boolean` | `true` | Show polar grid lines |
276
- | `showLegend` | `boolean` | auto | Show legend (auto-shown when multiple series) |
277
- | `valueFormatter` | `(v: number) => string` | — | Format axis tick and tooltip values |
278
- | + state props | — | — | `isLoading`, `error`, `onRetry`, etc. |
279
-
280
- ---
281
-
282
- ### Pie Chart
283
-
284
- Proportional slices. Supports donut mode (`innerRadius > 0`), percentage labels, and an exploded (offset) slice for emphasis.
285
-
286
- ```tsx
287
- import { PieMetricChart, ChartCard } from 'xertica-ui/ui';
288
-
289
- const data = [
290
- { segment: 'Enterprise', value: 52 },
291
- { segment: 'Mid-market', value: 31 },
292
- { segment: 'SMB', value: 17 },
293
- ];
294
-
295
- // Simple pie
296
- <ChartCard title="Revenue Mix">
297
- <PieMetricChart
298
- data={data}
299
- nameKey="segment"
300
- valueKey="value"
301
- showLabels
302
- />
303
- </ChartCard>
304
-
305
- // Donut variant
306
- <ChartCard title="Revenue Mix (Donut)">
307
- <PieMetricChart
308
- data={data}
309
- nameKey="segment"
310
- valueKey="value"
311
- innerRadius="55%"
312
- outerRadius="80%"
313
- />
314
- </ChartCard>
315
-
316
- // Exploded slice (highlight index 0)
317
- <ChartCard title="Top Segment">
318
- <PieMetricChart
319
- data={data}
320
- nameKey="segment"
321
- valueKey="value"
322
- explodeIndex={0}
323
- explodeOffset={14}
324
- />
325
- </ChartCard>
326
- ```
327
-
328
- **Props:**
329
-
330
- | Prop | Type | Default | Description |
331
- | ---------------- | ----------------------- | ------- | ------------------------------------------------ |
332
- | `data` | `DashboardChartDatum[]` | — | Data array; each item is one slice |
333
- | `nameKey` | `string` | — | Key used as the slice name/label |
334
- | `valueKey` | `string` | — | Key used as the slice value |
335
- | `colors` | `DashboardChartColors` | auto | Override colors as ordered array or per-name map |
336
- | `outerRadius` | `number \| string` | `"80%"` | Outer radius of the pie |
337
- | `innerRadius` | `number \| string` | `0` | Inner radius — set > 0 for donut |
338
- | `showLabels` | `boolean` | `false` | Show percentage labels on slices |
339
- | `showLegend` | `boolean` | `true` | Show the legend |
340
- | `explodeIndex` | `number` | — | Index of the slice to offset outward |
341
- | `explodeOffset` | `number` | `12` | Offset distance in px for the exploded slice |
342
- | `valueFormatter` | `(v: number) => string` | — | Format tooltip values |
343
- | + state props | — | — | `isLoading`, `error`, `onRetry`, etc. |
344
-
345
- ---
346
-
347
- ### Radial Bar Chart
348
-
349
- Circular progress rings. Each data item renders as a concentric arc. Useful for showing multiple metrics as percentage completion.
350
-
351
- ```tsx
352
- import { RadialBarMetricChart, ChartCard } from 'xertica-ui/ui';
353
-
354
- const data = [
355
- { name: 'CPU', value: 72 },
356
- { name: 'Memory', value: 58 },
357
- { name: 'Storage', value: 41 },
358
- { name: 'Network', value: 89 },
359
- ];
360
-
361
- // Full-circle rings (default)
362
- <ChartCard title="Resource Usage">
363
- <RadialBarMetricChart
364
- data={data}
365
- dataKey="value"
366
- nameKey="name"
367
- valueFormatter={(v) => `${v}%`}
368
- />
369
- </ChartCard>
370
-
371
- // Semi-circle layout
372
- <ChartCard title="Resource Usage (Semi)">
373
- <RadialBarMetricChart
374
- data={data}
375
- dataKey="value"
376
- nameKey="name"
377
- startAngle={180}
378
- endAngle={0}
379
- innerRadius="20%"
380
- outerRadius="90%"
381
- />
382
- </ChartCard>
383
- ```
384
-
385
- **Props:**
386
-
387
- | Prop | Type | Default | Description |
388
- | ---------------- | ----------------------- | --------- | ------------------------------------------------ |
389
- | `data` | `DashboardChartDatum[]` | — | Data array; each item is one ring |
390
- | `dataKey` | `string` | `"value"` | Key used as the bar value |
391
- | `nameKey` | `string` | `"name"` | Key used as the bar label |
392
- | `colors` | `DashboardChartColors` | auto | Override colors as ordered array or per-name map |
393
- | `innerRadius` | `number \| string` | `"30%"` | Inner radius of the radial bar |
394
- | `outerRadius` | `number \| string` | `"100%"` | Outer radius of the radial bar |
395
- | `startAngle` | `number` | `90` | Start angle in degrees (90 = top) |
396
- | `endAngle` | `number` | `-270` | End angle in degrees (-270 = full circle) |
397
- | `showBackground` | `boolean` | `true` | Show background track behind each bar |
398
- | `showLegend` | `boolean` | `true` | Show the legend below the chart |
399
- | `valueFormatter` | `(v: number) => string` | — | Format tooltip and legend values |
400
- | + state props | — | — | `isLoading`, `error`, `onRetry`, etc. |
401
-
402
- ---
403
-
404
- ### Gauge Chart
405
-
406
- Semicircle gauge with a needle indicator and optional color zones (thresholds). Implemented as pure SVG — no Recharts dependency.
407
-
408
- ```tsx
409
- import { GaugeChart, ChartCard, type GaugeChartThreshold } from 'xertica-ui/ui';
410
-
411
- // Simple percentage gauge
412
- <ChartCard title="CPU Usage">
413
- <div className="flex justify-center py-4">
414
- <GaugeChart value={72} label="CPU" />
415
- </div>
416
- </ChartCard>
417
-
418
- // With color thresholds
419
- const thresholds: GaugeChartThreshold[] = [
420
- { value: 40, color: 'var(--chart-2)', label: 'Healthy' },
421
- { value: 70, color: 'var(--chart-3)', label: 'Warning' },
422
- { value: 100, color: 'var(--chart-5)', label: 'Critical' },
423
- ];
424
-
425
- <ChartCard title="Memory Usage">
426
- <div className="flex justify-center py-4">
427
- <GaugeChart
428
- value={85}
429
- label="Memory"
430
- thresholds={thresholds}
431
- />
432
- </div>
433
- </ChartCard>
434
-
435
- // Custom range and formatter
436
- <GaugeChart
437
- value={1250}
438
- min={0}
439
- max={2000}
440
- label="Requests/s"
441
- valueFormatter={(value) => `${value.toLocaleString()} rps`}
442
- showNeedle={false}
443
- />
444
- ```
445
-
446
- **Props:**
447
-
448
- | Prop | Type | Default | Description |
449
- | ---------------- | -------------------------------------------- | ------- | -------------------------------------------------------------------------- |
450
- | `value` | `number` | — | Current value (must be within `[min, max]`) |
451
- | `min` | `number` | `0` | Minimum value |
452
- | `max` | `number` | `100` | Maximum value |
453
- | `thresholds` | `GaugeChartThreshold[]` | — | Color zones evaluated in order; first zone where `value >= current %` wins |
454
- | `label` | `React.ReactNode` | — | Label shown below the center value |
455
- | `valueFormatter` | `(value: number, percent: number) => string` | — | Format the center value text (default: shows `%`) |
456
- | `showNeedle` | `boolean` | `true` | Show the needle indicator |
457
- | `className` | `string` | — | Additional CSS classes |
458
-
459
- **`GaugeChartThreshold` type:**
460
-
461
- ```typescript
462
- interface GaugeChartThreshold {
463
- value: number; // Upper bound of this zone (0–100)
464
- color: string; // Color for this zone (use CSS var tokens)
465
- label?: string; // Optional label shown in the legend
466
- }
467
- ```
468
-
469
- **Infrastructure dashboard example:**
470
-
471
- ```tsx
472
- const metrics = [
473
- { label: 'CPU', value: 72 },
474
- { label: 'Memory', value: 85 },
475
- { label: 'Storage', value: 41 },
476
- ];
477
-
478
- const thresholds: GaugeChartThreshold[] = [
479
- { value: 60, color: 'var(--chart-2)', label: 'OK' },
480
- { value: 80, color: 'var(--chart-3)', label: 'Warning' },
481
- { value: 100, color: 'var(--chart-5)', label: 'Critical' },
482
- ];
483
-
484
- <div className="grid grid-cols-3 gap-4">
485
- {metrics.map(m => (
486
- <ChartCard key={m.label} title={m.label}>
487
- <div className="flex justify-center py-2">
488
- <GaugeChart value={m.value} label={m.label} thresholds={thresholds} />
489
- </div>
490
- </ChartCard>
491
- ))}
492
- </div>;
493
- ```
494
-
495
- ---
496
-
497
- ### Sparkline Chart
498
-
499
- Compact inline chart for KPI cards and metric summaries. Renders as a minimal area or line chart with no axes or labels.
500
-
501
- ```tsx
502
- import { SparklineChart } from 'xertica-ui/ui';
503
-
504
- // Filled area sparkline (default)
505
- <SparklineChart
506
- data={[{ v: 10 }, { v: 25 }, { v: 18 }, { v: 40 }, { v: 35 }]}
507
- dataKey="v"
508
- color="var(--chart-1)"
509
- filled
510
- />
511
-
512
- // Line-only sparkline
513
- <SparklineChart
514
- data={weeklyData}
515
- dataKey="sessions"
516
- color="var(--chart-2)"
517
- filled={false}
518
- />
519
- ```
520
-
521
- ---
522
-
523
- ### Empty and Connection States
524
-
525
- All dashboard-ready chart wrappers handle loading, empty data, and connection errors without forcing each feature to duplicate presentation logic. In an FSD architecture, keep fetching and error mapping in the feature/model layer, then pass the state into the UI component.
526
-
527
- ```tsx
528
- <DashboardLineChart
529
- data={analyticsData}
530
- config={config}
531
- isLoading={isLoading}
532
- error={connectionError}
533
- onRetry={refetchAnalytics}
534
- emptyTitle="No data available"
535
- emptyDescription="There is no data available for this period."
536
- errorTitle="Connection error"
537
- errorDescription="Unable to load analytics data."
538
- />
539
-
540
- // State props work on all dashboard-ready wrappers:
541
- <RadarMetricChart
542
- data={skillData}
543
- labelKey="skill"
544
- series={[{ key: 'score', label: 'Score' }]}
545
- isLoading={isLoading}
546
- error={error}
547
- onRetry={refetch}
548
- />
549
- ```
550
-
551
- State props (`isLoading`, `error`, `onRetry`, `retryLabel`, `emptyTitle`, `emptyDescription`, `errorTitle`, `errorDescription`, `loadingLabel`, `stateClassName`) are available on: `DashboardBarChart`, `DashboardLineChart`, `HorizontalBarChart`, `InteractiveTimeSeriesChart`, `ComboMetricChart`, `DonutBreakdownChart`, `RadarMetricChart`, `PieMetricChart`, and `RadialBarMetricChart`.
552
-
553
- > `GaugeChart` does not extend `ChartStateProps` — it is a pure display component with no async state.
554
-
555
- ---
556
-
557
- ### Stacked Bar Chart
558
-
559
- Pass `stacked` to `DashboardBarChart` to stack series on top of each other. When stacking, only the **topmost series** in the stack receives rounded top corners — intermediate and bottom bars have flat tops to avoid visual gaps between segments.
560
-
561
- ```tsx
562
- const config: ChartConfig = {
563
- receita: { label: 'Receita', color: 'var(--chart-1)' },
564
- despesa: { label: 'Despesa', color: 'var(--chart-5)' },
565
- };
566
-
567
- <DashboardBarChart
568
- data={data}
569
- indexKey="month"
570
- config={config}
571
- series={[
572
- { key: 'receita', label: 'Receita' },
573
- { key: 'despesa', label: 'Despesa' }, // ← this series sits on top, gets radius
574
- ]}
575
- stacked
576
- />;
577
- ```
578
-
579
- > The radius logic is automatic — the last `series` entry in each `stackId` group receives `radius={[4,4,0,0]}`; all others receive `radius={[0,0,0,0]}`. You do not need to configure this manually.
580
-
581
- > **v2.1.9**: The `topOfStack` computation was extracted from an inline IIFE in JSX into a `React.useMemo([stacked, chartSeries])` before the `return`. This is a performance improvement — the bar element array is no longer recalculated on every render when the chart re-renders for unrelated reasons.
582
-
583
- ---
584
-
585
- ### Bar Thickness
586
-
587
- Bar-based dashboard charts support `barSize="sm" | "md" | "lg" | "xl"` or a numeric pixel value. This controls the thickness of each rendered bar, not the chart container width.
588
-
589
- ```tsx
590
- <DashboardBarChart data={data} indexKey="date" config={config} barSize="lg" />
591
-
592
- <HorizontalBarChart
593
- data={segmentData}
594
- indexKey="segment"
595
- config={config}
596
- barSize={28}
597
- />
598
-
599
- <ComboMetricChart
600
- data={data}
601
- indexKey="date"
602
- config={config}
603
- series={[
604
- { key: 'pipeline', type: 'bar' },
605
- { key: 'conversion', type: 'line' },
606
- ]}
607
- barSize="sm"
608
- />
609
- ```
610
-
611
- `barSize` is available on `DashboardBarChart`, `HorizontalBarChart`, and the bar series inside `ComboMetricChart`.
612
-
613
- ---
614
-
615
- ## AI Rules
616
-
617
- - **Always** use `<ChartContainer config={config}>` — never use `<ResponsiveContainer>` directly.
618
- - **Never** use hard-coded hex colors on chart elements (`fill="#4F46E5"`). Always use `fill="var(--color-keyName)"` — this references the CSS variable injected by `ChartContainer`.
619
- - Define color via `color: 'var(--chart-1)'` in `ChartConfig`, or pass `colors={['var(--chart-1)', 'var(--chart-2)']}` to dashboard-ready chart wrappers. The `--chart-*` tokens are theme-aware.
620
- - `ChartContainer` already wraps `ResponsiveContainer width="100%" height="100%"` — do not add another one.
621
- - Set height on `ChartContainer` via `className="h-[300px]"` — this sizes the container, not the Recharts elements.
622
- - Import all base Recharts components (`BarChart`, `Bar`, `Line`, etc.) directly from `recharts` — they are not re-exported by `xertica-ui`.
623
- - For dashboard-ready charts, prefer `ChartCard` plus a dashboard-ready wrapper before hand-assembling Recharts primitives.
624
- - In FSD apps, keep data fetching in the feature/model layer and pass `data`, `isLoading`, `error`, and `onRetry` into chart wrappers.
625
- - Use `barSize` to control bar thickness. Do not use a chart wrapper prop to control graph width; layout width belongs to the parent grid/container.
626
- - When using `stacked`, order your `series` array so the visually topmost series is last — it will automatically receive the rounded top corners.
627
- - `RadarMetricChart`, `PieMetricChart`, and `RadialBarMetricChart` build their `ChartConfig` internally from the `series`/`nameKey` data — you do not need to pass a `config` prop.
628
- - When passing `stateClassName` to `RadarMetricChart`, `PieMetricChart`, or `RadialBarMetricChart`, it is included in the state object passed to `getChartState` — it does not need to be (and should not be) passed as a second `className` argument separately.
629
- - `GaugeChart` is a pure SVG component — it does not use `ChartContainer` or Recharts. Wrap it in a `div` with `flex justify-center` to control its width.
630
- - For `GaugeChart` thresholds, use `--chart-*` CSS tokens for colors so they remain theme-aware. Never use raw hex values.
631
- - `RadialBarMetricChart` renders its legend as HTML below the chart (not inside the SVG) — this is intentional to avoid Recharts polar chart legend positioning issues.
632
-
633
- ---
634
-
635
- ## Related Patterns
636
-
637
- - [Dashboard Pattern](../patterns/dashboard.md)
638
- - [Analytics Pattern](../patterns/analytics.md)
1
+ # Chart
2
+
3
+ ## Overview
4
+
5
+ Xertica UI provides a `ChartContainer` wrapper and related components built on top of **Recharts** for theme-aware, token-driven chart rendering. The chart system uses a `ChartConfig` object to define series labels and colors via CSS variables, ensuring full dark-mode support without hard-coded hex values.
6
+
7
+ The library ships **11 dashboard-ready chart wrappers** that handle loading, empty, and error states automatically, so feature layers only need to pass `data`, `isLoading`, `error`, and `onRetry`.
8
+
9
+ ---
10
+
11
+ ## Exports
12
+
13
+ | Export | Description |
14
+ | ---------------------------- | ------------------------------------------------------------------------------- |
15
+ | `ChartContainer` | Root container that injects CSS color variables and wraps `ResponsiveContainer` |
16
+ | `ChartTooltip` | Re-exported `recharts` `Tooltip` component |
17
+ | `ChartTooltipContent` | Styled tooltip content using the design system |
18
+ | `ChartLegend` | Re-exported `recharts` `Legend` component |
19
+ | `ChartLegendContent` | Styled legend content using the design system |
20
+ | `ChartStyle` | Internal style injector (used by `ChartContainer`, not used directly) |
21
+ | `ChartCard` | Card-based shell for dashboard chart panels |
22
+ | `DashboardBarChart` | Ready-to-use grouped or stacked bar chart |
23
+ | `DashboardLineChart` | Ready-to-use multi-series line chart |
24
+ | `HorizontalBarChart` | Ranking/comparison bar chart with horizontal layout |
25
+ | `InteractiveTimeSeriesChart` | Area time-series chart with metric tabs and period select |
26
+ | `ComboMetricChart` | Composed bar, line, and area chart for mixed metrics |
27
+ | `DonutBreakdownChart` | Donut/pie breakdown chart with interactive segment focus |
28
+ | `SparklineChart` | Compact inline area/line chart for KPI cards |
29
+ | `RadarMetricChart` | Multi-dimensional radar/spider chart |
30
+ | `PieMetricChart` | Proportional pie chart with optional donut, labels, and exploded slice |
31
+ | `RadialBarMetricChart` | Circular progress rings (radial bar chart) |
32
+ | `GaugeChart` | Semicircle gauge with needle, thresholds, and color zones |
33
+ | `ChartConfig` | TypeScript type for chart configuration |
34
+ | `GaugeChartThreshold` | TypeScript type for gauge color zone thresholds |
35
+
36
+ ---
37
+
38
+ ## Required Dependencies
39
+
40
+ ```bash
41
+ npm install recharts
42
+ ```
43
+
44
+ ---
45
+
46
+ ## How It Works
47
+
48
+ 1. Define a `ChartConfig` mapping each data key to a label and color.
49
+ 2. Wrap your Recharts chart in `<ChartContainer config={config}>`.
50
+ 3. Reference colors in chart elements using `fill="var(--color-yourKey)"`.
51
+ 4. The container automatically injects CSS variables for light and dark themes.
52
+
53
+ Dashboard-ready wrappers (`DashboardBarChart`, `RadarMetricChart`, etc.) build the config internally — you only need to pass `data` and `series`/`nameKey`/`valueKey`.
54
+
55
+ ---
56
+
57
+ ## ChartConfig Type
58
+
59
+ ```typescript
60
+ type ChartConfig = {
61
+ [key: string]: {
62
+ label?: string;
63
+ icon?: React.ComponentType;
64
+ color?: string; // CSS color or hsl() value
65
+ theme?: { light: string; dark: string }; // Per-theme colors
66
+ };
67
+ };
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Color Tokens
73
+
74
+ Chart colors use `--chart-1` through `--chart-8` CSS tokens. These are theme-aware and automatically switch between light and dark mode.
75
+
76
+ ```tsx
77
+ // In ChartConfig
78
+ { revenue: { label: 'Revenue', color: 'var(--chart-1)' } }
79
+
80
+ // In dashboard-ready wrappers — pass as array or per-key map
81
+ colors={['var(--chart-1)', 'var(--chart-2)']}
82
+ colors={{ revenue: 'var(--chart-1)', expenses: 'var(--chart-5)' }}
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Examples
88
+
89
+ ### Bar Chart (low-level)
90
+
91
+ ```tsx
92
+ import {
93
+ ChartContainer,
94
+ ChartTooltip,
95
+ ChartTooltipContent,
96
+ ChartLegend,
97
+ ChartLegendContent,
98
+ type ChartConfig,
99
+ } from 'xertica-ui/ui';
100
+ import { BarChart, Bar, XAxis, YAxis, CartesianGrid } from 'recharts';
101
+ import { Card, CardHeader, CardTitle, CardContent } from 'xertica-ui/ui';
102
+
103
+ const chartConfig: ChartConfig = {
104
+ revenue: { label: 'Revenue', color: 'var(--chart-1)' },
105
+ expenses: { label: 'Expenses', color: 'var(--chart-5)' },
106
+ };
107
+
108
+ const data = [
109
+ { month: 'Jan', revenue: 4000, expenses: 2400 },
110
+ { month: 'Feb', revenue: 3000, expenses: 1398 },
111
+ { month: 'Mar', revenue: 6000, expenses: 3200 },
112
+ ];
113
+
114
+ <Card>
115
+ <CardHeader>
116
+ <CardTitle>Revenue vs Expenses</CardTitle>
117
+ </CardHeader>
118
+ <CardContent>
119
+ <ChartContainer config={chartConfig} className="h-[300px]">
120
+ <BarChart data={data}>
121
+ <CartesianGrid vertical={false} />
122
+ <XAxis dataKey="month" tickLine={false} axisLine={false} />
123
+ <YAxis tickLine={false} axisLine={false} />
124
+ <ChartTooltip content={<ChartTooltipContent />} />
125
+ <ChartLegend content={<ChartLegendContent />} />
126
+ <Bar dataKey="revenue" fill="var(--color-revenue)" radius={4} />
127
+ <Bar dataKey="expenses" fill="var(--color-expenses)" radius={4} />
128
+ </BarChart>
129
+ </ChartContainer>
130
+ </CardContent>
131
+ </Card>;
132
+ ```
133
+
134
+ ### Line Chart (low-level)
135
+
136
+ ```tsx
137
+ const chartConfig: ChartConfig = {
138
+ users: { label: 'Active Users', color: 'var(--chart-1)' },
139
+ };
140
+
141
+ <ChartContainer config={chartConfig} className="h-[250px]">
142
+ <LineChart data={data}>
143
+ <CartesianGrid vertical={false} />
144
+ <XAxis dataKey="month" />
145
+ <YAxis />
146
+ <ChartTooltip content={<ChartTooltipContent />} />
147
+ <Line type="monotone" dataKey="users" stroke="var(--color-users)" strokeWidth={2} dot={false} />
148
+ </LineChart>
149
+ </ChartContainer>;
150
+ ```
151
+
152
+ ---
153
+
154
+ ### Dashboard-Ready Charts
155
+
156
+ ```tsx
157
+ import {
158
+ ChartCard,
159
+ DashboardBarChart,
160
+ DashboardLineChart,
161
+ HorizontalBarChart,
162
+ InteractiveTimeSeriesChart,
163
+ ComboMetricChart,
164
+ DonutBreakdownChart,
165
+ type ChartConfig,
166
+ } from 'xertica-ui/ui';
167
+
168
+ const config: ChartConfig = {
169
+ revenue: { label: 'Revenue', color: 'var(--chart-1)' },
170
+ pipeline: { label: 'Pipeline', color: 'var(--chart-4)' },
171
+ conversion: { label: 'Conversion', color: 'var(--chart-2)' },
172
+ };
173
+
174
+ const data = [
175
+ { date: 'Apr 01', revenue: 4200, pipeline: 2600, conversion: 32 },
176
+ { date: 'Apr 08', revenue: 5200, pipeline: 3200, conversion: 38 },
177
+ ];
178
+
179
+ <ChartCard title="Executive Trend" description="Metric and period controls">
180
+ <InteractiveTimeSeriesChart
181
+ data={data}
182
+ indexKey="date"
183
+ config={config}
184
+ series={[
185
+ { key: 'revenue', label: 'Revenue' },
186
+ { key: 'pipeline', label: 'Pipeline' },
187
+ ]}
188
+ />
189
+ </ChartCard>
190
+
191
+ <ChartCard title="Customer Mix">
192
+ <DonutBreakdownChart data={segments} config={segmentConfig} />
193
+ </ChartCard>
194
+
195
+ <DashboardBarChart data={data} indexKey="date" config={config} stacked />
196
+
197
+ <HorizontalBarChart
198
+ data={[
199
+ { segment: 'Enterprise', revenue: 7600 },
200
+ { segment: 'Mid-market', revenue: 5400 },
201
+ ]}
202
+ indexKey="segment"
203
+ config={{
204
+ revenue: { label: 'Revenue', color: 'var(--chart-1)' },
205
+ }}
206
+ showLegend={false}
207
+ />
208
+
209
+ <ComboMetricChart
210
+ data={data}
211
+ indexKey="date"
212
+ config={config}
213
+ series={[
214
+ { key: 'pipeline', type: 'bar' },
215
+ { key: 'conversion', type: 'line' },
216
+ ]}
217
+ />
218
+ ```
219
+
220
+ ---
221
+
222
+ ### Radar Chart
223
+
224
+ Multi-dimensional comparison across categorical axes. Use a single series for a simple spider chart, or multiple series for side-by-side comparison.
225
+
226
+ ```tsx
227
+ import { RadarMetricChart, ChartCard } from 'xertica-ui/ui';
228
+
229
+ const data = [
230
+ { skill: 'Speed', frontend: 80, backend: 60 },
231
+ { skill: 'Quality', frontend: 90, backend: 85 },
232
+ { skill: 'Coverage', frontend: 70, backend: 95 },
233
+ { skill: 'Security', frontend: 65, backend: 88 },
234
+ { skill: 'Perf', frontend: 75, backend: 72 },
235
+ ];
236
+
237
+ // Single series — filled polygon
238
+ <ChartCard title="Frontend Skills">
239
+ <RadarMetricChart
240
+ data={data}
241
+ labelKey="skill"
242
+ series={[{ key: 'frontend', label: 'Frontend' }]}
243
+ filled
244
+ fillOpacity={0.3}
245
+ />
246
+ </ChartCard>
247
+
248
+ // Multi-series comparison
249
+ <ChartCard title="Team Comparison">
250
+ <RadarMetricChart
251
+ data={data}
252
+ labelKey="skill"
253
+ series={[
254
+ { key: 'frontend', label: 'Frontend' },
255
+ { key: 'backend', label: 'Backend' },
256
+ ]}
257
+ filled={false}
258
+ showDots
259
+ showLegend
260
+ />
261
+ </ChartCard>
262
+ ```
263
+
264
+ **Props:**
265
+
266
+ | Prop | Type | Default | Description |
267
+ | ---------------- | ------------------------ | ------- | --------------------------------------------- |
268
+ | `data` | `DashboardChartDatum[]` | — | Data array; each item is one axis point |
269
+ | `labelKey` | `string` | — | Key used as the axis label |
270
+ | `series` | `DashboardChartSeries[]` | — | Series to render (one `<Radar>` per entry) |
271
+ | `colors` | `DashboardChartColors` | auto | Override colors per key or as ordered array |
272
+ | `filled` | `boolean` | `true` | Fill the radar polygon |
273
+ | `fillOpacity` | `number` | `0.25` | Fill opacity when `filled` is true |
274
+ | `showDots` | `boolean` | `false` | Show dots on each axis point |
275
+ | `showGrid` | `boolean` | `true` | Show polar grid lines |
276
+ | `showLegend` | `boolean` | auto | Show legend (auto-shown when multiple series) |
277
+ | `valueFormatter` | `(v: number) => string` | — | Format axis tick and tooltip values |
278
+ | + state props | — | — | `isLoading`, `error`, `onRetry`, etc. |
279
+
280
+ ---
281
+
282
+ ### Pie Chart
283
+
284
+ Proportional slices. Supports donut mode (`innerRadius > 0`), percentage labels, and an exploded (offset) slice for emphasis.
285
+
286
+ ```tsx
287
+ import { PieMetricChart, ChartCard } from 'xertica-ui/ui';
288
+
289
+ const data = [
290
+ { segment: 'Enterprise', value: 52 },
291
+ { segment: 'Mid-market', value: 31 },
292
+ { segment: 'SMB', value: 17 },
293
+ ];
294
+
295
+ // Simple pie
296
+ <ChartCard title="Revenue Mix">
297
+ <PieMetricChart
298
+ data={data}
299
+ nameKey="segment"
300
+ valueKey="value"
301
+ showLabels
302
+ />
303
+ </ChartCard>
304
+
305
+ // Donut variant
306
+ <ChartCard title="Revenue Mix (Donut)">
307
+ <PieMetricChart
308
+ data={data}
309
+ nameKey="segment"
310
+ valueKey="value"
311
+ innerRadius="55%"
312
+ outerRadius="80%"
313
+ />
314
+ </ChartCard>
315
+
316
+ // Exploded slice (highlight index 0)
317
+ <ChartCard title="Top Segment">
318
+ <PieMetricChart
319
+ data={data}
320
+ nameKey="segment"
321
+ valueKey="value"
322
+ explodeIndex={0}
323
+ explodeOffset={14}
324
+ />
325
+ </ChartCard>
326
+ ```
327
+
328
+ **Props:**
329
+
330
+ | Prop | Type | Default | Description |
331
+ | ---------------- | ----------------------- | ------- | ------------------------------------------------ |
332
+ | `data` | `DashboardChartDatum[]` | — | Data array; each item is one slice |
333
+ | `nameKey` | `string` | — | Key used as the slice name/label |
334
+ | `valueKey` | `string` | — | Key used as the slice value |
335
+ | `colors` | `DashboardChartColors` | auto | Override colors as ordered array or per-name map |
336
+ | `outerRadius` | `number \| string` | `"80%"` | Outer radius of the pie |
337
+ | `innerRadius` | `number \| string` | `0` | Inner radius — set > 0 for donut |
338
+ | `showLabels` | `boolean` | `false` | Show percentage labels on slices |
339
+ | `showLegend` | `boolean` | `true` | Show the legend |
340
+ | `explodeIndex` | `number` | — | Index of the slice to offset outward |
341
+ | `explodeOffset` | `number` | `12` | Offset distance in px for the exploded slice |
342
+ | `valueFormatter` | `(v: number) => string` | — | Format tooltip values |
343
+ | + state props | — | — | `isLoading`, `error`, `onRetry`, etc. |
344
+
345
+ ---
346
+
347
+ ### Radial Bar Chart
348
+
349
+ Circular progress rings. Each data item renders as a concentric arc. Useful for showing multiple metrics as percentage completion.
350
+
351
+ ```tsx
352
+ import { RadialBarMetricChart, ChartCard } from 'xertica-ui/ui';
353
+
354
+ const data = [
355
+ { name: 'CPU', value: 72 },
356
+ { name: 'Memory', value: 58 },
357
+ { name: 'Storage', value: 41 },
358
+ { name: 'Network', value: 89 },
359
+ ];
360
+
361
+ // Full-circle rings (default)
362
+ <ChartCard title="Resource Usage">
363
+ <RadialBarMetricChart
364
+ data={data}
365
+ dataKey="value"
366
+ nameKey="name"
367
+ valueFormatter={(v) => `${v}%`}
368
+ />
369
+ </ChartCard>
370
+
371
+ // Semi-circle layout
372
+ <ChartCard title="Resource Usage (Semi)">
373
+ <RadialBarMetricChart
374
+ data={data}
375
+ dataKey="value"
376
+ nameKey="name"
377
+ startAngle={180}
378
+ endAngle={0}
379
+ innerRadius="20%"
380
+ outerRadius="90%"
381
+ />
382
+ </ChartCard>
383
+ ```
384
+
385
+ **Props:**
386
+
387
+ | Prop | Type | Default | Description |
388
+ | ---------------- | ----------------------- | --------- | ------------------------------------------------ |
389
+ | `data` | `DashboardChartDatum[]` | — | Data array; each item is one ring |
390
+ | `dataKey` | `string` | `"value"` | Key used as the bar value |
391
+ | `nameKey` | `string` | `"name"` | Key used as the bar label |
392
+ | `colors` | `DashboardChartColors` | auto | Override colors as ordered array or per-name map |
393
+ | `innerRadius` | `number \| string` | `"30%"` | Inner radius of the radial bar |
394
+ | `outerRadius` | `number \| string` | `"100%"` | Outer radius of the radial bar |
395
+ | `startAngle` | `number` | `90` | Start angle in degrees (90 = top) |
396
+ | `endAngle` | `number` | `-270` | End angle in degrees (-270 = full circle) |
397
+ | `showBackground` | `boolean` | `true` | Show background track behind each bar |
398
+ | `showLegend` | `boolean` | `true` | Show the legend below the chart |
399
+ | `valueFormatter` | `(v: number) => string` | — | Format tooltip and legend values |
400
+ | + state props | — | — | `isLoading`, `error`, `onRetry`, etc. |
401
+
402
+ ---
403
+
404
+ ### Gauge Chart
405
+
406
+ Semicircle gauge with a needle indicator and optional color zones (thresholds). Implemented as pure SVG — no Recharts dependency.
407
+
408
+ ```tsx
409
+ import { GaugeChart, ChartCard, type GaugeChartThreshold } from 'xertica-ui/ui';
410
+
411
+ // Simple percentage gauge
412
+ <ChartCard title="CPU Usage">
413
+ <div className="flex justify-center py-4">
414
+ <GaugeChart value={72} label="CPU" />
415
+ </div>
416
+ </ChartCard>
417
+
418
+ // With color thresholds
419
+ const thresholds: GaugeChartThreshold[] = [
420
+ { value: 40, color: 'var(--chart-2)', label: 'Healthy' },
421
+ { value: 70, color: 'var(--chart-3)', label: 'Warning' },
422
+ { value: 100, color: 'var(--chart-5)', label: 'Critical' },
423
+ ];
424
+
425
+ <ChartCard title="Memory Usage">
426
+ <div className="flex justify-center py-4">
427
+ <GaugeChart
428
+ value={85}
429
+ label="Memory"
430
+ thresholds={thresholds}
431
+ />
432
+ </div>
433
+ </ChartCard>
434
+
435
+ // Custom range and formatter
436
+ <GaugeChart
437
+ value={1250}
438
+ min={0}
439
+ max={2000}
440
+ label="Requests/s"
441
+ valueFormatter={(value) => `${value.toLocaleString()} rps`}
442
+ showNeedle={false}
443
+ />
444
+ ```
445
+
446
+ **Props:**
447
+
448
+ | Prop | Type | Default | Description |
449
+ | ---------------- | -------------------------------------------- | ------- | -------------------------------------------------------------------------- |
450
+ | `value` | `number` | — | Current value (must be within `[min, max]`) |
451
+ | `min` | `number` | `0` | Minimum value |
452
+ | `max` | `number` | `100` | Maximum value |
453
+ | `thresholds` | `GaugeChartThreshold[]` | — | Color zones evaluated in order; first zone where `value >= current %` wins |
454
+ | `label` | `React.ReactNode` | — | Label shown below the center value |
455
+ | `valueFormatter` | `(value: number, percent: number) => string` | — | Format the center value text (default: shows `%`) |
456
+ | `showNeedle` | `boolean` | `true` | Show the needle indicator |
457
+ | `className` | `string` | — | Additional CSS classes |
458
+
459
+ **`GaugeChartThreshold` type:**
460
+
461
+ ```typescript
462
+ interface GaugeChartThreshold {
463
+ value: number; // Upper bound of this zone (0–100)
464
+ color: string; // Color for this zone (use CSS var tokens)
465
+ label?: string; // Optional label shown in the legend
466
+ }
467
+ ```
468
+
469
+ **Infrastructure dashboard example:**
470
+
471
+ ```tsx
472
+ const metrics = [
473
+ { label: 'CPU', value: 72 },
474
+ { label: 'Memory', value: 85 },
475
+ { label: 'Storage', value: 41 },
476
+ ];
477
+
478
+ const thresholds: GaugeChartThreshold[] = [
479
+ { value: 60, color: 'var(--chart-2)', label: 'OK' },
480
+ { value: 80, color: 'var(--chart-3)', label: 'Warning' },
481
+ { value: 100, color: 'var(--chart-5)', label: 'Critical' },
482
+ ];
483
+
484
+ <div className="grid grid-cols-3 gap-4">
485
+ {metrics.map(m => (
486
+ <ChartCard key={m.label} title={m.label}>
487
+ <div className="flex justify-center py-2">
488
+ <GaugeChart value={m.value} label={m.label} thresholds={thresholds} />
489
+ </div>
490
+ </ChartCard>
491
+ ))}
492
+ </div>;
493
+ ```
494
+
495
+ ---
496
+
497
+ ### Sparkline Chart
498
+
499
+ Compact inline chart for KPI cards and metric summaries. Renders as a minimal area or line chart with no axes or labels.
500
+
501
+ ```tsx
502
+ import { SparklineChart } from 'xertica-ui/ui';
503
+
504
+ // Filled area sparkline (default)
505
+ <SparklineChart
506
+ data={[{ v: 10 }, { v: 25 }, { v: 18 }, { v: 40 }, { v: 35 }]}
507
+ dataKey="v"
508
+ color="var(--chart-1)"
509
+ filled
510
+ />
511
+
512
+ // Line-only sparkline
513
+ <SparklineChart
514
+ data={weeklyData}
515
+ dataKey="sessions"
516
+ color="var(--chart-2)"
517
+ filled={false}
518
+ />
519
+ ```
520
+
521
+ ---
522
+
523
+ ### Empty and Connection States
524
+
525
+ All dashboard-ready chart wrappers handle loading, empty data, and connection errors without forcing each feature to duplicate presentation logic. In an FSD architecture, keep fetching and error mapping in the feature/model layer, then pass the state into the UI component.
526
+
527
+ ```tsx
528
+ <DashboardLineChart
529
+ data={analyticsData}
530
+ config={config}
531
+ isLoading={isLoading}
532
+ error={connectionError}
533
+ onRetry={refetchAnalytics}
534
+ emptyTitle="No data available"
535
+ emptyDescription="There is no data available for this period."
536
+ errorTitle="Connection error"
537
+ errorDescription="Unable to load analytics data."
538
+ />
539
+
540
+ // State props work on all dashboard-ready wrappers:
541
+ <RadarMetricChart
542
+ data={skillData}
543
+ labelKey="skill"
544
+ series={[{ key: 'score', label: 'Score' }]}
545
+ isLoading={isLoading}
546
+ error={error}
547
+ onRetry={refetch}
548
+ />
549
+ ```
550
+
551
+ State props (`isLoading`, `error`, `onRetry`, `retryLabel`, `emptyTitle`, `emptyDescription`, `errorTitle`, `errorDescription`, `loadingLabel`, `stateClassName`) are available on: `DashboardBarChart`, `DashboardLineChart`, `HorizontalBarChart`, `InteractiveTimeSeriesChart`, `ComboMetricChart`, `DonutBreakdownChart`, `RadarMetricChart`, `PieMetricChart`, and `RadialBarMetricChart`.
552
+
553
+ > `GaugeChart` does not extend `ChartStateProps` — it is a pure display component with no async state.
554
+
555
+ ---
556
+
557
+ ### Stacked Bar Chart
558
+
559
+ Pass `stacked` to `DashboardBarChart` to stack series on top of each other. When stacking, only the **topmost series** in the stack receives rounded top corners — intermediate and bottom bars have flat tops to avoid visual gaps between segments.
560
+
561
+ ```tsx
562
+ const config: ChartConfig = {
563
+ receita: { label: 'Receita', color: 'var(--chart-1)' },
564
+ despesa: { label: 'Despesa', color: 'var(--chart-5)' },
565
+ };
566
+
567
+ <DashboardBarChart
568
+ data={data}
569
+ indexKey="month"
570
+ config={config}
571
+ series={[
572
+ { key: 'receita', label: 'Receita' },
573
+ { key: 'despesa', label: 'Despesa' }, // ← this series sits on top, gets radius
574
+ ]}
575
+ stacked
576
+ />;
577
+ ```
578
+
579
+ > The radius logic is automatic — the last `series` entry in each `stackId` group receives `radius={[4,4,0,0]}`; all others receive `radius={[0,0,0,0]}`. You do not need to configure this manually.
580
+
581
+ > **v2.1.9**: The `topOfStack` computation was extracted from an inline IIFE in JSX into a `React.useMemo([stacked, chartSeries])` before the `return`. This is a performance improvement — the bar element array is no longer recalculated on every render when the chart re-renders for unrelated reasons.
582
+
583
+ ---
584
+
585
+ ### Bar Thickness
586
+
587
+ Bar-based dashboard charts support `barSize="sm" | "md" | "lg" | "xl"` or a numeric pixel value. This controls the thickness of each rendered bar, not the chart container width.
588
+
589
+ ```tsx
590
+ <DashboardBarChart data={data} indexKey="date" config={config} barSize="lg" />
591
+
592
+ <HorizontalBarChart
593
+ data={segmentData}
594
+ indexKey="segment"
595
+ config={config}
596
+ barSize={28}
597
+ />
598
+
599
+ <ComboMetricChart
600
+ data={data}
601
+ indexKey="date"
602
+ config={config}
603
+ series={[
604
+ { key: 'pipeline', type: 'bar' },
605
+ { key: 'conversion', type: 'line' },
606
+ ]}
607
+ barSize="sm"
608
+ />
609
+ ```
610
+
611
+ `barSize` is available on `DashboardBarChart`, `HorizontalBarChart`, and the bar series inside `ComboMetricChart`.
612
+
613
+ ---
614
+
615
+ ## AI Rules
616
+
617
+ - **Always** use `<ChartContainer config={config}>` — never use `<ResponsiveContainer>` directly.
618
+ - **Never** use hard-coded hex colors on chart elements (`fill="#4F46E5"`). Always use `fill="var(--color-keyName)"` — this references the CSS variable injected by `ChartContainer`.
619
+ - Define color via `color: 'var(--chart-1)'` in `ChartConfig`, or pass `colors={['var(--chart-1)', 'var(--chart-2)']}` to dashboard-ready chart wrappers. The `--chart-*` tokens are theme-aware.
620
+ - `ChartContainer` already wraps `ResponsiveContainer width="100%" height="100%"` — do not add another one.
621
+ - Set height on `ChartContainer` via `className="h-[300px]"` — this sizes the container, not the Recharts elements.
622
+ - Import all base Recharts components (`BarChart`, `Bar`, `Line`, etc.) directly from `recharts` — they are not re-exported by `xertica-ui`.
623
+ - For dashboard-ready charts, prefer `ChartCard` plus a dashboard-ready wrapper before hand-assembling Recharts primitives.
624
+ - In FSD apps, keep data fetching in the feature/model layer and pass `data`, `isLoading`, `error`, and `onRetry` into chart wrappers.
625
+ - Use `barSize` to control bar thickness. Do not use a chart wrapper prop to control graph width; layout width belongs to the parent grid/container.
626
+ - When using `stacked`, order your `series` array so the visually topmost series is last — it will automatically receive the rounded top corners.
627
+ - `RadarMetricChart`, `PieMetricChart`, and `RadialBarMetricChart` build their `ChartConfig` internally from the `series`/`nameKey` data — you do not need to pass a `config` prop.
628
+ - When passing `stateClassName` to `RadarMetricChart`, `PieMetricChart`, or `RadialBarMetricChart`, it is included in the state object passed to `getChartState` — it does not need to be (and should not be) passed as a second `className` argument separately.
629
+ - `GaugeChart` is a pure SVG component — it does not use `ChartContainer` or Recharts. Wrap it in a `div` with `flex justify-center` to control its width.
630
+ - For `GaugeChart` thresholds, use `--chart-*` CSS tokens for colors so they remain theme-aware. Never use raw hex values.
631
+ - `RadialBarMetricChart` renders its legend as HTML below the chart (not inside the SVG) — this is intentional to avoid Recharts polar chart legend positioning issues.
632
+
633
+ ---
634
+
635
+ ## Related Patterns
636
+
637
+ - [Dashboard Pattern](../patterns/dashboard.md)
638
+ - [Analytics Pattern](../patterns/analytics.md)