xertica-ui 2.1.2 → 2.1.3

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 (402) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +1 -1
  3. package/assets/xertica-logo.svg +37 -37
  4. package/assets/xertica-x-logo.svg +20 -20
  5. package/bin/cli.ts +1 -1
  6. package/bin/generate-tokens.ts +13 -7
  7. package/components/assistant/index.ts +6 -6
  8. package/components/assistant/xertica-assistant/index.ts +2 -0
  9. package/components/assistant/xertica-assistant/use-assistant.ts +564 -0
  10. package/components/assistant/xertica-assistant/xertica-assistant.stories.tsx +200 -0
  11. package/components/assistant/xertica-assistant/xertica-assistant.tsx +183 -474
  12. package/components/blocks/card-patterns/ActivityCard.tsx +72 -72
  13. package/components/blocks/card-patterns/FeatureCard.tsx +100 -100
  14. package/components/blocks/card-patterns/NotificationCard.tsx +127 -127
  15. package/components/blocks/card-patterns/ProfileCard.tsx +84 -84
  16. package/components/blocks/card-patterns/ProjectCard.tsx +89 -89
  17. package/components/blocks/card-patterns/QuickActionCard.tsx +62 -62
  18. package/components/blocks/card-patterns/card-patterns.stories.tsx +445 -445
  19. package/components/blocks/card-patterns/index.ts +17 -17
  20. package/components/blocks/index.ts +1 -1
  21. package/components/brand/index.ts +6 -6
  22. package/components/brand/xertica-provider/XerticaProvider.tsx +48 -48
  23. package/components/brand/xertica-provider/xertica-provider.mdx +61 -61
  24. package/components/brand/xertica-provider/xertica-provider.test.tsx +52 -52
  25. package/components/examples/MapExamples.tsx +282 -282
  26. package/components/examples/SimpleFilterableMap.tsx +191 -191
  27. package/components/examples/index.ts +51 -51
  28. package/components/figma/ImageWithFallback.tsx +27 -27
  29. package/components/hooks/index.ts +7 -7
  30. package/components/index.ts +5 -5
  31. package/components/layout/header/header.test.tsx +8 -8
  32. package/components/layout/header/header.tsx +4 -4
  33. package/components/layout/index.ts +2 -2
  34. package/components/layout/sidebar/index.ts +2 -0
  35. package/components/layout/sidebar/sidebar.mdx +1 -1
  36. package/components/layout/sidebar/sidebar.stories.tsx +160 -8
  37. package/components/layout/sidebar/sidebar.test.tsx +11 -11
  38. package/components/layout/sidebar/sidebar.tsx +610 -471
  39. package/components/layout/sidebar/use-sidebar.ts +113 -0
  40. package/components/media/FloatingMediaWrapper.tsx +11 -11
  41. package/components/media/audio-player/AudioPlayer.tsx +22 -22
  42. package/components/media/index.ts +3 -3
  43. package/components/pages/home-content/HomeContent.tsx +7 -7
  44. package/components/pages/home-content/home-content.mdx +62 -62
  45. package/components/pages/home-page/HomePage.stories.tsx +39 -39
  46. package/components/pages/home-page/HomePage.tsx +1 -1
  47. package/components/pages/home-page/home-page.mdx +53 -53
  48. package/components/pages/index.ts +8 -8
  49. package/components/pages/template-content/TemplateContent.tsx +5 -5
  50. package/components/pages/template-content/template-content.mdx +61 -61
  51. package/components/pages/template-page/TemplatePage.stories.tsx +39 -39
  52. package/components/pages/template-page/TemplatePage.tsx +5 -5
  53. package/components/pages/template-page/template-page.mdx +53 -53
  54. package/components/public-api-smoke.test.tsx +52 -52
  55. package/components/shared/assistant-utils.ts +43 -43
  56. package/components/shared/layout-constants.ts +1 -1
  57. package/components/ui/accordion/accordion.mdx +8 -8
  58. package/components/ui/accordion/accordion.stories.tsx +53 -53
  59. package/components/ui/alert/alert.mdx +8 -8
  60. package/components/ui/alert-dialog/alert-dialog.mdx +8 -8
  61. package/components/ui/aspect-ratio/aspect-ratio.mdx +8 -8
  62. package/components/ui/assistant-chart/assistant-chart.mdx +8 -8
  63. package/components/ui/avatar/avatar.mdx +8 -8
  64. package/components/ui/badge/badge.mdx +8 -8
  65. package/components/ui/badge/badge.tsx +9 -9
  66. package/components/ui/breadcrumb/breadcrumb.mdx +8 -8
  67. package/components/ui/button/button.mdx +8 -8
  68. package/components/ui/calendar/calendar.mdx +8 -8
  69. package/components/ui/calendar/calendar.tsx +258 -258
  70. package/components/ui/card/card.mdx +8 -8
  71. package/components/ui/card/card.stories.tsx +245 -245
  72. package/components/ui/carousel/carousel.mdx +8 -8
  73. package/components/ui/chart/chart.mdx +8 -8
  74. package/components/ui/chart/chart.stories.tsx +1303 -344
  75. package/components/ui/chart/chart.test.tsx +154 -154
  76. package/components/ui/chart/chart.tsx +2367 -1494
  77. package/components/ui/checkbox/checkbox.mdx +8 -8
  78. package/components/ui/checkbox/checkbox.stories.tsx +20 -20
  79. package/components/ui/collapsible/collapsible.mdx +8 -8
  80. package/components/ui/command/command.mdx +8 -8
  81. package/components/ui/context-menu/context-menu.mdx +8 -8
  82. package/components/ui/dialog/dialog.mdx +8 -8
  83. package/components/ui/drawer/drawer.mdx +8 -8
  84. package/components/ui/dropdown-menu/dropdown-menu.mdx +8 -8
  85. package/components/ui/empty/empty.mdx +8 -8
  86. package/components/ui/file-upload/file-upload.mdx +8 -8
  87. package/components/ui/file-upload/file-upload.stories.tsx +100 -0
  88. package/components/ui/file-upload/file-upload.tsx +14 -74
  89. package/components/ui/file-upload/index.ts +1 -0
  90. package/components/ui/file-upload/use-file-upload.ts +181 -0
  91. package/components/ui/google-maps-loader/google-maps-loader.tsx +2 -2
  92. package/components/ui/hover-card/hover-card.mdx +8 -8
  93. package/components/ui/input/input.mdx +8 -8
  94. package/components/ui/input-otp/input-otp.mdx +8 -8
  95. package/components/ui/input-otp/input-otp.stories.tsx +6 -6
  96. package/components/ui/label/label.mdx +8 -8
  97. package/components/ui/map/map.mdx +8 -8
  98. package/components/ui/map/map.stories.tsx +51 -51
  99. package/components/ui/map/map.tsx +2 -2
  100. package/components/ui/menubar/menubar.mdx +8 -8
  101. package/components/ui/navigation-menu/navigation-menu.mdx +8 -8
  102. package/components/ui/notification-badge/notification-badge.mdx +8 -8
  103. package/components/ui/pagination/index.ts +2 -0
  104. package/components/ui/pagination/pagination.mdx +8 -8
  105. package/components/ui/pagination/pagination.stories.tsx +94 -0
  106. package/components/ui/pagination/use-pagination.ts +194 -0
  107. package/components/ui/popover/popover.mdx +8 -8
  108. package/components/ui/progress/progress.mdx +8 -8
  109. package/components/ui/progress/progress.tsx +68 -68
  110. package/components/ui/radio-group/radio-group.mdx +8 -8
  111. package/components/ui/rating/rating.mdx +8 -8
  112. package/components/ui/resizable/resizable.mdx +8 -8
  113. package/components/ui/rich-text-editor/index.ts +2 -0
  114. package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +129 -1
  115. package/components/ui/rich-text-editor/rich-text-editor.tsx +86 -305
  116. package/components/ui/rich-text-editor/use-rich-text-editor.ts +439 -0
  117. package/components/ui/route-map/route-map.mdx +8 -8
  118. package/components/ui/route-map/route-map.stories.tsx +54 -54
  119. package/components/ui/route-map/route-map.tsx +2 -2
  120. package/components/ui/scroll-area/scroll-area.mdx +8 -8
  121. package/components/ui/search/search.mdx +8 -8
  122. package/components/ui/select/select.mdx +8 -8
  123. package/components/ui/select/select.stories.tsx +9 -9
  124. package/components/ui/separator/separator.mdx +8 -8
  125. package/components/ui/sheet/sheet.mdx +8 -8
  126. package/components/ui/sheet/sheet.stories.tsx +95 -95
  127. package/components/ui/simple-map/simple-map.mdx +8 -8
  128. package/components/ui/simple-map/simple-map.stories.tsx +48 -48
  129. package/components/ui/skeleton/skeleton.mdx +8 -8
  130. package/components/ui/slider/slider.mdx +8 -8
  131. package/components/ui/sonner/sonner.mdx +8 -8
  132. package/components/ui/stats-card/stats-card.mdx +8 -8
  133. package/components/ui/stepper/index.ts +3 -1
  134. package/components/ui/stepper/stepper.mdx +8 -8
  135. package/components/ui/stepper/stepper.stories.tsx +116 -0
  136. package/components/ui/stepper/stepper.tsx +4 -4
  137. package/components/ui/stepper/use-stepper.ts +137 -0
  138. package/components/ui/switch/switch.mdx +8 -8
  139. package/components/ui/switch/switch.stories.tsx +20 -20
  140. package/components/ui/table/table.mdx +8 -8
  141. package/components/ui/tabs/tabs.mdx +8 -8
  142. package/components/ui/tabs/tabs.stories.tsx +26 -26
  143. package/components/ui/textarea/textarea.mdx +8 -8
  144. package/components/ui/timeline/timeline.mdx +8 -8
  145. package/components/ui/toggle/toggle.mdx +8 -8
  146. package/components/ui/toggle-group/toggle-group.mdx +8 -8
  147. package/components/ui/tooltip/tooltip.mdx +8 -8
  148. package/components/ui/tree-view/index.ts +4 -1
  149. package/components/ui/tree-view/tree-view.mdx +8 -8
  150. package/components/ui/tree-view/tree-view.stories.tsx +110 -4
  151. package/components/ui/tree-view/tree-view.tsx +17 -125
  152. package/components/ui/tree-view/use-tree-view.ts +229 -0
  153. package/components.json +1512 -1512
  154. package/contexts/ApiKeyContext.tsx +72 -72
  155. package/contexts/BrandColorsContext.tsx +26 -26
  156. package/contexts/LanguageContext.tsx +13 -13
  157. package/contexts/LayoutContext.test.tsx +11 -11
  158. package/contexts/LayoutContext.tsx +29 -29
  159. package/contexts/ThemeContext.tsx +26 -26
  160. package/contexts/theme-data.ts +4 -4
  161. package/dist/{AssistantChart-CVzmmhx4.js → AssistantChart-C_hwFRRr.js} +4 -4
  162. package/dist/{AssistantChart-BAx9VQvb.cjs → AssistantChart-CldVCVDe.cjs} +311 -94
  163. package/dist/{AssistantChart-CVko2A1W.js → AssistantChart-Cu3m7RBo.js} +314 -97
  164. package/dist/{AssistantChart-9w31gdAb.cjs → AssistantChart-DoZCyS5r.cjs} +4 -4
  165. package/dist/AudioPlayer-B1lt5cPl.cjs +989 -0
  166. package/dist/AudioPlayer-BZ7bibzU.cjs +982 -0
  167. package/dist/AudioPlayer-C12BjQBV.cjs +997 -0
  168. package/dist/AudioPlayer-DMcG_c7L.js +990 -0
  169. package/dist/AudioPlayer-DcFKRJE_.js +998 -0
  170. package/dist/AudioPlayer-e8LfNoqO.js +983 -0
  171. package/dist/{xertica-assistant-Qp3ydksa.cjs → CodeBlock-7TTgmdGG.cjs} +263 -51
  172. package/dist/{xertica-assistant-gnCJdcZY.js → CodeBlock-BeSt1h5P.js} +219 -7
  173. package/dist/CodeBlock-BgfYL_rD.cjs +2094 -0
  174. package/dist/CodeBlock-BlcqlA9M.cjs +2094 -0
  175. package/dist/CodeBlock-Bnmeu5ez.cjs +2094 -0
  176. package/dist/CodeBlock-BtfPlbAI.js +2078 -0
  177. package/dist/CodeBlock-CIySIuYr.js +2078 -0
  178. package/dist/CodeBlock-CuPtUM-7.cjs +2094 -0
  179. package/dist/CodeBlock-D6ffWXgc.js +2078 -0
  180. package/dist/CodeBlock-D8dcwbit.cjs +2094 -0
  181. package/dist/CodeBlock-DMZrFnlw.cjs +2094 -0
  182. package/dist/CodeBlock-DlBehYN8.js +2078 -0
  183. package/dist/CodeBlock-DnYNI8rQ.js +2078 -0
  184. package/dist/CodeBlock-DvKWbSnE.cjs +2094 -0
  185. package/dist/CodeBlock-DwMCfkFY.js +2078 -0
  186. package/dist/CodeBlock-Dy6CNYyj.js +2078 -0
  187. package/dist/CodeBlock-U1pPOQI7.cjs +2094 -0
  188. package/dist/CodeBlock-f_GpNhEB.js +2078 -0
  189. package/dist/CodeBlock-oB6u8nI1.js +2078 -0
  190. package/dist/CodeBlock-tZC31B73.cjs +2094 -0
  191. package/dist/ImageWithFallback-CGtidP6B.cjs +4542 -0
  192. package/dist/ImageWithFallback-lsg3pdFg.js +4508 -0
  193. package/dist/LanguageSelector-B5YfbHra.js +231 -0
  194. package/dist/LanguageSelector-D6uacAIM.cjs +230 -0
  195. package/dist/LayoutContext-BAql6ZRY.js +97 -0
  196. package/dist/LayoutContext-BvK-ggDa.cjs +96 -0
  197. package/dist/ThemeContext-BoH4NLfN.js +734 -0
  198. package/dist/{ThemeContext-BbBNoFTG.js → ThemeContext-C2EwAPDt.js} +2 -2
  199. package/dist/ThemeContext-r69W20Xg.cjs +733 -0
  200. package/dist/{ThemeContext-Cmr8Ex8H.cjs → ThemeContext-vTjumZeM.cjs} +2 -2
  201. package/dist/{VerifyEmailPage-BE-L9mB7.js → VerifyEmailPage-C0c2e5n0.js} +7 -7
  202. package/dist/{VerifyEmailPage-DMBh4NM9.cjs → VerifyEmailPage-CYXtbKi3.cjs} +1 -1
  203. package/dist/{VerifyEmailPage-CR7kb5df.cjs → VerifyEmailPage-Cwi3kbol.cjs} +7 -7
  204. package/dist/{VerifyEmailPage-CdYPSJoO.js → VerifyEmailPage-DvMLZgFt.js} +1 -1
  205. package/dist/XerticaOrbe-KL1RBHzw.cjs +1354 -0
  206. package/dist/XerticaOrbe-zwS1p2a8.js +1355 -0
  207. package/dist/XerticaProvider-6btlAlzc.js +17 -0
  208. package/dist/XerticaProvider-BNoNOxQ5.cjs +16 -0
  209. package/dist/XerticaProvider-BlY2limY.cjs +38 -0
  210. package/dist/{XerticaProvider-BITjgC5p.js → XerticaProvider-CEoWMTxu.js} +2 -2
  211. package/dist/{XerticaProvider-By8q3Roe.cjs → XerticaProvider-CllrbMEJ.cjs} +2 -2
  212. package/dist/XerticaProvider-DDuiIcKo.js +39 -0
  213. package/dist/XerticaProvider-cI9hSs27.cjs +38 -0
  214. package/dist/XerticaProvider-hSwhNQex.js +39 -0
  215. package/dist/{alert-dialog-yckpaOpy.cjs → alert-dialog-DSKByiKZ.cjs} +3 -3
  216. package/dist/{alert-dialog-iDe5VE5o.js → alert-dialog-s-vmNkJ_.js} +3 -3
  217. package/dist/assistant.cjs.js +2 -1
  218. package/dist/assistant.es.js +3 -2
  219. package/dist/brand.cjs.js +1 -1
  220. package/dist/brand.es.js +1 -1
  221. package/dist/breadcrumb-CqJ7bHY5.js +161 -0
  222. package/dist/breadcrumb-m9Hb2_XN.cjs +177 -0
  223. package/dist/cli.js +14 -8
  224. package/dist/components/assistant/xertica-assistant/index.d.ts +2 -0
  225. package/dist/components/assistant/xertica-assistant/use-assistant.d.ts +126 -0
  226. package/dist/components/assistant/xertica-assistant/xertica-assistant.d.ts +7 -2
  227. package/dist/components/blocks/audio-player/AudioPlayer.d.ts +35 -0
  228. package/dist/components/blocks/audio-player/index.d.ts +1 -0
  229. package/dist/components/blocks/document-editor/DocumentEditor.d.ts +26 -0
  230. package/dist/components/blocks/document-editor/index.d.ts +1 -0
  231. package/dist/components/blocks/podcast-player/PodcastPlayer.d.ts +41 -0
  232. package/dist/components/blocks/podcast-player/index.d.ts +1 -0
  233. package/dist/components/layout/sidebar/index.d.ts +2 -0
  234. package/dist/components/layout/sidebar/sidebar.d.ts +80 -0
  235. package/dist/components/layout/sidebar/use-sidebar.d.ts +22 -0
  236. package/dist/components/shared/layout-constants.d.ts +1 -1
  237. package/dist/components/ui/button/button.d.ts +1 -1
  238. package/dist/components/ui/chart/chart.d.ts +162 -5
  239. package/dist/components/ui/file-upload/file-upload.d.ts +2 -0
  240. package/dist/components/ui/file-upload/index.d.ts +1 -0
  241. package/dist/components/ui/file-upload/use-file-upload.d.ts +49 -0
  242. package/dist/components/ui/pagination/index.d.ts +2 -0
  243. package/dist/components/ui/pagination/use-pagination.d.ts +78 -0
  244. package/dist/components/ui/rich-text-editor/index.d.ts +2 -0
  245. package/dist/components/ui/rich-text-editor/use-rich-text-editor.d.ts +107 -0
  246. package/dist/components/ui/stepper/index.d.ts +3 -1
  247. package/dist/components/ui/stepper/stepper.d.ts +2 -2
  248. package/dist/components/ui/stepper/use-stepper.d.ts +60 -0
  249. package/dist/components/ui/tree-view/index.d.ts +4 -1
  250. package/dist/components/ui/tree-view/tree-view.d.ts +4 -6
  251. package/dist/components/ui/tree-view/use-tree-view.d.ts +60 -0
  252. package/dist/dropdown-menu-BDB5CmQs.cjs +247 -0
  253. package/dist/dropdown-menu-DQidbKBD.js +231 -0
  254. package/dist/google-maps-loader-BFWp6VPd.js +287 -0
  255. package/dist/{google-maps-loader-t2IlYBzw.js → google-maps-loader-CTYySAun.js} +4 -0
  256. package/dist/{google-maps-loader-BqsYL48U.cjs → google-maps-loader-Y-QkD-Li.cjs} +5 -0
  257. package/dist/google-maps-loader-eS3uQ5TA.cjs +287 -0
  258. package/dist/header-Cgy6vYPk.cjs +731 -0
  259. package/dist/header-DRlT4jgI.js +715 -0
  260. package/dist/header-Dux00SI4.cjs +731 -0
  261. package/dist/header-EkGKXPsD.js +715 -0
  262. package/dist/header-WfEywpyc.cjs +731 -0
  263. package/dist/header-tifNQn2U.js +715 -0
  264. package/dist/hooks.cjs.js +1 -1
  265. package/dist/hooks.es.js +1 -1
  266. package/dist/index-BhapVLVj.js +8 -0
  267. package/dist/{index-D3RLKRAs.cjs → index-COtD8bRW.cjs} +1 -1
  268. package/dist/index-D6fxYEY8.cjs +7 -0
  269. package/dist/index-DW5tYe26.js +8 -0
  270. package/dist/index.cjs.js +19 -8
  271. package/dist/index.es.js +39 -28
  272. package/dist/index.umd.js +1043 -470
  273. package/dist/input-2R4loU86.js +127 -0
  274. package/dist/input-DWANSKGb.cjs +145 -0
  275. package/dist/layout.cjs.js +89 -1
  276. package/dist/layout.es.js +90 -2
  277. package/dist/pages.cjs.js +1 -1
  278. package/dist/pages.es.js +1 -1
  279. package/dist/rich-text-editor-0mraWT5y.cjs +2376 -0
  280. package/dist/rich-text-editor-B6jMRLzk.cjs +1939 -0
  281. package/dist/rich-text-editor-B8_oYcIR.js +1730 -0
  282. package/dist/rich-text-editor-B9UbSXNb.js +1203 -0
  283. package/dist/rich-text-editor-BYuRBNBU.js +2373 -0
  284. package/dist/rich-text-editor-Bb9pySTs.cjs +2374 -0
  285. package/dist/rich-text-editor-BcL6L3cm.cjs +2374 -0
  286. package/dist/rich-text-editor-BoVZYtTs.cjs +2391 -0
  287. package/dist/rich-text-editor-CPV1lEPH.cjs +1748 -0
  288. package/dist/rich-text-editor-CoKqbCtu.cjs +1799 -0
  289. package/dist/rich-text-editor-Cw56T_mB.js +2356 -0
  290. package/dist/rich-text-editor-Cyt8qs2b.js +1921 -0
  291. package/dist/rich-text-editor-D6H84OcX.cjs +1220 -0
  292. package/dist/rich-text-editor-D76gD-QI.js +2328 -0
  293. package/dist/rich-text-editor-DKkokOnA.js +1781 -0
  294. package/dist/rich-text-editor-DNsdpN64.cjs +2359 -0
  295. package/dist/rich-text-editor-DfG8bCyY.js +2358 -0
  296. package/dist/rich-text-editor-DgF8s7xW.js +2949 -0
  297. package/dist/rich-text-editor-Dxjw31Z4.js +2341 -0
  298. package/dist/rich-text-editor-DzP0Epmb.js +2356 -0
  299. package/dist/rich-text-editor-mWoaSCE4.cjs +2966 -0
  300. package/dist/rich-text-editor-skplNlBM.cjs +2345 -0
  301. package/dist/select-Bkbr0f-Z.cjs +162 -0
  302. package/dist/select-CvIVdX2n.js +145 -0
  303. package/dist/sidebar-CK_0ZQHj.cjs +803 -0
  304. package/dist/sidebar-CUuOvYhK.js +787 -0
  305. package/dist/slider-Bc5Hd0y1.js +56 -0
  306. package/dist/slider-N7hFFj6X.cjs +73 -0
  307. package/dist/tooltip-Ded96neP.cjs +137 -0
  308. package/dist/tooltip-HDOoD2-0.js +120 -0
  309. package/dist/ui.cjs.js +14 -4
  310. package/dist/ui.es.js +26 -16
  311. package/dist/use-mobile-B0hNy_Y6.cjs +4303 -0
  312. package/dist/use-mobile-BXuYROXM.js +4202 -0
  313. package/dist/use-mobile-Bbd51ASU.cjs +4392 -0
  314. package/dist/use-mobile-Bk6CX-TC.js +4359 -0
  315. package/dist/use-mobile-BvYdisLP.js +4202 -0
  316. package/dist/use-mobile-BzuxjzNX.cjs +4392 -0
  317. package/dist/use-mobile-CG2-SdXV.cjs +4235 -0
  318. package/dist/use-mobile-CKb5pqTs.js +4269 -0
  319. package/dist/use-mobile-CYuAuGDl.js +4202 -0
  320. package/dist/use-mobile-CaENcqm-.js +4508 -0
  321. package/dist/use-mobile-CbrYgJGJ.js +4203 -0
  322. package/dist/use-mobile-DMOvImGQ.cjs +4542 -0
  323. package/dist/use-mobile-DRB3BQgD.cjs +4235 -0
  324. package/dist/use-mobile-DZvv7QMR.js +4359 -0
  325. package/dist/use-mobile-DdI_TXam.cjs +4235 -0
  326. package/dist/use-mobile-DlceKf8a.js +4359 -0
  327. package/dist/use-mobile-DsOnow1o.cjs +4236 -0
  328. package/dist/use-mobile-Kcj6jSnK.cjs +4392 -0
  329. package/dist/use-mobile-bnKcua_i.js +4202 -0
  330. package/dist/use-mobile-ncXBeE2z.cjs +4235 -0
  331. package/dist/{xertica-assistant-B1IaHXnB.cjs → xertica-assistant-dyP7KHM5.cjs} +533 -392
  332. package/dist/{xertica-assistant-DPsESB6t.js → xertica-assistant-yX1CFBBo.js} +535 -394
  333. package/dist/xertica-ui.css +2 -2
  334. package/docs/ai-usage.md +28 -10
  335. package/docs/architecture.md +76 -0
  336. package/docs/components/assistant.md +159 -0
  337. package/docs/components/calendar.md +154 -154
  338. package/docs/components/card-patterns.md +337 -337
  339. package/docs/components/card.md +235 -235
  340. package/docs/components/chart.md +354 -39
  341. package/docs/components/file-upload.md +119 -2
  342. package/docs/components/map.md +84 -84
  343. package/docs/components/pagination.md +187 -0
  344. package/docs/components/rich-text-editor.md +164 -0
  345. package/docs/components/sidebar.md +153 -4
  346. package/docs/components/stepper.md +157 -12
  347. package/docs/components/tree-view.md +164 -6
  348. package/docs/components/xertica-provider.md +24 -24
  349. package/docs/decision-tree.md +287 -287
  350. package/docs/getting-started.md +1 -1
  351. package/docs/guidelines.md +14 -8
  352. package/docs/layout.md +2 -2
  353. package/docs/llms.md +4 -4
  354. package/guidelines/Guidelines.md +252 -250
  355. package/hooks/useTheme.ts +3 -3
  356. package/imports/Podcast.tsx +388 -388
  357. package/imports/XerticaAi.tsx +45 -45
  358. package/imports/XerticaX.tsx +19 -19
  359. package/imports/svg-aueiaqngck.ts +11 -11
  360. package/imports/svg-v9krss1ozd.ts +16 -16
  361. package/imports/svg-vhrdofe3qe.ts +5 -5
  362. package/llms-compact.txt +327 -327
  363. package/llms.txt +160 -160
  364. package/package.json +203 -203
  365. package/styles/xertica/app-overrides/chat.css +61 -61
  366. package/styles/xertica/app-overrides/scrollbar.css +33 -33
  367. package/styles/xertica/integrations/google-maps.css +76 -76
  368. package/styles/xertica/integrations/sonner.css +73 -73
  369. package/styles/xertica/tokens.css +41 -12
  370. package/templates/CLAUDE.md +182 -172
  371. package/templates/guidelines/Guidelines.md +325 -313
  372. package/templates/package.json +3 -3
  373. package/templates/src/features/auth/index.ts +4 -4
  374. package/templates/src/features/auth/ui/AuthPageShell.tsx +34 -34
  375. package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +70 -70
  376. package/templates/src/features/auth/ui/LoginContent.tsx +90 -90
  377. package/templates/src/features/auth/ui/ResetPasswordContent.tsx +151 -151
  378. package/templates/src/features/auth/ui/SocialLoginButtons.tsx +59 -59
  379. package/templates/src/features/auth/ui/VerifyEmailContent.tsx +82 -82
  380. package/templates/src/features/home/index.ts +1 -1
  381. package/templates/src/features/home/ui/HomeContent.tsx +100 -100
  382. package/templates/src/features/template/index.ts +5 -5
  383. package/templates/src/features/template/ui/CrudTemplate.tsx +3 -3
  384. package/templates/src/features/template/ui/DashboardTemplate.tsx +3 -3
  385. package/templates/src/features/template/ui/FormTemplate.tsx +120 -120
  386. package/templates/src/features/template/ui/LoginTemplate.tsx +3 -3
  387. package/templates/src/pages/AssistantPage.tsx +328 -328
  388. package/templates/src/pages/ForgotPasswordPage.tsx +6 -6
  389. package/templates/src/pages/HomePage.tsx +57 -57
  390. package/templates/src/pages/LoginPage.tsx +10 -10
  391. package/templates/src/pages/ResetPasswordPage.tsx +6 -6
  392. package/templates/src/pages/TemplatePage.tsx +30 -30
  393. package/templates/src/pages/VerifyEmailPage.tsx +6 -6
  394. package/templates/src/shared/config/navigation.ts +20 -20
  395. package/templates/src/shared/lib/auth.ts +20 -20
  396. package/templates/src/shared/types/auth.ts +3 -3
  397. package/templates/src/styles/xertica/tokens.css +39 -10
  398. package/templates/tsconfig.json +5 -5
  399. package/utils/gemini.ts +140 -140
  400. package/dist/VerifyEmailPage-Bae2cBXT.cjs +0 -2827
  401. package/dist/VerifyEmailPage-CbgjOF0v.js +0 -2828
  402. package/dist/index-CkTUgOwX.js +0 -8
@@ -6,6 +6,14 @@ The `Sidebar` is the primary vertical navigation panel of the application shell.
6
6
 
7
7
  It is a responsive component that can be expanded or collapsed as an icon-only strip, fully integrated with the `LayoutContext` for state management.
8
8
 
9
+ The component ships with **three usage patterns** to cover different levels of customization:
10
+
11
+ | Pattern | When to use |
12
+ |---|---|
13
+ | **Monolithic API** (`<Sidebar />`) | Standard usage — pass props, get a fully-featured sidebar |
14
+ | **Compound Component API** (`<Sidebar.Root>` + sub-components) | Custom layouts — compose only the parts you need |
15
+ | **Headless Hook** (`useSidebar()`) | Full control — manage state yourself, render anything |
16
+
9
17
  ---
10
18
 
11
19
  ## Variants
@@ -36,6 +44,8 @@ Designed for complex tools, agents, or multi-context navigation.
36
44
 
37
45
  ## Props
38
46
 
47
+ ### `<Sidebar />` (Monolithic API)
48
+
39
49
  | Prop | Type | Default | Description |
40
50
  |---|---|---|---|
41
51
  | `expanded` | `boolean` | `auto` | Controlled state. Defaults to `LayoutContext` or local state. |
@@ -47,8 +57,45 @@ Designed for complex tools, agents, or multi-context navigation.
47
57
  | `search` | `SidebarSearchConfig` | — | Search bar configuration (assistant variant). |
48
58
  | `logo` | `ReactNode` | — | Logo shown when expanded. |
49
59
  | `logoCollapsed` | `ReactNode` | — | Logo shown when collapsed. |
50
- | `width` | `number` | `256` | Expanded sidebar width in pixels. |
60
+ | `width` | `number` | `280` | Expanded sidebar width in pixels. |
51
61
  | `footer` | `SidebarFooterConfig` | — | Footer visibility flags (`showUser`, `showSettings`, `showLogout`). |
62
+ | `showFooter` | `boolean` | `true` for default, `false` for assistant | Whether to render the footer section. |
63
+
64
+ ### `<Sidebar.Root />` (Compound Component)
65
+
66
+ | Prop | Type | Default | Description |
67
+ |---|---|---|---|
68
+ | `expanded` | `boolean` | `auto` | Controlled expansion state. |
69
+ | `onToggle` | `() => void` | `auto` | Toggle callback. |
70
+ | `navigate` | `(path: string) => void` | `window.location.href` | Navigation handler. |
71
+ | `location` | `{ pathname: string }` | `window.location` | Current location for active state. |
72
+ | `width` | `number` | `280` | Expanded width in pixels. |
73
+ | `children` | `ReactNode` | — | Sub-components: `Sidebar.Header`, `Sidebar.Nav`, `Sidebar.Footer`, `Sidebar.Search`. |
74
+
75
+ ### `useSidebar()` (Headless Hook)
76
+
77
+ ```ts
78
+ import { useSidebar } from 'xertica-ui/layout';
79
+
80
+ const {
81
+ expanded, // boolean — current expansion state
82
+ setExpanded, // (value: boolean | fn) => void
83
+ toggleExpanded, // () => void
84
+ isMobileViewport, // boolean
85
+ hasOverflow, // boolean — nav items overflow the container
86
+ visibleItems, // RouteGroup[] — items that fit in the nav
87
+ overflowItems, // RouteGroup[] — items that overflow
88
+ openSubmenu, // string | null
89
+ setOpenSubmenu, // (id: string | null) => void
90
+ isFilterOpen, // boolean
91
+ setIsFilterOpen, // (open: boolean) => void
92
+ navRef, // RefObject<HTMLElement> — attach to nav container
93
+ navigationGroups, // RouteGroup[] — the resolved groups passed in
94
+ } = useSidebar({
95
+ defaultExpanded: true,
96
+ navigationGroups: myGroups,
97
+ });
98
+ ```
52
99
 
53
100
  ### RouteConfig
54
101
 
@@ -61,11 +108,21 @@ Designed for complex tools, agents, or multi-context navigation.
61
108
  | `actions` | `ActionMenuItem[]` | Contextual action menu items (ellipsis button — assistant variant) |
62
109
  | `description` | `ReactNode` | Auxiliary content shown when the route is active (assistant variant) |
63
110
 
111
+ ### RouteGroup
112
+
113
+ | Field | Type | Description |
114
+ |---|---|---|
115
+ | `id` | `string` | Unique identifier |
116
+ | `label` | `string` | Group title |
117
+ | `icon` | `ComponentType` | Group icon |
118
+ | `items` | `RouteConfig[]` | Navigation items in the group |
119
+ | `actions` | `ActionMenuItem[]` | Context menu for the entire group |
120
+
64
121
  ---
65
122
 
66
123
  ## Examples
67
124
 
68
- ### Default Variant — Flat Routes
125
+ ### 1. Monolithic API — Flat Routes
69
126
 
70
127
  ```tsx
71
128
  import { Sidebar } from 'xertica-ui/layout';
@@ -94,7 +151,7 @@ export function MySidebar() {
94
151
  }
95
152
  ```
96
153
 
97
- ### Default Variant — Groups with Children
154
+ ### 2. Monolithic API — Groups with Children
98
155
 
99
156
  ```tsx
100
157
  import { BarChart, Users, Settings, Home } from 'lucide-react';
@@ -129,15 +186,107 @@ import { BarChart, Users, Settings, Home } from 'lucide-react';
129
186
  />
130
187
  ```
131
188
 
189
+ ### 3. Compound Component API
190
+
191
+ Use this when you need to inject custom content between sections or reorder the layout:
192
+
193
+ ```tsx
194
+ import { Sidebar } from 'xertica-ui/layout';
195
+ import { Home, BarChart } from 'lucide-react';
196
+
197
+ export function CustomSidebar({ expanded, onToggle }) {
198
+ return (
199
+ <Sidebar.Root
200
+ expanded={expanded}
201
+ onToggle={onToggle}
202
+ width={280}
203
+ location={{ pathname: window.location.pathname }}
204
+ navigate={(path) => window.location.href = path}
205
+ >
206
+ {/* Toggle button + logo */}
207
+ <Sidebar.Header logo={<MyLogo />} logoCollapsed={<MyIcon />} />
208
+
209
+ {/* Custom content injected between header and nav */}
210
+ <div className="px-4 py-2">
211
+ <span className="text-xs text-sidebar-foreground/60">v2.0.0</span>
212
+ </div>
213
+
214
+ {/* Navigation */}
215
+ <Sidebar.Nav
216
+ navigationGroups={[
217
+ {
218
+ id: 'main',
219
+ items: [
220
+ { path: '/home', label: 'Home', icon: Home },
221
+ { path: '/dashboard', label: 'Dashboard', icon: BarChart },
222
+ ],
223
+ },
224
+ ]}
225
+ />
226
+
227
+ {/* Footer */}
228
+ <Sidebar.Footer
229
+ user={{ name: 'Admin', email: 'admin@example.com' }}
230
+ onLogout={() => signOut()}
231
+ showUser
232
+ showSettings
233
+ showLogout
234
+ />
235
+ </Sidebar.Root>
236
+ );
237
+ }
238
+ ```
239
+
240
+ ### 4. Headless Hook — Fully Custom UI
241
+
242
+ Use `useSidebar` when you need complete control over the rendered output:
243
+
244
+ ```tsx
245
+ import { useSidebar } from 'xertica-ui/layout';
246
+ import { Home, BarChart } from 'lucide-react';
247
+
248
+ const groups = [
249
+ {
250
+ id: 'main',
251
+ items: [
252
+ { path: '/home', label: 'Home', icon: Home },
253
+ { path: '/dashboard', label: 'Dashboard', icon: BarChart },
254
+ ],
255
+ },
256
+ ];
257
+
258
+ export function MyCustomSidebar() {
259
+ const { expanded, toggleExpanded, navigationGroups } = useSidebar({
260
+ defaultExpanded: true,
261
+ navigationGroups: groups,
262
+ });
263
+
264
+ return (
265
+ <aside style={{ width: expanded ? 280 : 80 }}>
266
+ <button onClick={toggleExpanded}>Toggle</button>
267
+ <nav>
268
+ {navigationGroups.flatMap(g => g.items).map(item => (
269
+ <a key={item.path} href={item.path}>
270
+ {expanded ? item.label : null}
271
+ </a>
272
+ ))}
273
+ </nav>
274
+ </aside>
275
+ );
276
+ }
277
+ ```
278
+
132
279
  ---
133
280
 
134
281
  ## AI Rules
135
282
 
136
- - **State Management** — Always use `useLayout()` to keep the Sidebar synchronized with the main content padding. Avoid managing `expanded` locally.
283
+ - **State Management** — Always use `useLayout()` to keep the Sidebar synchronized with the main content padding. Avoid managing `expanded` locally unless using the Headless Hook pattern.
137
284
  - **Icons** — Pass the icon **component source** (e.g., `HomeIcon`), not a rendered element.
138
285
  - **Groups** — Use `navigationGroups` in `default` variant for structured navigation with labels. Use `routes` for flat lists.
139
286
  - **Children** — Add `children` to a `RouteConfig` to expose sub-routes via a ChevronRight button at the end of the item. Do not nest more than 2 levels.
140
287
  - **Assistant Mode** — Use `fixedArea` to place high-priority "Create" buttons so they remain visible regardless of scrolling.
288
+ - **Compound Components** — Use `<Sidebar.Root>` + sub-components when you need to inject custom content between sections or reorder the layout.
289
+ - **Headless Hook** — Use `useSidebar()` only when you need a completely custom sidebar UI that shares none of the default rendering.
141
290
 
142
291
  ---
143
292
 
@@ -4,6 +4,20 @@
4
4
 
5
5
  A visual multi-step progress indicator that shows the user's current position within a sequential process. Uses a composable primitive pattern: `<Stepper>` wraps one or more `<Step>` children, automatically inferring the total number of steps.
6
6
 
7
+ The package also exports a **headless `useStepper` hook** for building fully custom step-navigation UIs — including async validation guards before advancing — while reusing all the step-state logic.
8
+
9
+ ---
10
+
11
+ ## Exports
12
+
13
+ | Export | Description |
14
+ |---|---|
15
+ | `Stepper` | Visual step indicator component |
16
+ | `Step` | Individual step item |
17
+ | `useStepper` | Headless hook — all step navigation logic, no UI |
18
+ | `UseStepperProps` | TypeScript props type for the hook |
19
+ | `UseStepperReturn` | TypeScript return type for the hook |
20
+
7
21
  ---
8
22
 
9
23
  ## When to Use
@@ -43,6 +57,7 @@ A visual multi-step progress indicator that shows the user's current position wi
43
57
  | Prop | Type | Required | Description |
44
58
  |---|---|---|---|
45
59
  | `currentStep` | `number` | **Yes** | The currently active step (1-indexed) |
60
+ | `orientation` | `'horizontal' \| 'vertical'` | No | Layout direction (default: `'horizontal'`) |
46
61
  | `className` | `string` | No | Additional CSS classes |
47
62
 
48
63
  ### `Step`
@@ -52,16 +67,9 @@ A visual multi-step progress indicator that shows the user's current position wi
52
67
  | `step` | `number` | **Yes** | Position of this step (1-indexed, must match order) |
53
68
  | `label` | `string` | **Yes** | Step label text |
54
69
  | `description` | `string` | No | Optional supplementary text below the label |
70
+ | `error` | `boolean` | No | When `true`, renders the step in error state (red) |
55
71
  | `className` | `string` | No | Additional CSS classes |
56
72
 
57
- ### `useStepper()` (hook)
58
-
59
- ```typescript
60
- const { currentStep, totalSteps } = useStepper();
61
- ```
62
-
63
- Access the stepper context from within a custom `Step` child component.
64
-
65
73
  ---
66
74
 
67
75
  ## Examples
@@ -97,7 +105,7 @@ const [currentStep, setCurrentStep] = useState(1);
97
105
  onClick={() => setCurrentStep(s => Math.min(3, s + 1))}
98
106
  disabled={currentStep === 3}
99
107
  >
100
- {currentStep === 2 ? 'Finish' : 'Next'}
108
+ {currentStep === 3 ? 'Finish' : 'Next'}
101
109
  </Button>
102
110
  </div>
103
111
  </div>
@@ -105,14 +113,151 @@ const [currentStep, setCurrentStep] = useState(1);
105
113
 
106
114
  ---
107
115
 
116
+ ## `useStepper` Hook
117
+
118
+ A headless hook that manages step navigation state. Supports both **uncontrolled** (internal state) and **controlled** (external `step` prop) modes, plus an optional async `onBeforeNext` guard for validating the current step before advancing.
119
+
120
+ ### Props
121
+
122
+ | Prop | Type | Default | Description |
123
+ |---|---|---|---|
124
+ | `totalSteps` | `number` | — | **Required.** Total number of steps in the flow |
125
+ | `initialStep` | `number` | `1` | Starting step (uncontrolled mode only) |
126
+ | `step` | `number` | — | Controlled current step — when provided, the hook uses this value instead of internal state |
127
+ | `onStepChange` | `(step: number) => void` | — | Called whenever the step changes |
128
+ | `onBeforeNext` | `(currentStep: number) => boolean \| Promise<boolean>` | — | Optional async guard — return `false` (or resolve to `false`) to block advancing to the next step |
129
+
130
+ ### Return Value
131
+
132
+ | Property | Type | Description |
133
+ |---|---|---|
134
+ | `currentStep` | `number` | The currently active step (1-indexed) |
135
+ | `totalSteps` | `number` | Total number of steps |
136
+ | `isFirstStep` | `boolean` | Whether the current step is the first step |
137
+ | `isLastStep` | `boolean` | Whether the current step is the last step |
138
+ | `canGoPrev` | `boolean` | Whether navigating to the previous step is possible |
139
+ | `canGoNext` | `boolean` | Whether navigating to the next step is possible |
140
+ | `next` | `() => Promise<void>` | Advance to the next step (runs `onBeforeNext` guard if provided) |
141
+ | `prev` | `() => void` | Go back to the previous step |
142
+ | `goTo` | `(step: number) => void` | Jump to a specific step number |
143
+ | `reset` | `() => void` | Reset to the initial step |
144
+
145
+ ### Uncontrolled Example
146
+
147
+ ```tsx
148
+ import { useStepper, Stepper, Step, Button } from 'xertica-ui/ui';
149
+
150
+ function OnboardingWizard() {
151
+ const { currentStep, isFirstStep, isLastStep, next, prev } = useStepper({
152
+ totalSteps: 3,
153
+ });
154
+
155
+ return (
156
+ <div className="space-y-8">
157
+ <Stepper currentStep={currentStep}>
158
+ <Step step={1} label="Account" />
159
+ <Step step={2} label="Plan" />
160
+ <Step step={3} label="Confirm" />
161
+ </Stepper>
162
+
163
+ <div className="min-h-[200px]">
164
+ {currentStep === 1 && <AccountForm />}
165
+ {currentStep === 2 && <PlanSelector />}
166
+ {currentStep === 3 && <ConfirmationSummary />}
167
+ </div>
168
+
169
+ <div className="flex justify-between">
170
+ <Button variant="outline" onClick={prev} disabled={isFirstStep}>
171
+ Previous
172
+ </Button>
173
+ <Button onClick={next} disabled={isLastStep}>
174
+ {isLastStep ? 'Finish' : 'Next'}
175
+ </Button>
176
+ </div>
177
+ </div>
178
+ );
179
+ }
180
+ ```
181
+
182
+ ### With Async Validation Guard
183
+
184
+ ```tsx
185
+ import { useStepper, Stepper, Step, Button } from 'xertica-ui/ui';
186
+ import { useForm } from 'react-hook-form';
187
+
188
+ function ValidatedWizard() {
189
+ const form = useForm();
190
+
191
+ const { currentStep, isFirstStep, isLastStep, next, prev } = useStepper({
192
+ totalSteps: 3,
193
+ onBeforeNext: async (step) => {
194
+ // Validate only the fields relevant to the current step
195
+ const fieldsPerStep: Record<number, string[]> = {
196
+ 1: ['email', 'password'],
197
+ 2: ['plan'],
198
+ };
199
+ const fields = fieldsPerStep[step];
200
+ if (!fields) return true;
201
+ return form.trigger(fields as never[]);
202
+ },
203
+ });
204
+
205
+ return (
206
+ <div className="space-y-8">
207
+ <Stepper currentStep={currentStep}>
208
+ <Step step={1} label="Account" />
209
+ <Step step={2} label="Plan" />
210
+ <Step step={3} label="Confirm" />
211
+ </Stepper>
212
+
213
+ <form>{/* step content */}</form>
214
+
215
+ <div className="flex justify-between">
216
+ <Button variant="outline" onClick={prev} disabled={isFirstStep}>
217
+ Previous
218
+ </Button>
219
+ <Button onClick={next}>
220
+ {isLastStep ? 'Submit' : 'Next'}
221
+ </Button>
222
+ </div>
223
+ </div>
224
+ );
225
+ }
226
+ ```
227
+
228
+ ### Controlled Example
229
+
230
+ ```tsx
231
+ import { useStepper } from 'xertica-ui/ui';
232
+ import { useState } from 'react';
233
+
234
+ function ControlledWizard() {
235
+ const [step, setStep] = useState(1);
236
+
237
+ const { currentStep, next, prev, isFirstStep, isLastStep } = useStepper({
238
+ totalSteps: 4,
239
+ step, // controlled
240
+ onStepChange: setStep,
241
+ });
242
+
243
+ // currentStep === step at all times
244
+ return (/* ... */);
245
+ }
246
+ ```
247
+
248
+ ---
249
+
108
250
  ## AI Rules
109
251
 
110
- - `step` props are **1-indexed** — the first step is `step={1}`, not `step={0}`.
252
+ - `step` props on `<Step>` are **1-indexed** — the first step is `step={1}`, not `step={0}`.
111
253
  - Each `<Step>` `step` prop must match its position sequentially: `1, 2, 3, ...`.
112
254
  - `currentStep` on `<Stepper>` must be a number from `1` to the total number of steps.
113
255
  - Always render the navigation buttons (Previous/Next) below the Stepper.
114
- - Disable "Previous" on step `1` and "Next" on the final step.
115
- - Validate the current step's form data **before** advancing `currentStep`.
256
+ - Disable "Previous" on step `1` (`isFirstStep`) and "Next" on the final step (`isLastStep`).
257
+ - Use `onBeforeNext` for async form validation return `false` to block advancing.
258
+ - `next()` is **async** — always `await` it or use it as an `onClick` handler directly (React handles the Promise).
259
+ - In controlled mode, pass both `step` and `onStepChange` — omitting `onStepChange` makes the hook read-only.
260
+ - Use `reset()` to return to step 1 after a successful submission.
116
261
 
117
262
  ---
118
263
 
@@ -2,7 +2,21 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- An interactive hierarchical tree component for displaying and navigating nested data structures — file systems, organizational charts, category trees, and recursive navigation menus.
5
+ An interactive hierarchical tree component for displaying and navigating nested data structures — file systems, organizational charts, category trees, and recursive navigation menus. Supports keyboard navigation (Arrow keys, Home, End, Space), expand/collapse, and single-node selection.
6
+
7
+ The package also exports a **headless `useTreeView` hook** for building fully custom tree UIs while reusing all the expand/collapse, selection, keyboard navigation, and focus management logic.
8
+
9
+ ---
10
+
11
+ ## Exports
12
+
13
+ | Export | Description |
14
+ |---|---|
15
+ | `TreeView` | Ready-to-use hierarchical tree component |
16
+ | `useTreeView` | Headless hook — all logic, no UI |
17
+ | `TreeNode` | TypeScript type for a single tree node |
18
+ | `UseTreeViewProps` | TypeScript props type for the hook |
19
+ | `UseTreeViewReturn` | TypeScript return type for the hook |
6
20
 
7
21
  ---
8
22
 
@@ -17,13 +31,18 @@ An interactive hierarchical tree component for displaying and navigating nested
17
31
 
18
32
  ## Props
19
33
 
34
+ ### `TreeView`
35
+
20
36
  | Prop | Type | Required | Description |
21
37
  |---|---|---|---|
22
38
  | `data` | `TreeNode[]` | **Yes** | The tree data structure |
23
- | `onSelect` | `(node: TreeNode) => void` | No | Selection handler |
39
+ | `defaultExpanded` | `string[]` | No | Node IDs to expand on initial render |
40
+ | `selectedNodeId` | `string` | No | Controlled selected node ID |
41
+ | `onNodeClick` | `(node: TreeNode) => void` | No | Called when any node is clicked |
42
+ | `onNodeSelect` | `(node: TreeNode) => void` | No | Called when a node is selected (leaf or branch) |
24
43
  | `className` | `string` | No | Additional CSS classes |
25
44
 
26
- ### TreeNode
45
+ ### `TreeNode`
27
46
 
28
47
  ```typescript
29
48
  interface TreeNode {
@@ -31,7 +50,6 @@ interface TreeNode {
31
50
  label: string;
32
51
  icon?: ReactNode;
33
52
  children?: TreeNode[];
34
- disabled?: boolean;
35
53
  }
36
54
  ```
37
55
 
@@ -39,6 +57,8 @@ interface TreeNode {
39
57
 
40
58
  ## Examples
41
59
 
60
+ ### File System Browser
61
+
42
62
  ```tsx
43
63
  import { TreeView } from 'xertica-ui/ui';
44
64
  import { Folder, File } from 'lucide-react';
@@ -65,14 +85,152 @@ const tree = [
65
85
 
66
86
  <TreeView
67
87
  data={tree}
68
- onSelect={(node) => console.log('Selected:', node.id)}
88
+ onNodeSelect={(node) => console.log('Selected:', node.id)}
89
+ />
90
+ ```
91
+
92
+ ### Pre-expanded Nodes
93
+
94
+ ```tsx
95
+ <TreeView
96
+ data={tree}
97
+ defaultExpanded={['src', 'components']}
98
+ onNodeSelect={(node) => setSelectedFile(node.id)}
69
99
  />
70
100
  ```
71
101
 
72
102
  ---
73
103
 
104
+ ## `useTreeView` Hook
105
+
106
+ A headless hook that manages expand/collapse state, selection, keyboard navigation, and focus refs for a tree structure. Use it when the `<TreeView>` component's visual design doesn't fit your needs.
107
+
108
+ ### Props
109
+
110
+ | Prop | Type | Default | Description |
111
+ |---|---|---|---|
112
+ | `data` | `TreeNode[]` | — | **Required.** The tree data structure |
113
+ | `defaultExpanded` | `string[]` | `[]` | Node IDs to expand on initial render |
114
+ | `selectedNodeId` | `string` | — | Controlled selected node ID — when provided, the hook uses this value instead of internal state |
115
+ | `onNodeClick` | `(node: TreeNode) => void` | — | Called when any node is clicked |
116
+ | `onNodeSelect` | `(node: TreeNode) => void` | — | Called when a node is selected |
117
+
118
+ ### Return Value
119
+
120
+ | Property | Type | Description |
121
+ |---|---|---|
122
+ | `expanded` | `Set<string>` | Set of currently expanded node IDs |
123
+ | `effectiveSelectedId` | `string \| undefined` | The currently selected node ID (controlled or internal) |
124
+ | `nodeRefs` | `Map<string, HTMLButtonElement>` | Map of node ID → DOM button element refs |
125
+ | `getNodeRef` | `(nodeId: string) => (el: HTMLButtonElement \| null) => void` | Ref callback factory — attach to each node's button element |
126
+ | `toggleExpand` | `(nodeId: string) => void` | Toggle the expand/collapse state of a node |
127
+ | `handleSelect` | `(node: TreeNode) => void` | Handle node selection (updates internal state and calls callbacks) |
128
+ | `handleKeyDown` | `(e: KeyboardEvent, node: TreeNode) => void` | Full keyboard navigation handler — attach to each node's `onKeyDown` |
129
+ | `getVisibleNodes` | `() => TreeNode[]` | Returns the flat list of currently visible (non-collapsed) nodes in DOM order |
130
+
131
+ ### Keyboard Navigation
132
+
133
+ The `handleKeyDown` handler implements the WAI-ARIA tree pattern:
134
+
135
+ | Key | Action |
136
+ |---|---|
137
+ | `ArrowDown` | Move focus to the next visible node |
138
+ | `ArrowUp` | Move focus to the previous visible node |
139
+ | `ArrowRight` | Expand a collapsed branch node; or move to first child if already expanded |
140
+ | `ArrowLeft` | Collapse an expanded branch node; or move to parent if already collapsed |
141
+ | `Home` | Move focus to the first node in the tree |
142
+ | `End` | Move focus to the last visible node in the tree |
143
+ | `Space` | Select the focused node |
144
+
145
+ ### Custom Tree Example
146
+
147
+ ```tsx
148
+ import { useTreeView, TreeNode } from 'xertica-ui/ui';
149
+ import { ChevronRight, ChevronDown, Folder, File } from 'lucide-react';
150
+ import { cn } from '@/shared/utils';
151
+
152
+ function CustomTree({ data }: { data: TreeNode[] }) {
153
+ const {
154
+ expanded,
155
+ effectiveSelectedId,
156
+ getNodeRef,
157
+ toggleExpand,
158
+ handleSelect,
159
+ handleKeyDown,
160
+ } = useTreeView({
161
+ data,
162
+ defaultExpanded: [],
163
+ onNodeSelect: (node) => console.log('Selected:', node.id),
164
+ });
165
+
166
+ const renderNode = (node: TreeNode, level: number): React.ReactNode => {
167
+ const hasChildren = !!node.children?.length;
168
+ const isExpanded = expanded.has(node.id);
169
+ const isSelected = effectiveSelectedId === node.id;
170
+
171
+ return (
172
+ <div key={node.id}>
173
+ <button
174
+ ref={getNodeRef(node.id)}
175
+ role="treeitem"
176
+ aria-expanded={hasChildren ? isExpanded : undefined}
177
+ aria-selected={isSelected}
178
+ onClick={() => {
179
+ if (hasChildren) toggleExpand(node.id);
180
+ handleSelect(node);
181
+ }}
182
+ onKeyDown={(e) => handleKeyDown(e, node)}
183
+ style={{ paddingLeft: `${level * 16}px` }}
184
+ className={cn(
185
+ "flex w-full items-center gap-2 rounded px-2 py-1 text-sm",
186
+ isSelected
187
+ ? "bg-primary text-primary-foreground"
188
+ : "hover:bg-accent"
189
+ )}
190
+ >
191
+ {hasChildren ? (
192
+ isExpanded
193
+ ? <ChevronDown className="size-4 shrink-0" />
194
+ : <ChevronRight className="size-4 shrink-0" />
195
+ ) : (
196
+ <span className="size-4 shrink-0" />
197
+ )}
198
+ {node.icon}
199
+ <span>{node.label}</span>
200
+ </button>
201
+
202
+ {hasChildren && isExpanded && (
203
+ <div role="group">
204
+ {node.children!.map(child => renderNode(child, level + 1))}
205
+ </div>
206
+ )}
207
+ </div>
208
+ );
209
+ };
210
+
211
+ return (
212
+ <div role="tree" className="w-full">
213
+ {data.map(node => renderNode(node, 0))}
214
+ </div>
215
+ );
216
+ }
217
+ ```
218
+
219
+ ---
220
+
74
221
  ## AI Rules
75
222
 
76
- - Each `TreeNode` must have a unique `id` — the component uses it to track expand/collapse state.
223
+ - Each `TreeNode` must have a unique `id` — the component uses it to track expand/collapse state and selection.
77
224
  - Leaf nodes (no `children`) do not show expand arrows.
78
225
  - Use `lucide-react` icons with `className="size-4"` consistently across all tree nodes.
226
+ - When using `useTreeView`, attach `getNodeRef(node.id)` as the `ref` on each node's button — keyboard navigation (`handleKeyDown`) requires DOM refs to move focus.
227
+ - Attach `handleKeyDown` to `onKeyDown` on every node button — omitting it breaks keyboard accessibility.
228
+ - `getVisibleNodes()` returns only nodes that are currently visible (not inside a collapsed branch) — use it to compute `ArrowDown`/`ArrowUp` targets.
229
+ - For controlled selection, pass `selectedNodeId` — the hook will use it as `effectiveSelectedId` instead of internal state.
230
+ - `expanded` is a `Set<string>` — use `expanded.has(nodeId)` to check if a node is expanded.
231
+
232
+ ---
233
+
234
+ ## Related Components
235
+
236
+ - [`Sidebar`](./sidebar.md) — Uses TreeView-style navigation for nested menu items