@dowel-ui/react 0.4.0 → 0.7.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 (335) hide show
  1. package/README.md +9 -5
  2. package/dist/blocks/admin-dashboard/meta.js +31 -0
  3. package/dist/blocks/admin-dashboard/meta.js.map +1 -0
  4. package/dist/blocks/agent-console/meta.js +27 -0
  5. package/dist/blocks/agent-console/meta.js.map +1 -0
  6. package/dist/blocks/ai-dashboard/meta.js +25 -0
  7. package/dist/blocks/ai-dashboard/meta.js.map +1 -0
  8. package/dist/blocks/ai-workspace/meta.js +33 -0
  9. package/dist/blocks/ai-workspace/meta.js.map +1 -0
  10. package/dist/blocks/analytics/meta.js +24 -0
  11. package/dist/blocks/analytics/meta.js.map +1 -0
  12. package/dist/blocks/billing/meta.js +25 -0
  13. package/dist/blocks/billing/meta.js.map +1 -0
  14. package/dist/blocks/command-center/meta.js +28 -0
  15. package/dist/blocks/command-center/meta.js.map +1 -0
  16. package/dist/blocks/crm/meta.js +32 -0
  17. package/dist/blocks/crm/meta.js.map +1 -0
  18. package/dist/blocks/onboarding/meta.js +23 -0
  19. package/dist/blocks/onboarding/meta.js.map +1 -0
  20. package/dist/components/accordion/accordion.js +1 -1
  21. package/dist/components/accordion/accordion.js.map +1 -1
  22. package/dist/components/activity-feed/activity-feed.js +1 -1
  23. package/dist/components/activity-feed/activity-feed.js.map +1 -1
  24. package/dist/components/ai-agent-plan/ai-agent-plan.js +1 -1
  25. package/dist/components/ai-agent-plan/ai-agent-plan.js.map +1 -1
  26. package/dist/components/ai-extraction-review/ai-extraction-review.d.ts +52 -0
  27. package/dist/components/ai-extraction-review/ai-extraction-review.d.ts.map +1 -0
  28. package/dist/components/ai-extraction-review/ai-extraction-review.js +249 -0
  29. package/dist/components/ai-extraction-review/ai-extraction-review.js.map +1 -0
  30. package/dist/components/ai-extraction-review/extraction-model.d.ts +94 -0
  31. package/dist/components/ai-extraction-review/extraction-model.d.ts.map +1 -0
  32. package/dist/components/ai-extraction-review/extraction-model.js +91 -0
  33. package/dist/components/ai-extraction-review/extraction-model.js.map +1 -0
  34. package/dist/components/ai-extraction-review/index.d.ts +3 -0
  35. package/dist/components/ai-extraction-review/index.js +3 -0
  36. package/dist/components/ai-extraction-review/meta.js +17 -0
  37. package/dist/components/ai-extraction-review/meta.js.map +1 -0
  38. package/dist/components/ai-prompt-input/ai-prompt-input.js +1 -1
  39. package/dist/components/ai-prompt-input/ai-prompt-input.js.map +1 -1
  40. package/dist/components/ai-reasoning/ai-reasoning.js +1 -1
  41. package/dist/components/ai-reasoning/ai-reasoning.js.map +1 -1
  42. package/dist/components/ai-response/ai-response.js +2 -2
  43. package/dist/components/ai-response/ai-response.js.map +1 -1
  44. package/dist/components/ai-suggested-value/ai-suggested-value.d.ts +72 -0
  45. package/dist/components/ai-suggested-value/ai-suggested-value.d.ts.map +1 -0
  46. package/dist/components/ai-suggested-value/ai-suggested-value.js +126 -0
  47. package/dist/components/ai-suggested-value/ai-suggested-value.js.map +1 -0
  48. package/dist/components/ai-suggested-value/index.d.ts +2 -0
  49. package/dist/components/ai-suggested-value/index.js +2 -0
  50. package/dist/components/ai-suggested-value/meta.js +17 -0
  51. package/dist/components/ai-suggested-value/meta.js.map +1 -0
  52. package/dist/components/ai-tool/ai-tool.js +2 -2
  53. package/dist/components/ai-tool/ai-tool.js.map +1 -1
  54. package/dist/components/breadcrumb/breadcrumb.d.ts +52 -0
  55. package/dist/components/breadcrumb/breadcrumb.d.ts.map +1 -0
  56. package/dist/components/breadcrumb/breadcrumb.js +141 -0
  57. package/dist/components/breadcrumb/breadcrumb.js.map +1 -0
  58. package/dist/components/breadcrumb/index.d.ts +2 -0
  59. package/dist/components/breadcrumb/index.js +2 -0
  60. package/dist/components/breadcrumb/meta.js +17 -0
  61. package/dist/components/breadcrumb/meta.js.map +1 -0
  62. package/dist/components/calendar/calendar.js +2 -2
  63. package/dist/components/calendar/calendar.js.map +1 -1
  64. package/dist/components/code-block/code-block.js +1 -1
  65. package/dist/components/code-block/code-block.js.map +1 -1
  66. package/dist/components/collapsible/collapsible.d.ts +30 -0
  67. package/dist/components/collapsible/collapsible.d.ts.map +1 -0
  68. package/dist/components/collapsible/collapsible.js +38 -0
  69. package/dist/components/collapsible/collapsible.js.map +1 -0
  70. package/dist/components/collapsible/index.d.ts +2 -0
  71. package/dist/components/collapsible/index.js +2 -0
  72. package/dist/components/collapsible/meta.js +17 -0
  73. package/dist/components/collapsible/meta.js.map +1 -0
  74. package/dist/components/combobox/combobox.js +2 -2
  75. package/dist/components/combobox/combobox.js.map +1 -1
  76. package/dist/components/command/command.js +1 -1
  77. package/dist/components/command/command.js.map +1 -1
  78. package/dist/components/confirm-typed/confirm-typed.d.ts +47 -0
  79. package/dist/components/confirm-typed/confirm-typed.d.ts.map +1 -0
  80. package/dist/components/confirm-typed/confirm-typed.js +106 -0
  81. package/dist/components/confirm-typed/confirm-typed.js.map +1 -0
  82. package/dist/components/confirm-typed/index.d.ts +2 -0
  83. package/dist/components/confirm-typed/index.js +2 -0
  84. package/dist/components/confirm-typed/meta.js +17 -0
  85. package/dist/components/confirm-typed/meta.js.map +1 -0
  86. package/dist/components/cron-editor/cron-editor.d.ts +36 -0
  87. package/dist/components/cron-editor/cron-editor.d.ts.map +1 -0
  88. package/dist/components/cron-editor/cron-editor.js +493 -0
  89. package/dist/components/cron-editor/cron-editor.js.map +1 -0
  90. package/dist/components/cron-editor/cron-expression.d.ts +82 -0
  91. package/dist/components/cron-editor/cron-expression.d.ts.map +1 -0
  92. package/dist/components/cron-editor/cron-expression.js +352 -0
  93. package/dist/components/cron-editor/cron-expression.js.map +1 -0
  94. package/dist/components/cron-editor/index.d.ts +3 -0
  95. package/dist/components/cron-editor/index.js +3 -0
  96. package/dist/components/cron-editor/meta.js +17 -0
  97. package/dist/components/cron-editor/meta.js.map +1 -0
  98. package/dist/components/data-table/data-table.d.ts.map +1 -1
  99. package/dist/components/data-table/data-table.js +4 -1
  100. package/dist/components/data-table/data-table.js.map +1 -1
  101. package/dist/components/dialog/dialog.js +2 -2
  102. package/dist/components/dialog/dialog.js.map +1 -1
  103. package/dist/components/diff-viewer/diff-viewer.js +4 -4
  104. package/dist/components/diff-viewer/diff-viewer.js.map +1 -1
  105. package/dist/components/direction/direction.d.ts +35 -0
  106. package/dist/components/direction/direction.d.ts.map +1 -0
  107. package/dist/components/direction/direction.js +14 -0
  108. package/dist/components/direction/direction.js.map +1 -0
  109. package/dist/components/direction/index.d.ts +2 -0
  110. package/dist/components/direction/index.js +2 -0
  111. package/dist/components/direction/meta.js +17 -0
  112. package/dist/components/direction/meta.js.map +1 -0
  113. package/dist/components/dns-record/dns-record.d.ts +61 -0
  114. package/dist/components/dns-record/dns-record.d.ts.map +1 -0
  115. package/dist/components/dns-record/dns-record.js +227 -0
  116. package/dist/components/dns-record/dns-record.js.map +1 -0
  117. package/dist/components/dns-record/index.d.ts +2 -0
  118. package/dist/components/dns-record/index.js +2 -0
  119. package/dist/components/dns-record/meta.js +17 -0
  120. package/dist/components/dns-record/meta.js.map +1 -0
  121. package/dist/components/drawer/drawer.js +1 -1
  122. package/dist/components/drawer/drawer.js.map +1 -1
  123. package/dist/components/dropdown-menu/dropdown-menu.d.ts.map +1 -1
  124. package/dist/components/dropdown-menu/dropdown-menu.js +9 -8
  125. package/dist/components/dropdown-menu/dropdown-menu.js.map +1 -1
  126. package/dist/components/input/input.js +1 -1
  127. package/dist/components/input/input.js.map +1 -1
  128. package/dist/components/log-viewer/log-viewer.js +2 -2
  129. package/dist/components/log-viewer/log-viewer.js.map +1 -1
  130. package/dist/components/meter/meter.js +1 -1
  131. package/dist/components/meter/meter.js.map +1 -1
  132. package/dist/components/pagination/pagination.d.ts.map +1 -1
  133. package/dist/components/pagination/pagination.js +3 -2
  134. package/dist/components/pagination/pagination.js.map +1 -1
  135. package/dist/components/permission-matrix/index.d.ts +3 -0
  136. package/dist/components/permission-matrix/index.js +3 -0
  137. package/dist/components/permission-matrix/meta.js +17 -0
  138. package/dist/components/permission-matrix/meta.js.map +1 -0
  139. package/dist/components/permission-matrix/permission-matrix.d.ts +46 -0
  140. package/dist/components/permission-matrix/permission-matrix.d.ts.map +1 -0
  141. package/dist/components/permission-matrix/permission-matrix.js +199 -0
  142. package/dist/components/permission-matrix/permission-matrix.js.map +1 -0
  143. package/dist/components/permission-matrix/permission-model.d.ts +53 -0
  144. package/dist/components/permission-matrix/permission-model.d.ts.map +1 -0
  145. package/dist/components/permission-matrix/permission-model.js +64 -0
  146. package/dist/components/permission-matrix/permission-model.js.map +1 -0
  147. package/dist/components/record-diff/record-diff.js +4 -4
  148. package/dist/components/record-diff/record-diff.js.map +1 -1
  149. package/dist/components/secret-field/index.d.ts +2 -0
  150. package/dist/components/secret-field/index.js +2 -0
  151. package/dist/components/secret-field/meta.js +17 -0
  152. package/dist/components/secret-field/meta.js.map +1 -0
  153. package/dist/components/secret-field/secret-field.d.ts +58 -0
  154. package/dist/components/secret-field/secret-field.d.ts.map +1 -0
  155. package/dist/components/secret-field/secret-field.js +168 -0
  156. package/dist/components/secret-field/secret-field.js.map +1 -0
  157. package/dist/components/select/select.js +2 -2
  158. package/dist/components/select/select.js.map +1 -1
  159. package/dist/components/session-expiry/index.d.ts +2 -0
  160. package/dist/components/session-expiry/index.js +2 -0
  161. package/dist/components/session-expiry/meta.js +17 -0
  162. package/dist/components/session-expiry/meta.js.map +1 -0
  163. package/dist/components/session-expiry/session-expiry.d.ts +64 -0
  164. package/dist/components/session-expiry/session-expiry.d.ts.map +1 -0
  165. package/dist/components/session-expiry/session-expiry.js +185 -0
  166. package/dist/components/session-expiry/session-expiry.js.map +1 -0
  167. package/dist/components/sheet/sheet.d.ts.map +1 -1
  168. package/dist/components/sheet/sheet.js +2 -2
  169. package/dist/components/sheet/sheet.js.map +1 -1
  170. package/dist/components/shortcut-recorder/index.d.ts +3 -0
  171. package/dist/components/shortcut-recorder/index.js +3 -0
  172. package/dist/components/shortcut-recorder/meta.js +17 -0
  173. package/dist/components/shortcut-recorder/meta.js.map +1 -0
  174. package/dist/components/shortcut-recorder/shortcut-model.d.ts +67 -0
  175. package/dist/components/shortcut-recorder/shortcut-model.d.ts.map +1 -0
  176. package/dist/components/shortcut-recorder/shortcut-model.js +168 -0
  177. package/dist/components/shortcut-recorder/shortcut-model.js.map +1 -0
  178. package/dist/components/shortcut-recorder/shortcut-recorder.d.ts +47 -0
  179. package/dist/components/shortcut-recorder/shortcut-recorder.d.ts.map +1 -0
  180. package/dist/components/shortcut-recorder/shortcut-recorder.js +212 -0
  181. package/dist/components/shortcut-recorder/shortcut-recorder.js.map +1 -0
  182. package/dist/components/sidebar/index.d.ts +2 -0
  183. package/dist/components/sidebar/index.js +2 -0
  184. package/dist/components/sidebar/meta.js +17 -0
  185. package/dist/components/sidebar/meta.js.map +1 -0
  186. package/dist/components/sidebar/sidebar.d.ts +69 -0
  187. package/dist/components/sidebar/sidebar.d.ts.map +1 -0
  188. package/dist/components/sidebar/sidebar.js +256 -0
  189. package/dist/components/sidebar/sidebar.js.map +1 -0
  190. package/dist/components/sync-status/index.d.ts +2 -0
  191. package/dist/components/sync-status/index.js +2 -0
  192. package/dist/components/sync-status/meta.js +17 -0
  193. package/dist/components/sync-status/meta.js.map +1 -0
  194. package/dist/components/sync-status/sync-status.d.ts +65 -0
  195. package/dist/components/sync-status/sync-status.d.ts.map +1 -0
  196. package/dist/components/sync-status/sync-status.js +103 -0
  197. package/dist/components/sync-status/sync-status.js.map +1 -0
  198. package/dist/components/table/table.js +2 -2
  199. package/dist/components/table/table.js.map +1 -1
  200. package/dist/components/tags-input/tags-input.js +1 -1
  201. package/dist/components/tags-input/tags-input.js.map +1 -1
  202. package/dist/components/textarea/index.d.ts +2 -0
  203. package/dist/components/textarea/index.js +2 -0
  204. package/dist/components/textarea/meta.js +17 -0
  205. package/dist/components/textarea/meta.js.map +1 -0
  206. package/dist/components/textarea/textarea.d.ts +43 -0
  207. package/dist/components/textarea/textarea.d.ts.map +1 -0
  208. package/dist/components/textarea/textarea.js +119 -0
  209. package/dist/components/textarea/textarea.js.map +1 -0
  210. package/dist/components/time-range-picker/time-range-picker.js +3 -3
  211. package/dist/components/time-range-picker/time-range-picker.js.map +1 -1
  212. package/dist/components/toast/toast.d.ts.map +1 -1
  213. package/dist/components/toast/toast.js +2 -2
  214. package/dist/components/toast/toast.js.map +1 -1
  215. package/dist/index.d.ts +36 -2
  216. package/dist/index.js +22 -3
  217. package/dist/lib/styles.d.ts +16 -1
  218. package/dist/lib/styles.d.ts.map +1 -1
  219. package/dist/lib/styles.js +16 -1
  220. package/dist/lib/styles.js.map +1 -1
  221. package/dist/registry/blocks.d.ts.map +1 -1
  222. package/dist/registry/blocks.js +27 -9
  223. package/dist/registry/blocks.js.map +1 -1
  224. package/dist/registry/components.d.ts.map +1 -1
  225. package/dist/registry/components.js +84 -54
  226. package/dist/registry/components.js.map +1 -1
  227. package/dist/registry/schema.d.ts +8 -0
  228. package/dist/registry/schema.d.ts.map +1 -1
  229. package/dist/registry/schema.js.map +1 -1
  230. package/package.json +5 -4
  231. package/src/components/accordion/accordion.tsx +1 -1
  232. package/src/components/activity-feed/activity-feed.tsx +1 -1
  233. package/src/components/ai-agent-plan/ai-agent-plan.tsx +0 -0
  234. package/src/components/ai-extraction-review/ai-extraction-review.tsx +492 -0
  235. package/src/components/ai-extraction-review/extraction-model.ts +159 -0
  236. package/src/components/ai-extraction-review/index.ts +13 -0
  237. package/src/components/ai-extraction-review/meta.ts +24 -0
  238. package/src/components/ai-prompt-input/ai-prompt-input.tsx +1 -1
  239. package/src/components/ai-reasoning/ai-reasoning.tsx +1 -1
  240. package/src/components/ai-response/ai-response.tsx +2 -2
  241. package/src/components/ai-suggested-value/ai-suggested-value.tsx +295 -0
  242. package/src/components/ai-suggested-value/index.ts +6 -0
  243. package/src/components/ai-suggested-value/meta.ts +24 -0
  244. package/src/components/ai-tool/ai-tool.tsx +2 -2
  245. package/src/components/breadcrumb/breadcrumb.tsx +157 -0
  246. package/src/components/breadcrumb/index.ts +10 -0
  247. package/src/components/breadcrumb/meta.ts +19 -0
  248. package/src/components/calendar/calendar.tsx +2 -2
  249. package/src/components/code-block/code-block.tsx +1 -1
  250. package/src/components/collapsible/collapsible.tsx +63 -0
  251. package/src/components/collapsible/index.ts +6 -0
  252. package/src/components/collapsible/meta.ts +16 -0
  253. package/src/components/combobox/combobox.tsx +2 -2
  254. package/src/components/command/command.tsx +1 -1
  255. package/src/components/confirm-typed/confirm-typed.tsx +191 -0
  256. package/src/components/confirm-typed/index.ts +1 -0
  257. package/src/components/confirm-typed/meta.ts +22 -0
  258. package/src/components/cron-editor/cron-editor.tsx +676 -0
  259. package/src/components/cron-editor/cron-expression.ts +552 -0
  260. package/src/components/cron-editor/index.ts +23 -0
  261. package/src/components/cron-editor/meta.ts +23 -0
  262. package/src/components/data-table/data-table.tsx +14 -3
  263. package/src/components/dialog/dialog.tsx +2 -2
  264. package/src/components/diff-viewer/diff-viewer.tsx +4 -4
  265. package/src/components/direction/direction.tsx +38 -0
  266. package/src/components/direction/index.ts +1 -0
  267. package/src/components/direction/meta.ts +19 -0
  268. package/src/components/dns-record/dns-record.tsx +315 -0
  269. package/src/components/dns-record/index.ts +7 -0
  270. package/src/components/dns-record/meta.ts +21 -0
  271. package/src/components/drawer/drawer.tsx +1 -1
  272. package/src/components/dropdown-menu/dropdown-menu.tsx +14 -8
  273. package/src/components/input/input.tsx +1 -1
  274. package/src/components/log-viewer/log-viewer.tsx +2 -2
  275. package/src/components/meter/meter.tsx +1 -1
  276. package/src/components/pagination/pagination.tsx +13 -2
  277. package/src/components/permission-matrix/index.ts +14 -0
  278. package/src/components/permission-matrix/meta.ts +23 -0
  279. package/src/components/permission-matrix/permission-matrix.tsx +368 -0
  280. package/src/components/permission-matrix/permission-model.ts +120 -0
  281. package/src/components/record-diff/record-diff.tsx +4 -4
  282. package/src/components/secret-field/index.ts +6 -0
  283. package/src/components/secret-field/meta.ts +21 -0
  284. package/src/components/secret-field/secret-field.tsx +284 -0
  285. package/src/components/select/select.tsx +2 -2
  286. package/src/components/session-expiry/index.ts +9 -0
  287. package/src/components/session-expiry/meta.ts +23 -0
  288. package/src/components/session-expiry/session-expiry.tsx +321 -0
  289. package/src/components/sheet/sheet.tsx +8 -4
  290. package/src/components/shortcut-recorder/index.ts +19 -0
  291. package/src/components/shortcut-recorder/meta.ts +22 -0
  292. package/src/components/shortcut-recorder/shortcut-model.ts +204 -0
  293. package/src/components/shortcut-recorder/shortcut-recorder.tsx +336 -0
  294. package/src/components/sidebar/index.ts +19 -0
  295. package/src/components/sidebar/meta.ts +25 -0
  296. package/src/components/sidebar/sidebar.tsx +374 -0
  297. package/src/components/sync-status/index.ts +9 -0
  298. package/src/components/sync-status/meta.ts +21 -0
  299. package/src/components/sync-status/sync-status.tsx +217 -0
  300. package/src/components/table/table.tsx +3 -3
  301. package/src/components/tags-input/tags-input.tsx +1 -1
  302. package/src/components/textarea/index.ts +1 -0
  303. package/src/components/textarea/meta.ts +21 -0
  304. package/src/components/textarea/textarea.tsx +210 -0
  305. package/src/components/time-range-picker/time-range-picker.tsx +3 -3
  306. package/src/components/toast/toast.tsx +14 -6
  307. package/src/index.ts +15 -0
  308. package/src/lib/styles.ts +16 -0
  309. package/src/registry/blocks.ts +18 -0
  310. package/src/registry/components.ts +30 -0
  311. package/src/registry/schema.ts +8 -0
  312. package/src/blocks/admin-users/admin-users.tsx +0 -251
  313. package/src/blocks/admin-users/index.ts +0 -1
  314. package/src/blocks/admin-users/meta.ts +0 -27
  315. package/src/blocks/ai-chat/ai-chat.tsx +0 -280
  316. package/src/blocks/ai-chat/index.ts +0 -7
  317. package/src/blocks/ai-chat/meta.ts +0 -32
  318. package/src/blocks/dashboard/dashboard.tsx +0 -192
  319. package/src/blocks/dashboard/index.ts +0 -6
  320. package/src/blocks/dashboard/meta.ts +0 -18
  321. package/src/blocks/forgot-password/forgot-password.tsx +0 -158
  322. package/src/blocks/forgot-password/index.ts +0 -1
  323. package/src/blocks/forgot-password/meta.ts +0 -18
  324. package/src/blocks/login/index.ts +0 -1
  325. package/src/blocks/login/login.tsx +0 -178
  326. package/src/blocks/login/meta.ts +0 -18
  327. package/src/blocks/pricing/index.ts +0 -1
  328. package/src/blocks/pricing/meta.ts +0 -18
  329. package/src/blocks/pricing/pricing.tsx +0 -176
  330. package/src/blocks/settings/index.ts +0 -6
  331. package/src/blocks/settings/meta.ts +0 -29
  332. package/src/blocks/settings/settings.tsx +0 -317
  333. package/src/blocks/signup/index.ts +0 -1
  334. package/src/blocks/signup/meta.ts +0 -18
  335. package/src/blocks/signup/signup.tsx +0 -240
@@ -1,240 +0,0 @@
1
- "use client";
2
-
3
- import { useState, type FormEvent } from "react";
4
-
5
- import { Button } from "@/components/button";
6
- import {
7
- Card,
8
- CardContent,
9
- CardDescription,
10
- CardFooter,
11
- CardHeader,
12
- CardTitle,
13
- } from "@/components/card";
14
- import { Checkbox } from "@/components/checkbox";
15
- import {
16
- Form,
17
- FormControl,
18
- FormDescription,
19
- FormField,
20
- FormLabel,
21
- FormMessage,
22
- } from "@/components/form";
23
- import { Input } from "@/components/input";
24
- import { Progress } from "@/components/progress";
25
- import { cn } from "@/lib/utils";
26
-
27
- /**
28
- * An account creation form.
29
- *
30
- * The password strength meter is the interesting part. It is a hint, not a
31
- * gate: the requirement is a length minimum, and the meter tells people how
32
- * they are doing without inventing rules about symbols that push everyone
33
- * towards the same predictable substitutions.
34
- */
35
-
36
- export interface SignupBlockProps {
37
- onSubmit?: (values: { name: string; email: string; password: string }) => void;
38
- error?: string;
39
- pending?: boolean;
40
- loginHref?: string;
41
- /** Minimum password length. Length is the requirement that actually helps. */
42
- minPasswordLength?: number;
43
- className?: string;
44
- }
45
-
46
- interface Strength {
47
- score: number;
48
- label: string;
49
- tone: "destructive" | "warning" | "success";
50
- }
51
-
52
- /**
53
- * A rough strength estimate.
54
- *
55
- * Deliberately crude, and deliberately not a validation rule. Its only job is
56
- * to nudge; the form is gated on length alone.
57
- */
58
- export function estimatePasswordStrength(password: string, minLength: number): Strength {
59
- if (password.length === 0)
60
- return { score: 0, label: "Enter a password", tone: "destructive" };
61
-
62
- let score = Math.min(60, (password.length / (minLength * 2)) * 60);
63
- if (/[a-z]/.test(password) && /[A-Z]/.test(password)) score += 15;
64
- if (/\d/.test(password)) score += 10;
65
- if (/[^\w\s]/.test(password)) score += 15;
66
-
67
- const rounded = Math.min(100, Math.round(score));
68
- if (password.length < minLength)
69
- return { score: rounded, label: "Too short", tone: "destructive" };
70
- if (rounded < 60) return { score: rounded, label: "Weak", tone: "warning" };
71
- if (rounded < 85) return { score: rounded, label: "Good", tone: "success" };
72
- return { score: rounded, label: "Strong", tone: "success" };
73
- }
74
-
75
- export function SignupBlock({
76
- onSubmit,
77
- error,
78
- pending = false,
79
- loginHref = "/login",
80
- minPasswordLength = 12,
81
- className,
82
- }: SignupBlockProps) {
83
- const [name, setName] = useState("");
84
- const [email, setEmail] = useState("");
85
- const [password, setPassword] = useState("");
86
- const [accepted, setAccepted] = useState(false);
87
- const [touched, setTouched] = useState(false);
88
-
89
- const strength = estimatePasswordStrength(password, minPasswordLength);
90
- const emailError =
91
- touched && !email.includes("@") ? "Enter a valid email address." : undefined;
92
- const passwordError =
93
- touched && password.length < minPasswordLength
94
- ? `Use at least ${String(minPasswordLength)} characters.`
95
- : undefined;
96
- const termsError = touched && !accepted ? "Accept the terms to continue." : undefined;
97
-
98
- function handleSubmit(event: FormEvent<HTMLFormElement>) {
99
- event.preventDefault();
100
- setTouched(true);
101
- if (!email.includes("@") || password.length < minPasswordLength || !accepted) return;
102
- onSubmit?.({ name, email, password });
103
- }
104
-
105
- return (
106
- <Card className={cn("w-full max-w-sm", className)}>
107
- <CardHeader>
108
- <CardTitle>Create an account</CardTitle>
109
- <CardDescription>Start building in a couple of minutes.</CardDescription>
110
- </CardHeader>
111
-
112
- <CardContent>
113
- <Form onSubmit={handleSubmit} className="gap-4">
114
- {error ? (
115
- <p role="alert" className="text-sm font-medium text-destructive">
116
- {error}
117
- </p>
118
- ) : null}
119
-
120
- <FormField name="name">
121
- <FormLabel>Name</FormLabel>
122
- <FormControl>
123
- <Input
124
- autoComplete="name"
125
- placeholder="Ada Lovelace"
126
- value={name}
127
- disabled={pending}
128
- onChange={(event) => {
129
- setName(event.target.value);
130
- }}
131
- />
132
- </FormControl>
133
- </FormField>
134
-
135
- <FormField name="email" error={emailError}>
136
- <FormLabel>Email</FormLabel>
137
- <FormControl>
138
- <Input
139
- type="email"
140
- autoComplete="email"
141
- placeholder="you@example.com"
142
- value={email}
143
- disabled={pending}
144
- onChange={(event) => {
145
- setEmail(event.target.value);
146
- }}
147
- />
148
- </FormControl>
149
- <FormMessage />
150
- </FormField>
151
-
152
- <FormField name="password" error={passwordError}>
153
- <FormLabel>Password</FormLabel>
154
- <FormControl>
155
- <Input
156
- type="password"
157
- autoComplete="new-password"
158
- value={password}
159
- disabled={pending}
160
- onChange={(event) => {
161
- setPassword(event.target.value);
162
- }}
163
- />
164
- </FormControl>
165
- <FormDescription>At least {minPasswordLength} characters.</FormDescription>
166
- <FormMessage />
167
- </FormField>
168
-
169
- {password.length > 0 ? (
170
- <div className="grid gap-1.5">
171
- <div className="flex items-center justify-between text-xs">
172
- <span className="text-muted-foreground">Password strength</span>
173
- <span
174
- className={cn(
175
- strength.tone === "success"
176
- ? "text-success"
177
- : strength.tone === "warning"
178
- ? "text-warning"
179
- : "text-destructive",
180
- )}
181
- >
182
- {strength.label}
183
- </span>
184
- </div>
185
- {/* The label above already says the strength, so the bar is a
186
- summary rather than a second thing to read. */}
187
- <Progress
188
- value={strength.score}
189
- size="sm"
190
- tone={
191
- strength.tone === "success"
192
- ? "success"
193
- : strength.tone === "warning"
194
- ? "warning"
195
- : "destructive"
196
- }
197
- aria-hidden="true"
198
- />
199
- </div>
200
- ) : null}
201
-
202
- <FormField name="terms" error={termsError}>
203
- <div className="flex items-start gap-2">
204
- <FormControl>
205
- <Checkbox
206
- className="mt-0.5"
207
- checked={accepted}
208
- disabled={pending}
209
- onCheckedChange={(checked) => {
210
- setAccepted(checked === true);
211
- }}
212
- />
213
- </FormControl>
214
- {/* FormLabel, not a Label with a guessed htmlFor: the field
215
- generates the control's id, so anything hard-coded points at
216
- nothing and leaves the checkbox unnamed. */}
217
- <FormLabel className="text-sm leading-snug font-normal">
218
- I agree to the terms of service and privacy policy.
219
- </FormLabel>
220
- </div>
221
- <FormMessage />
222
- </FormField>
223
-
224
- <Button type="submit" loading={pending} className="w-full">
225
- Create account
226
- </Button>
227
- </Form>
228
- </CardContent>
229
-
230
- <CardFooter className="justify-center">
231
- <p className="text-sm text-muted-foreground">
232
- Already have an account?{" "}
233
- <a href={loginHref} className="font-medium text-primary underline underline-offset-4">
234
- Sign in
235
- </a>
236
- </p>
237
- </CardFooter>
238
- </Card>
239
- );
240
- }