@entropy-softworks/ui 2026.7.31

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 (590) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/LICENSE +21 -0
  3. package/README.md +115 -0
  4. package/lib/components/auth/LockOverlay.d.ts +22 -0
  5. package/lib/components/auth/LockOverlay.d.ts.map +1 -0
  6. package/lib/components/auth/LockOverlay.jsx +82 -0
  7. package/lib/components/auth/LockOverlay.jsx.map +1 -0
  8. package/lib/components/auth/PasswordStrengthMeter.d.ts +12 -0
  9. package/lib/components/auth/PasswordStrengthMeter.d.ts.map +1 -0
  10. package/lib/components/auth/PasswordStrengthMeter.jsx +81 -0
  11. package/lib/components/auth/PasswordStrengthMeter.jsx.map +1 -0
  12. package/lib/components/auth/ProtectedRoute.d.ts +24 -0
  13. package/lib/components/auth/ProtectedRoute.d.ts.map +1 -0
  14. package/lib/components/auth/ProtectedRoute.jsx +56 -0
  15. package/lib/components/auth/ProtectedRoute.jsx.map +1 -0
  16. package/lib/components/auth/PwnedPasswordWarning.d.ts +13 -0
  17. package/lib/components/auth/PwnedPasswordWarning.d.ts.map +1 -0
  18. package/lib/components/auth/PwnedPasswordWarning.jsx +29 -0
  19. package/lib/components/auth/PwnedPasswordWarning.jsx.map +1 -0
  20. package/lib/components/auth/index.d.ts +5 -0
  21. package/lib/components/auth/index.d.ts.map +1 -0
  22. package/lib/components/auth/index.js +5 -0
  23. package/lib/components/auth/index.js.map +1 -0
  24. package/lib/components/bottom-nav.d.ts +25 -0
  25. package/lib/components/bottom-nav.d.ts.map +1 -0
  26. package/lib/components/bottom-nav.jsx +51 -0
  27. package/lib/components/bottom-nav.jsx.map +1 -0
  28. package/lib/components/button.d.ts +16 -0
  29. package/lib/components/button.d.ts.map +1 -0
  30. package/lib/components/button.jsx +73 -0
  31. package/lib/components/button.jsx.map +1 -0
  32. package/lib/components/card.d.ts +22 -0
  33. package/lib/components/card.d.ts.map +1 -0
  34. package/lib/components/card.jsx +36 -0
  35. package/lib/components/card.jsx.map +1 -0
  36. package/lib/components/checkbox.d.ts +12 -0
  37. package/lib/components/checkbox.d.ts.map +1 -0
  38. package/lib/components/checkbox.jsx +16 -0
  39. package/lib/components/checkbox.jsx.map +1 -0
  40. package/lib/components/connection-settings.d.ts +41 -0
  41. package/lib/components/connection-settings.d.ts.map +1 -0
  42. package/lib/components/connection-settings.jsx +354 -0
  43. package/lib/components/connection-settings.jsx.map +1 -0
  44. package/lib/components/context-menu.d.ts +52 -0
  45. package/lib/components/context-menu.d.ts.map +1 -0
  46. package/lib/components/context-menu.jsx +24 -0
  47. package/lib/components/context-menu.jsx.map +1 -0
  48. package/lib/components/data-table.d.ts +59 -0
  49. package/lib/components/data-table.d.ts.map +1 -0
  50. package/lib/components/data-table.jsx +101 -0
  51. package/lib/components/data-table.jsx.map +1 -0
  52. package/lib/components/dialog.d.ts +58 -0
  53. package/lib/components/dialog.d.ts.map +1 -0
  54. package/lib/components/dialog.jsx +197 -0
  55. package/lib/components/dialog.jsx.map +1 -0
  56. package/lib/components/dropdown-menu.d.ts +55 -0
  57. package/lib/components/dropdown-menu.d.ts.map +1 -0
  58. package/lib/components/dropdown-menu.jsx +38 -0
  59. package/lib/components/dropdown-menu.jsx.map +1 -0
  60. package/lib/components/entropy-boot-splash.d.ts +24 -0
  61. package/lib/components/entropy-boot-splash.d.ts.map +1 -0
  62. package/lib/components/entropy-boot-splash.jsx +83 -0
  63. package/lib/components/entropy-boot-splash.jsx.map +1 -0
  64. package/lib/components/entropy-mark-animated.d.ts +20 -0
  65. package/lib/components/entropy-mark-animated.d.ts.map +1 -0
  66. package/lib/components/entropy-mark-animated.jsx +148 -0
  67. package/lib/components/entropy-mark-animated.jsx.map +1 -0
  68. package/lib/components/entropy-mark-geometry.d.ts +8 -0
  69. package/lib/components/entropy-mark-geometry.d.ts.map +1 -0
  70. package/lib/components/entropy-mark-geometry.js +10 -0
  71. package/lib/components/entropy-mark-geometry.js.map +1 -0
  72. package/lib/components/entropy-mark-sequential.d.ts +12 -0
  73. package/lib/components/entropy-mark-sequential.d.ts.map +1 -0
  74. package/lib/components/entropy-mark-sequential.jsx +53 -0
  75. package/lib/components/entropy-mark-sequential.jsx.map +1 -0
  76. package/lib/components/entropy-mark.d.ts +29 -0
  77. package/lib/components/entropy-mark.d.ts.map +1 -0
  78. package/lib/components/entropy-mark.jsx +66 -0
  79. package/lib/components/entropy-mark.jsx.map +1 -0
  80. package/lib/components/error-boundary.d.ts +31 -0
  81. package/lib/components/error-boundary.d.ts.map +1 -0
  82. package/lib/components/error-boundary.jsx +40 -0
  83. package/lib/components/error-boundary.jsx.map +1 -0
  84. package/lib/components/index.d.ts +41 -0
  85. package/lib/components/index.d.ts.map +1 -0
  86. package/lib/components/index.js +43 -0
  87. package/lib/components/index.js.map +1 -0
  88. package/lib/components/input.d.ts +26 -0
  89. package/lib/components/input.d.ts.map +1 -0
  90. package/lib/components/input.jsx +95 -0
  91. package/lib/components/input.jsx.map +1 -0
  92. package/lib/components/item-icon.d.ts +32 -0
  93. package/lib/components/item-icon.d.ts.map +1 -0
  94. package/lib/components/item-icon.jsx +54 -0
  95. package/lib/components/item-icon.jsx.map +1 -0
  96. package/lib/components/label.d.ts +13 -0
  97. package/lib/components/label.d.ts.map +1 -0
  98. package/lib/components/label.jsx +9 -0
  99. package/lib/components/label.jsx.map +1 -0
  100. package/lib/components/legal-dialog.d.ts +18 -0
  101. package/lib/components/legal-dialog.d.ts.map +1 -0
  102. package/lib/components/legal-dialog.jsx +31 -0
  103. package/lib/components/legal-dialog.jsx.map +1 -0
  104. package/lib/components/license-gate.d.ts +17 -0
  105. package/lib/components/license-gate.d.ts.map +1 -0
  106. package/lib/components/license-gate.jsx +21 -0
  107. package/lib/components/license-gate.jsx.map +1 -0
  108. package/lib/components/logo.d.ts +15 -0
  109. package/lib/components/logo.d.ts.map +1 -0
  110. package/lib/components/logo.jsx +20 -0
  111. package/lib/components/logo.jsx.map +1 -0
  112. package/lib/components/onboarding-wizard.d.ts +89 -0
  113. package/lib/components/onboarding-wizard.d.ts.map +1 -0
  114. package/lib/components/onboarding-wizard.jsx +185 -0
  115. package/lib/components/onboarding-wizard.jsx.map +1 -0
  116. package/lib/components/pagination.d.ts +43 -0
  117. package/lib/components/pagination.d.ts.map +1 -0
  118. package/lib/components/pagination.jsx +72 -0
  119. package/lib/components/pagination.jsx.map +1 -0
  120. package/lib/components/password-generator.d.ts +15 -0
  121. package/lib/components/password-generator.d.ts.map +1 -0
  122. package/lib/components/password-generator.jsx +273 -0
  123. package/lib/components/password-generator.jsx.map +1 -0
  124. package/lib/components/pin-pad.d.ts +20 -0
  125. package/lib/components/pin-pad.d.ts.map +1 -0
  126. package/lib/components/pin-pad.jsx +93 -0
  127. package/lib/components/pin-pad.jsx.map +1 -0
  128. package/lib/components/popover.d.ts +27 -0
  129. package/lib/components/popover.d.ts.map +1 -0
  130. package/lib/components/popover.jsx +18 -0
  131. package/lib/components/popover.jsx.map +1 -0
  132. package/lib/components/profile/ProfileDialog.d.ts +25 -0
  133. package/lib/components/profile/ProfileDialog.d.ts.map +1 -0
  134. package/lib/components/profile/ProfileDialog.jsx +71 -0
  135. package/lib/components/profile/ProfileDialog.jsx.map +1 -0
  136. package/lib/components/profile/ProfileTab.d.ts +12 -0
  137. package/lib/components/profile/ProfileTab.d.ts.map +1 -0
  138. package/lib/components/profile/ProfileTab.jsx +112 -0
  139. package/lib/components/profile/ProfileTab.jsx.map +1 -0
  140. package/lib/components/profile/SecurityTab.d.ts +32 -0
  141. package/lib/components/profile/SecurityTab.d.ts.map +1 -0
  142. package/lib/components/profile/SecurityTab.jsx +145 -0
  143. package/lib/components/profile/SecurityTab.jsx.map +1 -0
  144. package/lib/components/profile/index.d.ts +4 -0
  145. package/lib/components/profile/index.d.ts.map +1 -0
  146. package/lib/components/profile/index.js +4 -0
  147. package/lib/components/profile/index.js.map +1 -0
  148. package/lib/components/segmented-toggle.d.ts +28 -0
  149. package/lib/components/segmented-toggle.d.ts.map +1 -0
  150. package/lib/components/segmented-toggle.jsx +64 -0
  151. package/lib/components/segmented-toggle.jsx.map +1 -0
  152. package/lib/components/separator.d.ts +13 -0
  153. package/lib/components/separator.d.ts.map +1 -0
  154. package/lib/components/separator.jsx +16 -0
  155. package/lib/components/separator.jsx.map +1 -0
  156. package/lib/components/server-settings.d.ts +27 -0
  157. package/lib/components/server-settings.d.ts.map +1 -0
  158. package/lib/components/server-settings.jsx +307 -0
  159. package/lib/components/server-settings.jsx.map +1 -0
  160. package/lib/components/settings/AccountSection.d.ts +26 -0
  161. package/lib/components/settings/AccountSection.d.ts.map +1 -0
  162. package/lib/components/settings/AccountSection.jsx +32 -0
  163. package/lib/components/settings/AccountSection.jsx.map +1 -0
  164. package/lib/components/settings/DangerZoneSection.d.ts +13 -0
  165. package/lib/components/settings/DangerZoneSection.d.ts.map +1 -0
  166. package/lib/components/settings/DangerZoneSection.jsx +16 -0
  167. package/lib/components/settings/DangerZoneSection.jsx.map +1 -0
  168. package/lib/components/settings/GeneralSection.d.ts +11 -0
  169. package/lib/components/settings/GeneralSection.d.ts.map +1 -0
  170. package/lib/components/settings/GeneralSection.jsx +12 -0
  171. package/lib/components/settings/GeneralSection.jsx.map +1 -0
  172. package/lib/components/settings/SupportSection.d.ts +11 -0
  173. package/lib/components/settings/SupportSection.d.ts.map +1 -0
  174. package/lib/components/settings/SupportSection.jsx +22 -0
  175. package/lib/components/settings/SupportSection.jsx.map +1 -0
  176. package/lib/components/settings/index.d.ts +5 -0
  177. package/lib/components/settings/index.d.ts.map +1 -0
  178. package/lib/components/settings/index.js +5 -0
  179. package/lib/components/settings/index.js.map +1 -0
  180. package/lib/components/settings-row.d.ts +28 -0
  181. package/lib/components/settings-row.d.ts.map +1 -0
  182. package/lib/components/settings-row.jsx +68 -0
  183. package/lib/components/settings-row.jsx.map +1 -0
  184. package/lib/components/skeleton.d.ts +8 -0
  185. package/lib/components/skeleton.d.ts.map +1 -0
  186. package/lib/components/skeleton.jsx +24 -0
  187. package/lib/components/skeleton.jsx.map +1 -0
  188. package/lib/components/social-connections.d.ts +15 -0
  189. package/lib/components/social-connections.d.ts.map +1 -0
  190. package/lib/components/social-connections.jsx +31 -0
  191. package/lib/components/social-connections.jsx.map +1 -0
  192. package/lib/components/stat-card.d.ts +29 -0
  193. package/lib/components/stat-card.d.ts.map +1 -0
  194. package/lib/components/stat-card.jsx +36 -0
  195. package/lib/components/stat-card.jsx.map +1 -0
  196. package/lib/components/tag-chip.d.ts +18 -0
  197. package/lib/components/tag-chip.d.ts.map +1 -0
  198. package/lib/components/tag-chip.jsx +54 -0
  199. package/lib/components/tag-chip.jsx.map +1 -0
  200. package/lib/components/tag-multi-select.d.ts +27 -0
  201. package/lib/components/tag-multi-select.d.ts.map +1 -0
  202. package/lib/components/tag-multi-select.jsx +65 -0
  203. package/lib/components/tag-multi-select.jsx.map +1 -0
  204. package/lib/components/text.d.ts +22 -0
  205. package/lib/components/text.d.ts.map +1 -0
  206. package/lib/components/text.jsx +43 -0
  207. package/lib/components/text.jsx.map +1 -0
  208. package/lib/components/toast/ToastPortal.d.ts +11 -0
  209. package/lib/components/toast/ToastPortal.d.ts.map +1 -0
  210. package/lib/components/toast/ToastPortal.jsx +15 -0
  211. package/lib/components/toast/ToastPortal.jsx.map +1 -0
  212. package/lib/components/toast/ToastPortal.web.d.ts +14 -0
  213. package/lib/components/toast/ToastPortal.web.d.ts.map +1 -0
  214. package/lib/components/toast/ToastPortal.web.jsx +39 -0
  215. package/lib/components/toast/ToastPortal.web.jsx.map +1 -0
  216. package/lib/components/toast/index.d.ts +3 -0
  217. package/lib/components/toast/index.d.ts.map +1 -0
  218. package/lib/components/toast/index.js +3 -0
  219. package/lib/components/toast/index.js.map +1 -0
  220. package/lib/components/toast/toast-config.d.ts +14 -0
  221. package/lib/components/toast/toast-config.d.ts.map +1 -0
  222. package/lib/components/toast/toast-config.jsx +24 -0
  223. package/lib/components/toast/toast-config.jsx.map +1 -0
  224. package/lib/components/tooltip.d.ts +30 -0
  225. package/lib/components/tooltip.d.ts.map +1 -0
  226. package/lib/components/tooltip.jsx +14 -0
  227. package/lib/components/tooltip.jsx.map +1 -0
  228. package/lib/components/totp-display.d.ts +23 -0
  229. package/lib/components/totp-display.d.ts.map +1 -0
  230. package/lib/components/totp-display.jsx +132 -0
  231. package/lib/components/totp-display.jsx.map +1 -0
  232. package/lib/components/user-avatar.d.ts +18 -0
  233. package/lib/components/user-avatar.d.ts.map +1 -0
  234. package/lib/components/user-avatar.jsx +25 -0
  235. package/lib/components/user-avatar.jsx.map +1 -0
  236. package/lib/context/AppConfigContext.d.ts +56 -0
  237. package/lib/context/AppConfigContext.d.ts.map +1 -0
  238. package/lib/context/AppConfigContext.jsx +14 -0
  239. package/lib/context/AppConfigContext.jsx.map +1 -0
  240. package/lib/context/NavigationContext.d.ts +42 -0
  241. package/lib/context/NavigationContext.d.ts.map +1 -0
  242. package/lib/context/NavigationContext.jsx +53 -0
  243. package/lib/context/NavigationContext.jsx.map +1 -0
  244. package/lib/context/NotificationContext.d.ts +32 -0
  245. package/lib/context/NotificationContext.d.ts.map +1 -0
  246. package/lib/context/NotificationContext.jsx +49 -0
  247. package/lib/context/NotificationContext.jsx.map +1 -0
  248. package/lib/context/ThemeContext.d.ts +12 -0
  249. package/lib/context/ThemeContext.d.ts.map +1 -0
  250. package/lib/context/ThemeContext.jsx +66 -0
  251. package/lib/context/ThemeContext.jsx.map +1 -0
  252. package/lib/context/index.d.ts +5 -0
  253. package/lib/context/index.d.ts.map +1 -0
  254. package/lib/context/index.js +5 -0
  255. package/lib/context/index.js.map +1 -0
  256. package/lib/flags.d.ts +9 -0
  257. package/lib/flags.d.ts.map +1 -0
  258. package/lib/flags.js +37 -0
  259. package/lib/flags.js.map +1 -0
  260. package/lib/forms/form-error.d.ts +12 -0
  261. package/lib/forms/form-error.d.ts.map +1 -0
  262. package/lib/forms/form-error.jsx +14 -0
  263. package/lib/forms/form-error.jsx.map +1 -0
  264. package/lib/forms/index.d.ts +3 -0
  265. package/lib/forms/index.d.ts.map +1 -0
  266. package/lib/forms/index.js +3 -0
  267. package/lib/forms/index.js.map +1 -0
  268. package/lib/forms/shake-field.d.ts +18 -0
  269. package/lib/forms/shake-field.d.ts.map +1 -0
  270. package/lib/forms/shake-field.jsx +30 -0
  271. package/lib/forms/shake-field.jsx.map +1 -0
  272. package/lib/hooks/index.d.ts +6 -0
  273. package/lib/hooks/index.d.ts.map +1 -0
  274. package/lib/hooks/index.js +6 -0
  275. package/lib/hooks/index.js.map +1 -0
  276. package/lib/hooks/useAuth.d.ts +109 -0
  277. package/lib/hooks/useAuth.d.ts.map +1 -0
  278. package/lib/hooks/useAuth.jsx +404 -0
  279. package/lib/hooks/useAuth.jsx.map +1 -0
  280. package/lib/hooks/useAutoLock.d.ts +22 -0
  281. package/lib/hooks/useAutoLock.d.ts.map +1 -0
  282. package/lib/hooks/useAutoLock.js +85 -0
  283. package/lib/hooks/useAutoLock.js.map +1 -0
  284. package/lib/hooks/useDebouncedValue.d.ts +19 -0
  285. package/lib/hooks/useDebouncedValue.d.ts.map +1 -0
  286. package/lib/hooks/useDebouncedValue.js +29 -0
  287. package/lib/hooks/useDebouncedValue.js.map +1 -0
  288. package/lib/hooks/useShakeAnimation.d.ts +17 -0
  289. package/lib/hooks/useShakeAnimation.d.ts.map +1 -0
  290. package/lib/hooks/useShakeAnimation.js +22 -0
  291. package/lib/hooks/useShakeAnimation.js.map +1 -0
  292. package/lib/hooks/useUploadBlobUrl.d.ts +13 -0
  293. package/lib/hooks/useUploadBlobUrl.d.ts.map +1 -0
  294. package/lib/hooks/useUploadBlobUrl.js +60 -0
  295. package/lib/hooks/useUploadBlobUrl.js.map +1 -0
  296. package/lib/index.d.ts +10 -0
  297. package/lib/index.d.ts.map +1 -0
  298. package/lib/index.js +47 -0
  299. package/lib/index.js.map +1 -0
  300. package/lib/screens/auth/AccountPickerScreen.d.ts +24 -0
  301. package/lib/screens/auth/AccountPickerScreen.d.ts.map +1 -0
  302. package/lib/screens/auth/AccountPickerScreen.jsx +47 -0
  303. package/lib/screens/auth/AccountPickerScreen.jsx.map +1 -0
  304. package/lib/screens/auth/AuthScreen.d.ts +59 -0
  305. package/lib/screens/auth/AuthScreen.d.ts.map +1 -0
  306. package/lib/screens/auth/AuthScreen.jsx +594 -0
  307. package/lib/screens/auth/AuthScreen.jsx.map +1 -0
  308. package/lib/screens/auth/ConsentScreen.d.ts +27 -0
  309. package/lib/screens/auth/ConsentScreen.d.ts.map +1 -0
  310. package/lib/screens/auth/ConsentScreen.jsx +55 -0
  311. package/lib/screens/auth/ConsentScreen.jsx.map +1 -0
  312. package/lib/screens/auth/ErrorScreen.d.ts +20 -0
  313. package/lib/screens/auth/ErrorScreen.d.ts.map +1 -0
  314. package/lib/screens/auth/ErrorScreen.jsx +43 -0
  315. package/lib/screens/auth/ErrorScreen.jsx.map +1 -0
  316. package/lib/screens/auth/ExpiredLinkScreen.d.ts +19 -0
  317. package/lib/screens/auth/ExpiredLinkScreen.d.ts.map +1 -0
  318. package/lib/screens/auth/ExpiredLinkScreen.jsx +38 -0
  319. package/lib/screens/auth/ExpiredLinkScreen.jsx.map +1 -0
  320. package/lib/screens/auth/ForgotPasswordScreen.d.ts +4 -0
  321. package/lib/screens/auth/ForgotPasswordScreen.d.ts.map +1 -0
  322. package/lib/screens/auth/ForgotPasswordScreen.jsx +123 -0
  323. package/lib/screens/auth/ForgotPasswordScreen.jsx.map +1 -0
  324. package/lib/screens/auth/ImportDataScreen.d.ts +17 -0
  325. package/lib/screens/auth/ImportDataScreen.d.ts.map +1 -0
  326. package/lib/screens/auth/ImportDataScreen.jsx +73 -0
  327. package/lib/screens/auth/ImportDataScreen.jsx.map +1 -0
  328. package/lib/screens/auth/LoginScreen.d.ts +38 -0
  329. package/lib/screens/auth/LoginScreen.d.ts.map +1 -0
  330. package/lib/screens/auth/LoginScreen.jsx +326 -0
  331. package/lib/screens/auth/LoginScreen.jsx.map +1 -0
  332. package/lib/screens/auth/MfaChallengeScreen.d.ts +4 -0
  333. package/lib/screens/auth/MfaChallengeScreen.d.ts.map +1 -0
  334. package/lib/screens/auth/MfaChallengeScreen.jsx +139 -0
  335. package/lib/screens/auth/MfaChallengeScreen.jsx.map +1 -0
  336. package/lib/screens/auth/MfaEnrollScreen.d.ts +12 -0
  337. package/lib/screens/auth/MfaEnrollScreen.d.ts.map +1 -0
  338. package/lib/screens/auth/MfaEnrollScreen.jsx +267 -0
  339. package/lib/screens/auth/MfaEnrollScreen.jsx.map +1 -0
  340. package/lib/screens/auth/PasskeyEnrollScreen.d.ts +18 -0
  341. package/lib/screens/auth/PasskeyEnrollScreen.d.ts.map +1 -0
  342. package/lib/screens/auth/PasskeyEnrollScreen.jsx +51 -0
  343. package/lib/screens/auth/PasskeyEnrollScreen.jsx.map +1 -0
  344. package/lib/screens/auth/PrivacyPolicyScreen.d.ts +19 -0
  345. package/lib/screens/auth/PrivacyPolicyScreen.d.ts.map +1 -0
  346. package/lib/screens/auth/PrivacyPolicyScreen.jsx +143 -0
  347. package/lib/screens/auth/PrivacyPolicyScreen.jsx.map +1 -0
  348. package/lib/screens/auth/RegisterScreen.d.ts +14 -0
  349. package/lib/screens/auth/RegisterScreen.d.ts.map +1 -0
  350. package/lib/screens/auth/RegisterScreen.jsx +296 -0
  351. package/lib/screens/auth/RegisterScreen.jsx.map +1 -0
  352. package/lib/screens/auth/ResetPasswordScreen.d.ts +12 -0
  353. package/lib/screens/auth/ResetPasswordScreen.d.ts.map +1 -0
  354. package/lib/screens/auth/ResetPasswordScreen.jsx +276 -0
  355. package/lib/screens/auth/ResetPasswordScreen.jsx.map +1 -0
  356. package/lib/screens/auth/ServerConfigScreen.d.ts +18 -0
  357. package/lib/screens/auth/ServerConfigScreen.d.ts.map +1 -0
  358. package/lib/screens/auth/ServerConfigScreen.jsx +259 -0
  359. package/lib/screens/auth/ServerConfigScreen.jsx.map +1 -0
  360. package/lib/screens/auth/TermsOfServiceScreen.d.ts +30 -0
  361. package/lib/screens/auth/TermsOfServiceScreen.d.ts.map +1 -0
  362. package/lib/screens/auth/TermsOfServiceScreen.jsx +130 -0
  363. package/lib/screens/auth/TermsOfServiceScreen.jsx.map +1 -0
  364. package/lib/screens/auth/VerifyEmailScreen.d.ts +4 -0
  365. package/lib/screens/auth/VerifyEmailScreen.d.ts.map +1 -0
  366. package/lib/screens/auth/VerifyEmailScreen.jsx +249 -0
  367. package/lib/screens/auth/VerifyEmailScreen.jsx.map +1 -0
  368. package/lib/screens/auth/WelcomeScreen.d.ts +17 -0
  369. package/lib/screens/auth/WelcomeScreen.d.ts.map +1 -0
  370. package/lib/screens/auth/WelcomeScreen.jsx +58 -0
  371. package/lib/screens/auth/WelcomeScreen.jsx.map +1 -0
  372. package/lib/screens/auth/index.d.ts +19 -0
  373. package/lib/screens/auth/index.d.ts.map +1 -0
  374. package/lib/screens/auth/index.js +19 -0
  375. package/lib/screens/auth/index.js.map +1 -0
  376. package/lib/screens/index.d.ts +2 -0
  377. package/lib/screens/index.d.ts.map +1 -0
  378. package/lib/screens/index.js +2 -0
  379. package/lib/screens/index.js.map +1 -0
  380. package/lib/services/api-config.d.ts +87 -0
  381. package/lib/services/api-config.d.ts.map +1 -0
  382. package/lib/services/api-config.js +202 -0
  383. package/lib/services/api-config.js.map +1 -0
  384. package/lib/services/auth.service.d.ts +140 -0
  385. package/lib/services/auth.service.d.ts.map +1 -0
  386. package/lib/services/auth.service.js +376 -0
  387. package/lib/services/auth.service.js.map +1 -0
  388. package/lib/services/favicon.d.ts +46 -0
  389. package/lib/services/favicon.d.ts.map +1 -0
  390. package/lib/services/favicon.js +84 -0
  391. package/lib/services/favicon.js.map +1 -0
  392. package/lib/services/hibp-cache.d.ts +23 -0
  393. package/lib/services/hibp-cache.d.ts.map +1 -0
  394. package/lib/services/hibp-cache.js +56 -0
  395. package/lib/services/hibp-cache.js.map +1 -0
  396. package/lib/services/hibp.d.ts +28 -0
  397. package/lib/services/hibp.d.ts.map +1 -0
  398. package/lib/services/hibp.js +92 -0
  399. package/lib/services/hibp.js.map +1 -0
  400. package/lib/services/index.d.ts +8 -0
  401. package/lib/services/index.d.ts.map +1 -0
  402. package/lib/services/index.js +7 -0
  403. package/lib/services/index.js.map +1 -0
  404. package/lib/services/passkey.d.ts +10 -0
  405. package/lib/services/passkey.d.ts.map +1 -0
  406. package/lib/services/passkey.js +192 -0
  407. package/lib/services/passkey.js.map +1 -0
  408. package/lib/utils/api-fetch.d.ts +11 -0
  409. package/lib/utils/api-fetch.d.ts.map +1 -0
  410. package/lib/utils/api-fetch.js +52 -0
  411. package/lib/utils/api-fetch.js.map +1 -0
  412. package/lib/utils/clipboard.d.ts +31 -0
  413. package/lib/utils/clipboard.d.ts.map +1 -0
  414. package/lib/utils/clipboard.js +66 -0
  415. package/lib/utils/clipboard.js.map +1 -0
  416. package/lib/utils/cn.d.ts +9 -0
  417. package/lib/utils/cn.d.ts.map +1 -0
  418. package/lib/utils/cn.js +12 -0
  419. package/lib/utils/cn.js.map +1 -0
  420. package/lib/utils/debounce.d.ts +13 -0
  421. package/lib/utils/debounce.d.ts.map +1 -0
  422. package/lib/utils/debounce.js +28 -0
  423. package/lib/utils/debounce.js.map +1 -0
  424. package/lib/utils/error.d.ts +9 -0
  425. package/lib/utils/error.d.ts.map +1 -0
  426. package/lib/utils/error.js +11 -0
  427. package/lib/utils/error.js.map +1 -0
  428. package/lib/utils/fetch.d.ts +17 -0
  429. package/lib/utils/fetch.d.ts.map +1 -0
  430. package/lib/utils/fetch.js +29 -0
  431. package/lib/utils/fetch.js.map +1 -0
  432. package/lib/utils/http-error.d.ts +41 -0
  433. package/lib/utils/http-error.d.ts.map +1 -0
  434. package/lib/utils/http-error.js +63 -0
  435. package/lib/utils/http-error.js.map +1 -0
  436. package/lib/utils/index.d.ts +11 -0
  437. package/lib/utils/index.d.ts.map +1 -0
  438. package/lib/utils/index.js +11 -0
  439. package/lib/utils/index.js.map +1 -0
  440. package/lib/utils/palette.d.ts +46 -0
  441. package/lib/utils/palette.d.ts.map +1 -0
  442. package/lib/utils/palette.js +75 -0
  443. package/lib/utils/palette.js.map +1 -0
  444. package/lib/utils/password.d.ts +20 -0
  445. package/lib/utils/password.d.ts.map +1 -0
  446. package/lib/utils/password.js +51 -0
  447. package/lib/utils/password.js.map +1 -0
  448. package/lib/utils/settings-storage.d.ts +3 -0
  449. package/lib/utils/settings-storage.d.ts.map +1 -0
  450. package/lib/utils/settings-storage.js +62 -0
  451. package/lib/utils/settings-storage.js.map +1 -0
  452. package/lib/utils/validation.d.ts +29 -0
  453. package/lib/utils/validation.d.ts.map +1 -0
  454. package/lib/utils/validation.js +58 -0
  455. package/lib/utils/validation.js.map +1 -0
  456. package/package.json +204 -0
  457. package/src/components/__tests__/data-table.test.ts +94 -0
  458. package/src/components/__tests__/pagination.test.ts +73 -0
  459. package/src/components/__tests__/stat-card.test.ts +21 -0
  460. package/src/components/auth/LockOverlay.tsx +122 -0
  461. package/src/components/auth/PasswordStrengthMeter.tsx +96 -0
  462. package/src/components/auth/ProtectedRoute.tsx +91 -0
  463. package/src/components/auth/PwnedPasswordWarning.tsx +54 -0
  464. package/src/components/auth/index.ts +10 -0
  465. package/src/components/bottom-nav.tsx +99 -0
  466. package/src/components/button.tsx +144 -0
  467. package/src/components/card.tsx +82 -0
  468. package/src/components/checkbox.tsx +48 -0
  469. package/src/components/connection-settings.tsx +583 -0
  470. package/src/components/context-menu.tsx +95 -0
  471. package/src/components/data-table.tsx +223 -0
  472. package/src/components/dialog.tsx +376 -0
  473. package/src/components/dropdown-menu.tsx +120 -0
  474. package/src/components/entropy-boot-splash.tsx +114 -0
  475. package/src/components/entropy-mark-animated.tsx +260 -0
  476. package/src/components/entropy-mark-geometry.ts +11 -0
  477. package/src/components/entropy-mark-sequential.tsx +132 -0
  478. package/src/components/entropy-mark.tsx +135 -0
  479. package/src/components/error-boundary.tsx +70 -0
  480. package/src/components/index.ts +156 -0
  481. package/src/components/input.tsx +246 -0
  482. package/src/components/item-icon.tsx +111 -0
  483. package/src/components/label.tsx +25 -0
  484. package/src/components/legal-dialog.tsx +47 -0
  485. package/src/components/license-gate.tsx +28 -0
  486. package/src/components/logo.tsx +34 -0
  487. package/src/components/onboarding-wizard.tsx +353 -0
  488. package/src/components/pagination.tsx +154 -0
  489. package/src/components/password-generator.tsx +393 -0
  490. package/src/components/pin-pad.tsx +156 -0
  491. package/src/components/popover.tsx +38 -0
  492. package/src/components/profile/ProfileDialog.tsx +129 -0
  493. package/src/components/profile/ProfileTab.tsx +151 -0
  494. package/src/components/profile/SecurityTab.tsx +229 -0
  495. package/src/components/profile/index.ts +3 -0
  496. package/src/components/segmented-toggle.tsx +119 -0
  497. package/src/components/separator.tsx +41 -0
  498. package/src/components/server-settings.tsx +442 -0
  499. package/src/components/settings/AccountSection.tsx +76 -0
  500. package/src/components/settings/DangerZoneSection.tsx +37 -0
  501. package/src/components/settings/GeneralSection.tsx +39 -0
  502. package/src/components/settings/SupportSection.tsx +53 -0
  503. package/src/components/settings/index.ts +4 -0
  504. package/src/components/settings-row.tsx +126 -0
  505. package/src/components/skeleton.tsx +48 -0
  506. package/src/components/social-connections.tsx +55 -0
  507. package/src/components/stat-card.tsx +64 -0
  508. package/src/components/tag-chip.tsx +78 -0
  509. package/src/components/tag-multi-select.tsx +136 -0
  510. package/src/components/text.tsx +77 -0
  511. package/src/components/toast/ToastPortal.tsx +16 -0
  512. package/src/components/toast/ToastPortal.web.tsx +47 -0
  513. package/src/components/toast/index.ts +2 -0
  514. package/src/components/toast/toast-config.tsx +31 -0
  515. package/src/components/tooltip.tsx +30 -0
  516. package/src/components/totp-display.tsx +207 -0
  517. package/src/components/user-avatar.tsx +46 -0
  518. package/src/context/AppConfigContext.tsx +76 -0
  519. package/src/context/NavigationContext.tsx +75 -0
  520. package/src/context/NotificationContext.tsx +69 -0
  521. package/src/context/ThemeContext.tsx +83 -0
  522. package/src/context/__tests__/NavigationContext.test.tsx +53 -0
  523. package/src/context/index.ts +24 -0
  524. package/src/flags.ts +44 -0
  525. package/src/forms/form-error.tsx +20 -0
  526. package/src/forms/index.ts +2 -0
  527. package/src/forms/shake-field.tsx +52 -0
  528. package/src/hooks/__tests__/useUploadBlobUrl.test.tsx +77 -0
  529. package/src/hooks/index.ts +18 -0
  530. package/src/hooks/useAuth.tsx +567 -0
  531. package/src/hooks/useAutoLock.ts +110 -0
  532. package/src/hooks/useDebouncedValue.ts +32 -0
  533. package/src/hooks/useShakeAnimation.ts +42 -0
  534. package/src/hooks/useUploadBlobUrl.ts +75 -0
  535. package/src/index.ts +48 -0
  536. package/src/screens/auth/AccountPickerScreen.tsx +103 -0
  537. package/src/screens/auth/AuthScreen.tsx +941 -0
  538. package/src/screens/auth/ConsentScreen.tsx +118 -0
  539. package/src/screens/auth/ErrorScreen.tsx +96 -0
  540. package/src/screens/auth/ExpiredLinkScreen.tsx +87 -0
  541. package/src/screens/auth/ForgotPasswordScreen.tsx +182 -0
  542. package/src/screens/auth/ImportDataScreen.tsx +112 -0
  543. package/src/screens/auth/LoginScreen.tsx +484 -0
  544. package/src/screens/auth/MfaChallengeScreen.tsx +216 -0
  545. package/src/screens/auth/MfaEnrollScreen.tsx +388 -0
  546. package/src/screens/auth/PasskeyEnrollScreen.tsx +96 -0
  547. package/src/screens/auth/PrivacyPolicyScreen.tsx +249 -0
  548. package/src/screens/auth/RegisterScreen.tsx +430 -0
  549. package/src/screens/auth/ResetPasswordScreen.tsx +377 -0
  550. package/src/screens/auth/ServerConfigScreen.tsx +388 -0
  551. package/src/screens/auth/TermsOfServiceScreen.tsx +236 -0
  552. package/src/screens/auth/VerifyEmailScreen.tsx +310 -0
  553. package/src/screens/auth/WelcomeScreen.tsx +78 -0
  554. package/src/screens/auth/index.ts +36 -0
  555. package/src/screens/index.ts +1 -0
  556. package/src/services/__tests__/api-config.test.ts +67 -0
  557. package/src/services/__tests__/favicon.test.ts +88 -0
  558. package/src/services/__tests__/hibp-cache.test.ts +37 -0
  559. package/src/services/__tests__/hibp.test.ts +39 -0
  560. package/src/services/api-config.ts +260 -0
  561. package/src/services/auth.service.ts +498 -0
  562. package/src/services/favicon.ts +102 -0
  563. package/src/services/hibp-cache.ts +71 -0
  564. package/src/services/hibp.ts +120 -0
  565. package/src/services/index.ts +52 -0
  566. package/src/services/passkey.ts +213 -0
  567. package/src/types/external.d.ts +24 -0
  568. package/src/utils/__tests__/clipboard.test.ts +59 -0
  569. package/src/utils/__tests__/cn.test.ts +24 -0
  570. package/src/utils/__tests__/debounce.test.ts +42 -0
  571. package/src/utils/__tests__/error.test.ts +18 -0
  572. package/src/utils/__tests__/http-error.test.ts +33 -0
  573. package/src/utils/__tests__/palette.test.ts +22 -0
  574. package/src/utils/__tests__/password.test.ts +55 -0
  575. package/src/utils/__tests__/settings-storage.test.ts +15 -0
  576. package/src/utils/__tests__/validation.test.ts +52 -0
  577. package/src/utils/api-fetch.ts +61 -0
  578. package/src/utils/clipboard.ts +69 -0
  579. package/src/utils/cn.ts +12 -0
  580. package/src/utils/debounce.ts +33 -0
  581. package/src/utils/error.ts +10 -0
  582. package/src/utils/fetch.ts +33 -0
  583. package/src/utils/http-error.ts +81 -0
  584. package/src/utils/index.ts +23 -0
  585. package/src/utils/palette.ts +105 -0
  586. package/src/utils/password.ts +64 -0
  587. package/src/utils/settings-storage.ts +68 -0
  588. package/src/utils/validation.ts +71 -0
  589. package/styles/globals.css +262 -0
  590. package/tailwind-preset.js +163 -0
@@ -0,0 +1,30 @@
1
+ import React from "react";
2
+ import * as TooltipPrimitive from "@rn-primitives/tooltip";
3
+ import { cn } from "../utils/cn";
4
+ import { Text } from "./text";
5
+
6
+ const Tooltip = TooltipPrimitive.Root;
7
+ const TooltipTrigger = TooltipPrimitive.Trigger;
8
+
9
+ const TooltipContent = React.forwardRef<
10
+ React.ElementRef<typeof TooltipPrimitive.Content>,
11
+ React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & { className?: string }
12
+ >(({ className, sideOffset = 6, children, ...props }, ref) => (
13
+ <TooltipPrimitive.Portal>
14
+ <TooltipPrimitive.Content
15
+ ref={ref}
16
+ sideOffset={sideOffset}
17
+ className={cn("z-50 rounded-md px-3 py-1.5", "bg-foreground dark:bg-white", className)}
18
+ {...props}
19
+ >
20
+ {typeof children === "string" ? (
21
+ <Text className="text-xs text-background dark:text-black">{children}</Text>
22
+ ) : (
23
+ children
24
+ )}
25
+ </TooltipPrimitive.Content>
26
+ </TooltipPrimitive.Portal>
27
+ ));
28
+ TooltipContent.displayName = "TooltipContent";
29
+
30
+ export { Tooltip, TooltipTrigger, TooltipContent };
@@ -0,0 +1,207 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Pressable, View } from "react-native";
3
+ import { Ionicons } from "@expo/vector-icons";
4
+ import { useColorScheme } from "nativewind";
5
+ import { MutedText, Text } from "./text";
6
+ import { copyToClipboard } from "../utils/clipboard";
7
+
8
+ export interface TotpDisplayProps {
9
+ /** Base32-encoded TOTP secret. Empty string disables the display. */
10
+ secret: string;
11
+ /**
12
+ * Pure function that computes the current TOTP code from `secret`.
13
+ * Apps inject their own implementation so this widget stays decoupled
14
+ * from the crypto module — e.g. vault wires
15
+ * `@vault/shared/crypto/totp.computeTotpCode`.
16
+ */
17
+ computeCode: (secret: string) => string;
18
+ /** TOTP step period in seconds. Defaults to 30. */
19
+ period?: number;
20
+ /** Optional callback fired after a successful clipboard write. */
21
+ onCopy?: (code: string) => void;
22
+ }
23
+
24
+ const PLACEHOLDER = "------";
25
+
26
+ /**
27
+ * TOTP code display with a circular countdown ring. Recomputes the code
28
+ * on each 30s window boundary; ticks the remaining-seconds value once
29
+ * per second to drive the ring animation.
30
+ */
31
+ export function TotpDisplay({
32
+ secret,
33
+ computeCode,
34
+ period = 30,
35
+ onCopy,
36
+ }: TotpDisplayProps): React.JSX.Element | null {
37
+ const { colorScheme } = useColorScheme();
38
+ const isDark = colorScheme === "dark";
39
+
40
+ const safeCompute = (s: string): string => {
41
+ if (!s) {
42
+ return PLACEHOLDER;
43
+ }
44
+ try {
45
+ return computeCode(s);
46
+ } catch {
47
+ return PLACEHOLDER;
48
+ }
49
+ };
50
+
51
+ const [code, setCode] = useState<string>(() => safeCompute(secret));
52
+ const [remaining, setRemaining] = useState<number>(() => {
53
+ const now = Math.floor(Date.now() / 1000);
54
+ return period - (now % period);
55
+ });
56
+
57
+ useEffect(() => {
58
+ if (!secret) {
59
+ return;
60
+ }
61
+ let lastWindow = -1;
62
+ const tick = () => {
63
+ const now = Math.floor(Date.now() / 1000);
64
+ const window = Math.floor(now / period);
65
+ setRemaining(period - (now % period));
66
+ if (window !== lastWindow) {
67
+ lastWindow = window;
68
+ setCode(safeCompute(secret));
69
+ }
70
+ };
71
+ tick();
72
+ const id = setInterval(tick, 1000);
73
+ return () => clearInterval(id);
74
+ // eslint-disable-next-line react-hooks/exhaustive-deps
75
+ }, [secret, period]);
76
+
77
+ if (!secret) {
78
+ return null;
79
+ }
80
+
81
+ const copy = async (): Promise<void> => {
82
+ if (!code || code === PLACEHOLDER) {
83
+ return;
84
+ }
85
+ // Route through the shared helper so the 30s auto-clear applies.
86
+ // TOTP codes rotate every 30s anyway, but the clipboard residue
87
+ // still leaks the code to whatever the user pastes next (or to
88
+ // a shoulder-surfer hitting paste).
89
+ const ok = await copyToClipboard(code);
90
+ if (ok) {
91
+ onCopy?.(code);
92
+ }
93
+ };
94
+
95
+ const urgent = remaining <= 5;
96
+ const foreground = isDark ? "rgb(255, 255, 255)" : "rgb(0, 0, 0)";
97
+ const destructive = "rgb(239, 68, 68)";
98
+ const border = isDark ? "rgb(38, 38, 38)" : "rgb(229, 229, 229)";
99
+ const card = isDark ? "rgb(0, 0, 0)" : "rgb(255, 255, 255)";
100
+ const secondary = isDark ? "rgb(38, 38, 38)" : "rgb(245, 245, 245)";
101
+ const accent = urgent ? destructive : foreground;
102
+
103
+ return (
104
+ <Pressable
105
+ onPress={copy}
106
+ accessibilityRole="button"
107
+ accessibilityLabel="Copy TOTP code"
108
+ accessibilityHint="Copies the current one-time code to the clipboard"
109
+ style={({ pressed }) => ({
110
+ flexDirection: "row",
111
+ alignItems: "center",
112
+ gap: 12,
113
+ padding: 12,
114
+ borderRadius: 8,
115
+ borderWidth: 1,
116
+ borderColor: border,
117
+ backgroundColor: pressed ? secondary : card,
118
+ })}
119
+ >
120
+ <CountdownRing remaining={remaining} total={period} color={accent} backgroundColor={border} />
121
+ <View style={{ flex: 1 }}>
122
+ <MutedText className="text-xs" style={{ marginBottom: 2 }}>
123
+ TOTP code
124
+ </MutedText>
125
+ <Text
126
+ style={{
127
+ color: accent,
128
+ fontSize: 22,
129
+ fontWeight: "600",
130
+ letterSpacing: 4,
131
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
132
+ }}
133
+ >
134
+ {`${code.slice(0, 3)} ${code.slice(3)}`}
135
+ </Text>
136
+ </View>
137
+ <Ionicons
138
+ name="copy-outline"
139
+ size={16}
140
+ color={isDark ? "rgb(163, 163, 163)" : "rgb(115, 115, 115)"}
141
+ />
142
+ </Pressable>
143
+ );
144
+ }
145
+
146
+ interface RingProps {
147
+ remaining: number;
148
+ total: number;
149
+ color: string;
150
+ backgroundColor: string;
151
+ }
152
+
153
+ function CountdownRing({ remaining, total, color, backgroundColor }: RingProps): React.JSX.Element {
154
+ const size = 36;
155
+ const stroke = 3;
156
+ const radius = (size - stroke) / 2;
157
+ const circumference = 2 * Math.PI * radius;
158
+ const fraction = Math.max(0, Math.min(1, remaining / total));
159
+ const dashOffset = circumference * (1 - fraction);
160
+
161
+ // Cast raw SVG tags through React.createElement so RN-Web renders them
162
+ // as real <svg> / <circle> elements without depending on
163
+ // `react-native-svg`. Native targets fall back to the View at the
164
+ // outer level — apps that want native parity should overlay this with
165
+ // an SVG-backed implementation in their own component layer.
166
+ const Svg = "svg" as unknown as React.ComponentType<Record<string, unknown>>;
167
+ const Circle = "circle" as unknown as React.ComponentType<Record<string, unknown>>;
168
+
169
+ return (
170
+ <View style={{ width: size, height: size, alignItems: "center", justifyContent: "center" }}>
171
+ <Svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
172
+ <Circle
173
+ cx={size / 2}
174
+ cy={size / 2}
175
+ r={radius}
176
+ fill="none"
177
+ stroke={backgroundColor}
178
+ strokeWidth={stroke}
179
+ />
180
+ <Circle
181
+ cx={size / 2}
182
+ cy={size / 2}
183
+ r={radius}
184
+ fill="none"
185
+ stroke={color}
186
+ strokeWidth={stroke}
187
+ strokeLinecap="round"
188
+ strokeDasharray={circumference}
189
+ strokeDashoffset={dashOffset}
190
+ transform={`rotate(-90 ${size / 2} ${size / 2})`}
191
+ style={{ transition: "stroke-dashoffset 1s linear" }}
192
+ />
193
+ </Svg>
194
+ <Text
195
+ style={{
196
+ position: "absolute",
197
+ color,
198
+ fontSize: 11,
199
+ fontWeight: "600",
200
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
201
+ }}
202
+ >
203
+ {remaining}
204
+ </Text>
205
+ </View>
206
+ );
207
+ }
@@ -0,0 +1,46 @@
1
+ import React from "react";
2
+ import { View } from "react-native";
3
+ import { useColorScheme } from "nativewind";
4
+ import { cn } from "../utils/cn";
5
+ import { useAuth } from "../hooks/useAuth";
6
+ import { Text } from "./text";
7
+
8
+ export interface UserAvatarProps {
9
+ /** Square pixel size. Defaults to 36. */
10
+ size?: number;
11
+ /**
12
+ * Override for the initial letter. By default the avatar pulls the
13
+ * first character of `display_name`, falling back to `username`, then
14
+ * `email`, then `?`.
15
+ */
16
+ initial?: string;
17
+ }
18
+
19
+ /**
20
+ * Initial-letter circular avatar. Pulls the current user from
21
+ * `useAuth()` and renders a foreground-on-primary disc. Apps that want
22
+ * a static initial (e.g. an icon strip) pass `initial` explicitly.
23
+ */
24
+ export const UserAvatar = React.memo(function UserAvatar({ size = 36, initial }: UserAvatarProps) {
25
+ const { user } = useAuth();
26
+ const { colorScheme } = useColorScheme();
27
+ const isDark = colorScheme === "dark";
28
+ const resolved =
29
+ initial ??
30
+ (user?.display_name || user?.username || user?.email || "?")[0]?.toUpperCase() ??
31
+ "?";
32
+
33
+ return (
34
+ <View
35
+ className={cn("items-center justify-center rounded-full", isDark ? "bg-white" : "bg-black")}
36
+ style={{ width: size, height: size }}
37
+ >
38
+ <Text
39
+ className="font-bold"
40
+ style={{ fontSize: size * 0.44, color: isDark ? "#000000" : "#FFFFFF" }}
41
+ >
42
+ {resolved}
43
+ </Text>
44
+ </View>
45
+ );
46
+ });
@@ -0,0 +1,76 @@
1
+ import React, { createContext, useContext, useMemo } from "react";
2
+ import { type Href } from "expo-router";
3
+ import { type ImageStyle, type StyleProp, type ViewStyle } from "react-native";
4
+
5
+ /**
6
+ * Per-app route map consumed by the entropy-ui auth screens / hooks.
7
+ * Apps supply this so the shared screens can navigate without hard-coding
8
+ * vault- or bootstrap-specific paths.
9
+ */
10
+ export interface AppRoutes {
11
+ welcome: Href;
12
+ login: Href;
13
+ register: Href;
14
+ forgotPassword: Href;
15
+ resetPassword: Href;
16
+ verifyEmail: Href;
17
+ mfaChallenge: Href;
18
+ mfaEnroll: Href;
19
+ termsOfService: Href;
20
+ privacyPolicy: Href;
21
+ serverConfig: Href;
22
+ importData: Href;
23
+ /** Where to land authenticated users with no pending onboarding step. */
24
+ home: Href;
25
+ }
26
+
27
+ export type LogoComponent = React.ComponentType<{
28
+ width?: number;
29
+ height?: number;
30
+ style?: StyleProp<ViewStyle> | StyleProp<ImageStyle>;
31
+ }>;
32
+
33
+ export interface AppConfig {
34
+ /** User-facing brand name. Renders in headings, toasts, MFA issuer, etc. */
35
+ appName: string;
36
+ /** Brand logo as a React component (SVG / Image). */
37
+ Logo: LogoComponent;
38
+ /** Per-app route map. */
39
+ routes: AppRoutes;
40
+ /**
41
+ * Tagline rendered under the brand on the welcome screen. Defaults to
42
+ * a generic "An Entropy Softworks platform".
43
+ */
44
+ tagline?: string;
45
+ /**
46
+ * Optional terms-of-service markdown / plain text. Welcome screen and
47
+ * the dedicated terms screen render this. When omitted, the screens
48
+ * render a generic stub.
49
+ */
50
+ termsText?: string;
51
+ /** Optional privacy-policy markdown / plain text. */
52
+ privacyText?: string;
53
+ }
54
+
55
+ const AppConfigContext = createContext<AppConfig | null>(null);
56
+
57
+ export function AppConfigProvider({
58
+ config,
59
+ children,
60
+ }: {
61
+ config: AppConfig;
62
+ children: React.ReactNode;
63
+ }) {
64
+ const value = useMemo(() => config, [config]);
65
+ return <AppConfigContext.Provider value={value}>{children}</AppConfigContext.Provider>;
66
+ }
67
+
68
+ export function useAppConfig(): AppConfig {
69
+ const ctx = useContext(AppConfigContext);
70
+ if (!ctx) {
71
+ throw new Error(
72
+ "entropy-ui: useAppConfig must be used inside <AppConfigProvider config={...}>."
73
+ );
74
+ }
75
+ return ctx;
76
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Pluggable navigation surface used by entropy-ui's auth screens.
3
+ *
4
+ * The shared screens used to call `useRouter()` from `expo-router`
5
+ * directly, which made them un-usable in non-Expo bundles (the browser-
6
+ * extension popup, future Electron / web targets without the Expo
7
+ * router runtime). Routing through this context lets every consumer
8
+ * supply its own router implementation — expo-router on mobile / web,
9
+ * a stack-reducer adapter inside the extension popup, etc.
10
+ *
11
+ * When no consumer is wrapped in `<NavigationProvider>`, `useNavigation`
12
+ * falls back to `expo-router`'s `useRouter()`, so the existing mobile
13
+ * client keeps working unchanged.
14
+ */
15
+
16
+ import React, { createContext, useContext, useMemo } from "react";
17
+ import { type Href, useRouter } from "expo-router";
18
+
19
+ export interface RouteTarget {
20
+ pathname: Href | string;
21
+ params?: Record<string, unknown>;
22
+ }
23
+
24
+ export interface AppRouter {
25
+ push(target: Href | string | RouteTarget): void;
26
+ replace(target: Href | string | RouteTarget): void;
27
+ back(): void;
28
+ }
29
+
30
+ const NavigationContext = createContext<AppRouter | null>(null);
31
+
32
+ export interface NavigationProviderProps {
33
+ router: AppRouter;
34
+ children: React.ReactNode;
35
+ }
36
+
37
+ /**
38
+ * Override the default expo-router-backed navigation for everything
39
+ * rendered below this provider. Apps without expo-router supply this
40
+ * with their own stack-reducer adapter; everyone else can ignore it.
41
+ */
42
+ export function NavigationProvider({ router, children }: NavigationProviderProps) {
43
+ const value = useMemo(() => router, [router]);
44
+ return <NavigationContext.Provider value={value}>{children}</NavigationContext.Provider>;
45
+ }
46
+
47
+ /**
48
+ * Hook used by entropy-ui screens to navigate. Returns the override
49
+ * router supplied by `NavigationProvider` when present; otherwise
50
+ * delegates to `expo-router`'s `useRouter()`.
51
+ */
52
+ export function useNavigation(): AppRouter {
53
+ const override = useContext(NavigationContext);
54
+ const expoRouter = useRouter();
55
+ // Memoize the expo-router adapter so consumers using the returned
56
+ // value as a `useEffect`/`useCallback` dep don't see a fresh
57
+ // reference every render. `useRouter()` itself returns a stable
58
+ // object across renders, so an empty-dep memo would also work, but
59
+ // depending on `expoRouter` is defensive against future changes.
60
+ const expoAdapter = useMemo<AppRouter>(
61
+ () => ({
62
+ push(target) {
63
+ expoRouter.push(target as Href);
64
+ },
65
+ replace(target) {
66
+ expoRouter.replace(target as Href);
67
+ },
68
+ back() {
69
+ expoRouter.back();
70
+ },
71
+ }),
72
+ [expoRouter]
73
+ );
74
+ return override ?? expoAdapter;
75
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Notification context — provides a `push()` helper that surfaces
3
+ * toast-style notifications via `react-native-toast-message`.
4
+ *
5
+ * Mount `<NotificationProvider>` somewhere above the components that
6
+ * consume `useNotificationContext()`. The `<Toast />` component itself
7
+ * must be rendered separately in the app root (see
8
+ * `react-native-toast-message` docs).
9
+ *
10
+ * The vault notification provider also bridged a WebSocket service into
11
+ * this context to dispatch server-pushed toasts; that piece is
12
+ * app-specific and not included here. Consumers that need it can build
13
+ * a thin wrapper around this provider.
14
+ */
15
+
16
+ import React, { createContext, useCallback, useContext, useMemo } from "react";
17
+ import Toast from "react-native-toast-message";
18
+
19
+ export type NotificationLevel = "success" | "error" | "warning" | "info";
20
+
21
+ export interface ToastOptions {
22
+ level: NotificationLevel;
23
+ title: string;
24
+ message?: string;
25
+ /** Milliseconds before auto-dismiss. Defaults to 4000. */
26
+ ttl_ms?: number;
27
+ }
28
+
29
+ interface NotificationContextValue {
30
+ push: (options: ToastOptions) => void;
31
+ }
32
+
33
+ const NotificationContext = createContext<NotificationContextValue | null>(null);
34
+
35
+ const LEVEL_TO_TOAST_TYPE: Record<NotificationLevel, "success" | "error" | "info"> = {
36
+ success: "success",
37
+ error: "error",
38
+ // react-native-toast-message only ships success/error/info — warnings
39
+ // map onto error so they show with the warning-coloured icon.
40
+ warning: "error",
41
+ info: "info",
42
+ };
43
+
44
+ export function NotificationProvider({ children }: { children: React.ReactNode }) {
45
+ const push = useCallback((options: ToastOptions) => {
46
+ Toast.show({
47
+ type: LEVEL_TO_TOAST_TYPE[options.level],
48
+ text1: options.title,
49
+ text2: options.message,
50
+ visibilityTime: options.ttl_ms ?? 4000,
51
+ });
52
+ }, []);
53
+
54
+ // Memoize the context value so an inline-object identity churn
55
+ // doesn't re-render every consumer on each NotificationProvider
56
+ // render. `push` is already `useCallback`-stable, so the memo
57
+ // effectively pins the value across the provider's lifetime.
58
+ const value = useMemo(() => ({ push }), [push]);
59
+
60
+ return <NotificationContext.Provider value={value}>{children}</NotificationContext.Provider>;
61
+ }
62
+
63
+ export function useNotificationContext(): NotificationContextValue {
64
+ const ctx = useContext(NotificationContext);
65
+ if (!ctx) {
66
+ throw new Error("useNotificationContext must be used inside <NotificationProvider>");
67
+ }
68
+ return ctx;
69
+ }
@@ -0,0 +1,83 @@
1
+ import React, { createContext, useContext, useEffect, useState, useMemo, useCallback } from "react";
2
+ import { colorScheme } from "nativewind";
3
+ import AsyncStorage from "@react-native-async-storage/async-storage";
4
+ import { getStoragePrefix } from "../services/api-config";
5
+
6
+ export type ThemePreference = "light" | "dark" | "system";
7
+
8
+ function themeKey(): string {
9
+ return `@${getStoragePrefix()}/theme-preference`;
10
+ }
11
+
12
+ function applyTheme(isDark: boolean) {
13
+ colorScheme.set(isDark ? "dark" : "light");
14
+ if (typeof document !== "undefined") {
15
+ if (isDark) {
16
+ document.documentElement.classList.add("dark");
17
+ } else {
18
+ document.documentElement.classList.remove("dark");
19
+ }
20
+ }
21
+ }
22
+
23
+ interface ThemeContextValue {
24
+ preference: ThemePreference;
25
+ setPreference: (pref: ThemePreference) => void;
26
+ }
27
+
28
+ const ThemeContext = createContext<ThemeContextValue>({
29
+ preference: "system",
30
+ setPreference: () => {},
31
+ });
32
+
33
+ export function ThemeProvider({ children }: { children: React.ReactNode }) {
34
+ const [preference, setPreferenceState] = useState<ThemePreference>("system");
35
+
36
+ useEffect(() => {
37
+ AsyncStorage.getItem(themeKey())
38
+ .then((stored) => {
39
+ if (stored === "light" || stored === "dark" || stored === "system") {
40
+ setPreferenceState(stored);
41
+ }
42
+ })
43
+ .catch(() => {});
44
+ }, []);
45
+
46
+ const setPreference = useCallback((pref: ThemePreference) => {
47
+ AsyncStorage.setItem(themeKey(), pref).catch(() => {});
48
+ setPreferenceState(pref);
49
+ }, []);
50
+
51
+ useEffect(() => {
52
+ if (preference !== "system") {
53
+ applyTheme(preference === "dark");
54
+ return;
55
+ }
56
+
57
+ if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
58
+ // Web system mode: react-native-css-interop's internal Appearance
59
+ // listener uses the removed `MediaQueryList.addListener` API
60
+ // (Chrome 121+) so it never fires. Drive it ourselves via
61
+ // `addEventListener` instead.
62
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
63
+ applyTheme(mq.matches);
64
+ const handler = (e: MediaQueryListEvent) => applyTheme(e.matches);
65
+ mq.addEventListener("change", handler);
66
+ return () => mq.removeEventListener("change", handler);
67
+ }
68
+
69
+ // Native system mode: react-native-css-interop's Appearance listener
70
+ // already tracks OS changes. Calling colorScheme.set("system") would
71
+ // pass null to the Android native module which rejects non-nullable
72
+ // parameters and crashes — leave it alone.
73
+ return undefined;
74
+ }, [preference]);
75
+
76
+ const contextValue = useMemo(() => ({ preference, setPreference }), [preference, setPreference]);
77
+
78
+ return <ThemeContext.Provider value={contextValue}>{children}</ThemeContext.Provider>;
79
+ }
80
+
81
+ export function useTheme() {
82
+ return useContext(ThemeContext);
83
+ }
@@ -0,0 +1,53 @@
1
+ import React from "react";
2
+ import { renderHook } from "@testing-library/react-native";
3
+
4
+ import { NavigationProvider, useNavigation, type AppRouter } from "../NavigationContext";
5
+ import * as expoRouterModule from "expo-router";
6
+
7
+ jest.mock("expo-router", () => {
8
+ const mockRouter = { push: jest.fn(), replace: jest.fn(), back: jest.fn() };
9
+ return {
10
+ __mockRouter: mockRouter,
11
+ useRouter: () => mockRouter,
12
+ };
13
+ });
14
+
15
+ const expoRouter = (expoRouterModule as unknown as { __mockRouter: AppRouter }).__mockRouter;
16
+
17
+ beforeEach(() => {
18
+ (expoRouter.push as jest.Mock).mockClear();
19
+ (expoRouter.replace as jest.Mock).mockClear();
20
+ (expoRouter.back as jest.Mock).mockClear();
21
+ });
22
+
23
+ describe("useNavigation", () => {
24
+ it("falls back to expo-router when no provider is present", () => {
25
+ const { result } = renderHook(() => useNavigation());
26
+ result.current.push("/welcome");
27
+ result.current.replace("/login");
28
+ result.current.back();
29
+ expect(expoRouter.push).toHaveBeenCalledWith("/welcome");
30
+ expect(expoRouter.replace).toHaveBeenCalledWith("/login");
31
+ expect(expoRouter.back).toHaveBeenCalled();
32
+ });
33
+
34
+ it("uses the override router when wrapped in NavigationProvider", () => {
35
+ const custom: AppRouter = {
36
+ push: jest.fn(),
37
+ replace: jest.fn(),
38
+ back: jest.fn(),
39
+ };
40
+ const { result } = renderHook(() => useNavigation(), {
41
+ wrapper: ({ children }) => (
42
+ <NavigationProvider router={custom}>{children}</NavigationProvider>
43
+ ),
44
+ });
45
+ result.current.push("/a");
46
+ result.current.replace("/b");
47
+ result.current.back();
48
+ expect(custom.push).toHaveBeenCalledWith("/a");
49
+ expect(custom.replace).toHaveBeenCalledWith("/b");
50
+ expect(custom.back).toHaveBeenCalled();
51
+ expect(expoRouter.push).not.toHaveBeenCalled();
52
+ });
53
+ });
@@ -0,0 +1,24 @@
1
+ export {
2
+ AppConfigProvider,
3
+ useAppConfig,
4
+ type AppConfig,
5
+ type AppRoutes,
6
+ type LogoComponent,
7
+ } from "./AppConfigContext";
8
+
9
+ export { ThemeProvider, useTheme, type ThemePreference } from "./ThemeContext";
10
+
11
+ export {
12
+ NavigationProvider,
13
+ useNavigation,
14
+ type AppRouter,
15
+ type NavigationProviderProps,
16
+ type RouteTarget,
17
+ } from "./NavigationContext";
18
+
19
+ export {
20
+ NotificationProvider,
21
+ useNotificationContext,
22
+ type NotificationLevel,
23
+ type ToastOptions,
24
+ } from "./NotificationContext";