xertica-ui 2.7.0 → 2.9.6

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 (480) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/README.md +20 -12
  3. package/bin/cli.ts +327 -87
  4. package/bin/generate-tokens.ts +25 -9
  5. package/bin/language-config.ts +58 -18
  6. package/components/assistant/xertica-assistant/xertica-assistant.tsx +1 -1
  7. package/components/blocks/auth/AuthPageShell.tsx +63 -18
  8. package/components/blocks/auth/SocialLoginButtons.tsx +3 -3
  9. package/components/blocks/index.ts +1 -0
  10. package/components/blocks/marketing/CTASection.tsx +73 -0
  11. package/components/blocks/marketing/ComplianceBadgeRow.tsx +49 -0
  12. package/components/blocks/marketing/EvidenceTimeline.tsx +91 -0
  13. package/components/blocks/marketing/FeatureRow.tsx +78 -0
  14. package/components/blocks/marketing/Hero.tsx +125 -0
  15. package/components/blocks/marketing/HowItWorksSteps.tsx +90 -0
  16. package/components/blocks/marketing/LogoCloud.tsx +47 -0
  17. package/components/blocks/marketing/MarketingFooter.tsx +109 -0
  18. package/components/blocks/marketing/MarketingNavbar.tsx +192 -0
  19. package/components/blocks/marketing/PillBadge.tsx +96 -0
  20. package/components/blocks/marketing/SectionHeading.tsx +82 -0
  21. package/components/blocks/marketing/ServiceCardGrid.tsx +238 -0
  22. package/components/blocks/marketing/StatBand.tsx +99 -0
  23. package/components/blocks/marketing/TopAccentCards.tsx +91 -0
  24. package/components/blocks/marketing/index.ts +41 -0
  25. package/components/brand/index.ts +1 -0
  26. package/components/brand/isotype/Isotype.tsx +64 -0
  27. package/components/brand/isotype/IsotypeDiagonal.tsx +51 -0
  28. package/components/brand/isotype/IsotypeFrames.tsx +82 -0
  29. package/components/brand/isotype/IsotypeMini.tsx +65 -0
  30. package/components/brand/isotype/IsotypeTwist.tsx +68 -0
  31. package/components/brand/isotype/frame-variants.ts +20 -0
  32. package/components/brand/isotype/index.ts +9 -0
  33. package/components/brand/isotype/isotype-diagonal.mdx +52 -0
  34. package/components/brand/isotype/isotype-diagonal.stories.tsx +44 -0
  35. package/components/brand/isotype/isotype-diagonal.test.tsx +180 -0
  36. package/components/brand/isotype/isotype-frames.mdx +50 -0
  37. package/components/brand/isotype/isotype-frames.stories.tsx +63 -0
  38. package/components/brand/isotype/isotype-frames.test.tsx +92 -0
  39. package/components/brand/isotype/isotype-mini.mdx +61 -0
  40. package/components/brand/isotype/isotype-mini.stories.tsx +75 -0
  41. package/components/brand/isotype/isotype-mini.test.tsx +45 -0
  42. package/components/brand/isotype/isotype-twist.test.tsx +71 -0
  43. package/components/brand/isotype/isotype.mdx +61 -0
  44. package/components/brand/isotype/isotype.stories.tsx +74 -0
  45. package/components/brand/isotype/isotype.test.tsx +41 -0
  46. package/components/brand/isotype/mini-patterns.ts +50 -0
  47. package/components/brand/isotype/patterns.ts +83 -0
  48. package/components/brand/isotype/twist-variants.ts +20 -0
  49. package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +3 -6
  50. package/components/pages/index.ts +1 -0
  51. package/components/pages/landing-page/LandingPage.tsx +360 -0
  52. package/components/pages/landing-page/index.ts +1 -0
  53. package/components/pages/login-page/LoginPage.tsx +3 -6
  54. package/components/pages/reset-password-page/ResetPasswordPage.tsx +1 -4
  55. package/components/pages/verify-email-page/VerifyEmailPage.tsx +2 -5
  56. package/components/ui/button/button.test.tsx +3 -3
  57. package/components/ui/button/button.tsx +5 -4
  58. package/components/ui/card/card.test.tsx +12 -0
  59. package/components/ui/card/card.tsx +16 -2
  60. package/components/ui/input/input.tsx +1 -1
  61. package/components/ui/input-otp/input-otp.tsx +1 -1
  62. package/components/ui/search/search.tsx +1 -1
  63. package/components/ui/select/select.tsx +2 -2
  64. package/components/ui/switch/switch.tsx +1 -1
  65. package/components/ui/textarea/textarea.tsx +1 -1
  66. package/contexts/BrandColorsContext.tsx +59 -7
  67. package/contexts/theme-data.ts +127 -3
  68. package/dist/AssistantChart-BFBJXVcm.js +3383 -0
  69. package/dist/AssistantChart-BTnE94FR.cjs +3551 -0
  70. package/dist/AssistantChart-BU48lxL2.js +3383 -0
  71. package/dist/AssistantChart-BvccsQMx.cjs +3551 -0
  72. package/dist/AssistantChart-CkskcBVD.js +3383 -0
  73. package/dist/AssistantChart-CoN6ga6Z.js +3383 -0
  74. package/dist/AssistantChart-CrPkO9ip.js +3383 -0
  75. package/dist/AssistantChart-DIRYJ7WY.js +3383 -0
  76. package/dist/AssistantChart-DKz2O1R8.cjs +3551 -0
  77. package/dist/AssistantChart-DOnY1ZlD.cjs +3551 -0
  78. package/dist/AssistantChart-DYL6UEvo.cjs +3551 -0
  79. package/dist/AssistantChart-DjM3qnp5.cjs +3551 -0
  80. package/dist/AssistantChart-hxPyE1S9.cjs +3551 -0
  81. package/dist/AssistantChart-keo-ogKi.js +3383 -0
  82. package/dist/AudioPlayer-AoU5MTiM.cjs +1282 -0
  83. package/dist/AudioPlayer-Bx1vrblm.js +1278 -0
  84. package/dist/AudioPlayer-CpihsbaD.js +1278 -0
  85. package/dist/AudioPlayer-CvGajzMC.cjs +1282 -0
  86. package/dist/AudioPlayer-CvHpFqDG.cjs +1282 -0
  87. package/dist/AudioPlayer-D0-I6J3J.cjs +1282 -0
  88. package/dist/AudioPlayer-D4S7GQou.js +1278 -0
  89. package/dist/AudioPlayer-DIWX_Yg7.cjs +1282 -0
  90. package/dist/AudioPlayer-DrWJnS7c.js +1278 -0
  91. package/dist/AudioPlayer-_P-Z7pAK.js +1278 -0
  92. package/dist/BrandColorsContext-B25Bpr3b.cjs +819 -0
  93. package/dist/BrandColorsContext-BCieATdW.js +812 -0
  94. package/dist/BrandColorsContext-BNKLUVcU.js +829 -0
  95. package/dist/BrandColorsContext-DNZGHItQ.cjs +836 -0
  96. package/dist/BrandColorsContext-DP0DXAXS.js +824 -0
  97. package/dist/BrandColorsContext-DjpC9wR_.cjs +798 -0
  98. package/dist/BrandColorsContext-MpXFhte7.cjs +831 -0
  99. package/dist/BrandColorsContext-Ug_TZ8yn.cjs +846 -0
  100. package/dist/BrandColorsContext-V3tOc-Zw.js +791 -0
  101. package/dist/BrandColorsContext-z0O2LlZz.js +839 -0
  102. package/dist/CodeBlock-BkaZf-R8.cjs +223 -0
  103. package/dist/CodeBlock-CK4rO6lM.js +221 -0
  104. package/dist/CodeBlock-CKXamfVd.cjs +223 -0
  105. package/dist/CodeBlock-CKu8LgbP.cjs +223 -0
  106. package/dist/CodeBlock-CVmE7isS.cjs +223 -0
  107. package/dist/CodeBlock-D7i5-cMv.js +221 -0
  108. package/dist/CodeBlock-Dg56j2ut.cjs +223 -0
  109. package/dist/CodeBlock-DiLS5LLI.js +221 -0
  110. package/dist/CodeBlock-Dt6nUQoo.js +221 -0
  111. package/dist/CodeBlock-zdylBGdZ.js +221 -0
  112. package/dist/CustomTooltipContent-BAR5qCQg.js +33 -0
  113. package/dist/CustomTooltipContent-Bxynuq7T.js +33 -0
  114. package/dist/CustomTooltipContent-BzjOSA0P.cjs +54 -0
  115. package/dist/CustomTooltipContent-C-ZeCNsf.js +33 -0
  116. package/dist/CustomTooltipContent-CBLHBxX8.cjs +54 -0
  117. package/dist/CustomTooltipContent-CON_QrXm.cjs +54 -0
  118. package/dist/CustomTooltipContent-CjWm3jjV.js +33 -0
  119. package/dist/CustomTooltipContent-DTV9MN9E.cjs +54 -0
  120. package/dist/CustomTooltipContent-UR_n2QfW.js +33 -0
  121. package/dist/CustomTooltipContent-v1SXjoFn.cjs +54 -0
  122. package/dist/EvidenceTimeline-DrRk4yqb.cjs +560 -0
  123. package/dist/EvidenceTimeline-l4MaV4C7.js +546 -0
  124. package/dist/FeatureCard-4n_8a63v.cjs +497 -0
  125. package/dist/FeatureCard-BLiAWT3w.js +485 -0
  126. package/dist/FeatureCard-BXRW97Ef.cjs +497 -0
  127. package/dist/FeatureCard-CDgLlWE2.js +485 -0
  128. package/dist/FeatureCard-CIbBHqeY.cjs +497 -0
  129. package/dist/FeatureCard-CgQ8lq-I.cjs +497 -0
  130. package/dist/FeatureCard-Cp8cVC6T.cjs +497 -0
  131. package/dist/FeatureCard-D0MwrTRP.js +485 -0
  132. package/dist/FeatureCard-DtoKPSfW.cjs +497 -0
  133. package/dist/FeatureCard-P4iEpBmB.js +485 -0
  134. package/dist/FeatureCard-e3f8bnF0.js +485 -0
  135. package/dist/FeatureCard-uE5i0in_.js +485 -0
  136. package/dist/ImageWithFallback-BOh1FM3I.js +98 -0
  137. package/dist/ImageWithFallback-BQO7952C.js +98 -0
  138. package/dist/ImageWithFallback-BkMXHCvV.cjs +122 -0
  139. package/dist/ImageWithFallback-C1ww9Hg3.cjs +122 -0
  140. package/dist/ImageWithFallback-C72nwszA.cjs +122 -0
  141. package/dist/ImageWithFallback-CBrkAEo3.cjs +122 -0
  142. package/dist/ImageWithFallback-CCUMDuEC.cjs +122 -0
  143. package/dist/ImageWithFallback-CGk5zPH-.js +98 -0
  144. package/dist/ImageWithFallback-CfnoFFSP.js +98 -0
  145. package/dist/ImageWithFallback-DQD5TTlY.js +98 -0
  146. package/dist/Isotype--fRZWwS6.js +85 -0
  147. package/dist/Isotype-0dpLqetB.js +85 -0
  148. package/dist/Isotype-B8XLEXSB.cjs +92 -0
  149. package/dist/Isotype-ChKwN7e-.cjs +91 -0
  150. package/dist/IsotypeDiagonal-CuPYPP4f.js +84 -0
  151. package/dist/IsotypeDiagonal-eNcOXRAc.cjs +91 -0
  152. package/dist/IsotypeDiagonal-oiwpXZhE.js +104 -0
  153. package/dist/IsotypeDiagonal-xMFoFXkb.cjs +109 -0
  154. package/dist/IsotypeFrames-BcWtyAWp.cjs +83 -0
  155. package/dist/IsotypeFrames-BnvSJKiH.cjs +73 -0
  156. package/dist/IsotypeFrames-iDRTRuIu.js +79 -0
  157. package/dist/IsotypeFrames-qoXOvOJt.js +69 -0
  158. package/dist/IsotypeMini-CQtWVo3h.js +126 -0
  159. package/dist/IsotypeMini-Cu_sW5yN.cjs +134 -0
  160. package/dist/IsotypeTwist-BTdNL4iV.js +106 -0
  161. package/dist/IsotypeTwist-DvsUgZs_.cjs +115 -0
  162. package/dist/LanguageContext-B1aOXO-K.js +1987 -0
  163. package/dist/LanguageContext-BP0k7AzI.js +1993 -0
  164. package/dist/LanguageContext-CChcIHIG.cjs +1998 -0
  165. package/dist/LanguageContext-ubC7TSs_.cjs +1992 -0
  166. package/dist/LanguageSelector-1XhM7R1i.cjs +48 -0
  167. package/dist/LanguageSelector-B3ZVNc55.js +46 -0
  168. package/dist/LanguageSelector-BLFPXGo8.cjs +48 -0
  169. package/dist/LanguageSelector-CYRzWkRZ.cjs +48 -0
  170. package/dist/LanguageSelector-Cj6zl0CM.js +46 -0
  171. package/dist/LanguageSelector-CyHjZgC4.cjs +48 -0
  172. package/dist/LanguageSelector-DE8lIySO.js +46 -0
  173. package/dist/LanguageSelector-DK1zD4VH.cjs +48 -0
  174. package/dist/LanguageSelector-DUr1hjBW.js +46 -0
  175. package/dist/LanguageSelector-DjbWIKWC.js +46 -0
  176. package/dist/LanguageSelector-DseCAa0p.cjs +48 -0
  177. package/dist/LanguageSelector-Du09anfM.js +46 -0
  178. package/dist/LanguageSelector-PZHlFfEs.cjs +48 -0
  179. package/dist/LanguageSelector-SB-NJSmx.js +46 -0
  180. package/dist/LogoCloud-C_uMKVNg.cjs +513 -0
  181. package/dist/LogoCloud-DJsMPNPh.js +500 -0
  182. package/dist/MarketingFooter-B_ycEdTJ.cjs +727 -0
  183. package/dist/MarketingFooter-Bhx-2Vlr.cjs +727 -0
  184. package/dist/MarketingFooter-Br1MGK9e.js +699 -0
  185. package/dist/MarketingFooter-BwE1vmeX.cjs +700 -0
  186. package/dist/MarketingFooter-CsZ1_xL9.js +709 -0
  187. package/dist/MarketingFooter-DCwf78Q4.cjs +716 -0
  188. package/dist/MarketingFooter-KH2r-OOL.js +709 -0
  189. package/dist/MarketingFooter-nB7G7gQ5.js +682 -0
  190. package/dist/PasswordStrengthMeter-B3S6i_k4.cjs +179 -0
  191. package/dist/PasswordStrengthMeter-B8ky1nJI.js +173 -0
  192. package/dist/PasswordStrengthMeter-C5VEopH-.cjs +179 -0
  193. package/dist/PasswordStrengthMeter-CIm7_jNT.js +173 -0
  194. package/dist/PasswordStrengthMeter-DKSAbQzu.js +173 -0
  195. package/dist/PasswordStrengthMeter-DxLu54p-.cjs +179 -0
  196. package/dist/PasswordStrengthMeter-k-e9Pole.cjs +179 -0
  197. package/dist/PasswordStrengthMeter-pAi2viq5.js +173 -0
  198. package/dist/SectionHeading-DEeOKcAd.cjs +857 -0
  199. package/dist/SectionHeading-DMNObcwm.js +838 -0
  200. package/dist/ThemeToggle--CGJjQJv.cjs +219 -0
  201. package/dist/ThemeToggle-4pQbVkpK.js +215 -0
  202. package/dist/ThemeToggle-B6rIVLvC.cjs +219 -0
  203. package/dist/ThemeToggle-BUOTps5l.cjs +219 -0
  204. package/dist/ThemeToggle-Bn_7Pmfe.js +215 -0
  205. package/dist/ThemeToggle-CO5mPl6e.js +215 -0
  206. package/dist/ThemeToggle-CoL8Ady7.js +215 -0
  207. package/dist/ThemeToggle-D2Wzm5bn.cjs +219 -0
  208. package/dist/ThemeToggle-DbZQ0JSV.cjs +219 -0
  209. package/dist/ThemeToggle-vLXEq2TS.js +215 -0
  210. package/dist/VerifyEmailPage-90lK6pP4.js +3258 -0
  211. package/dist/VerifyEmailPage-BJX1Rter.cjs +3320 -0
  212. package/dist/VerifyEmailPage-BSWvOgry.js +3310 -0
  213. package/dist/VerifyEmailPage-BTjI2c9n.js +2954 -0
  214. package/dist/VerifyEmailPage-CDqIkhx-.js +3224 -0
  215. package/dist/VerifyEmailPage-CJGfDSOx.js +2954 -0
  216. package/dist/VerifyEmailPage-Crxje3ZB.js +3323 -0
  217. package/dist/VerifyEmailPage-D2ShbuEN.cjs +3333 -0
  218. package/dist/VerifyEmailPage-DEBZXQ7c.cjs +3310 -0
  219. package/dist/VerifyEmailPage-DGaX-jZv.cjs +3268 -0
  220. package/dist/VerifyEmailPage-DOlZUNc0.cjs +2963 -0
  221. package/dist/VerifyEmailPage-DQPRl_RJ.js +2954 -0
  222. package/dist/VerifyEmailPage-DrdqMbLC.cjs +2963 -0
  223. package/dist/VerifyEmailPage-ZtOPkgOA.cjs +3234 -0
  224. package/dist/VerifyEmailPage-hyDfeCRa.cjs +2963 -0
  225. package/dist/VerifyEmailPage-kKSXl8vu.cjs +2963 -0
  226. package/dist/VerifyEmailPage-s927GSiR.js +3300 -0
  227. package/dist/VerifyEmailPage-w4N-bDhU.js +2954 -0
  228. package/dist/XerticaOrbe-B9tegV1n.js +1925 -0
  229. package/dist/XerticaOrbe-BHex09xs.js +1925 -0
  230. package/dist/XerticaOrbe-BKW3LJEz.js +1925 -0
  231. package/dist/XerticaOrbe-BQ_NjwPS.cjs +1927 -0
  232. package/dist/XerticaOrbe-BdUX171Q.cjs +1927 -0
  233. package/dist/XerticaOrbe-BdlKXRHU.cjs +1927 -0
  234. package/dist/XerticaOrbe-Br2i99U_.cjs +1927 -0
  235. package/dist/XerticaOrbe-CByPAFE5.js +1925 -0
  236. package/dist/XerticaOrbe-Ccu9eFMu.js +1925 -0
  237. package/dist/XerticaOrbe-kjFmuyx-.cjs +1927 -0
  238. package/dist/XerticaProvider-BVid1oqn.cjs +46 -0
  239. package/dist/XerticaProvider-Bi5lKC9N.js +44 -0
  240. package/dist/XerticaProvider-BrPMVhiv.js +44 -0
  241. package/dist/XerticaProvider-Bz_YfNY4.js +44 -0
  242. package/dist/XerticaProvider-CnX5kt5W.cjs +46 -0
  243. package/dist/XerticaProvider-CtvYfRbZ.cjs +46 -0
  244. package/dist/XerticaProvider-DEKNJTlN.js +44 -0
  245. package/dist/XerticaProvider-DMiyExQS.js +44 -0
  246. package/dist/XerticaProvider-DP2lzKip.cjs +46 -0
  247. package/dist/XerticaProvider-De79hhgp.js +44 -0
  248. package/dist/XerticaProvider-Dkk1Vbsy.js +44 -0
  249. package/dist/XerticaProvider-EdzH9Nrw.cjs +46 -0
  250. package/dist/XerticaProvider-X_wavDYA.cjs +46 -0
  251. package/dist/XerticaProvider-b3n_oL8w.cjs +46 -0
  252. package/dist/alert-dialog--qdlmB5i.cjs +872 -0
  253. package/dist/alert-dialog-9XYAn5z5.js +819 -0
  254. package/dist/alert-dialog-B281hud0.cjs +872 -0
  255. package/dist/alert-dialog-BVWbrcrw.cjs +872 -0
  256. package/dist/alert-dialog-B_Ko1xpu.js +819 -0
  257. package/dist/alert-dialog-C48TOdYU.cjs +872 -0
  258. package/dist/alert-dialog-CEPpnpXt.js +819 -0
  259. package/dist/alert-dialog-CIxE8T-J.cjs +872 -0
  260. package/dist/alert-dialog-DW-_iPuf.js +819 -0
  261. package/dist/alert-dialog-NjflitDa.js +819 -0
  262. package/dist/assistant.cjs.js +2 -2
  263. package/dist/assistant.es.js +2 -2
  264. package/dist/avatar-BJwIMbZ_.js +54 -0
  265. package/dist/avatar-C4Zh5fAJ.cjs +77 -0
  266. package/dist/avatar-CTEUKZUT.js +54 -0
  267. package/dist/avatar-CtEKgg7s.cjs +77 -0
  268. package/dist/avatar-D03MNQxs.js +54 -0
  269. package/dist/avatar-D1bZhlhL.cjs +77 -0
  270. package/dist/avatar-DKIxHeKG.cjs +77 -0
  271. package/dist/avatar-Df7KgSvs.js +54 -0
  272. package/dist/avatar-Gy0_Xu9i.cjs +77 -0
  273. package/dist/avatar-v16eZC8p.js +54 -0
  274. package/dist/blocks.cjs.js +33 -18
  275. package/dist/blocks.es.js +2 -2
  276. package/dist/brand.cjs.js +110 -4
  277. package/dist/brand.es.js +98 -4
  278. package/dist/breadcrumb-B1mUiaWB.cjs +98 -0
  279. package/dist/breadcrumb-BGO5PZPG.js +90 -0
  280. package/dist/breadcrumb-BIRgmem-.js +90 -0
  281. package/dist/breadcrumb-BSng-oUf.cjs +98 -0
  282. package/dist/breadcrumb-BvGAY4ne.cjs +98 -0
  283. package/dist/breadcrumb-CES7furU.js +90 -0
  284. package/dist/breadcrumb-CP275kbF.cjs +98 -0
  285. package/dist/breadcrumb-CU-punra.js +90 -0
  286. package/dist/breadcrumb-D7hr1EvJ.js +90 -0
  287. package/dist/breadcrumb-DjV9wfX1.cjs +98 -0
  288. package/dist/button-B05czY_8.js +62 -0
  289. package/dist/button-B3SE1liJ.js +62 -0
  290. package/dist/button-BMDlWZR8.cjs +85 -0
  291. package/dist/button-BYtQygX5.cjs +85 -0
  292. package/dist/button-BnAW-a_w.js +62 -0
  293. package/dist/button-CUPDQews.js +62 -0
  294. package/dist/button-DFa-rtPy.js +62 -0
  295. package/dist/button-DV1G6XrI.cjs +85 -0
  296. package/dist/button-DVhloDtr.cjs +85 -0
  297. package/dist/button-Kd9Fj53S.cjs +85 -0
  298. package/dist/cli.js +367 -65
  299. package/dist/components/blocks/auth/AuthPageShell.d.ts +21 -5
  300. package/dist/components/blocks/index.d.ts +1 -0
  301. package/dist/components/blocks/marketing/CTASection.d.ts +28 -0
  302. package/dist/components/blocks/marketing/ComplianceBadgeRow.d.ts +23 -0
  303. package/dist/components/blocks/marketing/EvidenceTimeline.d.ts +26 -0
  304. package/dist/components/blocks/marketing/FeatureRow.d.ts +25 -0
  305. package/dist/components/blocks/marketing/Hero.d.ts +35 -0
  306. package/dist/components/blocks/marketing/HowItWorksSteps.d.ts +29 -0
  307. package/dist/components/blocks/marketing/LogoCloud.d.ts +22 -0
  308. package/dist/components/blocks/marketing/MarketingFooter.d.ts +42 -0
  309. package/dist/components/blocks/marketing/MarketingNavbar.d.ts +47 -0
  310. package/dist/components/blocks/marketing/PillBadge.d.ts +21 -0
  311. package/dist/components/blocks/marketing/SectionHeading.d.ts +23 -0
  312. package/dist/components/blocks/marketing/ServiceCardGrid.d.ts +65 -0
  313. package/dist/components/blocks/marketing/StatBand.d.ts +25 -0
  314. package/dist/components/blocks/marketing/TopAccentCards.d.ts +29 -0
  315. package/dist/components/blocks/marketing/index.d.ts +28 -0
  316. package/dist/components/brand/index.d.ts +1 -0
  317. package/dist/components/brand/isotype/Isotype.d.ts +27 -0
  318. package/dist/components/brand/isotype/IsotypeDiagonal.d.ts +19 -0
  319. package/dist/components/brand/isotype/IsotypeFrames.d.ts +21 -0
  320. package/dist/components/brand/isotype/IsotypeMini.d.ts +26 -0
  321. package/dist/components/brand/isotype/IsotypeTwist.d.ts +22 -0
  322. package/dist/components/brand/isotype/frame-variants.d.ts +11 -0
  323. package/dist/components/brand/isotype/index.d.ts +9 -0
  324. package/dist/components/brand/isotype/mini-patterns.d.ts +25 -0
  325. package/dist/components/brand/isotype/patterns.d.ts +42 -0
  326. package/dist/components/brand/isotype/twist-variants.d.ts +11 -0
  327. package/dist/components/pages/forgot-password-page/ForgotPasswordPage.d.ts +2 -2
  328. package/dist/components/pages/index.d.ts +1 -0
  329. package/dist/components/pages/landing-page/LandingPage.d.ts +18 -0
  330. package/dist/components/pages/landing-page/index.d.ts +1 -0
  331. package/dist/components/pages/login-page/LoginPage.d.ts +2 -2
  332. package/dist/components/pages/verify-email-page/VerifyEmailPage.d.ts +1 -1
  333. package/dist/components/ui/card/card.d.ts +13 -1
  334. package/dist/contexts/theme-data.d.ts +21 -1
  335. package/dist/dropdown-menu-B9wTZ0uX.cjs +225 -0
  336. package/dist/dropdown-menu-BeBtZOrs.cjs +225 -0
  337. package/dist/dropdown-menu-ChQa9zW3.cjs +225 -0
  338. package/dist/dropdown-menu-D7mRDGis.js +190 -0
  339. package/dist/dropdown-menu-D8ZmqHB7.js +190 -0
  340. package/dist/dropdown-menu-DRvnsQAt.cjs +225 -0
  341. package/dist/dropdown-menu-DUk81i5Y.js +190 -0
  342. package/dist/dropdown-menu-NlUHhVmK.js +190 -0
  343. package/dist/dropdown-menu-_AWBeOts.cjs +225 -0
  344. package/dist/dropdown-menu-qGzLO_HO.js +190 -0
  345. package/dist/hooks.cjs.js +2 -2
  346. package/dist/hooks.es.js +2 -2
  347. package/dist/index.cjs.js +57 -41
  348. package/dist/index.es.js +25 -25
  349. package/dist/input-B53E6K8G.js +65 -0
  350. package/dist/input-B7Q7vcoG.cjs +91 -0
  351. package/dist/input-BysqLMK1.js +65 -0
  352. package/dist/input-CStdFsaH.cjs +91 -0
  353. package/dist/input-CXYth6nW.cjs +91 -0
  354. package/dist/input-CX_fWE2D.cjs +91 -0
  355. package/dist/input-CitUVnEn.js +65 -0
  356. package/dist/input-Csp_Metb.cjs +91 -0
  357. package/dist/input-DVRwGVLx.js +65 -0
  358. package/dist/input-Dqyj7Hdw.cjs +91 -0
  359. package/dist/input-dOgrFQ-3.js +65 -0
  360. package/dist/input-wkBYTp-B.js +65 -0
  361. package/dist/layout.cjs.js +1 -1
  362. package/dist/layout.es.js +1 -1
  363. package/dist/media.cjs.js +1 -1
  364. package/dist/media.es.js +1 -1
  365. package/dist/pages.cjs.js +2 -1
  366. package/dist/pages.es.js +1 -1
  367. package/dist/rich-text-editor-7K7UjLJN.cjs +2968 -0
  368. package/dist/rich-text-editor-B3jLP2bm.cjs +2968 -0
  369. package/dist/rich-text-editor-BHiRUzWZ.js +2894 -0
  370. package/dist/rich-text-editor-BWMRUMJ2.js +2894 -0
  371. package/dist/rich-text-editor-BntMVQsB.js +2894 -0
  372. package/dist/rich-text-editor-BoE6Ks5x.cjs +2968 -0
  373. package/dist/rich-text-editor-BzuEwR_X.js +2894 -0
  374. package/dist/rich-text-editor-CcopGbQ-.js +2894 -0
  375. package/dist/rich-text-editor-CmxSRJIi.cjs +2968 -0
  376. package/dist/rich-text-editor-Diz_onyB.js +2894 -0
  377. package/dist/rich-text-editor-DyYAu28v.cjs +2968 -0
  378. package/dist/rich-text-editor-JS_eMQCC.cjs +2968 -0
  379. package/dist/rich-text-editor-RWvK4hd3.cjs +2968 -0
  380. package/dist/rich-text-editor-gauEkzPM.js +2894 -0
  381. package/dist/select-B6PygS38.cjs +161 -0
  382. package/dist/select-BD763J5Y.cjs +161 -0
  383. package/dist/select-BNfFJwYp.js +130 -0
  384. package/dist/select-CN8IDjGB.js +130 -0
  385. package/dist/select-CwRzQHA7.cjs +161 -0
  386. package/dist/select-CwgD3nMD.js +130 -0
  387. package/dist/select-DEHUm_AC.cjs +161 -0
  388. package/dist/select-DJDgpVm3.cjs +161 -0
  389. package/dist/select-DSLWQLmo.cjs +161 -0
  390. package/dist/select-QJDKZITN.js +130 -0
  391. package/dist/select-YFx0wCYT.js +130 -0
  392. package/dist/select-q7aDfuPn.js +130 -0
  393. package/dist/sidebar-BF7JEL7U.js +1151 -0
  394. package/dist/sidebar-Bjr2doX5.cjs +1154 -0
  395. package/dist/sidebar-Bkk1YAsD.cjs +1154 -0
  396. package/dist/sidebar-CMrNCmhb.cjs +1154 -0
  397. package/dist/sidebar-CO9x8AVn.cjs +1154 -0
  398. package/dist/sidebar-Cn_KB4c6.js +1151 -0
  399. package/dist/sidebar-CuzYeOSz.cjs +1154 -0
  400. package/dist/sidebar-CwlW3LXE.js +1151 -0
  401. package/dist/sidebar-DNkf-Ug6.js +1151 -0
  402. package/dist/sidebar-DaS3fplw.cjs +1154 -0
  403. package/dist/sidebar-Db_C30ph.cjs +1154 -0
  404. package/dist/sidebar-FDCY42oP.js +1151 -0
  405. package/dist/sidebar-miPHsRz4.js +1151 -0
  406. package/dist/sidebar-pZF8mLLu.js +1151 -0
  407. package/dist/skeleton-BX2XTjMO.cjs +87 -0
  408. package/dist/skeleton-BoLK0iV7.js +78 -0
  409. package/dist/skeleton-BtBwJ39W.js +79 -0
  410. package/dist/skeleton-Bysq8yeB.js +79 -0
  411. package/dist/skeleton-C7nspYnC.cjs +87 -0
  412. package/dist/skeleton-CJyg0eJ1.cjs +88 -0
  413. package/dist/skeleton-D8WaauK0.cjs +88 -0
  414. package/dist/skeleton-DBYtjaZW.cjs +88 -0
  415. package/dist/skeleton-DL4V5Vub.cjs +87 -0
  416. package/dist/skeleton-DSMhdqp1.js +78 -0
  417. package/dist/skeleton-DY_lSFWf.js +79 -0
  418. package/dist/skeleton-Df65Ox10.js +79 -0
  419. package/dist/skeleton-DhJswvTW.cjs +88 -0
  420. package/dist/skeleton-DicUfozA.js +78 -0
  421. package/dist/slider-77T_Eqw4.js +56 -0
  422. package/dist/slider-B6puMLXS.cjs +78 -0
  423. package/dist/slider-B785N7lZ.js +56 -0
  424. package/dist/slider-BKV_vvsh.cjs +78 -0
  425. package/dist/slider-B_lUjFNa.cjs +78 -0
  426. package/dist/slider-C6yssKyZ.cjs +78 -0
  427. package/dist/slider-CKZO9gVh.cjs +78 -0
  428. package/dist/slider-Cn-ImSze.js +56 -0
  429. package/dist/slider-CtBpIaU4.js +56 -0
  430. package/dist/slider-KgWmSJbx.js +56 -0
  431. package/dist/tooltip-BPttuPxU.js +48 -0
  432. package/dist/tooltip-BiJVGob3.cjs +72 -0
  433. package/dist/tooltip-CIKRzQqE.cjs +72 -0
  434. package/dist/tooltip-CoDByjE_.cjs +72 -0
  435. package/dist/tooltip-D2OPn-1v.cjs +72 -0
  436. package/dist/tooltip-DlCHQuh1.js +48 -0
  437. package/dist/tooltip-_MAwsiOL.js +48 -0
  438. package/dist/tooltip-fQ2Va0G8.cjs +72 -0
  439. package/dist/tooltip-oAw00FX2.js +48 -0
  440. package/dist/tooltip-u147L0wD.js +48 -0
  441. package/dist/ui.cjs.js +13 -13
  442. package/dist/ui.es.js +13 -13
  443. package/dist/xertica-assistant-B1xAl2Vn.js +2173 -0
  444. package/dist/xertica-assistant-BBUMaUXw.js +2173 -0
  445. package/dist/xertica-assistant-C2A0R94j.js +2173 -0
  446. package/dist/xertica-assistant-CSUprvTR.js +2173 -0
  447. package/dist/xertica-assistant-CWuBwfzt.cjs +2180 -0
  448. package/dist/xertica-assistant-Caubm0HR.js +2173 -0
  449. package/dist/xertica-assistant-D2hlwiEP.js +2173 -0
  450. package/dist/xertica-assistant-DEexPM2u.cjs +2180 -0
  451. package/dist/xertica-assistant-DN2J_sQQ.cjs +2180 -0
  452. package/dist/xertica-assistant-DdYS6WXT.cjs +2180 -0
  453. package/dist/xertica-assistant-Dh1dmEx3.cjs +2180 -0
  454. package/dist/xertica-assistant-GGcyHEZG.cjs +2180 -0
  455. package/dist/xertica-assistant-USefPe2L.js +2173 -0
  456. package/dist/xertica-assistant-cwSHFwfv.cjs +2180 -0
  457. package/dist/xertica-ui.css +1 -1
  458. package/llms-compact.txt +1 -1
  459. package/llms.txt +1 -1
  460. package/package.json +3 -2
  461. package/styles/xertica/base.css +46 -0
  462. package/styles/xertica/tokens.css +10 -0
  463. package/templates/package.json +1 -1
  464. package/templates/src/app/App.tsx +5 -1
  465. package/templates/src/app/components/AuthGuard.tsx +6 -0
  466. package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +1 -4
  467. package/templates/src/features/auth/ui/LoginContent.tsx +1 -4
  468. package/templates/src/features/auth/ui/ResetPasswordContent.tsx +1 -4
  469. package/templates/src/features/auth/ui/VerifyEmailContent.tsx +1 -4
  470. package/templates/src/features/home/ui/HomeContent.tsx +12 -13
  471. package/templates/src/features/template/ui/TemplateContent.tsx +569 -26
  472. package/templates/src/locales/en/pages/landing.json +175 -0
  473. package/templates/src/locales/en/pages/templates.json +112 -4
  474. package/templates/src/locales/es/pages/landing.json +175 -0
  475. package/templates/src/locales/es/pages/templates.json +112 -4
  476. package/templates/src/locales/pt-BR/pages/landing.json +175 -0
  477. package/templates/src/locales/pt-BR/pages/templates.json +112 -4
  478. package/templates/src/pages/LandingPage.tsx +3 -0
  479. package/templates/src/styles/xertica/tokens.css +10 -0
  480. package/templates/vite.config.ts +25 -0
@@ -0,0 +1,61 @@
1
+ import { Meta, Title, Subtitle, Description } from '@storybook/addon-docs/blocks';
2
+
3
+ <Meta title="Brand/Isotype/Mini" />
4
+
5
+ <Title>Isotype Mini</Title>
6
+ <Subtitle>Third mark in the Xertica isotipos series — a compact 3x3 grid.</Subtitle>
7
+
8
+ ---
9
+
10
+ ## Overview
11
+
12
+ `IsotypeMini` renders a 3x3 grid of fixed brand colors that reads as a single composed image — a more compact sibling of the 4x4 `Isotype`, for spots where a full-size mark doesn't fit (e.g. beside a page title). It's built the same way as `Isotype`: one generic renderer over a pattern registry, so new 3x3 isotypes join the series as pure data, not new components.
13
+
14
+ ```tsx
15
+ import { IsotypeMini } from 'xertica-ui/brand';
16
+
17
+ <IsotypeMini className="w-14" />
18
+ ```
19
+
20
+ ---
21
+
22
+ ## Props
23
+
24
+ | Prop | Type | Default | Description |
25
+ |---|---|---|---|
26
+ | `pattern` | `IsotypeMiniPatternId` | `'core'` | Which registered pattern to render. |
27
+ | `variantSeed` | `number` | — | Deterministically blanks one cell for decorative variation. Omit for the pure, fully-filled base pattern. |
28
+ | `className` | `string` | — | Additional classes on the root grid container — use for sizing (`w-14`, `w-64`, etc). `aspect-square` is built in. |
29
+ | `aria-label` | `string` | — | Omit for decorative use (root gets `aria-hidden`); set it to render as `role="img"` instead. |
30
+
31
+ ---
32
+
33
+ ## Patterns
34
+
35
+ Today the registry (`ISOTYPE_MINI_PATTERNS` in `mini-patterns.ts`) has one entry, `'core'`, reusing the exact same brand colors as the main `Isotype` grid (`ISOTYPE_COLORS` in `patterns.ts`). Add new 3x3 isotypes to the series by adding a new entry there and widening `IsotypeMiniPatternId` — `IsotypeMini.tsx` itself never needs to change.
36
+
37
+ ## Variants
38
+
39
+ Passing `variantSeed` calls the pure, deterministic `getIsotypeMiniVariant(pattern, seed)` internally — the same `(pattern, seed)` pair always blanks the same cell. Unlike `Isotype`, the base `'core'` pattern has no inherent blank cell, so `variantSeed` always removes exactly one cell. Use it for decorative, repeated placements (e.g. a gallery of instances); canonical brand-mark spots should use the plain base pattern with no seed.
40
+
41
+ ```tsx
42
+ // Canonical brand-mark placement — pure base pattern, all 9 cells filled
43
+ <IsotypeMini />
44
+
45
+ // Decorative variation — exactly one cell missing
46
+ <IsotypeMini variantSeed={3} />
47
+
48
+ // Precomputing a batch of variants (e.g. a thumbnail sheet)
49
+ import { getIsotypeMiniVariant } from 'xertica-ui/brand';
50
+ const variants = Array.from({ length: 8 }, (_, seed) => getIsotypeMiniVariant('core', seed));
51
+ ```
52
+
53
+ ---
54
+
55
+ ## AI Best Practices
56
+
57
+ > [!IMPORTANT]
58
+ > - **Colors are fixed brand hex values, not theme tokens** — reuses `ISOTYPE_COLORS` from `patterns.ts` verbatim; never replace with CSS custom properties.
59
+ > - **No gaps or per-cell borders** — cells must render flush against each other so the grid reads as a single composed image.
60
+ > - **New 3x3 isotypes are data, not components** — add patterns via `ISOTYPE_MINI_PATTERNS`/`IsotypeMiniPatternId` in `mini-patterns.ts`.
61
+ > - **`variantSeed` is for decorative use only** — canonical placements (page headers, nav) should render the base pattern.
@@ -0,0 +1,75 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { IsotypeMini } from './IsotypeMini';
3
+ import { ISOTYPE_MINI_PATTERN_IDS } from './mini-patterns';
4
+ import React from 'react';
5
+
6
+ const meta: Meta<typeof IsotypeMini> = {
7
+ title: 'Brand/Isotype/Mini',
8
+ component: IsotypeMini,
9
+ parameters: {
10
+ layout: 'centered',
11
+ },
12
+ argTypes: {
13
+ pattern: {
14
+ control: 'select',
15
+ options: ISOTYPE_MINI_PATTERN_IDS,
16
+ },
17
+ variantSeed: {
18
+ control: 'number',
19
+ },
20
+ },
21
+ };
22
+
23
+ export default meta;
24
+ type Story = StoryObj<typeof IsotypeMini>;
25
+
26
+ export const Base: Story = {
27
+ args: {
28
+ pattern: 'core',
29
+ className: 'w-64',
30
+ },
31
+ };
32
+
33
+ export const Variant: Story = {
34
+ args: {
35
+ pattern: 'core',
36
+ variantSeed: 3,
37
+ className: 'w-64',
38
+ },
39
+ };
40
+
41
+ export const VariantGallery: Story = {
42
+ render: () => (
43
+ <div className="grid grid-cols-3 gap-4 p-6">
44
+ <IsotypeMini pattern="core" className="w-24" />
45
+ {Array.from({ length: 8 }, (_, seed) => (
46
+ <IsotypeMini key={seed} pattern="core" variantSeed={seed} className="w-24" />
47
+ ))}
48
+ </div>
49
+ ),
50
+ };
51
+
52
+ export const Sizes: Story = {
53
+ render: () => (
54
+ <div className="flex flex-col items-start gap-6 p-6">
55
+ <IsotypeMini className="w-16" />
56
+ <IsotypeMini className="w-32" />
57
+ <IsotypeMini className="w-64" />
58
+ <IsotypeMini className="w-96" />
59
+ </div>
60
+ ),
61
+ };
62
+
63
+ export const OnDark: Story = {
64
+ args: {
65
+ pattern: 'core',
66
+ className: 'w-64',
67
+ },
68
+ decorators: [
69
+ Story => (
70
+ <div className="rounded-xl bg-slate-950 p-8">
71
+ <Story />
72
+ </div>
73
+ ),
74
+ ],
75
+ };
@@ -0,0 +1,45 @@
1
+ import { render } from '@testing-library/react';
2
+ import { describe, it, expect } from 'vitest';
3
+ import { IsotypeMini } from './IsotypeMini';
4
+ import { getIsotypeMiniVariant } from './mini-patterns';
5
+ import React from 'react';
6
+
7
+ function countTransparentCells(container: HTMLElement): number {
8
+ const cells = Array.from(container.firstChild!.childNodes) as HTMLElement[];
9
+ return cells.filter(cell => !cell.style.backgroundColor).length;
10
+ }
11
+
12
+ function getCellColors(container: HTMLElement): string[] {
13
+ return Array.from(container.firstChild!.childNodes).map(
14
+ node => (node as HTMLElement).style.backgroundColor
15
+ );
16
+ }
17
+
18
+ describe('IsotypeMini', () => {
19
+ it('renders 9 cells with no blanks in the base pattern', () => {
20
+ const { container } = render(<IsotypeMini />);
21
+ const cells = container.firstChild!.childNodes;
22
+ expect(cells).toHaveLength(9);
23
+ expect(countTransparentCells(container)).toBe(0);
24
+ });
25
+
26
+ it('renders exactly 1 blank when a variantSeed is given', () => {
27
+ const { container } = render(<IsotypeMini variantSeed={3} />);
28
+ expect(countTransparentCells(container)).toBe(1);
29
+ });
30
+
31
+ it('getIsotypeMiniVariant is deterministic for the same seed', () => {
32
+ expect(getIsotypeMiniVariant('core', 5)).toEqual(getIsotypeMiniVariant('core', 5));
33
+ });
34
+
35
+ it('passes className through to the root', () => {
36
+ const { container } = render(<IsotypeMini className="w-64" />);
37
+ expect((container.firstChild as HTMLElement).className).toContain('w-64');
38
+ });
39
+
40
+ it('defaults to the core pattern', () => {
41
+ const { container: defaultContainer } = render(<IsotypeMini />);
42
+ const { container: explicitContainer } = render(<IsotypeMini pattern="core" />);
43
+ expect(getCellColors(defaultContainer)).toEqual(getCellColors(explicitContainer));
44
+ });
45
+ });
@@ -0,0 +1,71 @@
1
+ import { render } from '@testing-library/react';
2
+ import { describe, it, expect } from 'vitest';
3
+ import { IsotypeTwist } from './IsotypeTwist';
4
+ import { ISOTYPE_TWIST_VARIANTS, ISOTYPE_TWIST_VARIANT_IDS } from './twist-variants';
5
+ import { ISOTYPE_COLORS } from './patterns';
6
+ import React from 'react';
7
+
8
+ describe('IsotypeTwist', () => {
9
+ it('renders two paths', () => {
10
+ const { container } = render(<IsotypeTwist />);
11
+ expect(container.querySelectorAll('path')).toHaveLength(2);
12
+ });
13
+
14
+ it('defaults to the magenta-blue variant', () => {
15
+ const { container } = render(<IsotypeTwist />);
16
+ const paths = container.querySelectorAll('path');
17
+ const [backKey, frontKey] = ISOTYPE_TWIST_VARIANTS['magenta-blue'];
18
+ expect(paths[0].getAttribute('fill')).toBe(ISOTYPE_COLORS[backKey]);
19
+ expect(paths[1].getAttribute('fill')).toBe(ISOTYPE_COLORS[frontKey]);
20
+ });
21
+
22
+ it('renders every registered variant with the right fill colors', () => {
23
+ for (const variant of ISOTYPE_TWIST_VARIANT_IDS) {
24
+ const { container } = render(<IsotypeTwist variant={variant} />);
25
+ const paths = container.querySelectorAll('path');
26
+ const [backKey, frontKey] = ISOTYPE_TWIST_VARIANTS[variant];
27
+ expect(paths[0].getAttribute('fill')).toBe(ISOTYPE_COLORS[backKey]);
28
+ expect(paths[1].getAttribute('fill')).toBe(ISOTYPE_COLORS[frontKey]);
29
+ }
30
+ });
31
+
32
+ it('passes className through to the root', () => {
33
+ const { container } = render(<IsotypeTwist className="w-64" />);
34
+ expect((container.firstChild as HTMLElement).className).toContain('w-64');
35
+ });
36
+
37
+ it('is decorative by default (aria-hidden, no role)', () => {
38
+ const { container } = render(<IsotypeTwist />);
39
+ const root = container.firstChild as HTMLElement;
40
+ expect(root.getAttribute('aria-hidden')).toBe('true');
41
+ expect(root.getAttribute('role')).toBeNull();
42
+ });
43
+
44
+ it('renders as an image with a label when aria-label is set', () => {
45
+ const { container } = render(<IsotypeTwist aria-label="Xertica isotype" />);
46
+ const root = container.firstChild as HTMLElement;
47
+ expect(root.getAttribute('role')).toBe('img');
48
+ expect(root.getAttribute('aria-label')).toBe('Xertica isotype');
49
+ expect(root.getAttribute('aria-hidden')).toBeNull();
50
+ });
51
+
52
+ it('uses a 0 0 800 694 viewBox', () => {
53
+ const { container } = render(<IsotypeTwist />);
54
+ expect(container.querySelector('svg')!.getAttribute('viewBox')).toBe('0 0 800 694');
55
+ });
56
+
57
+ it('renders both shapes fully opaque and blends their intersection via mix-blend-mode on the front shape', () => {
58
+ const { container } = render(<IsotypeTwist />);
59
+ const [back, front] = Array.from(container.querySelectorAll('path'));
60
+
61
+ expect(back.getAttribute('opacity')).toBeNull();
62
+ expect(front.getAttribute('opacity')).toBeNull();
63
+ expect(front.style.mixBlendMode).toBeTruthy();
64
+ expect(front.style.mixBlendMode).not.toBe('normal');
65
+ });
66
+
67
+ it('isolates the blend mode to the two shapes via the root isolate class', () => {
68
+ const { container } = render(<IsotypeTwist />);
69
+ expect((container.firstChild as HTMLElement).className).toContain('isolate');
70
+ });
71
+ });
@@ -0,0 +1,61 @@
1
+ import { Meta, Title, Subtitle, Description } from '@storybook/addon-docs/blocks';
2
+
3
+ <Meta title="Brand/Isotype" />
4
+
5
+ <Title>Isotype</Title>
6
+ <Subtitle>First mark in a growing series of modular 4x4 Xertica isotypes.</Subtitle>
7
+
8
+ ---
9
+
10
+ ## Overview
11
+
12
+ `Isotype` renders a 4x4 grid of fixed brand colors that reads as a single composed image — a reusable visual mark for use standalone or alongside other Design System elements. It's built as one generic renderer over a pattern registry, so new isotypes join the series as pure data, not new components.
13
+
14
+ ```tsx
15
+ import { Isotype } from 'xertica-ui/brand';
16
+
17
+ <Isotype className="w-64" />
18
+ ```
19
+
20
+ ---
21
+
22
+ ## Props
23
+
24
+ | Prop | Type | Default | Description |
25
+ |---|---|---|---|
26
+ | `pattern` | `IsotypePatternId` | `'core'` | Which registered pattern to render. |
27
+ | `variantSeed` | `number` | — | Deterministically blanks one extra cell (beyond the pattern's own blank cell) for decorative variation. Omit for the pure base pattern. |
28
+ | `className` | `string` | — | Additional classes on the root grid container — use for sizing (`w-64`, `max-w-md`, etc). `aspect-square` is built in. |
29
+ | `aria-label` | `string` | — | Omit for decorative use (root gets `aria-hidden`); set it to render as `role="img"` instead. |
30
+
31
+ ---
32
+
33
+ ## Patterns
34
+
35
+ Today the registry (`ISOTYPE_PATTERNS` in `patterns.ts`) has one entry, `'core'`. Add new isotypes to the series by adding a new entry there and widening `IsotypePatternId` — `Isotype.tsx` itself never needs to change.
36
+
37
+ ## Variants
38
+
39
+ Passing `variantSeed` calls the pure, deterministic `getIsotypeVariant(pattern, seed)` internally — the same `(pattern, seed)` pair always blanks the same extra cell, so it's safe across server/client renders. Use it for decorative, repeated placements (e.g. a gallery of instances); canonical brand-mark spots should use the plain base pattern with no seed.
40
+
41
+ ```tsx
42
+ // Canonical brand-mark placement — pure base pattern
43
+ <Isotype />
44
+
45
+ // Decorative variation
46
+ <Isotype variantSeed={3} />
47
+
48
+ // Precomputing a batch of variants (e.g. a thumbnail sheet)
49
+ import { getIsotypeVariant } from 'xertica-ui/brand';
50
+ const variants = Array.from({ length: 8 }, (_, seed) => getIsotypeVariant('core', seed));
51
+ ```
52
+
53
+ ---
54
+
55
+ ## AI Best Practices
56
+
57
+ > [!IMPORTANT]
58
+ > - **Colors are fixed brand hex values, not theme tokens** — the isotype is a brand identity mark and must not reskin when the active color theme changes. Never replace `ISOTYPE_COLORS` with CSS custom properties.
59
+ > - **No gaps or per-cell borders** — cells must render flush against each other so the grid reads as a single composed image.
60
+ > - **New isotypes are data, not components** — add patterns via `ISOTYPE_PATTERNS`/`IsotypePatternId` in `patterns.ts`.
61
+ > - **`variantSeed` is for decorative use only** — canonical placements (Hero, nav, etc.) should render the base pattern.
@@ -0,0 +1,74 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Isotype } from './Isotype';
3
+ import { ISOTYPE_PATTERN_IDS } from './patterns';
4
+ import React from 'react';
5
+
6
+ const meta: Meta<typeof Isotype> = {
7
+ title: 'Brand/Isotype',
8
+ component: Isotype,
9
+ parameters: {
10
+ layout: 'centered',
11
+ },
12
+ argTypes: {
13
+ pattern: {
14
+ control: 'select',
15
+ options: ISOTYPE_PATTERN_IDS,
16
+ },
17
+ variantSeed: {
18
+ control: 'number',
19
+ },
20
+ },
21
+ };
22
+
23
+ export default meta;
24
+ type Story = StoryObj<typeof Isotype>;
25
+
26
+ export const Base: Story = {
27
+ args: {
28
+ pattern: 'core',
29
+ className: 'w-64',
30
+ },
31
+ };
32
+
33
+ export const Variant: Story = {
34
+ args: {
35
+ pattern: 'core',
36
+ variantSeed: 3,
37
+ className: 'w-64',
38
+ },
39
+ };
40
+
41
+ export const VariantGallery: Story = {
42
+ render: () => (
43
+ <div className="grid grid-cols-4 gap-4 p-6">
44
+ {Array.from({ length: 8 }, (_, seed) => (
45
+ <Isotype key={seed} pattern="core" variantSeed={seed} className="w-24" />
46
+ ))}
47
+ </div>
48
+ ),
49
+ };
50
+
51
+ export const Sizes: Story = {
52
+ render: () => (
53
+ <div className="flex flex-col items-start gap-6 p-6">
54
+ <Isotype className="w-16" />
55
+ <Isotype className="w-32" />
56
+ <Isotype className="w-64" />
57
+ <Isotype className="w-96" />
58
+ </div>
59
+ ),
60
+ };
61
+
62
+ export const OnDark: Story = {
63
+ args: {
64
+ pattern: 'core',
65
+ className: 'w-64',
66
+ },
67
+ decorators: [
68
+ Story => (
69
+ <div className="rounded-xl bg-slate-950 p-8">
70
+ <Story />
71
+ </div>
72
+ ),
73
+ ],
74
+ };
@@ -0,0 +1,41 @@
1
+ import { render } from '@testing-library/react';
2
+ import { describe, it, expect } from 'vitest';
3
+ import { Isotype } from './Isotype';
4
+ import { getIsotypeVariant, ISOTYPE_PATTERNS } from './patterns';
5
+ import React from 'react';
6
+
7
+ function countTransparentCells(container: HTMLElement): number {
8
+ const cells = Array.from(container.firstChild!.childNodes) as HTMLElement[];
9
+ return cells.filter(cell => !cell.style.backgroundColor).length;
10
+ }
11
+
12
+ describe('Isotype', () => {
13
+ it('renders 16 cells with exactly 1 blank in the base pattern', () => {
14
+ const { container } = render(<Isotype />);
15
+ const cells = container.firstChild!.childNodes;
16
+ expect(cells).toHaveLength(16);
17
+ expect(countTransparentCells(container)).toBe(1);
18
+ });
19
+
20
+ it('renders exactly 2 blanks when a variantSeed is given', () => {
21
+ const { container } = render(<Isotype variantSeed={3} />);
22
+ expect(countTransparentCells(container)).toBe(2);
23
+ });
24
+
25
+ it('getIsotypeVariant is deterministic for the same seed', () => {
26
+ expect(getIsotypeVariant('core', 5)).toEqual(getIsotypeVariant('core', 5));
27
+ });
28
+
29
+ it('passes className through to the root', () => {
30
+ const { container } = render(<Isotype className="w-64" />);
31
+ expect((container.firstChild as HTMLElement).className).toContain('w-64');
32
+ });
33
+
34
+ it('defaults to the core pattern', () => {
35
+ const { container } = render(<Isotype />);
36
+ const cells = Array.from(container.firstChild!.childNodes) as HTMLElement[];
37
+ const colors = cells.map(cell => cell.style.backgroundColor || 'blank');
38
+ const expectedBlankIndex = ISOTYPE_PATTERNS.core.indexOf('blank');
39
+ expect(colors[expectedBlankIndex]).toBe('blank');
40
+ });
41
+ });
@@ -0,0 +1,50 @@
1
+ import { mulberry32, type IsotypeCell } from './patterns';
2
+
3
+ /** Row-major 3x3 grid (9 cells) — a tuple so every pattern is guaranteed complete at compile time. */
4
+ export type IsotypeMiniPattern = readonly [
5
+ IsotypeCell,
6
+ IsotypeCell,
7
+ IsotypeCell,
8
+ IsotypeCell,
9
+ IsotypeCell,
10
+ IsotypeCell,
11
+ IsotypeCell,
12
+ IsotypeCell,
13
+ IsotypeCell,
14
+ ];
15
+
16
+ /** Widen this union as new 3x3 isotypes join the series. */
17
+ export type IsotypeMiniPatternId = 'core';
18
+
19
+ export const ISOTYPE_MINI_PATTERNS: Record<IsotypeMiniPatternId, IsotypeMiniPattern> = {
20
+ core: [
21
+ 'purple', 'blue', 'blue',
22
+ 'magenta', 'yellow', 'green',
23
+ 'magenta', 'red', 'brown',
24
+ ],
25
+ };
26
+
27
+ export const ISOTYPE_MINI_PATTERN_IDS = Object.keys(
28
+ ISOTYPE_MINI_PATTERNS
29
+ ) as IsotypeMiniPatternId[];
30
+
31
+ /**
32
+ * Returns a copy of the given pattern with exactly one cell (chosen
33
+ * deterministically from `seed`) swapped to `'blank'`. Pure — the same
34
+ * `(patternId, seed)` pair always returns the same result. Unlike
35
+ * `getIsotypeVariant`, the mini patterns have no inherent blank cell, so
36
+ * every cell is a candidate.
37
+ */
38
+ export function getIsotypeMiniVariant(
39
+ patternId: IsotypeMiniPatternId,
40
+ seed: number
41
+ ): IsotypeMiniPattern {
42
+ const base = ISOTYPE_MINI_PATTERNS[patternId];
43
+ const candidateIndices = base.reduce<number[]>(
44
+ (acc, cell, i) => (cell === 'blank' ? acc : [...acc, i]),
45
+ []
46
+ );
47
+ const rng = mulberry32(seed);
48
+ const chosen = candidateIndices[Math.floor(rng() * candidateIndices.length)];
49
+ return base.map((cell, i) => (i === chosen ? 'blank' : cell)) as unknown as IsotypeMiniPattern;
50
+ }
@@ -0,0 +1,83 @@
1
+ /** A single color role in the fixed isotype brand palette, or an empty cell. */
2
+ export type IsotypeColorKey = 'purple' | 'blue' | 'magenta' | 'yellow' | 'green' | 'red' | 'brown';
3
+
4
+ export type IsotypeCell = IsotypeColorKey | 'blank';
5
+
6
+ /** Row-major 4x4 grid (16 cells) — a tuple so every pattern is guaranteed complete at compile time. */
7
+ export type IsotypePattern = readonly [
8
+ IsotypeCell,
9
+ IsotypeCell,
10
+ IsotypeCell,
11
+ IsotypeCell,
12
+ IsotypeCell,
13
+ IsotypeCell,
14
+ IsotypeCell,
15
+ IsotypeCell,
16
+ IsotypeCell,
17
+ IsotypeCell,
18
+ IsotypeCell,
19
+ IsotypeCell,
20
+ IsotypeCell,
21
+ IsotypeCell,
22
+ IsotypeCell,
23
+ IsotypeCell,
24
+ ];
25
+
26
+ /**
27
+ * Fixed Xertica brand hex values for the `xertica` theme, provided directly
28
+ * by design. These are intentionally NOT CSS custom properties — an isotype
29
+ * is a brand identity mark, like a logo, and must not reskin when the
30
+ * active UI theme changes.
31
+ */
32
+ export const ISOTYPE_COLORS: Record<IsotypeColorKey, string> = {
33
+ purple: '#5A4A96',
34
+ blue: '#1899AF',
35
+ magenta: '#C45BAA',
36
+ yellow: '#FAF338',
37
+ green: '#2E8B5A',
38
+ red: '#DE5B48',
39
+ brown: '#2A2415',
40
+ };
41
+
42
+ /** Widen this union as new isotypes join the series. */
43
+ export type IsotypePatternId = 'core';
44
+
45
+ export const ISOTYPE_PATTERNS: Record<IsotypePatternId, IsotypePattern> = {
46
+ core: [
47
+ 'purple', 'blue', 'blue', 'blue',
48
+ 'magenta', 'blank', 'yellow', 'green',
49
+ 'magenta', 'yellow', 'yellow', 'green',
50
+ 'magenta', 'red', 'red', 'brown',
51
+ ],
52
+ };
53
+
54
+ export const ISOTYPE_PATTERN_IDS = Object.keys(ISOTYPE_PATTERNS) as IsotypePatternId[];
55
+
56
+ /** Deterministic PRNG (mulberry32) — the same seed always produces the same sequence. */
57
+ export function mulberry32(seed: number): () => number {
58
+ let a = seed >>> 0;
59
+ return () => {
60
+ a |= 0;
61
+ a = (a + 0x6d2b79f5) | 0;
62
+ let t = Math.imul(a ^ (a >>> 15), 1 | a);
63
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
64
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Returns a copy of the given pattern with exactly one additional non-blank
70
+ * cell (chosen deterministically from `seed`) swapped to `'blank'`. Pure —
71
+ * the same `(patternId, seed)` pair always returns the same result, and a
72
+ * cell that's already blank in the base pattern is never re-chosen.
73
+ */
74
+ export function getIsotypeVariant(patternId: IsotypePatternId, seed: number): IsotypePattern {
75
+ const base = ISOTYPE_PATTERNS[patternId];
76
+ const candidateIndices = base.reduce<number[]>(
77
+ (acc, cell, i) => (cell === 'blank' ? acc : [...acc, i]),
78
+ []
79
+ );
80
+ const rng = mulberry32(seed);
81
+ const chosen = candidateIndices[Math.floor(rng() * candidateIndices.length)];
82
+ return base.map((cell, i) => (i === chosen ? 'blank' : cell)) as unknown as IsotypePattern;
83
+ }
@@ -0,0 +1,20 @@
1
+ import type { IsotypeColorKey } from './patterns';
2
+
3
+ /**
4
+ * Ordered `[back, front]` color pair for `IsotypeTwist`. The front (second)
5
+ * color is painted on top and dominates the intersection blend produced by
6
+ * `mix-blend-mode` — the blended color is never hardcoded, only derived.
7
+ */
8
+ export type IsotypeTwistPair = readonly [IsotypeColorKey, IsotypeColorKey];
9
+
10
+ /** Only these two brand color pairs are in rotation — widen deliberately, not speculatively. */
11
+ export type IsotypeTwistVariantId = 'magenta-blue' | 'blue-red';
12
+
13
+ export const ISOTYPE_TWIST_VARIANTS: Record<IsotypeTwistVariantId, IsotypeTwistPair> = {
14
+ 'magenta-blue': ['magenta', 'blue'],
15
+ 'blue-red': ['blue', 'red'],
16
+ };
17
+
18
+ export const ISOTYPE_TWIST_VARIANT_IDS = Object.keys(
19
+ ISOTYPE_TWIST_VARIANTS
20
+ ) as IsotypeTwistVariantId[];
@@ -13,8 +13,8 @@ import { useTranslation } from 'react-i18next';
13
13
  *
14
14
  * @description
15
15
  * A screen that allows users to request a password reset link via email.
16
- * Includes a hero image side-panel (desktop) and alternative social login
17
- * options similar to the main Login page.
16
+ * Includes the shared brand isotype side-panel (desktop) and alternative
17
+ * social login options similar to the main Login page.
18
18
  *
19
19
  * @ai-rules
20
20
  * 1. Navigation: Successfully submitting the email triggers a navigation to `/verify-email`.
@@ -44,10 +44,7 @@ export function ForgotPasswordPage() {
44
44
  };
45
45
 
46
46
  return (
47
- <AuthPageShell
48
- imageSrc="https://images.unsplash.com/photo-1557804506-669a67965ba0?w=1200&h=800&fit=crop&auto=format"
49
- imageAlt={t('forgotPassword.heroImageAlt')}
50
- >
47
+ <AuthPageShell leftPanel="isotype">
51
48
  <div className="text-center">
52
49
  <div className="flex items-center justify-center mb-4">
53
50
  <XerticaLogo className="h-12 w-auto text-primary dark:text-foreground" variant="theme" />
@@ -1,6 +1,7 @@
1
1
  export * from './forgot-password-page';
2
2
  export * from './home-content';
3
3
  export * from './home-page';
4
+ export * from './landing-page';
4
5
  export * from './login-page';
5
6
  export * from './reset-password-page';
6
7
  export * from './template-content';