@atproto/oauth-provider 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (325) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/account/account-manager.d.ts +7 -5
  3. package/dist/account/account-manager.d.ts.map +1 -1
  4. package/dist/account/account-manager.js +34 -25
  5. package/dist/account/account-manager.js.map +1 -1
  6. package/dist/account/account-store.d.ts +13 -5
  7. package/dist/account/account-store.d.ts.map +1 -1
  8. package/dist/account/account-store.js +24 -8
  9. package/dist/account/account-store.js.map +1 -1
  10. package/dist/account/account.d.ts +1 -11
  11. package/dist/account/account.d.ts.map +1 -1
  12. package/dist/account/{sign-up-data.d.ts → sign-up-input.d.ts} +5 -5
  13. package/dist/account/sign-up-input.d.ts.map +1 -0
  14. package/dist/account/{sign-up-data.js → sign-up-input.js} +3 -3
  15. package/dist/account/sign-up-input.js.map +1 -0
  16. package/dist/assets/assets-middleware.d.ts +2 -0
  17. package/dist/assets/assets-middleware.d.ts.map +1 -1
  18. package/dist/assets/assets-middleware.js +12 -14
  19. package/dist/assets/assets-middleware.js.map +1 -1
  20. package/dist/errors/invalid-invite-code-error.d.ts +5 -0
  21. package/dist/errors/invalid-invite-code-error.d.ts.map +1 -0
  22. package/dist/errors/invalid-invite-code-error.js +11 -0
  23. package/dist/errors/invalid-invite-code-error.js.map +1 -0
  24. package/dist/errors/oauth-error.d.ts +2 -2
  25. package/dist/errors/oauth-error.js.map +1 -1
  26. package/dist/lib/csp/index.d.ts +5 -6
  27. package/dist/lib/csp/index.d.ts.map +1 -1
  28. package/dist/lib/csp/index.js +14 -11
  29. package/dist/lib/csp/index.js.map +1 -1
  30. package/dist/lib/hcaptcha.d.ts +5 -3
  31. package/dist/lib/hcaptcha.d.ts.map +1 -1
  32. package/dist/lib/hcaptcha.js +7 -4
  33. package/dist/lib/hcaptcha.js.map +1 -1
  34. package/dist/lib/html/build-document.d.ts +2 -2
  35. package/dist/lib/html/build-document.d.ts.map +1 -1
  36. package/dist/lib/html/build-document.js +11 -7
  37. package/dist/lib/html/build-document.js.map +1 -1
  38. package/dist/lib/html/html.d.ts.map +1 -1
  39. package/dist/lib/html/html.js +10 -13
  40. package/dist/lib/html/html.js.map +1 -1
  41. package/dist/lib/html/util.d.ts +0 -1
  42. package/dist/lib/html/util.d.ts.map +1 -1
  43. package/dist/lib/html/util.js +0 -4
  44. package/dist/lib/html/util.js.map +1 -1
  45. package/dist/lib/http/response.d.ts +3 -1
  46. package/dist/lib/http/response.d.ts.map +1 -1
  47. package/dist/lib/http/response.js +3 -0
  48. package/dist/lib/http/response.js.map +1 -1
  49. package/dist/lib/http/security-headers.d.ts +48 -0
  50. package/dist/lib/http/security-headers.d.ts.map +1 -0
  51. package/dist/lib/http/security-headers.js +62 -0
  52. package/dist/lib/http/security-headers.js.map +1 -0
  53. package/dist/lib/util/type.d.ts +8 -0
  54. package/dist/lib/util/type.d.ts.map +1 -1
  55. package/dist/lib/util/type.js.map +1 -1
  56. package/dist/oauth-errors.d.ts +1 -0
  57. package/dist/oauth-errors.d.ts.map +1 -1
  58. package/dist/oauth-errors.js +3 -1
  59. package/dist/oauth-errors.js.map +1 -1
  60. package/dist/oauth-hooks.d.ts +4 -25
  61. package/dist/oauth-hooks.d.ts.map +1 -1
  62. package/dist/oauth-provider.d.ts.map +1 -1
  63. package/dist/oauth-provider.js +26 -25
  64. package/dist/oauth-provider.js.map +1 -1
  65. package/dist/output/backend-data.d.ts +4 -0
  66. package/dist/output/backend-data.d.ts.map +1 -0
  67. package/dist/output/backend-data.js +19 -0
  68. package/dist/output/backend-data.js.map +1 -0
  69. package/dist/output/build-authorize-data.d.ts +3 -19
  70. package/dist/output/build-authorize-data.d.ts.map +1 -1
  71. package/dist/output/build-authorize-data.js.map +1 -1
  72. package/dist/output/build-customization-data.d.ts +11 -18
  73. package/dist/output/build-customization-data.d.ts.map +1 -1
  74. package/dist/output/build-customization-data.js +1 -1
  75. package/dist/output/build-customization-data.js.map +1 -1
  76. package/dist/output/build-error-data.d.ts +3 -0
  77. package/dist/output/build-error-data.d.ts.map +1 -0
  78. package/dist/output/build-error-data.js +10 -0
  79. package/dist/output/build-error-data.js.map +1 -0
  80. package/dist/output/build-error-payload.d.ts +2 -1
  81. package/dist/output/build-error-payload.d.ts.map +1 -1
  82. package/dist/output/build-error-payload.js.map +1 -1
  83. package/dist/output/output-manager.d.ts +10 -4
  84. package/dist/output/output-manager.d.ts.map +1 -1
  85. package/dist/output/output-manager.js +68 -39
  86. package/dist/output/output-manager.js.map +1 -1
  87. package/dist/output/send-web-page.d.ts +6 -10
  88. package/dist/output/send-web-page.d.ts.map +1 -1
  89. package/dist/output/send-web-page.js +27 -47
  90. package/dist/output/send-web-page.js.map +1 -1
  91. package/dist/signer/signed-token-payload.d.ts +3 -3
  92. package/dist/signer/signer.d.ts +2 -2
  93. package/package.json +7 -39
  94. package/src/account/account-manager.ts +55 -34
  95. package/src/account/account-store.ts +29 -6
  96. package/src/account/account.ts +1 -14
  97. package/src/account/{sign-up-data.ts → sign-up-input.ts} +2 -2
  98. package/src/assets/assets-middleware.ts +11 -17
  99. package/src/errors/invalid-invite-code-error.ts +10 -0
  100. package/src/errors/oauth-error.ts +1 -1
  101. package/src/lib/csp/index.ts +16 -13
  102. package/src/lib/hcaptcha.ts +10 -7
  103. package/src/lib/html/build-document.ts +15 -8
  104. package/src/lib/html/html.ts +11 -18
  105. package/src/lib/html/util.ts +0 -4
  106. package/src/lib/http/response.ts +9 -1
  107. package/src/lib/http/security-headers.ts +91 -0
  108. package/src/lib/util/type.ts +18 -0
  109. package/src/oauth-errors.ts +1 -0
  110. package/src/oauth-hooks.ts +4 -25
  111. package/src/oauth-provider.ts +40 -34
  112. package/src/output/backend-data.ts +18 -0
  113. package/src/output/build-authorize-data.ts +3 -26
  114. package/src/output/build-customization-data.ts +2 -13
  115. package/src/output/build-error-data.ts +8 -0
  116. package/src/output/build-error-payload.ts +4 -2
  117. package/src/output/output-manager.ts +86 -47
  118. package/src/output/send-web-page.ts +29 -58
  119. package/tsconfig.backend.json +1 -2
  120. package/tsconfig.backend.tsbuildinfo +1 -1
  121. package/tsconfig.json +1 -5
  122. package/.linguirc +0 -57
  123. package/dist/account/sign-up-data.d.ts.map +0 -1
  124. package/dist/account/sign-up-data.js.map +0 -1
  125. package/dist/assets/app/bundle-manifest.json +0 -614
  126. package/dist/assets/app/index-ItwwtJ8r.js +0 -36
  127. package/dist/assets/app/index-ItwwtJ8r.js.map +0 -1
  128. package/dist/assets/app/main-B_dNxQo_.js +0 -4
  129. package/dist/assets/app/main-B_dNxQo_.js.map +0 -1
  130. package/dist/assets/app/main-CSatvmRR.css +0 -3
  131. package/dist/assets/app/main-CSatvmRR.js +0 -306
  132. package/dist/assets/app/main-CSatvmRR.js.map +0 -1
  133. package/dist/assets/app/messages-BQeltXSF.js +0 -4
  134. package/dist/assets/app/messages-BQeltXSF.js.map +0 -1
  135. package/dist/assets/app/messages-BQkEhfjg.js +0 -4
  136. package/dist/assets/app/messages-BQkEhfjg.js.map +0 -1
  137. package/dist/assets/app/messages-BUjKj_UJ.js +0 -4
  138. package/dist/assets/app/messages-BUjKj_UJ.js.map +0 -1
  139. package/dist/assets/app/messages-BWIQa8fO.js +0 -4
  140. package/dist/assets/app/messages-BWIQa8fO.js.map +0 -1
  141. package/dist/assets/app/messages-BaNVb0bp.js +0 -4
  142. package/dist/assets/app/messages-BaNVb0bp.js.map +0 -1
  143. package/dist/assets/app/messages-BaizVXcF.js +0 -4
  144. package/dist/assets/app/messages-BaizVXcF.js.map +0 -1
  145. package/dist/assets/app/messages-BfoClA1Y.js +0 -4
  146. package/dist/assets/app/messages-BfoClA1Y.js.map +0 -1
  147. package/dist/assets/app/messages-BsKGDZnC.js +0 -4
  148. package/dist/assets/app/messages-BsKGDZnC.js.map +0 -1
  149. package/dist/assets/app/messages-Bu-TJhml.js +0 -4
  150. package/dist/assets/app/messages-Bu-TJhml.js.map +0 -1
  151. package/dist/assets/app/messages-BvOKnBQk.js +0 -4
  152. package/dist/assets/app/messages-BvOKnBQk.js.map +0 -1
  153. package/dist/assets/app/messages-BxDzCiWz.js +0 -4
  154. package/dist/assets/app/messages-BxDzCiWz.js.map +0 -1
  155. package/dist/assets/app/messages-CDgFOy4S.js +0 -4
  156. package/dist/assets/app/messages-CDgFOy4S.js.map +0 -1
  157. package/dist/assets/app/messages-CLbTz0o9.js +0 -4
  158. package/dist/assets/app/messages-CLbTz0o9.js.map +0 -1
  159. package/dist/assets/app/messages-CNwSh0t7.js +0 -4
  160. package/dist/assets/app/messages-CNwSh0t7.js.map +0 -1
  161. package/dist/assets/app/messages-CSMNJ6P8.js +0 -4
  162. package/dist/assets/app/messages-CSMNJ6P8.js.map +0 -1
  163. package/dist/assets/app/messages-CZQUw3mp.js +0 -4
  164. package/dist/assets/app/messages-CZQUw3mp.js.map +0 -1
  165. package/dist/assets/app/messages-CZT41oVp.js +0 -4
  166. package/dist/assets/app/messages-CZT41oVp.js.map +0 -1
  167. package/dist/assets/app/messages-C_b-d3t8.js +0 -4
  168. package/dist/assets/app/messages-C_b-d3t8.js.map +0 -1
  169. package/dist/assets/app/messages-C_u3MTc2.js +0 -4
  170. package/dist/assets/app/messages-C_u3MTc2.js.map +0 -1
  171. package/dist/assets/app/messages-Cn8nHZic.js +0 -4
  172. package/dist/assets/app/messages-Cn8nHZic.js.map +0 -1
  173. package/dist/assets/app/messages-CtDywJUm.js +0 -4
  174. package/dist/assets/app/messages-CtDywJUm.js.map +0 -1
  175. package/dist/assets/app/messages-CurtIjBF.js +0 -4
  176. package/dist/assets/app/messages-CurtIjBF.js.map +0 -1
  177. package/dist/assets/app/messages-Cv6zIbaP.js +0 -4
  178. package/dist/assets/app/messages-Cv6zIbaP.js.map +0 -1
  179. package/dist/assets/app/messages-D1eLQuPE.js +0 -4
  180. package/dist/assets/app/messages-D1eLQuPE.js.map +0 -1
  181. package/dist/assets/app/messages-D8vHEaYW.js +0 -4
  182. package/dist/assets/app/messages-D8vHEaYW.js.map +0 -1
  183. package/dist/assets/app/messages-DJ1Q4GeC.js +0 -4
  184. package/dist/assets/app/messages-DJ1Q4GeC.js.map +0 -1
  185. package/dist/assets/app/messages-DRL3exqd.js +0 -4
  186. package/dist/assets/app/messages-DRL3exqd.js.map +0 -1
  187. package/dist/assets/app/messages-DWLPQRTp.js +0 -4
  188. package/dist/assets/app/messages-DWLPQRTp.js.map +0 -1
  189. package/dist/assets/app/messages-DjVaE9YE.js +0 -4
  190. package/dist/assets/app/messages-DjVaE9YE.js.map +0 -1
  191. package/dist/assets/app/messages-DqpMfFJR.js +0 -4
  192. package/dist/assets/app/messages-DqpMfFJR.js.map +0 -1
  193. package/dist/assets/app/messages-ETjhJBEN.js +0 -4
  194. package/dist/assets/app/messages-ETjhJBEN.js.map +0 -1
  195. package/dist/assets/app/messages-EUKrgrGn.js +0 -4
  196. package/dist/assets/app/messages-EUKrgrGn.js.map +0 -1
  197. package/dist/assets/app/messages-QQrOUcPW.js +0 -4
  198. package/dist/assets/app/messages-QQrOUcPW.js.map +0 -1
  199. package/dist/assets/app/messages-e2QGqFL6.js +0 -4
  200. package/dist/assets/app/messages-e2QGqFL6.js.map +0 -1
  201. package/dist/assets/app/messages-p61py7gD.js +0 -4
  202. package/dist/assets/app/messages-p61py7gD.js.map +0 -1
  203. package/dist/assets/asset.d.ts +0 -9
  204. package/dist/assets/asset.d.ts.map +0 -1
  205. package/dist/assets/asset.js +0 -3
  206. package/dist/assets/asset.js.map +0 -1
  207. package/dist/assets/index.d.ts +0 -5
  208. package/dist/assets/index.d.ts.map +0 -1
  209. package/dist/assets/index.js +0 -78
  210. package/dist/assets/index.js.map +0 -1
  211. package/rollup.config.js +0 -98
  212. package/src/assets/app/app.tsx +0 -43
  213. package/src/assets/app/backend-data.ts +0 -27
  214. package/src/assets/app/backend-types.ts +0 -66
  215. package/src/assets/app/components/forms/button-toggle-visibility.tsx +0 -43
  216. package/src/assets/app/components/forms/button.tsx +0 -60
  217. package/src/assets/app/components/forms/fieldset.tsx +0 -55
  218. package/src/assets/app/components/forms/form-card-async.tsx +0 -103
  219. package/src/assets/app/components/forms/form-card.tsx +0 -49
  220. package/src/assets/app/components/forms/input-checkbox.tsx +0 -73
  221. package/src/assets/app/components/forms/input-container.tsx +0 -107
  222. package/src/assets/app/components/forms/input-email-address.tsx +0 -66
  223. package/src/assets/app/components/forms/input-new-password.tsx +0 -62
  224. package/src/assets/app/components/forms/input-password.tsx +0 -88
  225. package/src/assets/app/components/forms/input-text.tsx +0 -76
  226. package/src/assets/app/components/forms/input-token.tsx +0 -94
  227. package/src/assets/app/components/forms/wizard-card.tsx +0 -116
  228. package/src/assets/app/components/layouts/layout-title-page.tsx +0 -77
  229. package/src/assets/app/components/layouts/layout-welcome.tsx +0 -73
  230. package/src/assets/app/components/utils/account-identifier.tsx +0 -23
  231. package/src/assets/app/components/utils/account-image.tsx +0 -33
  232. package/src/assets/app/components/utils/admonition.tsx +0 -52
  233. package/src/assets/app/components/utils/client-name.tsx +0 -45
  234. package/src/assets/app/components/utils/error-card.tsx +0 -93
  235. package/src/assets/app/components/utils/error-message.tsx +0 -62
  236. package/src/assets/app/components/utils/help-card.tsx +0 -46
  237. package/src/assets/app/components/utils/icons.tsx +0 -88
  238. package/src/assets/app/components/utils/link-anchor.tsx +0 -28
  239. package/src/assets/app/components/utils/link-title.tsx +0 -26
  240. package/src/assets/app/components/utils/multi-lang-string.tsx +0 -56
  241. package/src/assets/app/components/utils/password-strength-label.tsx +0 -37
  242. package/src/assets/app/components/utils/password-strength-meter.tsx +0 -58
  243. package/src/assets/app/components/utils/url-viewer.tsx +0 -73
  244. package/src/assets/app/cookies.ts +0 -11
  245. package/src/assets/app/hooks/use-api.ts +0 -178
  246. package/src/assets/app/hooks/use-async-action.ts +0 -120
  247. package/src/assets/app/hooks/use-bound-dispatch.ts +0 -5
  248. package/src/assets/app/hooks/use-browser-color-scheme.ts +0 -31
  249. package/src/assets/app/hooks/use-csrf-token.ts +0 -5
  250. package/src/assets/app/hooks/use-random-string.ts +0 -37
  251. package/src/assets/app/hooks/use-stepper.ts +0 -87
  252. package/src/assets/app/index.html +0 -182
  253. package/src/assets/app/lib/api.ts +0 -267
  254. package/src/assets/app/lib/clsx.ts +0 -6
  255. package/src/assets/app/lib/json-client.ts +0 -94
  256. package/src/assets/app/lib/password.ts +0 -98
  257. package/src/assets/app/lib/ref.ts +0 -17
  258. package/src/assets/app/lib/util.ts +0 -13
  259. package/src/assets/app/locales/an/messages.po +0 -492
  260. package/src/assets/app/locales/ast/messages.po +0 -492
  261. package/src/assets/app/locales/ca/messages.po +0 -492
  262. package/src/assets/app/locales/da/messages.po +0 -492
  263. package/src/assets/app/locales/de/messages.po +0 -492
  264. package/src/assets/app/locales/el/messages.po +0 -492
  265. package/src/assets/app/locales/en/messages.po +0 -492
  266. package/src/assets/app/locales/en-GB/messages.po +0 -492
  267. package/src/assets/app/locales/es/messages.po +0 -492
  268. package/src/assets/app/locales/eu/messages.po +0 -492
  269. package/src/assets/app/locales/fi/messages.po +0 -492
  270. package/src/assets/app/locales/fr/messages.po +0 -492
  271. package/src/assets/app/locales/ga/messages.po +0 -492
  272. package/src/assets/app/locales/gl/messages.po +0 -492
  273. package/src/assets/app/locales/hi/messages.po +0 -492
  274. package/src/assets/app/locales/hu/messages.po +0 -492
  275. package/src/assets/app/locales/ia/messages.po +0 -492
  276. package/src/assets/app/locales/id/messages.po +0 -492
  277. package/src/assets/app/locales/it/messages.po +0 -492
  278. package/src/assets/app/locales/ja/messages.po +0 -492
  279. package/src/assets/app/locales/km/messages.po +0 -492
  280. package/src/assets/app/locales/ko/messages.po +0 -492
  281. package/src/assets/app/locales/load.ts +0 -8
  282. package/src/assets/app/locales/locale-context.ts +0 -19
  283. package/src/assets/app/locales/locale-provider.tsx +0 -112
  284. package/src/assets/app/locales/locale-selector.tsx +0 -58
  285. package/src/assets/app/locales/locales.ts +0 -168
  286. package/src/assets/app/locales/ne/messages.po +0 -492
  287. package/src/assets/app/locales/nl/messages.po +0 -492
  288. package/src/assets/app/locales/pl/messages.po +0 -492
  289. package/src/assets/app/locales/pt-BR/messages.po +0 -492
  290. package/src/assets/app/locales/ro/messages.po +0 -492
  291. package/src/assets/app/locales/ru/messages.po +0 -492
  292. package/src/assets/app/locales/sv/messages.po +0 -492
  293. package/src/assets/app/locales/th/messages.po +0 -492
  294. package/src/assets/app/locales/tr/messages.po +0 -492
  295. package/src/assets/app/locales/uk/messages.po +0 -492
  296. package/src/assets/app/locales/vi/messages.po +0 -492
  297. package/src/assets/app/locales/zh-CN/messages.po +0 -492
  298. package/src/assets/app/locales/zh-HK/messages.po +0 -492
  299. package/src/assets/app/locales/zh-TW/messages.po +0 -492
  300. package/src/assets/app/main.css +0 -33
  301. package/src/assets/app/main.tsx +0 -44
  302. package/src/assets/app/views/authorize/accept/accept-form.tsx +0 -150
  303. package/src/assets/app/views/authorize/accept/accept-view.tsx +0 -70
  304. package/src/assets/app/views/authorize/authorize-view.tsx +0 -180
  305. package/src/assets/app/views/authorize/reset-password/reset-password-confirm-form.tsx +0 -88
  306. package/src/assets/app/views/authorize/reset-password/reset-password-request-form.tsx +0 -80
  307. package/src/assets/app/views/authorize/reset-password/reset-password-view.tsx +0 -127
  308. package/src/assets/app/views/authorize/sign-in/sign-in-form.tsx +0 -244
  309. package/src/assets/app/views/authorize/sign-in/sign-in-picker.tsx +0 -116
  310. package/src/assets/app/views/authorize/sign-in/sign-in-view.tsx +0 -145
  311. package/src/assets/app/views/authorize/sign-up/sign-up-account-form.tsx +0 -140
  312. package/src/assets/app/views/authorize/sign-up/sign-up-disclaimer.tsx +0 -51
  313. package/src/assets/app/views/authorize/sign-up/sign-up-handle-form.tsx +0 -289
  314. package/src/assets/app/views/authorize/sign-up/sign-up-hcaptcha-form.tsx +0 -108
  315. package/src/assets/app/views/authorize/sign-up/sign-up-view.tsx +0 -158
  316. package/src/assets/app/views/authorize/welcome/welcome-view.tsx +0 -56
  317. package/src/assets/app/views/error/error-view.tsx +0 -31
  318. package/src/assets/asset.ts +0 -9
  319. package/src/assets/index.ts +0 -86
  320. package/tailwind.config.js +0 -31
  321. package/tsconfig.frontend.json +0 -11
  322. package/tsconfig.frontend.tsbuildinfo +0 -1
  323. package/tsconfig.tools.json +0 -8
  324. package/tsconfig.tools.tsbuildinfo +0 -1
  325. package/vite.config.mjs +0 -16
@@ -1,107 +0,0 @@
1
- import { JSX, ReactNode, useState } from 'react'
2
- import { clsx } from '../../lib/clsx.ts'
3
- import { Override } from '../../lib/util.ts'
4
-
5
- export type InputContainerProps = Override<
6
- JSX.IntrinsicElements['div'],
7
- {
8
- icon: ReactNode
9
- append?: ReactNode
10
- bellow?: ReactNode
11
- }
12
- >
13
-
14
- export function InputContainer({
15
- icon,
16
- append,
17
- bellow,
18
-
19
- // div
20
- className,
21
- children,
22
- onFocus,
23
- onBlur,
24
- ...props
25
- }: InputContainerProps) {
26
- const [hasFocus, setHasFocus] = useState(false)
27
-
28
- return (
29
- <div
30
- {...props}
31
- onFocus={(event) => {
32
- onFocus?.(event)
33
- if (!event.defaultPrevented) setHasFocus(true)
34
- }}
35
- onBlur={(event) => {
36
- onBlur?.(event)
37
- if (!event.defaultPrevented) setHasFocus(false)
38
- }}
39
- className={clsx(
40
- // Layout
41
- 'min-h-12',
42
- 'max-w-full',
43
- 'overflow-hidden',
44
- // Border
45
- 'rounded-lg',
46
- className,
47
- )}
48
- >
49
- <div
50
- className={clsx(
51
- // Layout
52
- 'px-1',
53
- 'w-full min-h-12',
54
- 'flex items-center justify-stretch',
55
- // Border
56
- 'rounded-lg',
57
- bellow ? 'rounded-br-none rounded-bl-none' : undefined,
58
- 'outline-none',
59
- 'border-solid border-2 border-transparent',
60
- 'focus:border-brand has-[:focus]:border-brand',
61
- 'hover:border-gray-400 hover:focus:border-gray-400',
62
- 'dark:hover:border-gray-500 dark:hover:focus:border-gray-500',
63
- // Background
64
- 'bg-gray-100 focus:bg-slate-200 has-[:focus]:bg-slate-200',
65
- 'dark:bg-slate-800 dark:focus:bg-slate-700 dark:has-[:focus]:bg-slate-700',
66
- // Font
67
- 'text-slate-600 dark:text-slate-300',
68
- 'accent-brand',
69
- )}
70
- >
71
- {icon && (
72
- <div
73
- className={clsx(
74
- 'shrink-0 grow-0',
75
- 'mx-1',
76
- hasFocus ? 'text-brand' : 'text-slate-500',
77
- )}
78
- >
79
- {icon}
80
- </div>
81
- )}
82
-
83
- {children}
84
-
85
- <div className="ml-1 grow-0 shrink-0 flex items-center">{append}</div>
86
- </div>
87
- {bellow && (
88
- <div
89
- className={clsx(
90
- // Layout
91
- 'px-3 py-2 space-x-2',
92
- 'flex flex-row items-center gap-1',
93
- // Border
94
- 'rounded-br-2 rounded-bl-2',
95
- // Background
96
- 'bg-gray-200 dark:bg-slate-700',
97
- // Font
98
- 'text-gray-700 dark:text-gray-300',
99
- 'text-sm italic',
100
- )}
101
- >
102
- {bellow}
103
- </div>
104
- )}
105
- </div>
106
- )
107
- }
@@ -1,66 +0,0 @@
1
- import { useLingui } from '@lingui/react/macro'
2
- import { ChangeEvent, useCallback, useState } from 'react'
3
- import { Override } from '../../lib/util.ts'
4
- import { AtSymbolIcon } from '../utils/icons.tsx'
5
- import { InputText, InputTextProps } from './input-text.tsx'
6
-
7
- export type InputEmailAddressProps = Override<
8
- Omit<InputTextProps, 'type'>,
9
- {
10
- onEmail?: (email: string | undefined) => void
11
- }
12
- >
13
-
14
- export function InputEmailAddress({
15
- onEmail,
16
-
17
- // InputTextProps
18
- autoCapitalize = 'none',
19
- autoComplete = 'email',
20
- autoCorrect = 'off',
21
- dir = 'auto',
22
- icon = <AtSymbolIcon className="w-5" />,
23
- onBlur,
24
- onChange,
25
- pattern = '^[^@]+@[^@]+\\.[^@]+$',
26
- spellCheck = 'false',
27
- value,
28
- defaultValue = value,
29
- ...props
30
- }: InputEmailAddressProps) {
31
- const { t } = useLingui()
32
- const [email, setEmail] = useState<string>(
33
- typeof defaultValue === 'string' ? defaultValue : '',
34
- )
35
-
36
- const doChange = useCallback(
37
- (event: ChangeEvent<HTMLInputElement>) => {
38
- const email = event.target.value.toLowerCase()
39
-
40
- setEmail(email)
41
- onChange?.(event)
42
- onEmail?.(event.target.validity.valid ? email : undefined)
43
- },
44
- [onChange, onEmail],
45
- )
46
-
47
- return (
48
- <InputText
49
- aria-label={t`Email`}
50
- placeholder={t`Email`}
51
- title={t`Email`}
52
- {...props}
53
- type="email"
54
- autoCapitalize={autoCapitalize}
55
- autoCorrect={autoCorrect}
56
- dir={dir}
57
- spellCheck={spellCheck}
58
- icon={icon}
59
- pattern={pattern}
60
- autoComplete={autoComplete}
61
- value={email}
62
- onChange={doChange}
63
- onBlur={onBlur}
64
- />
65
- )
66
- }
@@ -1,62 +0,0 @@
1
- import { useLingui } from '@lingui/react/macro'
2
- import { ChangeEvent, useCallback, useState } from 'react'
3
- import { MIN_PASSWORD_LENGTH } from '../../lib/password.ts'
4
- import { Override } from '../../lib/util.ts'
5
- import { PasswordStrengthLabel } from '../utils/password-strength-label.tsx'
6
- import { PasswordStrengthMeter } from '../utils/password-strength-meter.tsx'
7
- import { InputPassword, InputPasswordProps } from './input-password.tsx'
8
-
9
- export type InputNewPasswordProps = Override<
10
- Omit<InputPasswordProps, 'value' | 'defaultValue'>,
11
- {
12
- password?: string
13
- onPassword?: (password: undefined | string) => void
14
- }
15
- >
16
-
17
- export function InputNewPassword({
18
- password: passwordInit = '',
19
- onPassword,
20
-
21
- // InputPasswordProps
22
- onChange,
23
- autoComplete = 'new-password',
24
- minLength = MIN_PASSWORD_LENGTH,
25
- ...props
26
- }: InputNewPasswordProps) {
27
- const { t } = useLingui()
28
- const [password, setPassword] = useState<string>(passwordInit)
29
-
30
- const doChange = useCallback(
31
- (event: ChangeEvent<HTMLInputElement>) => {
32
- const { value } = event.target
33
- onChange?.(event)
34
- if (event.defaultPrevented) return
35
- setPassword(value)
36
- onPassword?.(event.target.validity.valid ? value : undefined)
37
- },
38
- [onChange, onPassword],
39
- )
40
-
41
- return (
42
- <InputPassword
43
- {...props}
44
- placeholder={t`Enter a password`}
45
- aria-label={t`Enter your new password`}
46
- title={t`Password with at least ${MIN_PASSWORD_LENGTH} characters`}
47
- minLength={minLength}
48
- onChange={doChange}
49
- value={password}
50
- autoComplete={autoComplete}
51
- bellow={
52
- <>
53
- <PasswordStrengthMeter password={password} />
54
- <PasswordStrengthLabel
55
- className="grow-1 min-w-max text-xs text-gray-500 dark:text-gray-400"
56
- password={password}
57
- />
58
- </>
59
- }
60
- />
61
- )
62
- }
@@ -1,88 +0,0 @@
1
- import { useLingui } from '@lingui/react/macro'
2
- import { ChangeEvent, useCallback, useRef, useState } from 'react'
3
- import { mergeRefs } from '../../lib/ref.ts'
4
- import { Override } from '../../lib/util.ts'
5
- import { LockIcon } from '../utils/icons.tsx'
6
- import { ButtonToggleVisibility } from './button-toggle-visibility.tsx'
7
- import { InputText, InputTextProps } from './input-text.tsx'
8
-
9
- export type InputPasswordProps = Override<
10
- Omit<InputTextProps, 'type' | 'children'>,
11
- {
12
- autoHide?: boolean
13
- }
14
- >
15
-
16
- export function InputPassword({
17
- autoHide = true,
18
-
19
- // InputTextProps
20
- onBlur,
21
- onChange,
22
- append,
23
- autoComplete = 'current-password',
24
- icon = <LockIcon className="w-5" />,
25
- value,
26
- defaultValue = value,
27
- ref,
28
- dir = 'auto',
29
- autoCapitalize = 'none',
30
- autoCorrect = 'off',
31
- spellCheck = 'false',
32
- ...props
33
- }: InputPasswordProps) {
34
- const { t } = useLingui()
35
- const inputRef = useRef<HTMLInputElement>(null)
36
- const [visible, setVisible] = useState<boolean>(false)
37
- const [password, setPassword] = useState<string>(
38
- typeof defaultValue === 'string' ? defaultValue : '',
39
- )
40
-
41
- const doChange = useCallback(
42
- (event: ChangeEvent<HTMLInputElement>) => {
43
- onChange?.(event)
44
- setPassword(event.target.value)
45
- },
46
- [onChange],
47
- )
48
-
49
- return (
50
- <InputText
51
- placeholder={t`Password`}
52
- aria-label={t`Password`}
53
- title={t`Password`}
54
- {...props}
55
- ref={mergeRefs([ref, inputRef])}
56
- dir={dir}
57
- autoCapitalize={autoCapitalize}
58
- autoCorrect={autoCorrect}
59
- spellCheck={spellCheck}
60
- icon={icon}
61
- onBlur={
62
- autoHide
63
- ? (event) => {
64
- onBlur?.(event)
65
- if (!event.defaultPrevented) setVisible(false)
66
- }
67
- : onBlur
68
- }
69
- value={password}
70
- onChange={doChange}
71
- type={visible ? 'text' : 'password'}
72
- autoComplete={autoComplete}
73
- append={
74
- <>
75
- <ButtonToggleVisibility
76
- className="m-1"
77
- visible={visible}
78
- toggleVisible={() => {
79
- setVisible((prev) => !prev)
80
- inputRef.current?.focus()
81
- }}
82
- />
83
- {append}
84
- </>
85
- }
86
- />
87
- )
88
- }
@@ -1,76 +0,0 @@
1
- import { JSX, ReactNode, useContext, useRef } from 'react'
2
- import { clsx } from '../../lib/clsx.ts'
3
- import { mergeRefs } from '../../lib/ref.ts'
4
- import { Override } from '../../lib/util.ts'
5
- import { FieldsetContext } from './fieldset.tsx'
6
- import { InputContainer } from './input-container.tsx'
7
-
8
- export type InputTextProps = Override<
9
- Omit<JSX.IntrinsicElements['input'], 'children'>,
10
- {
11
- icon?: ReactNode
12
- append?: ReactNode
13
- bellow?: ReactNode
14
- className?: string
15
- }
16
- >
17
-
18
- export function InputText({
19
- icon,
20
- append,
21
- bellow,
22
- className,
23
-
24
- // input
25
- onFocus,
26
- onBlur,
27
- ref,
28
- disabled,
29
- 'aria-labelledby': ariaLabelledBy,
30
- ...props
31
- }: InputTextProps) {
32
- const ctx = useContext(FieldsetContext)
33
-
34
- const inputRef = useRef<HTMLInputElement>(null)
35
- const focusedRef = useRef(false) // ref instead of state to avoid re-renders
36
-
37
- return (
38
- <InputContainer
39
- icon={icon}
40
- append={append}
41
- bellow={bellow}
42
- className={clsx('cursor-text', className)}
43
- tabIndex={-1}
44
- onClick={(event) => {
45
- if (inputRef.current !== event.target) {
46
- event.preventDefault()
47
- event.stopPropagation()
48
- inputRef.current?.focus()
49
- }
50
- }}
51
- onMouseDown={(event) => {
52
- if (focusedRef.current && event.target !== inputRef.current) {
53
- // Prevent "blur" event from firing when clicking outside the input
54
- event.preventDefault()
55
- event.stopPropagation()
56
- }
57
- }}
58
- >
59
- <input
60
- {...props}
61
- disabled={disabled ?? ctx.disabled}
62
- aria-labelledby={ariaLabelledBy ?? ctx.labelId}
63
- ref={mergeRefs([ref, inputRef])}
64
- className="w-full bg-transparent bg-clip-padding text-base text-inherit outline-none dark:placeholder-gray-500 text-ellipsis"
65
- onFocus={(event) => {
66
- onFocus?.(event)
67
- if (!event.defaultPrevented) focusedRef.current = true
68
- }}
69
- onBlur={(event) => {
70
- onBlur?.(event)
71
- if (!event.defaultPrevented) focusedRef.current = false
72
- }}
73
- />
74
- </InputContainer>
75
- )
76
- }
@@ -1,94 +0,0 @@
1
- import { useLingui } from '@lingui/react/macro'
2
- import { ChangeEvent, useState } from 'react'
3
- import { Override } from '../../lib/util.ts'
4
- import { TokenIcon } from '../utils/icons.tsx'
5
- import { InputText, InputTextProps } from './input-text.tsx'
6
-
7
- export type InputTokenProps = Override<
8
- Omit<
9
- InputTextProps,
10
- | 'type'
11
- | 'pattern'
12
- | 'autoCapitalize'
13
- | 'autoCorrect'
14
- | 'autoComplete'
15
- | 'spellCheck'
16
- | 'minLength'
17
- | 'maxLength'
18
- | 'placeholder'
19
- | 'dir'
20
- >,
21
- {
22
- example?: string
23
- onToken?: (code: string | null) => void
24
- }
25
- >
26
-
27
- export const OTP_CODE_EXAMPLE = 'XXXXX-XXXXX'
28
-
29
- export function InputToken({
30
- example = OTP_CODE_EXAMPLE,
31
- onToken,
32
-
33
- // InputTextProps
34
- icon = <TokenIcon className="w-5" />,
35
- title = example,
36
- onChange,
37
- value,
38
- defaultValue = value,
39
- ...props
40
- }: InputTokenProps) {
41
- const { t } = useLingui()
42
- const [token, setToken] = useState<string>(
43
- typeof defaultValue === 'string' ? defaultValue : '',
44
- )
45
-
46
- return (
47
- <InputText
48
- {...props}
49
- type="text"
50
- autoCapitalize="none"
51
- autoCorrect="off"
52
- autoComplete="off"
53
- spellCheck="false"
54
- minLength={11}
55
- maxLength={11}
56
- dir="auto"
57
- icon={icon}
58
- pattern="^[A-Z2-7]{5}-[A-Z2-7]{5}$"
59
- placeholder={t`Looks like ${example}`}
60
- title={title}
61
- value={token}
62
- onChange={(event: ChangeEvent<HTMLInputElement>) => {
63
- const { value, selectionEnd, selectionStart } = event.currentTarget
64
-
65
- const fixedValue = fix(value)
66
-
67
- event.currentTarget.value = fixedValue
68
-
69
- // Move the cursor back where it was relative to the original value
70
- const pos = selectionEnd ?? selectionStart
71
- if (pos != null) {
72
- const fixedSlicedValue = fix(value.slice(0, pos))
73
- event.currentTarget.selectionStart =
74
- event.currentTarget.selectionEnd = fixedSlicedValue.length
75
- }
76
-
77
- setToken(fixedValue)
78
- onChange?.(event)
79
-
80
- if (!event.isDefaultPrevented()) {
81
- onToken?.(fixedValue.length === 11 ? fixedValue : null)
82
- }
83
- }}
84
- />
85
- )
86
- }
87
-
88
- function fix(value: string) {
89
- const normalized = value.toUpperCase().replaceAll(/[^A-Z2-7]/g, '')
90
-
91
- if (normalized.length <= 5) return normalized
92
-
93
- return `${normalized.slice(0, 5)}-${normalized.slice(5, 10)}`
94
- }
@@ -1,116 +0,0 @@
1
- import { Trans } from '@lingui/react/macro'
2
- import { JSX, ReactNode, useCallback } from 'react'
3
- import { DisabledStep, Step, useStepper } from '../../hooks/use-stepper.ts'
4
- import { clsx } from '../../lib/clsx.ts'
5
- import { Override } from '../../lib/util.ts'
6
-
7
- export type DoneFn = (...a: any) => unknown
8
-
9
- export type WizardRenderProps<TDone extends DoneFn> = {
10
- /**
11
- * Indicates wether the render function being invoked corresponds to the step
12
- * currently active. The steps titles could, for example, be rendered in a
13
- * list of links, where the current step is highlighted (based on `current`).
14
- *
15
- * Another use for this is to render the next/previous steps in order to
16
- * provide animated transitions between steps. In this case, `current` would
17
- * be used to disable any form interaction with the form transitioning in/out.
18
- */
19
- current: boolean
20
- invalid: boolean
21
-
22
- prev?: () => void
23
- prevLabel: ReactNode
24
-
25
- // On the last step, the "next()" function will actually be the done function
26
- next: (() => void) | TDone
27
- nextLabel: ReactNode
28
- }
29
-
30
- export type WizardRenderFn<TDone extends DoneFn> = (
31
- data: WizardRenderProps<TDone>,
32
- ) => ReactNode
33
-
34
- export type WizardStep<TDone extends DoneFn> = Step & {
35
- titleRender?: WizardRenderFn<TDone>
36
- contentRender: WizardRenderFn<TDone>
37
- }
38
-
39
- export type WizardCardProps<TDone extends DoneFn> = Override<
40
- Omit<JSX.IntrinsicElements['div'], 'children'>,
41
- {
42
- prevLabel?: ReactNode
43
- nextLabel?: ReactNode
44
-
45
- onBack?: () => void
46
- backLabel?: ReactNode
47
-
48
- onDone: TDone
49
- doneLabel?: ReactNode
50
-
51
- steps: readonly (WizardStep<TDone> | DisabledStep)[]
52
- }
53
- >
54
-
55
- export function WizardCard<TDone extends DoneFn>({
56
- prevLabel,
57
- nextLabel,
58
-
59
- onBack,
60
- backLabel,
61
-
62
- onDone,
63
- doneLabel,
64
-
65
- steps,
66
- className,
67
-
68
- ...props
69
- }: WizardCardProps<TDone>) {
70
- const {
71
- atFirst,
72
- atLast,
73
- count,
74
- current,
75
- currentPosition,
76
- completed,
77
- toNext,
78
- toPrev,
79
- toRequired,
80
- } = useStepper(steps)
81
-
82
- // Memoized to avoid re-renders in child (rendered) components
83
- const onNext = useCallback(() => {
84
- // If already at last step, go to the first incomplete (required) step
85
- if (!toNext()) toRequired()
86
- }, [toNext, toRequired])
87
-
88
- const data: WizardRenderProps<TDone> = {
89
- // The current UI only displays the current title & content.
90
- current: true,
91
- invalid: current ? current.invalid : false,
92
-
93
- prevLabel: (atFirst && backLabel) || prevLabel || <Trans>Back</Trans>,
94
- prev: atFirst ? onBack : toPrev,
95
-
96
- nextLabel: (atLast && doneLabel) || nextLabel || <Trans>Next</Trans>,
97
- next: atLast && completed ? onDone : onNext,
98
- }
99
-
100
- const stepTitle = current?.titleRender?.(data)
101
- const stepContent = current?.contentRender?.(data)
102
-
103
- return (
104
- <div className={clsx(className, 'flex flex-col')} {...props}>
105
- <p className="text-slate-500 dark:text-slate-400">
106
- <Trans>
107
- Step {currentPosition} of {count}
108
- </Trans>
109
- </p>
110
-
111
- {stepTitle && <h2 className="font-medium text-xl mb-4">{stepTitle}</h2>}
112
-
113
- {stepContent}
114
- </div>
115
- )
116
- }
@@ -1,77 +0,0 @@
1
- import { JSX, ReactNode } from 'react'
2
- import { clsx } from '../../lib/clsx.ts'
3
- import { Override } from '../../lib/util.ts'
4
- import { LocaleSelector } from '../../locales/locale-selector.tsx'
5
-
6
- export type LayoutTitlePageProps = Override<
7
- JSX.IntrinsicElements['div'],
8
- {
9
- title?: string
10
- subtitle?: ReactNode
11
- children?: ReactNode
12
- }
13
- >
14
-
15
- export function LayoutTitlePage({
16
- children,
17
- title,
18
- subtitle,
19
-
20
- // HTMLDivElement
21
- className,
22
- ...props
23
- }: LayoutTitlePageProps) {
24
- return (
25
- <div
26
- {...props}
27
- className={clsx(
28
- className,
29
- 'flex flex-col items-center',
30
- 'md:flex md:flex-row md:justify-stretch md:items-center',
31
- 'min-h-screen min-w-screen',
32
- 'bg-white text-slate-900',
33
- 'dark:bg-slate-900 dark:text-slate-100',
34
- )}
35
- >
36
- {title && <title>{title}</title>}
37
-
38
- <div
39
- className={clsx(
40
- 'px-6 pt-4',
41
- 'w-full',
42
- 'md:max-w-lg',
43
- 'flex flex-row md:flex-col',
44
- 'md:self-stretch',
45
- 'md:w-1/2 md:max-w-fix md:p-4',
46
- 'md:text-right',
47
- 'md:dark:border-r md:dark:border-slate-700',
48
- 'md:bg-slate-100 md:dark:bg-slate-800',
49
- )}
50
- >
51
- <div className="flex-grow grid content-center md:justify-items-end">
52
- {title && (
53
- <h1
54
- key="title"
55
- className="text-xl md:text-2xl lg:text-5xl md:my-4 font-semibold text-brand"
56
- >
57
- {title}
58
- </h1>
59
- )}
60
-
61
- {subtitle && (
62
- <p
63
- key="subtitle"
64
- className="hidden md:block max-w-xs text-slate-600 dark:text-slate-400"
65
- >
66
- {subtitle}
67
- </p>
68
- )}
69
- </div>
70
-
71
- <LocaleSelector key="localeSelector" className="m-1 md:m-2" />
72
- </div>
73
-
74
- <main className="w-full p-6 md:max-w-3xl md:px-12">{children}</main>
75
- </div>
76
- )
77
- }