@masmarino/gabarit 2.0.0 → 2.1.1

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 (333) hide show
  1. package/README.md +131 -85
  2. package/accordion/README.md +56 -0
  3. package/alert/README.md +87 -0
  4. package/app-shell/README.md +133 -0
  5. package/auth/README.md +155 -0
  6. package/auth-activate/README.md +119 -0
  7. package/auth-login/README.md +113 -0
  8. package/auth-register/README.md +104 -0
  9. package/auth-reset-password/README.md +120 -0
  10. package/autocomplete/README.md +77 -0
  11. package/avatar/README.md +34 -0
  12. package/avatar-group/README.md +47 -0
  13. package/badge/README.md +177 -0
  14. package/bar-chart/README.md +44 -0
  15. package/breadcrumb/README.md +38 -0
  16. package/button/README.md +175 -0
  17. package/card/README.md +179 -0
  18. package/checkbox/README.md +50 -0
  19. package/checkbox-group/README.md +78 -0
  20. package/confirm-danger-modal/README.md +77 -0
  21. package/copy-button/README.md +90 -0
  22. package/copy-field/README.md +54 -0
  23. package/date-picker/README.md +84 -0
  24. package/description-list/README.md +63 -0
  25. package/dimension-card/README.md +39 -0
  26. package/disclosure/README.md +48 -0
  27. package/divider/README.md +31 -0
  28. package/drawer/README.md +49 -0
  29. package/empty-state/README.md +84 -0
  30. package/fesm2022/masmarino-gabarit-accordion.mjs +243 -0
  31. package/fesm2022/masmarino-gabarit-accordion.mjs.map +1 -0
  32. package/fesm2022/masmarino-gabarit-alert.mjs +208 -0
  33. package/fesm2022/masmarino-gabarit-alert.mjs.map +1 -0
  34. package/fesm2022/masmarino-gabarit-app-shell.mjs +378 -0
  35. package/fesm2022/masmarino-gabarit-app-shell.mjs.map +1 -0
  36. package/fesm2022/masmarino-gabarit-auth-activate.mjs +415 -0
  37. package/fesm2022/masmarino-gabarit-auth-activate.mjs.map +1 -0
  38. package/fesm2022/masmarino-gabarit-auth-login.mjs +467 -0
  39. package/fesm2022/masmarino-gabarit-auth-login.mjs.map +1 -0
  40. package/fesm2022/masmarino-gabarit-auth-register.mjs +457 -0
  41. package/fesm2022/masmarino-gabarit-auth-register.mjs.map +1 -0
  42. package/fesm2022/masmarino-gabarit-auth-reset-password.mjs +364 -0
  43. package/fesm2022/masmarino-gabarit-auth-reset-password.mjs.map +1 -0
  44. package/fesm2022/masmarino-gabarit-auth.mjs +844 -0
  45. package/fesm2022/masmarino-gabarit-auth.mjs.map +1 -0
  46. package/fesm2022/masmarino-gabarit-autocomplete.mjs +475 -0
  47. package/fesm2022/masmarino-gabarit-autocomplete.mjs.map +1 -0
  48. package/fesm2022/masmarino-gabarit-avatar-group.mjs +202 -0
  49. package/fesm2022/masmarino-gabarit-avatar-group.mjs.map +1 -0
  50. package/fesm2022/masmarino-gabarit-avatar.mjs +107 -0
  51. package/fesm2022/masmarino-gabarit-avatar.mjs.map +1 -0
  52. package/fesm2022/masmarino-gabarit-badge.mjs +449 -0
  53. package/fesm2022/masmarino-gabarit-badge.mjs.map +1 -0
  54. package/fesm2022/masmarino-gabarit-bar-chart.mjs +408 -0
  55. package/fesm2022/masmarino-gabarit-bar-chart.mjs.map +1 -0
  56. package/fesm2022/masmarino-gabarit-breadcrumb.mjs +59 -0
  57. package/fesm2022/masmarino-gabarit-breadcrumb.mjs.map +1 -0
  58. package/fesm2022/masmarino-gabarit-button.mjs +374 -0
  59. package/fesm2022/masmarino-gabarit-button.mjs.map +1 -0
  60. package/fesm2022/masmarino-gabarit-card.mjs +400 -0
  61. package/fesm2022/masmarino-gabarit-card.mjs.map +1 -0
  62. package/fesm2022/masmarino-gabarit-chart.mjs +1289 -0
  63. package/fesm2022/masmarino-gabarit-chart.mjs.map +1 -0
  64. package/fesm2022/masmarino-gabarit-checkbox-group.mjs +335 -0
  65. package/fesm2022/masmarino-gabarit-checkbox-group.mjs.map +1 -0
  66. package/fesm2022/masmarino-gabarit-checkbox.mjs +170 -0
  67. package/fesm2022/masmarino-gabarit-checkbox.mjs.map +1 -0
  68. package/fesm2022/masmarino-gabarit-confirm-danger-modal.mjs +387 -0
  69. package/fesm2022/masmarino-gabarit-confirm-danger-modal.mjs.map +1 -0
  70. package/fesm2022/masmarino-gabarit-copy-button.mjs +407 -0
  71. package/fesm2022/masmarino-gabarit-copy-button.mjs.map +1 -0
  72. package/fesm2022/masmarino-gabarit-copy-field.mjs +229 -0
  73. package/fesm2022/masmarino-gabarit-copy-field.mjs.map +1 -0
  74. package/fesm2022/masmarino-gabarit-date-picker.mjs +1242 -0
  75. package/fesm2022/masmarino-gabarit-date-picker.mjs.map +1 -0
  76. package/fesm2022/masmarino-gabarit-description-list.mjs +127 -0
  77. package/fesm2022/masmarino-gabarit-description-list.mjs.map +1 -0
  78. package/fesm2022/masmarino-gabarit-dimension-card.mjs +162 -0
  79. package/fesm2022/masmarino-gabarit-dimension-card.mjs.map +1 -0
  80. package/fesm2022/masmarino-gabarit-disclosure.mjs +154 -0
  81. package/fesm2022/masmarino-gabarit-disclosure.mjs.map +1 -0
  82. package/fesm2022/masmarino-gabarit-divider.mjs +90 -0
  83. package/fesm2022/masmarino-gabarit-divider.mjs.map +1 -0
  84. package/fesm2022/masmarino-gabarit-docs.mjs +16 -2
  85. package/fesm2022/masmarino-gabarit-docs.mjs.map +1 -1
  86. package/fesm2022/masmarino-gabarit-drawer.mjs +209 -0
  87. package/fesm2022/masmarino-gabarit-drawer.mjs.map +1 -0
  88. package/fesm2022/masmarino-gabarit-empty-state.mjs +226 -0
  89. package/fesm2022/masmarino-gabarit-empty-state.mjs.map +1 -0
  90. package/fesm2022/masmarino-gabarit-file-upload.mjs +335 -0
  91. package/fesm2022/masmarino-gabarit-file-upload.mjs.map +1 -0
  92. package/fesm2022/masmarino-gabarit-floating-panel.mjs +24 -0
  93. package/fesm2022/masmarino-gabarit-floating-panel.mjs.map +1 -0
  94. package/fesm2022/masmarino-gabarit-format.mjs +345 -0
  95. package/fesm2022/masmarino-gabarit-format.mjs.map +1 -0
  96. package/fesm2022/masmarino-gabarit-funnel-chart.mjs +247 -0
  97. package/fesm2022/masmarino-gabarit-funnel-chart.mjs.map +1 -0
  98. package/fesm2022/masmarino-gabarit-gauge-bar.mjs +180 -0
  99. package/fesm2022/masmarino-gabarit-gauge-bar.mjs.map +1 -0
  100. package/fesm2022/masmarino-gabarit-git-field.mjs +127 -0
  101. package/fesm2022/masmarino-gabarit-git-field.mjs.map +1 -0
  102. package/fesm2022/masmarino-gabarit-icon-marker.mjs +150 -0
  103. package/fesm2022/masmarino-gabarit-icon-marker.mjs.map +1 -0
  104. package/fesm2022/masmarino-gabarit-icon.mjs +308 -0
  105. package/fesm2022/masmarino-gabarit-icon.mjs.map +1 -0
  106. package/fesm2022/masmarino-gabarit-input.mjs +493 -0
  107. package/fesm2022/masmarino-gabarit-input.mjs.map +1 -0
  108. package/fesm2022/masmarino-gabarit-job-graph.mjs +216 -0
  109. package/fesm2022/masmarino-gabarit-job-graph.mjs.map +1 -0
  110. package/fesm2022/masmarino-gabarit-job-status.mjs +104 -0
  111. package/fesm2022/masmarino-gabarit-job-status.mjs.map +1 -0
  112. package/fesm2022/masmarino-gabarit-line-chart.mjs +574 -0
  113. package/fesm2022/masmarino-gabarit-line-chart.mjs.map +1 -0
  114. package/fesm2022/masmarino-gabarit-list-card.mjs +320 -0
  115. package/fesm2022/masmarino-gabarit-list-card.mjs.map +1 -0
  116. package/fesm2022/masmarino-gabarit-list-row.mjs +58 -0
  117. package/fesm2022/masmarino-gabarit-list-row.mjs.map +1 -0
  118. package/fesm2022/masmarino-gabarit-list-toolbar.mjs +369 -0
  119. package/fesm2022/masmarino-gabarit-list-toolbar.mjs.map +1 -0
  120. package/fesm2022/masmarino-gabarit-menu.mjs +464 -0
  121. package/fesm2022/masmarino-gabarit-menu.mjs.map +1 -0
  122. package/fesm2022/masmarino-gabarit-mfa-enrollment.mjs +897 -0
  123. package/fesm2022/masmarino-gabarit-mfa-enrollment.mjs.map +1 -0
  124. package/fesm2022/masmarino-gabarit-mfa-settings.mjs +629 -0
  125. package/fesm2022/masmarino-gabarit-mfa-settings.mjs.map +1 -0
  126. package/fesm2022/masmarino-gabarit-modal.mjs +260 -0
  127. package/fesm2022/masmarino-gabarit-modal.mjs.map +1 -0
  128. package/fesm2022/masmarino-gabarit-nav-tabs.mjs +332 -0
  129. package/fesm2022/masmarino-gabarit-nav-tabs.mjs.map +1 -0
  130. package/fesm2022/masmarino-gabarit-notification-dot.mjs +119 -0
  131. package/fesm2022/masmarino-gabarit-notification-dot.mjs.map +1 -0
  132. package/fesm2022/masmarino-gabarit-page-header.mjs +78 -0
  133. package/fesm2022/masmarino-gabarit-page-header.mjs.map +1 -0
  134. package/fesm2022/masmarino-gabarit-page-layout.mjs +157 -0
  135. package/fesm2022/masmarino-gabarit-page-layout.mjs.map +1 -0
  136. package/fesm2022/masmarino-gabarit-pagination.mjs +415 -0
  137. package/fesm2022/masmarino-gabarit-pagination.mjs.map +1 -0
  138. package/fesm2022/masmarino-gabarit-panel.mjs +80 -0
  139. package/fesm2022/masmarino-gabarit-panel.mjs.map +1 -0
  140. package/fesm2022/masmarino-gabarit-passkey-settings.mjs +606 -0
  141. package/fesm2022/masmarino-gabarit-passkey-settings.mjs.map +1 -0
  142. package/fesm2022/masmarino-gabarit-pie-chart.mjs +317 -0
  143. package/fesm2022/masmarino-gabarit-pie-chart.mjs.map +1 -0
  144. package/fesm2022/masmarino-gabarit-popover.mjs +142 -0
  145. package/fesm2022/masmarino-gabarit-popover.mjs.map +1 -0
  146. package/fesm2022/masmarino-gabarit-radio-group.mjs +202 -0
  147. package/fesm2022/masmarino-gabarit-radio-group.mjs.map +1 -0
  148. package/fesm2022/masmarino-gabarit-save-status.mjs +142 -0
  149. package/fesm2022/masmarino-gabarit-save-status.mjs.map +1 -0
  150. package/fesm2022/masmarino-gabarit-search-bar.mjs +576 -0
  151. package/fesm2022/masmarino-gabarit-search-bar.mjs.map +1 -0
  152. package/fesm2022/masmarino-gabarit-secret-reveal.mjs +348 -0
  153. package/fesm2022/masmarino-gabarit-secret-reveal.mjs.map +1 -0
  154. package/fesm2022/masmarino-gabarit-segmented-control.mjs +272 -0
  155. package/fesm2022/masmarino-gabarit-segmented-control.mjs.map +1 -0
  156. package/fesm2022/masmarino-gabarit-select.mjs +512 -0
  157. package/fesm2022/masmarino-gabarit-select.mjs.map +1 -0
  158. package/fesm2022/masmarino-gabarit-skeleton-list.mjs +189 -0
  159. package/fesm2022/masmarino-gabarit-skeleton-list.mjs.map +1 -0
  160. package/fesm2022/masmarino-gabarit-skeleton.mjs +109 -0
  161. package/fesm2022/masmarino-gabarit-skeleton.mjs.map +1 -0
  162. package/fesm2022/masmarino-gabarit-slider.mjs +239 -0
  163. package/fesm2022/masmarino-gabarit-slider.mjs.map +1 -0
  164. package/fesm2022/masmarino-gabarit-sparkline.mjs +276 -0
  165. package/fesm2022/masmarino-gabarit-sparkline.mjs.map +1 -0
  166. package/fesm2022/masmarino-gabarit-spinner.mjs +86 -0
  167. package/fesm2022/masmarino-gabarit-spinner.mjs.map +1 -0
  168. package/fesm2022/masmarino-gabarit-stat-grid.mjs +139 -0
  169. package/fesm2022/masmarino-gabarit-stat-grid.mjs.map +1 -0
  170. package/fesm2022/masmarino-gabarit-stat-tile.mjs +312 -0
  171. package/fesm2022/masmarino-gabarit-stat-tile.mjs.map +1 -0
  172. package/fesm2022/masmarino-gabarit-stepper.mjs +219 -0
  173. package/fesm2022/masmarino-gabarit-stepper.mjs.map +1 -0
  174. package/fesm2022/masmarino-gabarit-switch.mjs +151 -0
  175. package/fesm2022/masmarino-gabarit-switch.mjs.map +1 -0
  176. package/fesm2022/masmarino-gabarit-table.mjs +206 -0
  177. package/fesm2022/masmarino-gabarit-table.mjs.map +1 -0
  178. package/fesm2022/masmarino-gabarit-tabs.mjs +210 -0
  179. package/fesm2022/masmarino-gabarit-tabs.mjs.map +1 -0
  180. package/fesm2022/masmarino-gabarit-tag-input.mjs +288 -0
  181. package/fesm2022/masmarino-gabarit-tag-input.mjs.map +1 -0
  182. package/fesm2022/masmarino-gabarit-tag.mjs +155 -0
  183. package/fesm2022/masmarino-gabarit-tag.mjs.map +1 -0
  184. package/fesm2022/masmarino-gabarit-textarea.mjs +369 -0
  185. package/fesm2022/masmarino-gabarit-textarea.mjs.map +1 -0
  186. package/fesm2022/masmarino-gabarit-timeline-chart.mjs +521 -0
  187. package/fesm2022/masmarino-gabarit-timeline-chart.mjs.map +1 -0
  188. package/fesm2022/masmarino-gabarit-toaster.mjs +220 -0
  189. package/fesm2022/masmarino-gabarit-toaster.mjs.map +1 -0
  190. package/fesm2022/masmarino-gabarit-tooltip.mjs +185 -0
  191. package/fesm2022/masmarino-gabarit-tooltip.mjs.map +1 -0
  192. package/fesm2022/masmarino-gabarit-tree.mjs +258 -0
  193. package/fesm2022/masmarino-gabarit-tree.mjs.map +1 -0
  194. package/fesm2022/masmarino-gabarit-user-chip.mjs +106 -0
  195. package/fesm2022/masmarino-gabarit-user-chip.mjs.map +1 -0
  196. package/fesm2022/masmarino-gabarit.mjs +83 -24785
  197. package/fesm2022/masmarino-gabarit.mjs.map +1 -1
  198. package/file-upload/README.md +47 -0
  199. package/funnel-chart/README.md +39 -0
  200. package/gauge-bar/README.md +35 -0
  201. package/git-field/README.md +34 -0
  202. package/icon/README.md +52 -0
  203. package/icon-marker/README.md +37 -0
  204. package/input/README.md +120 -0
  205. package/job-graph/README.md +76 -0
  206. package/job-status/README.md +34 -0
  207. package/line-chart/README.md +52 -0
  208. package/list-card/README.md +144 -0
  209. package/list-row/README.md +72 -0
  210. package/list-toolbar/README.md +52 -0
  211. package/menu/README.md +90 -0
  212. package/mfa-enrollment/README.md +189 -0
  213. package/mfa-settings/README.md +154 -0
  214. package/modal/README.md +72 -0
  215. package/nav-tabs/README.md +106 -0
  216. package/notification-dot/README.md +43 -0
  217. package/package.json +329 -1
  218. package/page-header/README.md +56 -0
  219. package/page-layout/README.md +76 -0
  220. package/pagination/README.md +73 -0
  221. package/panel/README.md +56 -0
  222. package/passkey-settings/README.md +120 -0
  223. package/pie-chart/README.md +85 -0
  224. package/popover/README.md +62 -0
  225. package/radio-group/README.md +47 -0
  226. package/save-status/README.md +44 -0
  227. package/search-bar/README.md +84 -0
  228. package/secret-reveal/README.md +60 -0
  229. package/segmented-control/README.md +79 -0
  230. package/select/README.md +61 -0
  231. package/skeleton/README.md +49 -0
  232. package/skeleton-list/README.md +40 -0
  233. package/slider/README.md +44 -0
  234. package/sparkline/README.md +37 -0
  235. package/spinner/README.md +41 -0
  236. package/stat-grid/README.md +47 -0
  237. package/stat-tile/README.md +75 -0
  238. package/stepper/README.md +67 -0
  239. package/switch/README.md +51 -0
  240. package/table/README.md +75 -0
  241. package/tabs/README.md +34 -0
  242. package/tag/README.md +34 -0
  243. package/tag-input/README.md +45 -0
  244. package/textarea/README.md +76 -0
  245. package/timeline-chart/README.md +49 -0
  246. package/toaster/README.md +92 -0
  247. package/tooltip/README.md +50 -0
  248. package/tree/README.md +79 -0
  249. package/types/masmarino-gabarit-accordion.d.ts +54 -0
  250. package/types/masmarino-gabarit-alert.d.ts +65 -0
  251. package/types/masmarino-gabarit-app-shell.d.ts +102 -0
  252. package/types/masmarino-gabarit-auth-activate.d.ts +70 -0
  253. package/types/masmarino-gabarit-auth-login.d.ts +63 -0
  254. package/types/masmarino-gabarit-auth-register.d.ts +66 -0
  255. package/types/masmarino-gabarit-auth-reset-password.d.ts +53 -0
  256. package/types/masmarino-gabarit-auth.d.ts +543 -0
  257. package/types/masmarino-gabarit-autocomplete.d.ts +140 -0
  258. package/types/masmarino-gabarit-avatar-group.d.ts +60 -0
  259. package/types/masmarino-gabarit-avatar.d.ts +31 -0
  260. package/types/masmarino-gabarit-badge.d.ts +139 -0
  261. package/types/masmarino-gabarit-bar-chart.d.ts +111 -0
  262. package/types/masmarino-gabarit-breadcrumb.d.ts +12 -0
  263. package/types/masmarino-gabarit-button.d.ts +108 -0
  264. package/types/masmarino-gabarit-card.d.ts +102 -0
  265. package/types/masmarino-gabarit-chart.d.ts +361 -0
  266. package/types/masmarino-gabarit-checkbox-group.d.ts +113 -0
  267. package/types/masmarino-gabarit-checkbox.d.ts +49 -0
  268. package/types/masmarino-gabarit-confirm-danger-modal.d.ts +94 -0
  269. package/types/masmarino-gabarit-copy-button.d.ts +111 -0
  270. package/types/masmarino-gabarit-copy-field.d.ts +64 -0
  271. package/types/masmarino-gabarit-date-picker.d.ts +399 -0
  272. package/types/masmarino-gabarit-description-list.d.ts +40 -0
  273. package/types/masmarino-gabarit-dimension-card.d.ts +55 -0
  274. package/types/masmarino-gabarit-disclosure.d.ts +44 -0
  275. package/types/masmarino-gabarit-divider.d.ts +20 -0
  276. package/types/masmarino-gabarit-docs.d.ts +2 -1
  277. package/types/masmarino-gabarit-drawer.d.ts +51 -0
  278. package/types/masmarino-gabarit-empty-state.d.ts +67 -0
  279. package/types/masmarino-gabarit-file-upload.d.ts +95 -0
  280. package/types/masmarino-gabarit-floating-panel.d.ts +14 -0
  281. package/types/masmarino-gabarit-format.d.ts +54 -0
  282. package/types/masmarino-gabarit-funnel-chart.d.ts +78 -0
  283. package/types/masmarino-gabarit-gauge-bar.d.ts +54 -0
  284. package/types/masmarino-gabarit-git-field.d.ts +39 -0
  285. package/types/masmarino-gabarit-icon-marker.d.ts +47 -0
  286. package/types/masmarino-gabarit-icon.d.ts +23 -0
  287. package/types/masmarino-gabarit-input.d.ts +181 -0
  288. package/types/masmarino-gabarit-job-graph.d.ts +63 -0
  289. package/types/masmarino-gabarit-job-status.d.ts +20 -0
  290. package/types/masmarino-gabarit-line-chart.d.ts +153 -0
  291. package/types/masmarino-gabarit-list-card.d.ts +87 -0
  292. package/types/masmarino-gabarit-list-row.d.ts +14 -0
  293. package/types/masmarino-gabarit-list-toolbar.d.ts +100 -0
  294. package/types/masmarino-gabarit-menu.d.ts +93 -0
  295. package/types/masmarino-gabarit-mfa-enrollment.d.ts +142 -0
  296. package/types/masmarino-gabarit-mfa-settings.d.ts +89 -0
  297. package/types/masmarino-gabarit-modal.d.ts +60 -0
  298. package/types/masmarino-gabarit-nav-tabs.d.ts +65 -0
  299. package/types/masmarino-gabarit-notification-dot.d.ts +34 -0
  300. package/types/masmarino-gabarit-page-header.d.ts +20 -0
  301. package/types/masmarino-gabarit-page-layout.d.ts +46 -0
  302. package/types/masmarino-gabarit-pagination.d.ts +109 -0
  303. package/types/masmarino-gabarit-panel.d.ts +21 -0
  304. package/types/masmarino-gabarit-passkey-settings.d.ts +94 -0
  305. package/types/masmarino-gabarit-pie-chart.d.ts +94 -0
  306. package/types/masmarino-gabarit-popover.d.ts +33 -0
  307. package/types/masmarino-gabarit-radio-group.d.ts +66 -0
  308. package/types/masmarino-gabarit-save-status.d.ts +39 -0
  309. package/types/masmarino-gabarit-search-bar.d.ts +183 -0
  310. package/types/masmarino-gabarit-secret-reveal.d.ts +95 -0
  311. package/types/masmarino-gabarit-segmented-control.d.ts +76 -0
  312. package/types/masmarino-gabarit-select.d.ts +146 -0
  313. package/types/masmarino-gabarit-skeleton-list.d.ts +54 -0
  314. package/types/masmarino-gabarit-skeleton.d.ts +26 -0
  315. package/types/masmarino-gabarit-slider.d.ts +73 -0
  316. package/types/masmarino-gabarit-sparkline.d.ts +70 -0
  317. package/types/masmarino-gabarit-spinner.d.ts +20 -0
  318. package/types/masmarino-gabarit-stat-grid.d.ts +39 -0
  319. package/types/masmarino-gabarit-stat-tile.d.ts +79 -0
  320. package/types/masmarino-gabarit-stepper.d.ts +67 -0
  321. package/types/masmarino-gabarit-switch.d.ts +42 -0
  322. package/types/masmarino-gabarit-table.d.ts +60 -0
  323. package/types/masmarino-gabarit-tabs.d.ts +40 -0
  324. package/types/masmarino-gabarit-tag-input.d.ts +78 -0
  325. package/types/masmarino-gabarit-tag.d.ts +35 -0
  326. package/types/masmarino-gabarit-textarea.d.ts +109 -0
  327. package/types/masmarino-gabarit-timeline-chart.d.ts +145 -0
  328. package/types/masmarino-gabarit-toaster.d.ts +62 -0
  329. package/types/masmarino-gabarit-tooltip.d.ts +39 -0
  330. package/types/masmarino-gabarit-tree.d.ts +71 -0
  331. package/types/masmarino-gabarit-user-chip.d.ts +26 -0
  332. package/types/masmarino-gabarit.d.ts +83 -6599
  333. package/user-chip/README.md +42 -0
package/auth/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # Auth kit
2
+
3
+ The public sign-in pages and the account's second-factor settings, as components an application uses
4
+ as they are: login (with the MFA challenge), free registration, invitation activation, the new
5
+ password after an administrator's reset, the mandatory
6
+ first MFA enrolment (authenticator app or passkey, then backup codes), and the account cards for the
7
+ authenticator app and the passkeys. Every application that uses them gets the same behaviour, the same
8
+ accessibility and the same look, by construction.
9
+
10
+ The kit is **router-agnostic** (it never imports `@angular/router`: it emits outputs and shows the
11
+ links the application projects), **backend-agnostic** (it never talks HTTP: every call goes through a
12
+ port the application implements), **storage-agnostic** (it never touches `localStorage`: sessions are
13
+ the port's business) and **locale-agnostic** (every string is a label with an English default).
14
+
15
+ | Component | Selector | Port |
16
+ | --------------------------------------------------------- | ---------------------- | ---------------------------------------- |
17
+ | [`AuthLogin`](../auth-login/README.md) | `gbt-auth-login` | `AUTH_PORT` |
18
+ | [`AuthRegister`](../auth-register/README.md) | `gbt-auth-register` | `AUTH_PORT` |
19
+ | [`AuthActivate`](../auth-activate/README.md) | `gbt-auth-activate` | `AUTH_PORT` |
20
+ | [`AuthResetPassword`](../auth-reset-password/README.md) | `gbt-auth-reset-password` | `AUTH_PORT` |
21
+ | [`MfaEnrollment`](../mfa-enrollment/README.md) | `gbt-mfa-enrollment` | `AUTH_PORT` |
22
+ | [`MfaSettings`](../mfa-settings/README.md) | `gbt-mfa-settings` | `MFA_PORT` |
23
+ | [`PasskeySettings`](../passkey-settings/README.md) | `gbt-passkey-settings` | `MFA_PORT` (and `AUTH_PORT` if provided) |
24
+ | [`AuthPanel`](auth-panel/README.md) | `gbt-auth-panel` | — |
25
+ | [`AuthFooter`, `AuthFooterLink`](auth-footer/README.md) | `gbt-auth-footer` | — |
26
+ | [`TotpQr`](../mfa-enrollment/totp-qr/README.md) | `gbt-totp-qr` | — (`TOTP_QR_RENDERER`) |
27
+ | [`BackupCodes`](../mfa-enrollment/backup-codes/README.md) | `gbt-backup-codes` | — |
28
+
29
+ ## Wiring
30
+
31
+ ```ts
32
+ // app.config.ts
33
+ providers: [
34
+ { provide: AUTH_PORT, useExisting: AuthService }, // your service implements AuthPort
35
+ { provide: MFA_PORT, useExisting: MfaService }, // your service implements MfaPort
36
+ {
37
+ provide: TOTP_QR_RENDERER, // Gabarit ships no QR encoder: bring one, loaded lazily
38
+ useValue: (text: string, options: TotpQrRenderOptions) =>
39
+ import('qrcode').then((qr) => qr.toDataURL(text, options)),
40
+ },
41
+ provideAuthLabels(MY_AUTH_LABELS), // optional: localise the whole kit once
42
+ ]
43
+ ```
44
+
45
+ > **Security: `TOTP_QR_RENDERER` receives the user's TOTP secret.** It is called with the full
46
+ > `otpauth://…?secret=…` URL, raw secret included. The renderer **must encode locally**, in the
47
+ > browser (a bundled library such as `qrcode`, as above): **no network call, never a hosted or
48
+ > third-party QR service** (a `https://…?data=otpauth…` image would hand every user's second factor
49
+ > to that service and its access logs). It **must not log** the text, nor send it to analytics or
50
+ > error reports. See [TotpQr](../mfa-enrollment/totp-qr/README.md).
51
+
52
+ ```html
53
+ <!-- login.page.html: a thin wrapper, routed at /login -->
54
+ <gbt-auth-login (loggedIn)="router.navigateByUrl('/home')">
55
+ <img auth-logo src="logo.svg" alt="Acme" width="480" height="120" />
56
+ <a gbtButton variant="link" gbtAuthFooterLink routerLink="/register">Create an account</a>
57
+ </gbt-auth-login>
58
+ ```
59
+
60
+ Every page takes the application's logo in its `[auth-logo]` slot (an `img`, a `picture` or an
61
+ `svg`) and the link of its footer in `[gbtAuthFooterLink]` (an `a[gbtButton]` in its `link` variant,
62
+ carrying the application's `routerLink` or `href`). A page without a projected footer link shows no
63
+ footer.
64
+
65
+ **`gbt-auth-register`, `gbt-auth-activate` and `gbt-auth-reset-password` also emit `(signIn)`**, from
66
+ their own terminal states (registration closed, account created, activation succeeded, password
67
+ changed, dead link), where "Sign in" is a button
68
+ rather than the projected link. That output is in addition to the projected `[gbtAuthFooterLink]`,
69
+ not instead of it: **wire both** (`(signIn)="router.navigateByUrl('/login')"` and the footer link)
70
+ for every path to reach the sign-in page.
71
+
72
+ ## The `AuthPort` contract
73
+
74
+ - **Sessions.** `login`, `register`, `verifyMfa` and `finishPasskeyChallenge` store the session they
75
+ obtain, when there is one (`LoginResponse.token` not null), then the page emits its success output.
76
+ `confirmTotp` and `finishPasskeySetup` must **not** store theirs: the enrolment holds the session
77
+ back until the user has acknowledged the backup codes (shown once), then the page hands it to
78
+ `setToken(token)` and emits.
79
+ - **MFA.** A `LoginResponse` with `token: null` and an `mfaToken` sends the user to the challenge
80
+ (`mfaHasTotp`, `mfaHasPasskey` say what they can use) or, with `mfaSetupRequired`, to the mandatory
81
+ enrolment.
82
+ - **Configuration.** `authConfig()` is read once by the login page (a failed read hides the
83
+ registration link; passkeys stay "unknown", which does not block them) and by the registration page
84
+ (a failed read shows the form: the server has the last word).
85
+
86
+ ## The error contract
87
+
88
+ A failed port call errors with `{ status, error }`: the HTTP status and the response body, the shape
89
+ of Angular's `HttpErrorResponse` (an adapter on `HttpClient` passes its errors through untouched). A
90
+ browser's WebAuthn error (a `DOMException`, no `status`) is told apart from a server answer by that
91
+ shape. The kit words every failure itself; the server's text is never shown. What it recognises
92
+ (`AUTH_PORT_ERROR_BODIES` holds the strings):
93
+
94
+ | Call | Answer | Read as |
95
+ | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
96
+ | `login` | 401 | wrong username or password (any other failure: "sign-in failed") |
97
+ | any | 429 | too many attempts |
98
+ | MFA calls with an `mfaToken` | 401 `invalid or expired token` | the sign-in expired: back to the credentials |
99
+ | `verifyMfa`, `finishPasskeyChallenge` | 401 (any other body) | wrong code / passkey refused |
100
+ | `confirmTotp`, `confirm` | 400 `invalid code` | wrong code |
101
+ | enrolment calls | 400 `MFA is already set up` | the account got a factor meanwhile: back to the credentials |
102
+ | passkey calls | 503 | passkeys not available on this server |
103
+ | `finishPasskeySetup`, registration | 409 | this key is already registered |
104
+ | password-gated `MfaPort` calls | 400 `current password is incorrect` (exactly) | wrong password (never a 401, which an interceptor would take for a sign-out) |
105
+ | `startPasskeyRegistration`/`finish…` | 400 `too many passkeys` | the account holds the most passkeys the server keeps |
106
+ | `deletePasskey` | 404 | already gone: removed from the list, nobody signed out |
107
+ | `register` | 400 `registration is disabled` | the closed state |
108
+ | `register` | 400 `username is reserved` / `username …` / `email is not a valid address` / `password must be at least …` / other | the field concerned, else "check the fields" |
109
+ | `register` | 409 `email already in use` / other 409 | address taken / name taken |
110
+ | `activate`, `resetPassword` | 400 `password must be at least …` / other 400 | weak password (the link still works) / dead link |
111
+
112
+ An adapter for a backend that words these differently maps its answers onto them with `catchError`.
113
+
114
+ ## Session revocation
115
+
116
+ `MfaPort.disable` and `MfaPort.deletePasskey` revoke the caller's own session on the server (MFA
117
+ being mandatory, removing a factor signs every device out). The cards then emit `sessionRevoked`:
118
+ the application must discard its local session and go to its sign-in page. As a safety net, the card
119
+ that revoked the session also turns inert ("You have been signed out", its `signedOut` label, and no
120
+ action left), so an unbound output never leaves a live card acting on a dead session; it cannot clear
121
+ the application's stored session, though: binding `sessionRevoked` stays mandatory.
122
+
123
+ ## Activation and password-reset links
124
+
125
+ The mail should carry the token in the URL fragment (`/activate#token=…`,
126
+ `/reset-password#token=…`), which no server ever sees. The application's wrapper reads it once with
127
+ `activationToken(fragment, query)`, removes it from the address bar and history
128
+ (`navigateByUrl('/activate', { replaceUrl: true })`), and hands it to the `token` input of
129
+ `gbt-auth-activate` or `gbt-auth-reset-password`.
130
+
131
+ **The `token` input must be a one-time snapshot of the URL, never a value that reactively follows the
132
+ URL (e.g. a signal derived from `route.fragment`): the component resets when it changes.** Scrubbing
133
+ the URL would otherwise turn the token into `null` and flip the page to the dead-link view, even over
134
+ its success view.
135
+
136
+ ## Labels
137
+
138
+ Each component has a `labels` input (a partial object) over `provideAuthLabels({ … })` over its
139
+ English defaults (`DEFAULT_LOGIN_LABELS`, …); nested pieces (`gbt-mfa-enrollment` inside the login
140
+ page, `gbt-totp-qr` and `gbt-backup-codes` inside the enrolment and the settings) read the provided
141
+ labels, so an application localises the whole kit in one place. Interpolated strings are functions
142
+ (`step(current, total)`, `codesLeft(count)`, `passkeyAdded(name)`…).
143
+
144
+ ## The account cards together
145
+
146
+ `gbt-mfa-settings` and `gbt-passkey-settings` are meant to sit side by side. They share
147
+ `MfaSettingsState` (root-provided; provide it on a page to scope it): the factors as last read or
148
+ changed by either card, so the app becomes optional as soon as a passkey is added and deleting the
149
+ only key is flagged as removing the last factor; and which card owns the open form, so a view never
150
+ shows two password prompts (two primary buttons) at once.
151
+
152
+ ## Theming
153
+
154
+ `--gbt-auth-panel-logo-width` (15rem) sizes the logo; `--gbt-auth-panel-logo-offset` (0) pulls it
155
+ up when the artwork has a transparent margin above its drawing.
@@ -0,0 +1,119 @@
1
+ # AuthActivate
2
+
3
+ The activation page of the auth kit: where the link of an invitation mail lands, outside the app shell,
4
+ in the sign-in panel ([`gbt-auth-panel`](../auth/auth-panel/auth-panel.ts)). The invited user chooses a
5
+ password; no session comes out of it: they sign in afterwards and are taken through the mandatory MFA
6
+ enrolment like everybody. It never talks HTTP, never reads the URL and never navigates: the backend is
7
+ the application's `AUTH_PORT`, the token is an input, and the page tells the application where to go
8
+ through its outputs.
9
+
10
+ **Selector**: `gbt-auth-activate`
11
+
12
+ ## Views
13
+
14
+ | View | What shows |
15
+ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
16
+ | form | A token was given: "Activate your account", New password (with its hint), Confirm the password, one primary "Activate my account", then the projected sign-in link. |
17
+ | success | The server accepted: "Your account is activated", what comes next, one "Sign in" button. |
18
+ | invalid | No token (`null` or `''`), or the server refused it (unknown, expired or used): an error-toned state, "This link does not work", ask for a new invitation, one "Sign in". |
19
+
20
+ ## Inputs
21
+
22
+ | Input | Type | Default | Role |
23
+ | ------------------- | ------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
24
+ | `token` | `string \| null` | `null` | The invitation's token, as the application read it from its URL with `activationToken(fragment, query)`. `null` (or `''`) is the dead link, without any request. A new value starts the page over. |
25
+ | `labels` | `Partial<ActivateLabels>` | `{}` | Strings to change, over `provideAuthLabels({ activate })` and the English defaults (`DEFAULT_ACTIVATE_LABELS`). |
26
+ | `minPasswordLength` | `number` | `MIN_PASSWORD_LENGTH` (8) | The server's minimum password length, checked before the round trip; also worded in the hint and the errors. |
27
+ | `chooseUsername` | `boolean` | `false` | For servers where the administrator invites by e-mail only: a Username field comes first, and the invitee's choice is sent as `activate(token, password, username)`. |
28
+ | `usernamePattern` | `RegExp` | `USERNAME_PATTERN` | The server's username rule, checked before the round trip when `chooseUsername` is on. |
29
+
30
+ ## Outputs
31
+
32
+ | Output | Payload | Role |
33
+ | ----------- | ------- | -------------------------------------------------------------------------------- |
34
+ | `activated` | `void` | The server accepted the password: the success view shows. No session was opened. |
35
+ | `signIn` | `void` | "Sign in" was pressed in the success or dead-link view: go to the sign-in page. |
36
+
37
+ ## Slots
38
+
39
+ | Selector | Role |
40
+ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
41
+ | `[auth-logo]` | The application's logo (an `img`, `picture` or `svg`), on top of the panel. Optional. |
42
+ | `[auth-backdrop]` | What is drawn on the graphite page, behind the panel: `gbt-git-field`, the family's animated commit graph (`@masmarino/gabarit/git-field`). Optional. |
43
+ | `[gbtAuthFooterLink]` | The link to the sign-in page, under the form after "Is your account already active?". An `a gbtButton variant="link"` carrying `routerLink` or `href`. No footer when absent. |
44
+
45
+ ## Behaviour
46
+
47
+ - **The token.** The page sends it with the password (`activate(token, password)`) and never renders it
48
+ (not in the markup, not in a field). Once spent (success) or refused (a 400 other than a weak password),
49
+ it is dropped: the page does not send it again until a new `token` arrives.
50
+ - **The application's part** (it owns the URL): put the token in the link's **fragment**
51
+ (`/activate#token=…`) so that no server, proxy or access log ever sees it; read it once with
52
+ `activationToken(route.snapshot.fragment, route.snapshot.queryParamMap.get('token'))` (the query is only a
53
+ fallback for older links; a token not shaped like the server's is `null`); then remove it (and any other
54
+ parameter) from the address bar and the history entry, e.g.
55
+ `router.navigateByUrl('/activate', { replaceUrl: true })` after the first render, so it does not linger in
56
+ a screenshot or a shared tab.
57
+ - **The `token` input must be a one-time snapshot of the URL, never a value that reactively follows the
58
+ URL (e.g. a signal derived from `route.fragment`): the component resets when it changes.** Scrubbing the
59
+ URL as above would otherwise turn the token into `null` and flip the page to the dead-link view, even over
60
+ its success view. Read it into a plain field, as in the example below.
61
+ - **`chooseUsername`.** The intro becomes `introWithUsername`, the Username field (with `usernameHint`) comes
62
+ before the passwords and takes the first focus, and it is checked first (`usernameEmpty`,
63
+ `usernameInvalid`). The value is sent trimmed; the server keeps the final say: a 400 `username is reserved`
64
+ (`usernameReserved`), another 400 starting with `username ` (`usernameInvalid`) or a 409
65
+ (`usernameTaken`) keeps the form, in an alert, the focus in the Username field.
66
+ - **`minPasswordLength` must mirror the server's own rule.** It only spares a round trip: the server stays
67
+ the authority, and a looser value only moves the refusal to the server's answer.
68
+ - **Checks before the request.** Nothing is said while typing; after a first attempt the password rule and
69
+ the confirmation ("Confirm your password", "The passwords do not match") show under their fields, the
70
+ focus moves to the first wrong one, and the checks stay live.
71
+ - **Failures** are worded from the labels, in an alert, the focus back in the password field: a weak-password
72
+ 400 keeps the form (the link is still good), a 429 says to wait, anything else (5xx, network) says the
73
+ activation failed and the same token can be retried. Any other 400 (but the username ones, with
74
+ `chooseUsername`) is the dead link.
75
+ - **Focus**: the form starts in the new-password field; the success and dead-link views move the focus to
76
+ their `h1` (focusable by script, not a tab stop). The passwords are emptied when the server accepted or
77
+ refused the link.
78
+
79
+ ## Example
80
+
81
+ ```ts
82
+ // app.config.ts
83
+ providers: [
84
+ { provide: AUTH_PORT, useClass: HttpAuthPort }, // your adapter over HttpClient
85
+ provideAuthLabels({ activate: { signInPrompt: 'Already signed up?' } }),
86
+ ]
87
+ ```
88
+
89
+ ```ts
90
+ @Component({
91
+ imports: [AuthActivate, Button, AuthFooterLink, RouterLink],
92
+ template: `
93
+ <gbt-auth-activate [token]="token" (signIn)="router.navigateByUrl('/login')">
94
+ <img auth-logo src="/logo.svg" alt="Acme" width="160" height="40" />
95
+ <a gbtButton variant="link" gbtAuthFooterLink routerLink="/login">Sign in</a>
96
+ </gbt-auth-activate>
97
+ `,
98
+ })
99
+ export class ActivateRoute {
100
+ protected readonly router = inject(Router)
101
+ private readonly route = inject(ActivatedRoute)
102
+ // Read once, then scrubbed from the address bar and the history entry.
103
+ protected readonly token = activationToken(
104
+ this.route.snapshot.fragment,
105
+ this.route.snapshot.queryParamMap.get('token'),
106
+ )
107
+
108
+ constructor() {
109
+ const { fragment, queryParamMap } = this.route.snapshot
110
+ if (fragment !== null || queryParamMap.keys.length > 0) {
111
+ afterNextRender(() => void this.router.navigateByUrl('/activate', { replaceUrl: true }))
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ ## Accessibility
118
+
119
+ See [AUDIT.md](AUDIT.md). The panel owns the page's `<main>` landmark and its `h1`.
@@ -0,0 +1,113 @@
1
+ # AuthLogin
2
+
3
+ The sign-in page of the auth kit, outside the app shell: the application's logo,
4
+ a heading, the username and password fields and one "Sign in" button; then,
5
+ when the password is accepted, the second factor. It is router-, storage- and
6
+ backend-agnostic: every call goes through the application's
7
+ [`AuthPort`](../auth/ports/auth.port.ts), and the page tells the application the
8
+ user is signed in with `loggedIn` (the application navigates).
9
+
10
+ **Selector**: `gbt-auth-login`
11
+
12
+ ## States
13
+
14
+ | State | When | What shows |
15
+ | ----------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
16
+ | Credentials | On open, after "Back", after an expired second step. | "Sign in", the two fields, the submit button; the registration footer when registration is open and the application projected a link. |
17
+ | Challenge | `login` answered an `mfaToken` without `mfaSetupRequired`. | "Two-step verification", with what this user can do here: their passkey (when they have one and both the browser and the server can run it), the 6-digit code of their app (when they have one), and always a backup code. |
18
+ | Enrolment | `login` answered an `mfaToken` with `mfaSetupRequired` (no second factor yet). | "Two-factor authentication" and [`gbt-mfa-enrollment`](../mfa-enrollment/mfa-enrollment.ts) in a wider panel: the mandatory first set-up of an app or a passkey, then the backup codes. The session is only handed over once the user acknowledged the codes. |
19
+
20
+ ## Inputs
21
+
22
+ | Input | Type | Default | Role |
23
+ | -------- | ---------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------- |
24
+ | `labels` | `Partial<LoginLabels>` | `{}` | Strings to change, string by string, over `provideAuthLabels({ login })` and the English defaults (`DEFAULT_LOGIN_LABELS`). |
25
+
26
+ The enrolment takes its strings from `provideAuthLabels({ mfaEnrollment, totpQr, backupCodes })`.
27
+
28
+ ## Outputs
29
+
30
+ | Output | Payload | Role |
31
+ | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
32
+ | `loggedIn` | `void` | The user is signed in: the port stored the session (`login`, `verifyMfa`, `finishPasskeyChallenge`), or the page handed the held-back session of a finished enrolment to `AuthPort.setToken`. Navigate to the application. |
33
+
34
+ ## Slots
35
+
36
+ | Selector | Role |
37
+ | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
38
+ | `[auth-logo]` | The application's logo (an `img`, a `picture`, an `svg`) at the top of the panel, on every state. Give it its `alt`. |
39
+ | `[auth-backdrop]` | What is drawn on the graphite page, behind the panel: `gbt-git-field`, the family's animated commit graph (`@masmarino/gabarit/git-field`). Optional. |
40
+ | `[gbtAuthFooterLink]` | The link to the application's registration page (`<a gbtButton variant="link" gbtAuthFooterLink routerLink="/register">`). Shown under the form, after "No account yet?", only when `authConfig` says registration is open. |
41
+ | `[auth-notice]` | Something the application has to say before the credentials (a session that ended, a sign-in link that failed), e.g. a `gbt-alert`. First in the form, on the credentials step only. |
42
+
43
+ ## Providers
44
+
45
+ | Token | Required | Role |
46
+ | ----------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
47
+ | `AUTH_PORT` | Yes | The backend: `authConfig`, `login`, `verifyMfa`, `startPasskeyChallenge`, `finishPasskeyChallenge`, `setToken`, and the enrolment's calls. |
48
+ | `TOTP_QR_RENDERER` | For the enrolment's QR | The QR encoder of the authenticator-app set-up. Without one the enrolment shows the secret to type by hand. |
49
+ | `AUTH_LABELS` (`provideAuthLabels`) | No | The application's wording, once for the whole kit. |
50
+
51
+ ## Behaviour
52
+
53
+ - **Configuration.** `authConfig` is read once, when the page opens. A failed read only hides
54
+ the registration link, and is not taken for "no passkeys on this server": signing in never
55
+ depends on it.
56
+ - **Password step.** Only a 401 says "Incorrect username or password"; a 429 says to wait; any
57
+ other failure (a 5xx, a network error, an answer with neither `token` nor `mfaToken`) says the
58
+ sign-in failed. The password is dropped from memory as soon as the server accepted it.
59
+ - **Challenge.** One primary button per view: "Use a passkey" when it is offered, else "Verify".
60
+ A user with both factors gets the passkey first and the code form under "or". Spaces are
61
+ stripped from a code. A refused code empties the field; a 429 keeps it. A passkey-only user
62
+ whose passkey cannot run here (no WebAuthn in the browser, or passkeys off on the server) is
63
+ told why and given the backup-code form, never a dead end.
64
+ - **Passkey.** `startPasskeyChallenge`, the browser's prompt, then `finishPasskeyChallenge`. A
65
+ dismissed prompt is a quiet "Operation cancelled" (not an error) and keeps the screen. While
66
+ the prompt is open "Use a backup code" and "Back" stay usable; leaving drops the ceremony, so a
67
+ late answer is never sent.
68
+ - **Expiry.** A dead `mfaToken` (401 `invalid or expired token`, at the challenge, the passkey
69
+ or the enrolment) goes back to the credentials with "Your sign-in has expired, sign in again."
70
+ and the username kept.
71
+ - **Enrolment.** The page embeds `gbt-mfa-enrollment`: `completed` hands the session to
72
+ `AuthPort.setToken` then emits `loggedIn`; `cancelled` ("Back") returns to the credentials;
73
+ `expired` returns with the expiry message. The passkey option is only offered when the
74
+ server said `passkeysAvailable: true` and the browser has WebAuthn.
75
+ - **Focus.** On open the username field; after a failed sign-in the password field; on the
76
+ challenge the passkey button or the code field; after a failure the field (or button) to retry;
77
+ after "Back" the password field.
78
+
79
+ Failures are classified by status and by the body's `error` string (see
80
+ `AUTH_PORT_ERROR_BODIES`): the backend's own text is never shown.
81
+
82
+ ## Example
83
+
84
+ ```ts
85
+ // app.config.ts
86
+ providers: [
87
+ { provide: AUTH_PORT, useClass: HttpAuthPort }, // your adapter over HttpClient
88
+ {
89
+ provide: TOTP_QR_RENDERER,
90
+ useValue: (text, options) => import('qrcode').then((m) => m.toDataURL(text, options)),
91
+ },
92
+ provideAuthLabels({ login: { heading: 'Connexion', submit: 'Se connecter' /* … */ } }),
93
+ ]
94
+ ```
95
+
96
+ ```ts
97
+ @Component({
98
+ imports: [AuthLogin, Button, AuthFooterLink, RouterLink],
99
+ template: `
100
+ <gbt-auth-login (loggedIn)="router.navigateByUrl('/home')">
101
+ <img auth-logo src="/logo.svg" alt="Acme" width="160" height="40" />
102
+ <a gbtButton variant="link" gbtAuthFooterLink routerLink="/register">Create an account</a>
103
+ </gbt-auth-login>
104
+ `,
105
+ })
106
+ export class LoginPage {
107
+ protected readonly router = inject(Router)
108
+ }
109
+ ```
110
+
111
+ ## Accessibility
112
+
113
+ See [AUDIT.md](AUDIT.md). The page title (`<title>`) is the application's: set it on the route.
@@ -0,0 +1,104 @@
1
+ # AuthRegister
2
+
3
+ The free registration page of the auth kit, outside the app shell, in the sign-in panel
4
+ ([`gbt-auth-panel`](../auth/auth-panel/auth-panel.ts)). It asks the backend whether registration is open,
5
+ shows the form (or "Registration is closed"), creates the account, then takes the new account through
6
+ the mandatory first MFA enrolment ([`gbt-mfa-enrollment`](../mfa-enrollment/mfa-enrollment.ts)) right
7
+ in the panel. It never talks HTTP, never touches storage and never navigates: the backend is the
8
+ application's `AUTH_PORT`, and the page tells the application where to go through its outputs.
9
+
10
+ **Selector**: `gbt-auth-register`
11
+
12
+ ## States
13
+
14
+ | State | What shows |
15
+ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
16
+ | loading | Until `AuthPort.authConfig()` answers: a skeleton of the form (`role="status"`, `aria-busy`, a visually hidden "Loading"), no heading, never a flash of the form. |
17
+ | open | The form: username, email address, password, one primary "Create my account", then the projected sign-in link. Also shown when `authConfig()` fails: the server enforces the switch anyway. |
18
+ | closed | `registrationEnabled` is false (or the server answered "registration is disabled" to a submit): a lock state with "Registration is closed", its explanation and one "Sign in" button. |
19
+ | enrolment | The server answered an `mfaToken`: the panel widens (`wide`), its heading becomes "Two-factor authentication" and `gbt-mfa-enrollment` replaces the form. A passkey is offered when `authConfig().passkeysAvailable` is true and the browser supports WebAuthn. |
20
+ | created | The enrolment was left ("Back") or its token expired: the account exists, so the page says "Your account has been created", names it (lower-cased, as stored; "The setup has expired." first when it expired) and offers one "Sign in" button. No session is held. |
21
+
22
+ ## Inputs
23
+
24
+ | Input | Type | Default | Role |
25
+ | ------------------- | ------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
26
+ | `labels` | `Partial<RegisterLabels>` | `{}` | Strings to change, over `provideAuthLabels({ register })` and the English defaults (`DEFAULT_REGISTER_LABELS`). |
27
+ | `minPasswordLength` | `number` | `MIN_PASSWORD_LENGTH` (8) | The server's minimum password length, checked before the round trip; also worded in the hint and the error. |
28
+ | `usernamePattern` | `RegExp` | `USERNAME_PATTERN` (a letter, 3 to 32) | The server's username rule, checked on the trimmed name before the round trip. Adjust the `usernameHint` and `usernameInvalid` labels with it. |
29
+
30
+ The enrolment's own strings are `MfaEnrollmentLabels`: localise them with `provideAuthLabels({ mfaEnrollment })`.
31
+
32
+ **A custom `usernamePattern` must not use the `g` or `y` regex flags (they make `.test()` stateful across
33
+ calls, so the same name would pass and fail in turn) and must mirror the server's own rule.** The same goes
34
+ for `minPasswordLength`: both only spare a round trip, the server stays the authority.
35
+
36
+ ## Outputs
37
+
38
+ | Output | Payload | Role |
39
+ | ------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
40
+ | `registered` | `void` | The account exists and has a session: either the backend issued one at once (the port stored it), or the enrolment finished and the held-back session was handed to `AuthPort.setToken`. Navigate into the app. |
41
+ | `signIn` | `void` | "Sign in" was pressed in the closed or created state: go to the sign-in page. |
42
+
43
+ ## Slots
44
+
45
+ | Selector | Role |
46
+ | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
47
+ | `[auth-logo]` | The application's logo (an `img`, `picture` or `svg`), on top of the panel. Optional. |
48
+ | `[auth-backdrop]` | What is drawn on the graphite page, behind the panel: `gbt-git-field`, the family's animated commit graph (`@masmarino/gabarit/git-field`). Optional. |
49
+ | `[gbtAuthFooterLink]` | The link to the sign-in page, under the form after "Already have an account?". An `a gbtButton variant="link"` carrying `routerLink` or `href`. No footer when absent. |
50
+
51
+ ## Behaviour
52
+
53
+ - **Checks before the request.** Nothing is said while the user types; after a first "Create my account"
54
+ every wrong field shows its rule (in place of its hint, as its only `aria-describedby`) and the focus moves
55
+ to the first wrong one. The checks then stay live. Nothing is sent while a field is wrong.
56
+ - **Sent**: `register(username.trim(), email.trim(), password)`. A second submit while in flight is ignored;
57
+ the button shows its spinner and is disabled. The password is emptied as soon as the server answered.
58
+ - **Failures** are worded from the labels, never from the backend's text, in an alert (`role="alert"`), and the
59
+ focus goes where the user retypes: a 400 naming a field focuses that field ("Check the fields"); a 400 naming
60
+ none focuses the alert; a reserved name, a taken name or address (409) focus the field concerned; a 429 says
61
+ to wait; anything else (5xx, network, a browser error) says the creation failed and keeps what was typed. A
62
+ 400 "registration is disabled" switches to the closed state. The recognised bodies are in
63
+ `AUTH_PORT_ERROR_BODIES`.
64
+ - **Focus**: the form starts in the username field; the closed and created states move the focus to their
65
+ `h1` (focusable by script, not a tab stop) so the change is announced.
66
+ - **Sessions**: the page never stores one. A backend without MFA enforcement answers a `token` (the port stores
67
+ it): `registered` fires at once. Otherwise the enrolment keeps the session until the backup codes are
68
+ acknowledged, then the page hands it to `AuthPort.setToken` and emits `registered`.
69
+
70
+ ## Example
71
+
72
+ ```ts
73
+ // app.config.ts
74
+ providers: [
75
+ { provide: AUTH_PORT, useClass: HttpAuthPort }, // your adapter over HttpClient
76
+ {
77
+ provide: TOTP_QR_RENDERER,
78
+ useValue: (text, options) => import('qrcode').then((m) => m.toDataURL(text, options)),
79
+ },
80
+ provideAuthLabels({ register: { intro: 'Join Acme to host your repositories.' } }),
81
+ ]
82
+ ```
83
+
84
+ ```ts
85
+ @Component({
86
+ imports: [AuthRegister, Button, AuthFooterLink, RouterLink],
87
+ template: `
88
+ <gbt-auth-register
89
+ (registered)="router.navigateByUrl('/home')"
90
+ (signIn)="router.navigateByUrl('/login')"
91
+ >
92
+ <img auth-logo src="/logo.svg" alt="Acme" width="160" height="40" />
93
+ <a gbtButton variant="link" gbtAuthFooterLink routerLink="/login">Sign in</a>
94
+ </gbt-auth-register>
95
+ `,
96
+ })
97
+ export class RegisterRoute {
98
+ protected readonly router = inject(Router)
99
+ }
100
+ ```
101
+
102
+ ## Accessibility
103
+
104
+ See [AUDIT.md](AUDIT.md). The panel owns the page's `<main>` landmark and its `h1`.
@@ -0,0 +1,120 @@
1
+ # AuthResetPassword
2
+
3
+ The password-reset page of the auth kit: where the link of a password-reset mail lands, outside the app
4
+ shell, in the sign-in panel ([`gbt-auth-panel`](../auth/auth-panel/auth-panel.ts)). An administrator has
5
+ reset the password of an existing account; the user follows the link and chooses a new password. No
6
+ session comes out of it: they sign in afterwards, through their second factor as on any sign-in (a
7
+ password reset leaves the account's factors untouched). It never talks HTTP, never reads the URL and
8
+ never navigates: the backend is the application's `AUTH_PORT`, the token is an input, and the page tells
9
+ the application where to go through its outputs.
10
+
11
+ **Selector**: `gbt-auth-reset-password`
12
+
13
+ It is the sibling of [`gbt-auth-activate`](../auth-activate/README.md): same one-time link mechanics, same
14
+ form, same failure handling; only the call (`resetPassword` instead of `activate`), the output and the
15
+ wording differ.
16
+
17
+ ## Views
18
+
19
+ | View | What shows |
20
+ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
21
+ | form | A token was given: "Choose a new password", why (an administrator reset it), New password (with its hint), Confirm the new password, one primary "Set new password", then the projected sign-in link. |
22
+ | success | The server accepted: "Your password has been changed", sign in with the new one, one "Sign in" button. |
23
+ | invalid | No token (`null` or `''`), or the server refused it (unknown, expired or used): an error-toned state, "This link does not work", ask an administrator for a new link, one "Sign in". |
24
+
25
+ ## Inputs
26
+
27
+ | Input | Type | Default | Role |
28
+ | ------------------- | ------------------------------ | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
29
+ | `token` | `string \| null` | `null` | The reset link's token, as the application read it from its URL with `activationToken(fragment, null)`. `null` (or `''`) is the dead link, without any request. A new value starts the page over. |
30
+ | `labels` | `Partial<ResetPasswordLabels>` | `{}` | Strings to change, over `provideAuthLabels({ resetPassword })` and the English defaults (`DEFAULT_RESET_PASSWORD_LABELS`). |
31
+ | `minPasswordLength` | `number` | `MIN_PASSWORD_LENGTH` (8) | The server's minimum password length, checked before the round trip; also worded in the hint and the errors. |
32
+
33
+ ## Outputs
34
+
35
+ | Output | Payload | Role |
36
+ | --------------- | ------- | ------------------------------------------------------------------------------------ |
37
+ | `passwordReset` | `void` | The server accepted the new password: the success view shows. No session was opened. |
38
+ | `signIn` | `void` | "Sign in" was pressed in the success or dead-link view: go to the sign-in page. |
39
+
40
+ The success output is `passwordReset`, not `reset`: an output named after a native DOM event would
41
+ also catch the `reset` events bubbling from the page's own `<form>`.
42
+
43
+ ## Slots
44
+
45
+ | Selector | Role |
46
+ | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
47
+ | `[auth-logo]` | The application's logo (an `img`, `picture` or `svg`), on top of the panel. Optional. |
48
+ | `[auth-backdrop]` | What is drawn on the graphite page, behind the panel: `gbt-git-field`, the family's animated commit graph (`@masmarino/gabarit/git-field`). Optional. |
49
+ | `[gbtAuthFooterLink]` | The link to the sign-in page, under the form after "Already set your new password?". An `a gbtButton variant="link"` carrying `routerLink` or `href`. No footer when absent. |
50
+
51
+ ## Behaviour
52
+
53
+ - **The token.** The page sends it with the new password (`resetPassword(token, password)`) and never
54
+ renders it (not in the markup, not in a field). Once spent (success) or refused (a 400 other than a weak
55
+ password), it is dropped: the page does not send it again until a new `token` arrives.
56
+ - **The application's part** (it owns the URL): put the token in the link's **fragment**
57
+ (`/reset-password#token=…`) so that no server, proxy or access log ever sees it; read it once with
58
+ `activationToken(route.snapshot.fragment, null)` (the helper is shared with the activation: a token not
59
+ shaped like the server's, 64 hexadecimal characters by default, is `null`; pass your own `shape` as its
60
+ third argument if your backend's differs); then remove it (and any other parameter) from the address bar
61
+ and the history entry, e.g. `router.navigateByUrl('/reset-password', { replaceUrl: true })` after the
62
+ first render, so it does not linger in a screenshot or a shared tab. Unlike the activation, there is no
63
+ older `?token=` link to support: read the fragment only.
64
+ - **The `token` input must be a one-time snapshot of the URL, never a value that reactively follows the
65
+ URL (e.g. a signal derived from `route.fragment`): the component resets when it changes.** Scrubbing the
66
+ URL as above would otherwise turn the token into `null` and flip the page to the dead-link view, even over
67
+ its success view. Read it into a plain field, as in the example below.
68
+ - **`minPasswordLength` must mirror the server's own rule.** It only spares a round trip: the server stays
69
+ the authority, and a looser value only moves the refusal to the server's answer.
70
+ - **Checks before the request.** Nothing is said while typing; after a first attempt the password rule and
71
+ the confirmation ("Confirm your new password", "The passwords do not match") show under their fields, the
72
+ focus moves to the first wrong one, and the checks stay live.
73
+ - **Failures** are worded from the labels, in an alert, the focus back in the password field: a weak-password
74
+ 400 keeps the form (the link is still good), a 429 says to wait, anything else (5xx, network) says the new
75
+ password could not be set and the same token can be retried. Any other 400 is the dead link: the server
76
+ is expected to answer one generic 400 for an unknown, expired, used or malformed token, so that nobody
77
+ probing links can tell them apart; the page words them all the same way. The failures are read by
78
+ `classifyActivateFailure`, shared with the activation.
79
+ - **Focus**: the form starts in the new-password field; the success and dead-link views move the focus to
80
+ their `h1` (focusable by script, not a tab stop). The passwords are emptied when the server accepted or
81
+ refused the link.
82
+
83
+ ## Example
84
+
85
+ ```ts
86
+ // app.config.ts
87
+ providers: [
88
+ { provide: AUTH_PORT, useClass: HttpAuthPort }, // your adapter over HttpClient
89
+ provideAuthLabels({ resetPassword: { signInPrompt: 'Password already changed?' } }),
90
+ ]
91
+ ```
92
+
93
+ ```ts
94
+ @Component({
95
+ imports: [AuthResetPassword, Button, AuthFooterLink, RouterLink],
96
+ template: `
97
+ <gbt-auth-reset-password [token]="token" (signIn)="router.navigateByUrl('/login')">
98
+ <img auth-logo src="/logo.svg" alt="Acme" width="160" height="40" />
99
+ <a gbtButton variant="link" gbtAuthFooterLink routerLink="/login">Sign in</a>
100
+ </gbt-auth-reset-password>
101
+ `,
102
+ })
103
+ export class ResetPasswordRoute {
104
+ protected readonly router = inject(Router)
105
+ private readonly route = inject(ActivatedRoute)
106
+ // Read once, then scrubbed from the address bar and the history entry.
107
+ protected readonly token = activationToken(this.route.snapshot.fragment, null)
108
+
109
+ constructor() {
110
+ const { fragment, queryParamMap } = this.route.snapshot
111
+ if (fragment !== null || queryParamMap.keys.length > 0) {
112
+ afterNextRender(() => void this.router.navigateByUrl('/reset-password', { replaceUrl: true }))
113
+ }
114
+ }
115
+ }
116
+ ```
117
+
118
+ ## Accessibility
119
+
120
+ See [AUDIT.md](AUDIT.md). The panel owns the page's `<main>` landmark and its `h1`.