@stackcraftmx/calcita 0.47.0 → 0.51.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 (488) hide show
  1. package/README.md +173 -12
  2. package/cli/calcita.js +15 -0
  3. package/cli/checkTexts.js +209 -0
  4. package/cli/packageVersions.js +6 -1
  5. package/cli/projectFiles.js +4 -2
  6. package/cli/templates/project/README.md.tpl +21 -1
  7. package/cli/templates/project/eslint.config.js.tpl +27 -0
  8. package/cli/templates/project/src/app/appTexts.js.tpl +2 -1
  9. package/cli/templates/project/src/core/publicPaths.js.tpl +10 -2
  10. package/cli/templates/project/vite.config.js.tpl +8 -1
  11. package/dist/DataTable/AuditTrailDialog.js +3 -2
  12. package/dist/DataTable/AuditTrailDialog.js.map +1 -1
  13. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +3 -2
  14. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
  15. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +3 -2
  16. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
  17. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +3 -2
  18. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
  19. package/dist/DataTable/EmptyState.js +3 -2
  20. package/dist/DataTable/EmptyState.js.map +1 -1
  21. package/dist/DataTable/FilterChips.js +3 -2
  22. package/dist/DataTable/FilterChips.js.map +1 -1
  23. package/dist/DataTable/GoToPage.js +3 -2
  24. package/dist/DataTable/GoToPage.js.map +1 -1
  25. package/dist/DataTable/ServerTable.js +95 -28
  26. package/dist/DataTable/ServerTable.js.map +1 -1
  27. package/dist/DataTable/ServerTableFilterDrawer.js +8 -3
  28. package/dist/DataTable/ServerTableFilterDrawer.js.map +1 -1
  29. package/dist/DataTable/StackedCell.js +60 -0
  30. package/dist/DataTable/StackedCell.js.map +1 -0
  31. package/dist/DataTable/TableCardsView.js +88 -0
  32. package/dist/DataTable/TableCardsView.js.map +1 -0
  33. package/dist/DataTable/columnWidths.js +30 -0
  34. package/dist/DataTable/columnWidths.js.map +1 -0
  35. package/dist/DataTable/columns.js +47 -1
  36. package/dist/DataTable/columns.js.map +1 -1
  37. package/dist/DataTable/fixedColumns.js +24 -0
  38. package/dist/DataTable/fixedColumns.js.map +1 -0
  39. package/dist/DataTable/useTableView.js +29 -0
  40. package/dist/DataTable/useTableView.js.map +1 -0
  41. package/dist/access/PermissionMatrix.js +3 -2
  42. package/dist/access/PermissionMatrix.js.map +1 -1
  43. package/dist/account/AccountProvider.js +1 -1
  44. package/dist/account/AccountSecuritySection.js +3 -2
  45. package/dist/account/AccountSecuritySection.js.map +1 -1
  46. package/dist/account/DemoTotpCodeButton.js +3 -2
  47. package/dist/account/DemoTotpCodeButton.js.map +1 -1
  48. package/dist/account/ProfileScreen.js +3 -2
  49. package/dist/account/ProfileScreen.js.map +1 -1
  50. package/dist/account/SignInScreen.js +3 -2
  51. package/dist/account/SignInScreen.js.map +1 -1
  52. package/dist/appShell/AccountMenu.js +3 -2
  53. package/dist/appShell/AccountMenu.js.map +1 -1
  54. package/dist/appShell/AppLayout.js +3 -2
  55. package/dist/appShell/AppLayout.js.map +1 -1
  56. package/dist/appShell/AppearanceSettings.js +3 -2
  57. package/dist/appShell/AppearanceSettings.js.map +1 -1
  58. package/dist/appShell/AuthLayout.js +3 -2
  59. package/dist/appShell/AuthLayout.js.map +1 -1
  60. package/dist/appShell/BarActionButton.js +11 -4
  61. package/dist/appShell/BarActionButton.js.map +1 -1
  62. package/dist/appShell/BarActions.js +3 -2
  63. package/dist/appShell/BarActions.js.map +1 -1
  64. package/dist/appShell/BarCapsule.js +3 -2
  65. package/dist/appShell/BarCapsule.js.map +1 -1
  66. package/dist/appShell/BarSearch.js +3 -2
  67. package/dist/appShell/BarSearch.js.map +1 -1
  68. package/dist/appShell/HeaderTools.js +3 -2
  69. package/dist/appShell/HeaderTools.js.map +1 -1
  70. package/dist/appShell/MobileTabBar.js +3 -2
  71. package/dist/appShell/MobileTabBar.js.map +1 -1
  72. package/dist/appShell/SettingsMenu.js +3 -2
  73. package/dist/appShell/SettingsMenu.js.map +1 -1
  74. package/dist/appShell/SideMenu.js +3 -2
  75. package/dist/appShell/SideMenu.js.map +1 -1
  76. package/dist/appShell/SideMenuEntry.js +3 -2
  77. package/dist/appShell/SideMenuEntry.js.map +1 -1
  78. package/dist/appShell/SubmenuActionsMenu.js +3 -2
  79. package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
  80. package/dist/appShell/TabBarEditor.js +3 -2
  81. package/dist/appShell/TabBarEditor.js.map +1 -1
  82. package/dist/appShell/TopMenu.js +3 -2
  83. package/dist/appShell/TopMenu.js.map +1 -1
  84. package/dist/appShell/Wordmark.js +3 -2
  85. package/dist/appShell/Wordmark.js.map +1 -1
  86. package/dist/auth/PasswordChecklist.js +3 -2
  87. package/dist/auth/PasswordChecklist.js.map +1 -1
  88. package/dist/calendar/EventCalendar.js +3 -2
  89. package/dist/calendar/EventCalendar.js.map +1 -1
  90. package/dist/calendar/EventDetails.js +3 -2
  91. package/dist/calendar/EventDetails.js.map +1 -1
  92. package/dist/datePickers/DateInput.js +28 -22
  93. package/dist/datePickers/DateInput.js.map +1 -1
  94. package/dist/datePickers/DateTimeInput.js +33 -27
  95. package/dist/datePickers/DateTimeInput.js.map +1 -1
  96. package/dist/datePickers/MonthInput.js +27 -21
  97. package/dist/datePickers/MonthInput.js.map +1 -1
  98. package/dist/datePickers/TimeInput.js +26 -20
  99. package/dist/datePickers/TimeInput.js.map +1 -1
  100. package/dist/datePickers/usePickerField.js +5 -4
  101. package/dist/datePickers/usePickerField.js.map +1 -1
  102. package/dist/downloads/DownloadManager.js +3 -2
  103. package/dist/downloads/DownloadManager.js.map +1 -1
  104. package/dist/feedback/ConfirmDialog.js +3 -2
  105. package/dist/feedback/ConfirmDialog.js.map +1 -1
  106. package/dist/feedback/ModalWaiting.js +3 -2
  107. package/dist/feedback/ModalWaiting.js.map +1 -1
  108. package/dist/feedback/NewBuildNotice.js +3 -2
  109. package/dist/feedback/NewBuildNotice.js.map +1 -1
  110. package/dist/filepond/FileDropzone.js +3 -2
  111. package/dist/filepond/FileDropzone.js.map +1 -1
  112. package/dist/forms/FormProblemAlert.js +3 -2
  113. package/dist/forms/FormProblemAlert.js.map +1 -1
  114. package/dist/forms/SubmitButton.js +7 -2
  115. package/dist/forms/SubmitButton.js.map +1 -1
  116. package/dist/forms/auth/SignInForm.js +3 -2
  117. package/dist/forms/auth/SignInForm.js.map +1 -1
  118. package/dist/forms/fieldRules.js +30 -0
  119. package/dist/forms/fieldRules.js.map +1 -0
  120. package/dist/forms/security/SecondStepForm.js +3 -2
  121. package/dist/forms/security/SecondStepForm.js.map +1 -1
  122. package/dist/forms/security/TwoStepVerificationCard.js +3 -2
  123. package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
  124. package/dist/forms/useValidationText.js +18 -0
  125. package/dist/forms/useValidationText.js.map +1 -0
  126. package/dist/forms/validation.js +35 -31
  127. package/dist/forms/validation.js.map +1 -1
  128. package/dist/forms/validationMessages.js +64 -7
  129. package/dist/forms/validationMessages.js.map +1 -1
  130. package/dist/forms.js +3 -0
  131. package/dist/forms.js.map +1 -1
  132. package/dist/hookForm/FormProblemAlert.js +3 -2
  133. package/dist/hookForm/FormProblemAlert.js.map +1 -1
  134. package/dist/hookForm/SubmitButton.js +7 -2
  135. package/dist/hookForm/SubmitButton.js.map +1 -1
  136. package/dist/inbox/InboxLayout.js +3 -2
  137. package/dist/inbox/InboxLayout.js.map +1 -1
  138. package/dist/inbox/MessageList.js +3 -2
  139. package/dist/inbox/MessageList.js.map +1 -1
  140. package/dist/inbox/MessageView.js +3 -2
  141. package/dist/inbox/MessageView.js.map +1 -1
  142. package/dist/index.js +186 -163
  143. package/dist/index.js.map +1 -1
  144. package/dist/inputs/CatalogInput.js +32 -25
  145. package/dist/inputs/CatalogInput.js.map +1 -1
  146. package/dist/inputs/CheckboxGroupInput.js +8 -5
  147. package/dist/inputs/CheckboxGroupInput.js.map +1 -1
  148. package/dist/inputs/ColorInput.js +7 -4
  149. package/dist/inputs/ColorInput.js.map +1 -1
  150. package/dist/inputs/FieldFrame.js +10 -4
  151. package/dist/inputs/FieldFrame.js.map +1 -1
  152. package/dist/inputs/FormSection.js +1 -1
  153. package/dist/inputs/MaskedInput.js +1 -0
  154. package/dist/inputs/MaskedInput.js.map +1 -1
  155. package/dist/inputs/NumberInput.js +29 -24
  156. package/dist/inputs/NumberInput.js.map +1 -1
  157. package/dist/inputs/RepeatingFields.js +8 -5
  158. package/dist/inputs/RepeatingFields.js.map +1 -1
  159. package/dist/inputs/SelectInput.js +8 -5
  160. package/dist/inputs/SelectInput.js.map +1 -1
  161. package/dist/inputs/TextInput.js +5 -3
  162. package/dist/inputs/TextInput.js.map +1 -1
  163. package/dist/inputs/TransferListInput.js +8 -5
  164. package/dist/inputs/TransferListInput.js.map +1 -1
  165. package/dist/inputs/WizardLayout.js +3 -2
  166. package/dist/inputs/WizardLayout.js.map +1 -1
  167. package/dist/kanban/KanbanBoard.js +3 -2
  168. package/dist/kanban/KanbanBoard.js.map +1 -1
  169. package/dist/legal/CookieNotice.js +3 -2
  170. package/dist/legal/CookieNotice.js.map +1 -1
  171. package/dist/legal/TermsAcceptanceDialog.js +3 -2
  172. package/dist/legal/TermsAcceptanceDialog.js.map +1 -1
  173. package/dist/locales/en.js +24 -0
  174. package/dist/locales/en.js.map +1 -1
  175. package/dist/locales/es.js +24 -0
  176. package/dist/locales/es.js.map +1 -1
  177. package/dist/maps/MapView.js +3 -2
  178. package/dist/maps/MapView.js.map +1 -1
  179. package/dist/mexico/CfdiSummary.js +3 -2
  180. package/dist/mexico/CfdiSummary.js.map +1 -1
  181. package/dist/mexico/EfirmaFields.js +3 -2
  182. package/dist/mexico/EfirmaFields.js.map +1 -1
  183. package/dist/mexico/mexicoIdentifiers.js +5 -0
  184. package/dist/mexico/mexicoIdentifiers.js.map +1 -1
  185. package/dist/mexico/mexicoRules.js +9 -4
  186. package/dist/mexico/mexicoRules.js.map +1 -1
  187. package/dist/mexico.js +4 -2
  188. package/dist/pwa/InstallAppSetting.js +3 -2
  189. package/dist/pwa/InstallAppSetting.js.map +1 -1
  190. package/dist/pwa/InstallInstructionsDialog.js +3 -2
  191. package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
  192. package/dist/pwa/InstallPromptBanner.js +3 -2
  193. package/dist/pwa/InstallPromptBanner.js.map +1 -1
  194. package/dist/react-hook-form.js +3 -0
  195. package/dist/react-hook-form.js.map +1 -1
  196. package/dist/richText/RichTextEditor.js +7 -4
  197. package/dist/richText/RichTextEditor.js.map +1 -1
  198. package/dist/richText/RichTextView.js +3 -2
  199. package/dist/richText/RichTextView.js.map +1 -1
  200. package/dist/security/ActivityLog.js +3 -2
  201. package/dist/security/ActivityLog.js.map +1 -1
  202. package/dist/security/RecoveryCodesDialog.js +3 -2
  203. package/dist/security/RecoveryCodesDialog.js.map +1 -1
  204. package/dist/security/SessionsCard.js +3 -2
  205. package/dist/security/SessionsCard.js.map +1 -1
  206. package/dist/table.js +21 -2
  207. package/dist/table.js.map +1 -1
  208. package/dist/theme/themePieces.js +70 -4
  209. package/dist/theme/themePieces.js.map +1 -1
  210. package/dist/toolkit/ToolkitProvider.js +8 -1
  211. package/dist/toolkit/ToolkitProvider.js.map +1 -1
  212. package/dist/toolkit/browserNavigation.js +19 -4
  213. package/dist/toolkit/browserNavigation.js.map +1 -1
  214. package/dist/toolkit/combineTexts.js +32 -0
  215. package/dist/toolkit/combineTexts.js.map +1 -0
  216. package/dist/toolkit/hashNavigation.js +17 -3
  217. package/dist/toolkit/hashNavigation.js.map +1 -1
  218. package/dist/toolkit/navigationPaths.js +15 -0
  219. package/dist/toolkit/navigationPaths.js.map +1 -1
  220. package/dist/toolkit/pathIndex.js +66 -0
  221. package/dist/toolkit/pathIndex.js.map +1 -0
  222. package/dist/toolkit/toolkitSettings.js +19 -1
  223. package/dist/toolkit/toolkitSettings.js.map +1 -1
  224. package/dist/types/DataTable/AuditTrailDialog.d.ts +6 -17
  225. package/dist/types/DataTable/ColumnFilters/HeaderFilterPopover.d.ts +6 -5
  226. package/dist/types/DataTable/ColumnFilters/MultiSelectColumnFilter.d.ts +6 -9
  227. package/dist/types/DataTable/ColumnFilters/SortableFilterHeader.d.ts +6 -14
  228. package/dist/types/DataTable/EmptyState.d.ts +6 -9
  229. package/dist/types/DataTable/FilterChips.d.ts +6 -11
  230. package/dist/types/DataTable/GoToPage.d.ts +6 -9
  231. package/dist/types/DataTable/ServerTable.d.ts +16 -80
  232. package/dist/types/DataTable/ServerTableFilterDrawer.d.ts +6 -13
  233. package/dist/types/DataTable/StackedCell.d.ts +12 -0
  234. package/dist/types/DataTable/TableCardsView.d.ts +27 -0
  235. package/dist/types/DataTable/columnWidths.d.ts +21 -0
  236. package/dist/types/DataTable/columns.d.ts +111 -0
  237. package/dist/types/DataTable/fixedColumns.d.ts +29 -0
  238. package/dist/types/DataTable/index.d.ts +6 -1
  239. package/dist/types/DataTable/useTableView.d.ts +22 -0
  240. package/dist/types/access/PermissionMatrix.d.ts +6 -10
  241. package/dist/types/account/AccountSecuritySection.d.ts +6 -7
  242. package/dist/types/account/DemoTotpCodeButton.d.ts +6 -5
  243. package/dist/types/account/ProfileScreen.d.ts +6 -18
  244. package/dist/types/account/SignInScreen.d.ts +6 -13
  245. package/dist/types/appShell/AccountMenu.d.ts +6 -11
  246. package/dist/types/appShell/AppLayout.d.ts +3 -40
  247. package/dist/types/appShell/AppearanceSettings.d.ts +6 -12
  248. package/dist/types/appShell/AuthLayout.d.ts +3 -11
  249. package/dist/types/appShell/BarActionButton.d.ts +6 -10
  250. package/dist/types/appShell/BarActions.d.ts +6 -15
  251. package/dist/types/appShell/BarCapsule.d.ts +6 -9
  252. package/dist/types/appShell/BarSearch.d.ts +6 -15
  253. package/dist/types/appShell/HeaderTools.d.ts +6 -16
  254. package/dist/types/appShell/MobileTabBar.d.ts +6 -13
  255. package/dist/types/appShell/SettingsMenu.d.ts +6 -10
  256. package/dist/types/appShell/SideMenu.d.ts +6 -20
  257. package/dist/types/appShell/SideMenuEntry.d.ts +6 -11
  258. package/dist/types/appShell/SubmenuActionsMenu.d.ts +6 -12
  259. package/dist/types/appShell/TabBarEditor.d.ts +6 -9
  260. package/dist/types/appShell/TopMenu.d.ts +6 -5
  261. package/dist/types/appShell/Wordmark.d.ts +6 -7
  262. package/dist/types/auth/PasswordChecklist.d.ts +6 -9
  263. package/dist/types/calendar/EventCalendar.d.ts +6 -23
  264. package/dist/types/calendar/EventDetails.d.ts +6 -10
  265. package/dist/types/datePickers/DateInput.d.ts +7 -22
  266. package/dist/types/datePickers/DateTimeInput.d.ts +7 -27
  267. package/dist/types/datePickers/MonthInput.d.ts +7 -21
  268. package/dist/types/datePickers/TimeInput.d.ts +7 -21
  269. package/dist/types/datePickers/usePickerField.d.ts +5 -1
  270. package/dist/types/downloads/DownloadManager.d.ts +6 -6
  271. package/dist/types/feedback/ConfirmDialog.d.ts +6 -18
  272. package/dist/types/feedback/ModalWaiting.d.ts +6 -9
  273. package/dist/types/feedback/NewBuildNotice.d.ts +6 -10
  274. package/dist/types/filepond/FileDropzone.d.ts +6 -29
  275. package/dist/types/forms/FormProblemAlert.d.ts +6 -5
  276. package/dist/types/forms/SubmitButton.d.ts +6 -6
  277. package/dist/types/forms/auth/SignInForm.d.ts +6 -11
  278. package/dist/types/forms/fieldRules.d.ts +44 -0
  279. package/dist/types/forms/index.d.ts +1 -0
  280. package/dist/types/forms/security/SecondStepForm.d.ts +6 -14
  281. package/dist/types/forms/security/TwoStepVerificationCard.d.ts +6 -21
  282. package/dist/types/forms/useValidationText.d.ts +12 -0
  283. package/dist/types/forms/validation.d.ts +117 -174
  284. package/dist/types/forms/validationMessages.d.ts +54 -6
  285. package/dist/types/forms.d.ts +1 -1
  286. package/dist/types/hookForm/FormProblemAlert.d.ts +6 -5
  287. package/dist/types/hookForm/SubmitButton.d.ts +6 -13
  288. package/dist/types/inbox/InboxLayout.d.ts +6 -17
  289. package/dist/types/inbox/MessageList.d.ts +6 -18
  290. package/dist/types/inbox/MessageView.d.ts +6 -14
  291. package/dist/types/index.d.ts +8 -1
  292. package/dist/types/inputs/CatalogInput.d.ts +7 -24
  293. package/dist/types/inputs/CheckboxGroupInput.d.ts +7 -18
  294. package/dist/types/inputs/ColorInput.d.ts +7 -16
  295. package/dist/types/inputs/FieldFrame.d.ts +6 -10
  296. package/dist/types/inputs/MaskedInput.d.ts +3 -0
  297. package/dist/types/inputs/NumberInput.d.ts +7 -20
  298. package/dist/types/inputs/RepeatingFields.d.ts +7 -28
  299. package/dist/types/inputs/SelectInput.d.ts +7 -20
  300. package/dist/types/inputs/TextInput.d.ts +3 -0
  301. package/dist/types/inputs/TransferListInput.d.ts +7 -20
  302. package/dist/types/inputs/WizardLayout.d.ts +6 -19
  303. package/dist/types/kanban/KanbanBoard.d.ts +6 -25
  304. package/dist/types/legal/CookieNotice.d.ts +6 -16
  305. package/dist/types/legal/TermsAcceptanceDialog.d.ts +6 -18
  306. package/dist/types/locales/en.d.ts +24 -0
  307. package/dist/types/locales/es.d.ts +24 -0
  308. package/dist/types/maps/MapView.d.ts +6 -17
  309. package/dist/types/mexico/CfdiSummary.d.ts +6 -11
  310. package/dist/types/mexico/EfirmaFields.d.ts +6 -16
  311. package/dist/types/mexico/mexicoIdentifiers.d.ts +7 -0
  312. package/dist/types/mexico/mexicoRules.d.ts +19 -3
  313. package/dist/types/mexico.d.ts +2 -2
  314. package/dist/types/pwa/InstallAppSetting.d.ts +6 -6
  315. package/dist/types/pwa/InstallInstructionsDialog.d.ts +6 -9
  316. package/dist/types/pwa/InstallPromptBanner.d.ts +6 -11
  317. package/dist/types/react-hook-form.d.ts +1 -0
  318. package/dist/types/richText/RichTextEditor.d.ts +7 -22
  319. package/dist/types/richText/RichTextView.d.ts +6 -9
  320. package/dist/types/security/ActivityLog.d.ts +6 -9
  321. package/dist/types/security/RecoveryCodesDialog.d.ts +6 -11
  322. package/dist/types/security/SessionsCard.d.ts +6 -11
  323. package/dist/types/table.d.ts +3 -1
  324. package/dist/types/theme/themePieces.d.ts +55 -3
  325. package/dist/types/toolkit/ToolkitProvider.d.ts +13 -1
  326. package/dist/types/toolkit/browserNavigation.d.ts +7 -3
  327. package/dist/types/toolkit/combineTexts.d.ts +6 -0
  328. package/dist/types/toolkit/hashNavigation.d.ts +4 -2
  329. package/dist/types/toolkit/navigationPaths.d.ts +35 -0
  330. package/dist/types/toolkit/pathIndex.d.ts +27 -0
  331. package/dist/types/toolkit/toolkitSettings.d.ts +7 -4
  332. package/dist/types/ui/actions/ActionsMenu.d.ts +9 -11
  333. package/dist/types/ui/actions/CopyButton.d.ts +6 -12
  334. package/dist/types/ui/actions/DownloadMenu.d.ts +6 -29
  335. package/dist/types/ui/actions/SecretField.d.ts +6 -11
  336. package/dist/types/ui/actions/SelectionActions.d.ts +6 -13
  337. package/dist/types/ui/cards/RecordCard.d.ts +6 -31
  338. package/dist/types/ui/cards/RecordCardSkeleton.d.ts +6 -11
  339. package/dist/types/ui/countdown/Countdown.d.ts +6 -15
  340. package/dist/types/ui/documents/PdfViewerDialog.d.ts +6 -13
  341. package/dist/types/ui/filters/DateRangeFilter.d.ts +6 -10
  342. package/dist/types/ui/filters/FilterDrawer.d.ts +6 -17
  343. package/dist/types/ui/filters/PeriodRangeSelector.d.ts +6 -13
  344. package/dist/types/ui/filters/QuickFilters.d.ts +6 -12
  345. package/dist/types/ui/help/HelpButton.d.ts +6 -10
  346. package/dist/types/ui/help/HelpCarouselDialog.d.ts +6 -14
  347. package/dist/types/ui/labels/MarkedText.d.ts +10 -0
  348. package/dist/types/ui/labels/Tag.d.ts +6 -12
  349. package/dist/types/ui/labels/markedTextPieces.d.ts +22 -0
  350. package/dist/types/ui/layout/CollapsibleSection.d.ts +6 -12
  351. package/dist/types/ui/layout/ContentDialog.d.ts +6 -10
  352. package/dist/types/ui/layout/DefinitionList.d.ts +6 -9
  353. package/dist/types/ui/layout/DetailHeader.d.ts +6 -10
  354. package/dist/types/ui/layout/ErrorPage.d.ts +6 -17
  355. package/dist/types/ui/layout/FullPageLoader.d.ts +6 -6
  356. package/dist/types/ui/layout/GlassPanel.d.ts +6 -8
  357. package/dist/types/ui/layout/PageHeader.d.ts +6 -10
  358. package/dist/types/ui/layout/PageHeading.d.ts +6 -11
  359. package/dist/types/ui/layout/ProfileHeader.d.ts +6 -11
  360. package/dist/types/ui/layout/ScrollableRow.d.ts +6 -13
  361. package/dist/types/ui/layout/SectionCard.d.ts +6 -8
  362. package/dist/types/ui/metrics/BarList.d.ts +6 -12
  363. package/dist/types/ui/metrics/CalendarHeatmap.d.ts +6 -19
  364. package/dist/types/ui/metrics/ChartTooltip.d.ts +6 -6
  365. package/dist/types/ui/metrics/ColumnChart.d.ts +6 -25
  366. package/dist/types/ui/metrics/LineChart.d.ts +6 -20
  367. package/dist/types/ui/metrics/MetricCard.d.ts +6 -17
  368. package/dist/types/ui/metrics/TableToggle.d.ts +6 -6
  369. package/dist/types/ui/metrics/chartParts.d.ts +15 -30
  370. package/dist/types/ui/navigation/BackButton.d.ts +6 -9
  371. package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +6 -9
  372. package/dist/types/ui/navigation/FontSizeToggle.d.ts +6 -8
  373. package/dist/types/ui/navigation/LanguageToggle.d.ts +6 -8
  374. package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +6 -7
  375. package/dist/types/ui/navigation/RouteTabs.d.ts +7 -12
  376. package/dist/types/ui/timeline/GroupedTimeline.d.ts +6 -23
  377. package/dist/types/upload/AttachmentsInput.d.ts +11 -1
  378. package/dist/types/upload/FileDropzone.d.ts +6 -21
  379. package/dist/types/upload/FileInput.d.ts +7 -24
  380. package/dist/types/upload/FileUploadInput.d.ts +7 -31
  381. package/dist/types/upload/ImageInput.d.ts +7 -25
  382. package/dist/types/upload/TemplateDownloadButton.d.ts +6 -18
  383. package/dist/ui/actions/ActionsMenu.js +14 -5
  384. package/dist/ui/actions/ActionsMenu.js.map +1 -1
  385. package/dist/ui/actions/CopyButton.js +8 -3
  386. package/dist/ui/actions/CopyButton.js.map +1 -1
  387. package/dist/ui/actions/DownloadMenu.js +3 -2
  388. package/dist/ui/actions/DownloadMenu.js.map +1 -1
  389. package/dist/ui/actions/SecretField.js +8 -3
  390. package/dist/ui/actions/SecretField.js.map +1 -1
  391. package/dist/ui/actions/SelectionActions.js +3 -2
  392. package/dist/ui/actions/SelectionActions.js.map +1 -1
  393. package/dist/ui/cards/RecordCard.js +4 -3
  394. package/dist/ui/cards/RecordCard.js.map +1 -1
  395. package/dist/ui/cards/RecordCardSkeleton.js +8 -3
  396. package/dist/ui/cards/RecordCardSkeleton.js.map +1 -1
  397. package/dist/ui/countdown/Countdown.js +3 -2
  398. package/dist/ui/countdown/Countdown.js.map +1 -1
  399. package/dist/ui/documents/PdfViewerDialog.js +3 -2
  400. package/dist/ui/documents/PdfViewerDialog.js.map +1 -1
  401. package/dist/ui/filters/DateRangeFilter.js +3 -2
  402. package/dist/ui/filters/DateRangeFilter.js.map +1 -1
  403. package/dist/ui/filters/FilterDrawer.js +3 -2
  404. package/dist/ui/filters/FilterDrawer.js.map +1 -1
  405. package/dist/ui/filters/PeriodRangeSelector.js +3 -2
  406. package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
  407. package/dist/ui/filters/QuickFilters.js +3 -2
  408. package/dist/ui/filters/QuickFilters.js.map +1 -1
  409. package/dist/ui/help/HelpButton.js +8 -3
  410. package/dist/ui/help/HelpButton.js.map +1 -1
  411. package/dist/ui/help/HelpCarouselDialog.js +3 -2
  412. package/dist/ui/help/HelpCarouselDialog.js.map +1 -1
  413. package/dist/ui/labels/MarkedText.js +31 -0
  414. package/dist/ui/labels/MarkedText.js.map +1 -0
  415. package/dist/ui/labels/Tag.js +3 -2
  416. package/dist/ui/labels/Tag.js.map +1 -1
  417. package/dist/ui/labels/markedTextPieces.js +64 -0
  418. package/dist/ui/labels/markedTextPieces.js.map +1 -0
  419. package/dist/ui/layout/CollapsibleSection.js +3 -2
  420. package/dist/ui/layout/CollapsibleSection.js.map +1 -1
  421. package/dist/ui/layout/ContentDialog.js +3 -2
  422. package/dist/ui/layout/ContentDialog.js.map +1 -1
  423. package/dist/ui/layout/DefinitionList.js +3 -2
  424. package/dist/ui/layout/DefinitionList.js.map +1 -1
  425. package/dist/ui/layout/DetailHeader.js +3 -2
  426. package/dist/ui/layout/DetailHeader.js.map +1 -1
  427. package/dist/ui/layout/ErrorPage.js +3 -2
  428. package/dist/ui/layout/ErrorPage.js.map +1 -1
  429. package/dist/ui/layout/FullPageLoader.js +3 -2
  430. package/dist/ui/layout/FullPageLoader.js.map +1 -1
  431. package/dist/ui/layout/GlassPanel.js +3 -2
  432. package/dist/ui/layout/GlassPanel.js.map +1 -1
  433. package/dist/ui/layout/PageHeader.js +3 -2
  434. package/dist/ui/layout/PageHeader.js.map +1 -1
  435. package/dist/ui/layout/PageHeading.js +3 -2
  436. package/dist/ui/layout/PageHeading.js.map +1 -1
  437. package/dist/ui/layout/ProfileHeader.js +3 -2
  438. package/dist/ui/layout/ProfileHeader.js.map +1 -1
  439. package/dist/ui/layout/ScrollableRow.js +3 -2
  440. package/dist/ui/layout/ScrollableRow.js.map +1 -1
  441. package/dist/ui/layout/SectionCard.js +3 -2
  442. package/dist/ui/layout/SectionCard.js.map +1 -1
  443. package/dist/ui/metrics/BarList.js +3 -2
  444. package/dist/ui/metrics/BarList.js.map +1 -1
  445. package/dist/ui/metrics/CalendarHeatmap.js +3 -2
  446. package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
  447. package/dist/ui/metrics/ChartTooltip.js +3 -2
  448. package/dist/ui/metrics/ChartTooltip.js.map +1 -1
  449. package/dist/ui/metrics/ColumnChart.js +3 -2
  450. package/dist/ui/metrics/ColumnChart.js.map +1 -1
  451. package/dist/ui/metrics/LineChart.js +3 -2
  452. package/dist/ui/metrics/LineChart.js.map +1 -1
  453. package/dist/ui/metrics/MetricCard.js +3 -2
  454. package/dist/ui/metrics/MetricCard.js.map +1 -1
  455. package/dist/ui/metrics/TableToggle.js +3 -2
  456. package/dist/ui/metrics/TableToggle.js.map +1 -1
  457. package/dist/ui/metrics/chartParts.js +7 -4
  458. package/dist/ui/metrics/chartParts.js.map +1 -1
  459. package/dist/ui/navigation/BackButton.js +7 -2
  460. package/dist/ui/navigation/BackButton.js.map +1 -1
  461. package/dist/ui/navigation/ColorSchemeToggle.js +3 -2
  462. package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
  463. package/dist/ui/navigation/FontSizeToggle.js +3 -2
  464. package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
  465. package/dist/ui/navigation/LanguageToggle.js +3 -2
  466. package/dist/ui/navigation/LanguageToggle.js.map +1 -1
  467. package/dist/ui/navigation/PageBreadcrumbs.js +3 -2
  468. package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
  469. package/dist/ui/navigation/RouteTabs.js +8 -4
  470. package/dist/ui/navigation/RouteTabs.js.map +1 -1
  471. package/dist/ui/timeline/GroupedTimeline.js +3 -2
  472. package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
  473. package/dist/upload/AttachmentsInput.js +9 -6
  474. package/dist/upload/AttachmentsInput.js.map +1 -1
  475. package/dist/upload/FileChip.js +2 -1
  476. package/dist/upload/FileChip.js.map +1 -1
  477. package/dist/upload/FileDropzone.js +5 -4
  478. package/dist/upload/FileDropzone.js.map +1 -1
  479. package/dist/upload/FileInput.js +9 -6
  480. package/dist/upload/FileInput.js.map +1 -1
  481. package/dist/upload/FileUploadInput.js +9 -6
  482. package/dist/upload/FileUploadInput.js.map +1 -1
  483. package/dist/upload/ImageInput.js +8 -5
  484. package/dist/upload/ImageInput.js.map +1 -1
  485. package/dist/upload/TemplateDownloadButton.js +3 -2
  486. package/dist/upload/TemplateDownloadButton.js.map +1 -1
  487. package/package.json +1 -1
  488. package/cli/templates/project/src/app/combineTexts.js.tpl +0 -31
@@ -1 +1 @@
1
- {"version":3,"file":"TwoStepVerificationCard.js","sources":["../../../src/forms/security/TwoStepVerificationCard.jsx"],"sourcesContent":["// «Verificación en dos pasos» de «Mi perfil»: las llaves de acceso, la app autenticadora y los códigos de recuperación.\n//\n// Lo que QUITA protección (desactivar la app, quitar una llave, generar códigos nuevos) pide la contraseña: una sesión que\n// alguien dejó abierta no debe bastar para desarmar la cuenta. Activar no la pide.\n//\n// La tarjeta no sabe del servidor: el proyecto le pasa el estado (security) y qué hacer en cada caso (actions); cada\n// acción regresa {security, recoveryCodes?} y la tarjeta avisa el estado nuevo con onSecurityChange. Las llaves de acceso\n// las crea el proyecto con createPasskey (@stackcraftmx/calcita/passkeys) dentro de actions.addPasskey: así esta puerta no\n// carga la librería de llaves.\n//\n// <TwoStepVerificationCard security={security} onSecurityChange={setSecurity} account={session.email}\n// canUsePasskeys={passkeysSupported()} actions={securityActions} />\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTwoStepVerification con defaultProps y\n// styleOverrides de sus partes: qr, secret, secretCode, header, headerTitle, headerText, menuIcon.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {Form, Formik} from 'formik';\nimport Alert from '@mui/material/Alert';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Dialog from '@mui/material/Dialog';\nimport DialogActions from '@mui/material/DialogActions';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogContentText from '@mui/material/DialogContentText';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport List from '@mui/material/List';\nimport ListItem from '@mui/material/ListItem';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Stack from '@mui/material/Stack';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined';\nimport FingerprintOutlinedIcon from '@mui/icons-material/FingerprintOutlined';\nimport PhonelinkLockOutlinedIcon from '@mui/icons-material/PhonelinkLockOutlined';\nimport VpnKeyOutlinedIcon from '@mui/icons-material/VpnKeyOutlined';\n\nimport {toastSuccess} from '@/feedback/toast.jsx';\nimport FormProblemAlert from '@/forms/FormProblemAlert.jsx';\nimport FormTextField from '@/forms/FormTextField.jsx';\nimport SubmitButton from '@/forms/SubmitButton.jsx';\nimport {applyServerProblem} from '@/forms/applyServerProblem.js';\nimport {Yup} from '@/forms/validation.js';\nimport {\n CURRENT_PASSWORD_MAX_LENGTH, PASSKEY_NAME_MAX_LENGTH, TOTP_CODE_MAX_LENGTH, TOTP_CODE_MIN_LENGTH, TOTP_CODE_PATTERN, normalizeTotpCode,\n} from '@/forms/security/securityRules.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport RecoveryCodesDialog from '@/security/RecoveryCodesDialog.jsx';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport CopyButton from '@/ui/actions/CopyButton.jsx';\nimport Tag from '@/ui/labels/Tag.jsx';\nimport SectionCard from '@/ui/layout/SectionCard.jsx';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaTwoStepVerification)\nconst THEME_NAME = 'CalcitaTwoStepVerification';\nconst TwoStepQr = piecePart(THEME_NAME, 'Qr', Box);\nconst TwoStepSecret = piecePart(THEME_NAME, 'Secret', Stack);\nconst TwoStepSecretCode = piecePart(THEME_NAME, 'SecretCode', Box);\nconst TwoStepHeader = piecePart(THEME_NAME, 'Header', Stack);\nconst TwoStepHeaderTitle = piecePart(THEME_NAME, 'HeaderTitle', Stack);\nconst TwoStepHeaderText = piecePart(THEME_NAME, 'HeaderText', Box);\nconst TwoStepMenuIcon = piecePart(THEME_NAME, 'MenuIcon', ListItemIcon);\n\n// los códigos que quedan desde donde se avisa en ámbar que ya son pocos\nconst FEW_CODES_LEFT = 2;\nconst QR_SIZE_PIXELS = 200;\nconst CODE_FONT = 'ui-monospace, SFMono-Regular, Menlo, monospace';\n\n/**\n * Lo que hace un formulario de la tarjeta con un error: un ApiError va a su campo o arriba (applyServerProblem); un\n * error del navegador (la llave de acceso) va arriba; si la persona solo canceló, nada.\n *\n * @param {Error & {cancelled?: boolean, status?: number}} error\n * @param {object} formikHelpers\n * @param {object} values\n */\nfunction showFormError(error, formikHelpers, values) {\n if (error?.cancelled) {\n return;\n }\n if (error?.status === undefined) {\n formikHelpers.setStatus(error?.message);\n return;\n }\n applyServerProblem(error, {...formikHelpers, values});\n}\n\n/** Confirmar con la contraseña antes de quitar protección. */\nfunction PasswordDialog({open, title, description, confirmLabel, onConfirm, onClose}) {\n const {t} = useToolkitTranslation('security');\n const passwordSchema = Yup.object({password: Yup.string().max(CURRENT_PASSWORD_MAX_LENGTH).required(t('twoStep.passwordRequired'))});\n\n return (\n <Dialog open={open} onClose={onClose} maxWidth=\"xs\" fullWidth>\n <Formik initialValues={{password: ''}} validationSchema={passwordSchema} enableReinitialize\n onSubmit={async (values, helpers) => {\n try {\n await onConfirm(values.password);\n } catch (error) {\n showFormError(error, helpers, values);\n }\n }}>\n {() => (\n <Form noValidate>\n <DialogTitle>{title}</DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <DialogContentText>{description}</DialogContentText>\n <FormProblemAlert />\n <FormTextField name=\"password\" label={t('twoStep.passwordLabel')} type=\"password\" autoComplete=\"current-password\" autoFocus />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{t('common:actions.cancel')}</Button>\n <SubmitButton size=\"medium\" color=\"error\">{confirmLabel}</SubmitButton>\n </DialogActions>\n </Form>\n )}\n </Formik>\n </Dialog>\n );\n}\n\n/** Activar la app: escanear el QR (o teclear la clave) y confirmar con un código. */\nfunction TotpDialog({setup, onConfirm, onClose}) {\n const {t} = useToolkitTranslation('security');\n const codeSchema = Yup.object({\n code: Yup.string().trim().required(t('twoStep.codeRequired')).min(TOTP_CODE_MIN_LENGTH).max(TOTP_CODE_MAX_LENGTH)\n .matches(TOTP_CODE_PATTERN, t('twoStep.codeFormat')),\n });\n\n return (\n <Dialog open={Boolean(setup)} onClose={onClose} maxWidth=\"xs\" fullWidth>\n <Formik initialValues={{code: ''}} validationSchema={codeSchema}\n onSubmit={async (values, helpers) => {\n try {\n await onConfirm(normalizeTotpCode(values.code));\n } catch (error) {\n showFormError(error, helpers, values);\n }\n }}>\n {() => (\n <Form noValidate>\n <DialogTitle>{t('twoStep.totpDialogTitle')}</DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <Typography variant=\"body2\">{t('twoStep.totpStep1')}</Typography>\n {setup?.qrImageUrl && (\n <TwoStepQr component=\"img\" src={setup.qrImageUrl} alt={t('twoStep.totpQrAlt')}\n ownSx={{width: QR_SIZE_PIXELS, height: QR_SIZE_PIXELS, alignSelf: 'center', borderRadius: 1, bgcolor: 'common.white'}} />\n )}\n <Typography variant=\"caption\" color=\"text.secondary\">{t('twoStep.totpCantScan')}</Typography>\n <TwoStepSecret direction=\"row\" spacing={1} ownSx={{alignItems: 'center'}}>\n <TwoStepSecretCode component=\"code\" ownSx={{fontFamily: CODE_FONT, fontSize: 13, wordBreak: 'break-all'}}>{setup?.secret}</TwoStepSecretCode>\n <CopyButton value={setup?.secret ?? ''} />\n </TwoStepSecret>\n <Typography variant=\"body2\">{t('twoStep.totpStep2')}</Typography>\n <FormProblemAlert />\n <FormTextField name=\"code\" label={t('twoStep.codeLabel')} autoComplete=\"one-time-code\" clearable={false}\n slotProps={{htmlInput: {inputMode: 'numeric', maxLength: TOTP_CODE_MAX_LENGTH}}} />\n {setup?.extra}\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{t('common:actions.cancel')}</Button>\n <SubmitButton size=\"medium\">{t('twoStep.activate')}</SubmitButton>\n </DialogActions>\n </Form>\n )}\n </Formik>\n </Dialog>\n );\n}\n\n/** Nombrar y crear una llave nueva (el navegador pide la huella, el rostro o el PIN); notice va arriba del nombre. */\nfunction PasskeyDialog({open, onAdd, onClose, notice}) {\n const {t} = useToolkitTranslation('security');\n const nameSchema = Yup.object({name: Yup.string().trim().max(PASSKEY_NAME_MAX_LENGTH)});\n\n return (\n <Dialog open={open} onClose={onClose} maxWidth=\"xs\" fullWidth>\n <Formik initialValues={{name: ''}} validationSchema={nameSchema}\n onSubmit={async (values, helpers) => {\n try {\n await onAdd(values.name.trim());\n } catch (error) {\n showFormError(error, helpers, values);\n }\n }}>\n {() => (\n <Form noValidate>\n <DialogTitle>{t('twoStep.passkeyDialogTitle')}</DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <DialogContentText>{t('twoStep.passkeyDialogText')}</DialogContentText>\n {notice && <Alert severity=\"info\">{notice}</Alert>}\n <FormProblemAlert />\n <FormTextField name=\"name\" label={t('twoStep.passkeyName')} placeholder={t('twoStep.passkeyNamePlaceholder')} autoFocus\n slotProps={{htmlInput: {maxLength: PASSKEY_NAME_MAX_LENGTH}}} />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{t('common:actions.cancel')}</Button>\n <SubmitButton size=\"medium\" startIcon={<FingerprintOutlinedIcon />}>{t('twoStep.createPasskey')}</SubmitButton>\n </DialogActions>\n </Form>\n )}\n </Formik>\n </Dialog>\n );\n}\n\n/**\n * Un renglón de la tarjeta: ícono, nombre, explicación chica y su botón a la derecha.\n *\n * @param {{Icon: import('react').ElementType, title: string, caption?: import('react').ReactNode, captionColor?: string, action?: import('react').ReactNode}} props\n */\nfunction SettingRow({Icon, title, caption, captionColor = 'text.secondary', action}) {\n return (\n <TwoStepHeader direction=\"row\" spacing={1} ownSx={{alignItems: 'center', justifyContent: 'space-between'}}>\n <TwoStepHeaderTitle direction=\"row\" spacing={1.5} ownSx={{alignItems: 'center', minWidth: 0}}>\n <Icon color=\"action\" />\n <TwoStepHeaderText ownSx={{minWidth: 0}}>\n <Typography variant=\"subtitle2\">{title}</Typography>\n {caption && <Typography variant=\"caption\" color={captionColor} component=\"p\">{caption}</Typography>}\n </TwoStepHeaderText>\n </TwoStepHeaderTitle>\n {action}\n </TwoStepHeader>\n );\n}\n\n/**\n * @param {object} props\n * @param {{isEnabled: boolean, enabledAt?: string|null, passkeys: Array<{id: string, name: string, createdAt: string, lastUsedAt?: string|null}>, totp: {isEnabled: boolean, enabledAt?: string|null}, recoveryCodesRemaining: number}} props.security\n * @param {(security: {isEnabled: boolean, enabledAt?: string|null, passkeys: Array<{id: string, name: string, createdAt: string, lastUsedAt?: string|null}>, totp: {isEnabled: boolean, enabledAt?: string|null}, recoveryCodesRemaining: number}) => void} props.onSecurityChange\n * @param {object} props.actions lo que hace el proyecto en cada caso; cada una regresa {security, recoveryCodes?}\n * @param {(name: string) => Promise<{security: object, recoveryCodes?: string[]}>} props.actions.addPasskey crea la llave\n * (createPasskey) y la guarda en el servidor\n * @param {(passkey: {id: string, name: string}, password: string) => Promise<{security: object}>} props.actions.removePasskey\n * @param {() => Promise<{secret: string, qrImageUrl: string, extra?: import('react').ReactNode}>} props.actions.startTotp\n * la clave y su QR; extra va abajo del campo (p. ej. un atajo de los ejemplos)\n * @param {(code: string) => Promise<{security: object, recoveryCodes?: string[]}>} props.actions.confirmTotp\n * @param {(password: string) => Promise<{security: object}>} props.actions.disableTotp\n * @param {(password: string) => Promise<{security: object, recoveryCodes: string[]}>} props.actions.regenerateRecoveryCodes\n * @param {boolean} [props.canUsePasskeys] passkeysSupported() de /passkeys; sin él no se ofrece agregar llaves\n * @param {string} [props.account] la cuenta (el correo), para el archivo de los códigos\n * @param {import('react').ReactNode} [props.passkeyNotice] un aviso en el diálogo de crear la llave, antes de que el\n * navegador la guarde (p. ej. el de la demostración: la llave queda de verdad en el llavero de la persona)\n * @param {object} [props.texts] los textos que cambian, con la forma de `security` en los textos del paquete\n */\nexport default function TwoStepVerificationCard(props) {\n // lo que el proyecto puso en su tema (components.CalcitaTwoStepVerification.defaultProps) y encima lo que llega aquí\n const {security, onSecurityChange, actions, canUsePasskeys = false, account, passkeyNotice, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('security', texts);\n const {formatDateTime} = useFormatters();\n // qué diálogo está abierto: uno a la vez\n const [dialog, setDialog] = useState(null);\n const [totpSetup, setTotpSetup] = useState(null);\n const [recoveryCodes, setRecoveryCodes] = useState(null);\n const [error, setError] = useState(null);\n\n const close = () => setDialog(null);\n // lo que regresa cada acción: el estado nuevo, los códigos si hubo, el aviso y cerrar el diálogo\n const apply = (result, message) => {\n onSecurityChange(result.security);\n if (result.recoveryCodes?.length) {\n setRecoveryCodes(result.recoveryCodes);\n }\n if (message) {\n toastSuccess(message);\n }\n close();\n };\n\n const startTotp = async () => {\n setError(null);\n try {\n setTotpSetup(await actions.startTotp());\n } catch (caught) {\n setError(caught.message);\n }\n };\n\n const passkeyBeingRemoved = dialog?.passkey;\n const codesLeft = security.recoveryCodesRemaining;\n\n return (\n <ComponentTexts namespace=\"security\" texts={texts}>\n <SectionCard title={t('twoStep.title')}>\n <Stack spacing={2}>\n <Typography variant=\"body2\" color=\"text.secondary\">{t('twoStep.description')}</Typography>\n <Box>\n {security.isEnabled\n ? <Tag label={t('twoStep.active')} color=\"success\" tooltip={t('twoStep.activeSince', {date: formatDateTime(security.enabledAt)})} />\n : <Tag label={t('twoStep.inactive')} color=\"warning\" tooltip={t('twoStep.inactiveTooltip')} />}\n </Box>\n {error && <Alert severity=\"error\" onClose={() => setError(null)}>{error}</Alert>}\n\n <Divider />\n <SettingRow Icon={FingerprintOutlinedIcon} title={t('twoStep.passkeysTitle')}\n caption={security.passkeys.length === 0 ? (canUsePasskeys ? t('twoStep.passkeysEmpty') : t('passkeys.unsupported')) : null}\n action={canUsePasskeys && <Button size=\"small\" onClick={() => setDialog({kind: 'passkey'})}>{t('twoStep.add')}</Button>} />\n {security.passkeys.length > 0 && (\n <List dense disablePadding>\n {security.passkeys.map((passkey) => (\n <ListItem key={passkey.id} disableGutters secondaryAction={(\n <Tooltip title={t('twoStep.removePasskeyTooltip')}>\n <IconButton edge=\"end\" aria-label={t('twoStep.removePasskey', {name: passkey.name})}\n onClick={() => setDialog({kind: 'removePasskey', passkey})}>\n <DeleteOutlineOutlinedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}>\n <TwoStepMenuIcon ownSx={{minWidth: 32}}><VpnKeyOutlinedIcon fontSize=\"small\" /></TwoStepMenuIcon>\n <ListItemText primary={passkey.name}\n secondary={passkey.lastUsedAt\n ? t('twoStep.passkeyUsed', {date: formatDateTime(passkey.lastUsedAt)})\n : t('twoStep.passkeyCreated', {date: formatDateTime(passkey.createdAt)})} />\n </ListItem>\n ))}\n </List>\n )}\n\n <Divider />\n <SettingRow Icon={PhonelinkLockOutlinedIcon} title={t('twoStep.appTitle')}\n caption={security.totp.isEnabled ? t('twoStep.appActiveSince', {date: formatDateTime(security.totp.enabledAt)}) : t('twoStep.appDescription')}\n action={security.totp.isEnabled\n ? <Button size=\"small\" color=\"error\" onClick={() => setDialog({kind: 'disableTotp'})}>{t('twoStep.deactivate')}</Button>\n : <Button size=\"small\" onClick={startTotp}>{t('twoStep.activate')}</Button>} />\n\n {/* los códigos de recuperación solo existen con la verificación activa */}\n {security.isEnabled && (\n <>\n <Divider />\n <SettingRow Icon={VpnKeyOutlinedIcon} title={t('twoStep.codesTitle')}\n caption={codesLeft ? t('twoStep.codesRemaining', {count: codesLeft}) : t('twoStep.codesNone')}\n captionColor={codesLeft <= FEW_CODES_LEFT ? 'warning.main' : 'text.secondary'}\n action={<Button size=\"small\" onClick={() => setDialog({kind: 'regenerateCodes'})}>{t('twoStep.regenerate')}</Button>} />\n </>\n )}\n </Stack>\n\n <PasskeyDialog open={dialog?.kind === 'passkey'} onClose={close} notice={passkeyNotice}\n onAdd={async (name) => apply(await actions.addPasskey(name), t('twoStep.passkeyAdded'))} />\n <TotpDialog setup={totpSetup} onClose={() => setTotpSetup(null)}\n onConfirm={async (code) => {\n const result = await actions.confirmTotp(code);\n setTotpSetup(null);\n apply(result, t('twoStep.appActivated'));\n }} />\n <PasswordDialog open={dialog?.kind === 'disableTotp'} onClose={close} title={t('twoStep.disableTitle')}\n description={t('twoStep.disableText')} confirmLabel={t('twoStep.deactivate')}\n onConfirm={async (password) => apply(await actions.disableTotp(password), t('twoStep.appDeactivated'))} />\n <PasswordDialog open={dialog?.kind === 'removePasskey'} onClose={close}\n title={t('twoStep.removeTitle', {name: passkeyBeingRemoved?.name ?? ''})} description={t('twoStep.removeText')}\n confirmLabel={t('twoStep.remove')}\n onConfirm={async (password) => apply(await actions.removePasskey(passkeyBeingRemoved, password), t('twoStep.passkeyRemoved'))} />\n <PasswordDialog open={dialog?.kind === 'regenerateCodes'} onClose={close} title={t('twoStep.regenerateTitle')}\n description={t('twoStep.regenerateText')} confirmLabel={t('twoStep.generate')}\n onConfirm={async (password) => apply(await actions.regenerateRecoveryCodes(password))} />\n <RecoveryCodesDialog codes={recoveryCodes} account={account} onClose={() => setRecoveryCodes(null)} />\n </SectionCard>\n </ComponentTexts>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TwoStepVerificationCard.js","sources":["../../../src/forms/security/TwoStepVerificationCard.jsx"],"sourcesContent":["// «Verificación en dos pasos» de «Mi perfil»: las llaves de acceso, la app autenticadora y los códigos de recuperación.\n//\n// Lo que QUITA protección (desactivar la app, quitar una llave, generar códigos nuevos) pide la contraseña: una sesión que\n// alguien dejó abierta no debe bastar para desarmar la cuenta. Activar no la pide.\n//\n// La tarjeta no sabe del servidor: el proyecto le pasa el estado (security) y qué hacer en cada caso (actions); cada\n// acción regresa {security, recoveryCodes?} y la tarjeta avisa el estado nuevo con onSecurityChange. Las llaves de acceso\n// las crea el proyecto con createPasskey (@stackcraftmx/calcita/passkeys) dentro de actions.addPasskey: así esta puerta no\n// carga la librería de llaves.\n//\n// <TwoStepVerificationCard security={security} onSecurityChange={setSecurity} account={session.email}\n// canUsePasskeys={passkeysSupported()} actions={securityActions} />\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTwoStepVerification con defaultProps y\n// styleOverrides de sus partes: qr, secret, secretCode, header, headerTitle, headerText, menuIcon.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {Form, Formik} from 'formik';\nimport Alert from '@mui/material/Alert';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Dialog from '@mui/material/Dialog';\nimport DialogActions from '@mui/material/DialogActions';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogContentText from '@mui/material/DialogContentText';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport List from '@mui/material/List';\nimport ListItem from '@mui/material/ListItem';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Stack from '@mui/material/Stack';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined';\nimport FingerprintOutlinedIcon from '@mui/icons-material/FingerprintOutlined';\nimport PhonelinkLockOutlinedIcon from '@mui/icons-material/PhonelinkLockOutlined';\nimport VpnKeyOutlinedIcon from '@mui/icons-material/VpnKeyOutlined';\n\nimport {toastSuccess} from '@/feedback/toast.jsx';\nimport FormProblemAlert from '@/forms/FormProblemAlert.jsx';\nimport FormTextField from '@/forms/FormTextField.jsx';\nimport SubmitButton from '@/forms/SubmitButton.jsx';\nimport {applyServerProblem} from '@/forms/applyServerProblem.js';\nimport {Yup} from '@/forms/validation.js';\nimport {\n CURRENT_PASSWORD_MAX_LENGTH, PASSKEY_NAME_MAX_LENGTH, TOTP_CODE_MAX_LENGTH, TOTP_CODE_MIN_LENGTH, TOTP_CODE_PATTERN, normalizeTotpCode,\n} from '@/forms/security/securityRules.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport RecoveryCodesDialog from '@/security/RecoveryCodesDialog.jsx';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport CopyButton from '@/ui/actions/CopyButton.jsx';\nimport Tag from '@/ui/labels/Tag.jsx';\nimport SectionCard from '@/ui/layout/SectionCard.jsx';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaTwoStepVerification)\nconst THEME_NAME = 'CalcitaTwoStepVerification';\nconst TwoStepQr = piecePart(THEME_NAME, 'Qr', Box);\nconst TwoStepSecret = piecePart(THEME_NAME, 'Secret', Stack);\nconst TwoStepSecretCode = piecePart(THEME_NAME, 'SecretCode', Box);\nconst TwoStepHeader = piecePart(THEME_NAME, 'Header', Stack);\nconst TwoStepHeaderTitle = piecePart(THEME_NAME, 'HeaderTitle', Stack);\nconst TwoStepHeaderText = piecePart(THEME_NAME, 'HeaderText', Box);\nconst TwoStepMenuIcon = piecePart(THEME_NAME, 'MenuIcon', ListItemIcon);\n\n// los códigos que quedan desde donde se avisa en ámbar que ya son pocos\nconst FEW_CODES_LEFT = 2;\nconst QR_SIZE_PIXELS = 200;\nconst CODE_FONT = 'ui-monospace, SFMono-Regular, Menlo, monospace';\n\n/**\n * Lo que hace un formulario de la tarjeta con un error: un ApiError va a su campo o arriba (applyServerProblem); un\n * error del navegador (la llave de acceso) va arriba; si la persona solo canceló, nada.\n *\n * @param {Error & {cancelled?: boolean, status?: number}} error\n * @param {object} formikHelpers\n * @param {object} values\n */\nfunction showFormError(error, formikHelpers, values) {\n if (error?.cancelled) {\n return;\n }\n if (error?.status === undefined) {\n formikHelpers.setStatus(error?.message);\n return;\n }\n applyServerProblem(error, {...formikHelpers, values});\n}\n\n/** Confirmar con la contraseña antes de quitar protección. */\nfunction PasswordDialog({open, title, description, confirmLabel, onConfirm, onClose}) {\n const {t} = useToolkitTranslation('security');\n const passwordSchema = Yup.object({password: Yup.string().max(CURRENT_PASSWORD_MAX_LENGTH).required(t('twoStep.passwordRequired'))});\n\n return (\n <Dialog open={open} onClose={onClose} maxWidth=\"xs\" fullWidth>\n <Formik initialValues={{password: ''}} validationSchema={passwordSchema} enableReinitialize\n onSubmit={async (values, helpers) => {\n try {\n await onConfirm(values.password);\n } catch (error) {\n showFormError(error, helpers, values);\n }\n }}>\n {() => (\n <Form noValidate>\n <DialogTitle>{title}</DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <DialogContentText>{description}</DialogContentText>\n <FormProblemAlert />\n <FormTextField name=\"password\" label={t('twoStep.passwordLabel')} type=\"password\" autoComplete=\"current-password\" autoFocus />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{t('common:actions.cancel')}</Button>\n <SubmitButton size=\"medium\" color=\"error\">{confirmLabel}</SubmitButton>\n </DialogActions>\n </Form>\n )}\n </Formik>\n </Dialog>\n );\n}\n\n/** Activar la app: escanear el QR (o teclear la clave) y confirmar con un código. */\nfunction TotpDialog({setup, onConfirm, onClose}) {\n const {t} = useToolkitTranslation('security');\n const codeSchema = Yup.object({\n code: Yup.string().trim().required(t('twoStep.codeRequired')).min(TOTP_CODE_MIN_LENGTH).max(TOTP_CODE_MAX_LENGTH)\n .matches(TOTP_CODE_PATTERN, t('twoStep.codeFormat')),\n });\n\n return (\n <Dialog open={Boolean(setup)} onClose={onClose} maxWidth=\"xs\" fullWidth>\n <Formik initialValues={{code: ''}} validationSchema={codeSchema}\n onSubmit={async (values, helpers) => {\n try {\n await onConfirm(normalizeTotpCode(values.code));\n } catch (error) {\n showFormError(error, helpers, values);\n }\n }}>\n {() => (\n <Form noValidate>\n <DialogTitle>{t('twoStep.totpDialogTitle')}</DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <Typography variant=\"body2\">{t('twoStep.totpStep1')}</Typography>\n {setup?.qrImageUrl && (\n <TwoStepQr component=\"img\" src={setup.qrImageUrl} alt={t('twoStep.totpQrAlt')}\n ownSx={{width: QR_SIZE_PIXELS, height: QR_SIZE_PIXELS, alignSelf: 'center', borderRadius: 1, bgcolor: 'common.white'}} />\n )}\n <Typography variant=\"caption\" color=\"text.secondary\">{t('twoStep.totpCantScan')}</Typography>\n <TwoStepSecret direction=\"row\" spacing={1} ownSx={{alignItems: 'center'}}>\n <TwoStepSecretCode component=\"code\" ownSx={{fontFamily: CODE_FONT, fontSize: 13, wordBreak: 'break-all'}}>{setup?.secret}</TwoStepSecretCode>\n <CopyButton value={setup?.secret ?? ''} />\n </TwoStepSecret>\n <Typography variant=\"body2\">{t('twoStep.totpStep2')}</Typography>\n <FormProblemAlert />\n <FormTextField name=\"code\" label={t('twoStep.codeLabel')} autoComplete=\"one-time-code\" clearable={false}\n slotProps={{htmlInput: {inputMode: 'numeric', maxLength: TOTP_CODE_MAX_LENGTH}}} />\n {setup?.extra}\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{t('common:actions.cancel')}</Button>\n <SubmitButton size=\"medium\">{t('twoStep.activate')}</SubmitButton>\n </DialogActions>\n </Form>\n )}\n </Formik>\n </Dialog>\n );\n}\n\n/** Nombrar y crear una llave nueva (el navegador pide la huella, el rostro o el PIN); notice va arriba del nombre. */\nfunction PasskeyDialog({open, onAdd, onClose, notice}) {\n const {t} = useToolkitTranslation('security');\n const nameSchema = Yup.object({name: Yup.string().trim().max(PASSKEY_NAME_MAX_LENGTH)});\n\n return (\n <Dialog open={open} onClose={onClose} maxWidth=\"xs\" fullWidth>\n <Formik initialValues={{name: ''}} validationSchema={nameSchema}\n onSubmit={async (values, helpers) => {\n try {\n await onAdd(values.name.trim());\n } catch (error) {\n showFormError(error, helpers, values);\n }\n }}>\n {() => (\n <Form noValidate>\n <DialogTitle>{t('twoStep.passkeyDialogTitle')}</DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <DialogContentText>{t('twoStep.passkeyDialogText')}</DialogContentText>\n {notice && <Alert severity=\"info\">{notice}</Alert>}\n <FormProblemAlert />\n <FormTextField name=\"name\" label={t('twoStep.passkeyName')} placeholder={t('twoStep.passkeyNamePlaceholder')} autoFocus\n slotProps={{htmlInput: {maxLength: PASSKEY_NAME_MAX_LENGTH}}} />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{t('common:actions.cancel')}</Button>\n <SubmitButton size=\"medium\" startIcon={<FingerprintOutlinedIcon />}>{t('twoStep.createPasskey')}</SubmitButton>\n </DialogActions>\n </Form>\n )}\n </Formik>\n </Dialog>\n );\n}\n\n/**\n * Un renglón de la tarjeta: ícono, nombre, explicación chica y su botón a la derecha.\n *\n * @param {{Icon: import('react').ElementType, title: string, caption?: import('react').ReactNode, captionColor?: string, action?: import('react').ReactNode}} props\n */\nfunction SettingRow({Icon, title, caption, captionColor = 'text.secondary', action}) {\n return (\n <TwoStepHeader direction=\"row\" spacing={1} ownSx={{alignItems: 'center', justifyContent: 'space-between'}}>\n <TwoStepHeaderTitle direction=\"row\" spacing={1.5} ownSx={{alignItems: 'center', minWidth: 0}}>\n <Icon color=\"action\" />\n <TwoStepHeaderText ownSx={{minWidth: 0}}>\n <Typography variant=\"subtitle2\">{title}</Typography>\n {caption && <Typography variant=\"caption\" color={captionColor} component=\"p\">{caption}</Typography>}\n </TwoStepHeaderText>\n </TwoStepHeaderTitle>\n {action}\n </TwoStepHeader>\n );\n}\n\n/**\n * @param {object} props\n * @param {{isEnabled: boolean, enabledAt?: string|null, passkeys: Array<{id: string, name: string, createdAt: string, lastUsedAt?: string|null}>, totp: {isEnabled: boolean, enabledAt?: string|null}, recoveryCodesRemaining: number}} props.security\n * @param {(security: {isEnabled: boolean, enabledAt?: string|null, passkeys: Array<{id: string, name: string, createdAt: string, lastUsedAt?: string|null}>, totp: {isEnabled: boolean, enabledAt?: string|null}, recoveryCodesRemaining: number}) => void} props.onSecurityChange\n * @param {object} props.actions lo que hace el proyecto en cada caso; cada una regresa {security, recoveryCodes?}\n * @param {(name: string) => Promise<{security: object, recoveryCodes?: string[]}>} props.actions.addPasskey crea la llave\n * (createPasskey) y la guarda en el servidor\n * @param {(passkey: {id: string, name: string}, password: string) => Promise<{security: object}>} props.actions.removePasskey\n * @param {() => Promise<{secret: string, qrImageUrl: string, extra?: import('react').ReactNode}>} props.actions.startTotp\n * la clave y su QR; extra va abajo del campo (p. ej. un atajo de los ejemplos)\n * @param {(code: string) => Promise<{security: object, recoveryCodes?: string[]}>} props.actions.confirmTotp\n * @param {(password: string) => Promise<{security: object}>} props.actions.disableTotp\n * @param {(password: string) => Promise<{security: object, recoveryCodes: string[]}>} props.actions.regenerateRecoveryCodes\n * @param {boolean} [props.canUsePasskeys] passkeysSupported() de /passkeys; sin él no se ofrece agregar llaves\n * @param {string} [props.account] la cuenta (el correo), para el archivo de los códigos\n * @param {import('react').ReactNode} [props.passkeyNotice] un aviso en el diálogo de crear la llave, antes de que el\n * navegador la guarde (p. ej. el de la demostración: la llave queda de verdad en el llavero de la persona)\n * @param {object} [props.texts] los textos que cambian, con la forma de `security` en los textos del paquete\n */\nfunction TwoStepVerificationCardContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaTwoStepVerification.defaultProps) y encima lo que llega aquí\n const {security, onSecurityChange, actions, canUsePasskeys = false, account, passkeyNotice, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('security', texts);\n const {formatDateTime} = useFormatters();\n // qué diálogo está abierto: uno a la vez\n const [dialog, setDialog] = useState(null);\n const [totpSetup, setTotpSetup] = useState(null);\n const [recoveryCodes, setRecoveryCodes] = useState(null);\n const [error, setError] = useState(null);\n\n const close = () => setDialog(null);\n // lo que regresa cada acción: el estado nuevo, los códigos si hubo, el aviso y cerrar el diálogo\n const apply = (result, message) => {\n onSecurityChange(result.security);\n if (result.recoveryCodes?.length) {\n setRecoveryCodes(result.recoveryCodes);\n }\n if (message) {\n toastSuccess(message);\n }\n close();\n };\n\n const startTotp = async () => {\n setError(null);\n try {\n setTotpSetup(await actions.startTotp());\n } catch (caught) {\n setError(caught.message);\n }\n };\n\n const passkeyBeingRemoved = dialog?.passkey;\n const codesLeft = security.recoveryCodesRemaining;\n\n return (\n <ComponentTexts namespace=\"security\" texts={texts}>\n <SectionCard title={t('twoStep.title')}>\n <Stack spacing={2}>\n <Typography variant=\"body2\" color=\"text.secondary\">{t('twoStep.description')}</Typography>\n <Box>\n {security.isEnabled\n ? <Tag label={t('twoStep.active')} color=\"success\" tooltip={t('twoStep.activeSince', {date: formatDateTime(security.enabledAt)})} />\n : <Tag label={t('twoStep.inactive')} color=\"warning\" tooltip={t('twoStep.inactiveTooltip')} />}\n </Box>\n {error && <Alert severity=\"error\" onClose={() => setError(null)}>{error}</Alert>}\n\n <Divider />\n <SettingRow Icon={FingerprintOutlinedIcon} title={t('twoStep.passkeysTitle')}\n caption={security.passkeys.length === 0 ? (canUsePasskeys ? t('twoStep.passkeysEmpty') : t('passkeys.unsupported')) : null}\n action={canUsePasskeys && <Button size=\"small\" onClick={() => setDialog({kind: 'passkey'})}>{t('twoStep.add')}</Button>} />\n {security.passkeys.length > 0 && (\n <List dense disablePadding>\n {security.passkeys.map((passkey) => (\n <ListItem key={passkey.id} disableGutters secondaryAction={(\n <Tooltip title={t('twoStep.removePasskeyTooltip')}>\n <IconButton edge=\"end\" aria-label={t('twoStep.removePasskey', {name: passkey.name})}\n onClick={() => setDialog({kind: 'removePasskey', passkey})}>\n <DeleteOutlineOutlinedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}>\n <TwoStepMenuIcon ownSx={{minWidth: 32}}><VpnKeyOutlinedIcon fontSize=\"small\" /></TwoStepMenuIcon>\n <ListItemText primary={passkey.name}\n secondary={passkey.lastUsedAt\n ? t('twoStep.passkeyUsed', {date: formatDateTime(passkey.lastUsedAt)})\n : t('twoStep.passkeyCreated', {date: formatDateTime(passkey.createdAt)})} />\n </ListItem>\n ))}\n </List>\n )}\n\n <Divider />\n <SettingRow Icon={PhonelinkLockOutlinedIcon} title={t('twoStep.appTitle')}\n caption={security.totp.isEnabled ? t('twoStep.appActiveSince', {date: formatDateTime(security.totp.enabledAt)}) : t('twoStep.appDescription')}\n action={security.totp.isEnabled\n ? <Button size=\"small\" color=\"error\" onClick={() => setDialog({kind: 'disableTotp'})}>{t('twoStep.deactivate')}</Button>\n : <Button size=\"small\" onClick={startTotp}>{t('twoStep.activate')}</Button>} />\n\n {/* los códigos de recuperación solo existen con la verificación activa */}\n {security.isEnabled && (\n <>\n <Divider />\n <SettingRow Icon={VpnKeyOutlinedIcon} title={t('twoStep.codesTitle')}\n caption={codesLeft ? t('twoStep.codesRemaining', {count: codesLeft}) : t('twoStep.codesNone')}\n captionColor={codesLeft <= FEW_CODES_LEFT ? 'warning.main' : 'text.secondary'}\n action={<Button size=\"small\" onClick={() => setDialog({kind: 'regenerateCodes'})}>{t('twoStep.regenerate')}</Button>} />\n </>\n )}\n </Stack>\n\n <PasskeyDialog open={dialog?.kind === 'passkey'} onClose={close} notice={passkeyNotice}\n onAdd={async (name) => apply(await actions.addPasskey(name), t('twoStep.passkeyAdded'))} />\n <TotpDialog setup={totpSetup} onClose={() => setTotpSetup(null)}\n onConfirm={async (code) => {\n const result = await actions.confirmTotp(code);\n setTotpSetup(null);\n apply(result, t('twoStep.appActivated'));\n }} />\n <PasswordDialog open={dialog?.kind === 'disableTotp'} onClose={close} title={t('twoStep.disableTitle')}\n description={t('twoStep.disableText')} confirmLabel={t('twoStep.deactivate')}\n onConfirm={async (password) => apply(await actions.disableTotp(password), t('twoStep.appDeactivated'))} />\n <PasswordDialog open={dialog?.kind === 'removePasskey'} onClose={close}\n title={t('twoStep.removeTitle', {name: passkeyBeingRemoved?.name ?? ''})} description={t('twoStep.removeText')}\n confirmLabel={t('twoStep.remove')}\n onConfirm={async (password) => apply(await actions.removePasskey(passkeyBeingRemoved, password), t('twoStep.passkeyRemoved'))} />\n <PasswordDialog open={dialog?.kind === 'regenerateCodes'} onClose={close} title={t('twoStep.regenerateTitle')}\n description={t('twoStep.regenerateText')} confirmLabel={t('twoStep.generate')}\n onConfirm={async (password) => apply(await actions.regenerateRecoveryCodes(password))} />\n <RecoveryCodesDialog codes={recoveryCodes} account={account} onClose={() => setRecoveryCodes(null)} />\n </SectionCard>\n </ComponentTexts>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst TwoStepVerificationCard = withPieceSlots(TwoStepVerificationCardContent, THEME_NAME);\nexport default TwoStepVerificationCard;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { useCallback } from "react";
3
+ import { translateValidationMessage } from "./validationMessages.js";
4
+ import { useToolkitSettings } from "../toolkit/toolkitContext.js";
5
+ import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
6
+ function useValidationText({ name, label, messages } = {}) {
7
+ const { readValidationMessage } = useToolkitSettings();
8
+ const { t } = useToolkitTranslation(["validation"]);
9
+ const labelText = typeof label === "string" ? label : void 0;
10
+ return useCallback(
11
+ (error) => translateValidationMessage(t, error, { label: labelText, messages, readMessage: readValidationMessage, fieldName: name }),
12
+ [t, name, labelText, messages, readValidationMessage]
13
+ );
14
+ }
15
+ export {
16
+ useValidationText
17
+ };
18
+ //# sourceMappingURL=useValidationText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useValidationText.js","sources":["../../src/forms/useValidationText.js"],"sourcesContent":["// El texto del error de un campo, dentro de un componente: con el idioma, los textos y la lectura de mensajes\n// (readValidationMessage) del proveedor más cercano. Lo usan todos los campos de la casa; un campo propio del proyecto\n// también:\n//\n// const validationTextOf = useValidationText({name, label, messages});\n// const errorText = validationTextOf(error);\n//\n// No importa yup (validationMessages.js tampoco): sirve en un proyecto que valida con otra cosa.\n//\n// Hook genérico: function (regla de la casa).\nimport {useCallback} from 'react';\n\nimport {translateValidationMessage} from '@/forms/validationMessages.js';\nimport {useToolkitSettings} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\n\n/**\n * @param {object} [options]\n * @param {string} [options.name] el name del campo: para su texto propio (validation:fields.<campo>.<regla>)\n * @param {string} [options.label] el nombre del campo, para los textos que lo dicen ({{label}})\n * @param {Record<string, string|object>} [options.messages] los textos de la pantalla para este campo, por regla\n * @returns {(error: unknown) => string|undefined}\n */\nexport function useValidationText({name, label, messages} = {}) {\n const {readValidationMessage} = useToolkitSettings();\n const {t} = useToolkitTranslation(['validation']);\n const labelText = typeof label === 'string' ? label : undefined;\n return useCallback(\n (error) => translateValidationMessage(t, error, {label: labelText, messages, readMessage: readValidationMessage, fieldName: name}),\n [t, name, labelText, messages, readValidationMessage],\n );\n}\n"],"names":[],"mappings":";;;;;AAuBO,SAAS,kBAAkB,EAAC,MAAM,OAAO,SAAQ,IAAI,CAAA,GAAI;AAC5D,QAAM,EAAC,sBAAqB,IAAI,mBAAkB;AAClD,QAAM,EAAC,EAAC,IAAI,sBAAsB,CAAC,YAAY,CAAC;AAChD,QAAM,YAAY,OAAO,UAAU,WAAW,QAAQ;AACtD,SAAO;AAAA,IACH,CAAC,UAAU,2BAA2B,GAAG,OAAO,EAAC,OAAO,WAAW,UAAU,aAAa,uBAAuB,WAAW,KAAI,CAAC;AAAA,IACjI,CAAC,GAAG,MAAM,WAAW,UAAU,qBAAqB;AAAA,EAC5D;AACA;"}
@@ -1,47 +1,51 @@
1
1
  import * as Yup from "yup";
2
2
  const NAMESPACE = "validation";
3
- function messageKey(name, values) {
4
- return values === void 0 ? { key: `${NAMESPACE}:${name}` } : { key: `${NAMESPACE}:${name}`, values };
3
+ function messageOf(name, rule, valuesOf) {
4
+ return (params = {}) => {
5
+ const values = { ...valuesOf ? valuesOf(params) : {}, ...params.label ? { label: params.label } : {} };
6
+ const fieldPath = params.originalPath ?? params.path;
7
+ return { key: `${NAMESPACE}:${name}`, values, rule, ...fieldPath ? { path: fieldPath } : {} };
8
+ };
5
9
  }
6
10
  const YUP_LOCALE = Object.freeze({
7
11
  mixed: {
8
- default: messageKey("default"),
9
- required: messageKey("required"),
10
- defined: messageKey("required"),
11
- notNull: messageKey("required"),
12
- notType: messageKey("notType"),
13
- oneOf: ({ values }) => messageKey("oneOf", { values: String(values) }),
14
- notOneOf: ({ values }) => messageKey("notOneOf", { values: String(values) })
12
+ default: messageOf("default", "default"),
13
+ required: messageOf("required", "required"),
14
+ defined: messageOf("required", "defined"),
15
+ notNull: messageOf("required", "notNull"),
16
+ notType: messageOf("notType", "notType"),
17
+ oneOf: messageOf("oneOf", "oneOf", ({ values }) => ({ values: String(values) })),
18
+ notOneOf: messageOf("notOneOf", "notOneOf", ({ values }) => ({ values: String(values) }))
15
19
  },
16
20
  string: {
17
- length: ({ length }) => messageKey("stringLength", { count: length }),
18
- min: ({ min }) => messageKey("stringMin", { count: min }),
19
- max: ({ max }) => messageKey("stringMax", { count: max }),
20
- matches: messageKey("matches"),
21
- email: messageKey("email"),
22
- url: messageKey("url"),
23
- uuid: messageKey("uuid"),
24
- trim: messageKey("trim"),
25
- lowercase: messageKey("lowercase"),
26
- uppercase: messageKey("uppercase")
21
+ length: messageOf("stringLength", "length", ({ length }) => ({ count: length })),
22
+ min: messageOf("stringMin", "min", ({ min }) => ({ count: min })),
23
+ max: messageOf("stringMax", "max", ({ max }) => ({ count: max })),
24
+ matches: messageOf("matches", "matches"),
25
+ email: messageOf("email", "email"),
26
+ url: messageOf("url", "url"),
27
+ uuid: messageOf("uuid", "uuid"),
28
+ trim: messageOf("trim", "trim"),
29
+ lowercase: messageOf("lowercase", "lowercase"),
30
+ uppercase: messageOf("uppercase", "uppercase")
27
31
  },
28
32
  number: {
29
- min: ({ min }) => messageKey("numberMin", { min }),
30
- max: ({ max }) => messageKey("numberMax", { max }),
31
- lessThan: ({ less }) => messageKey("lessThan", { less }),
32
- moreThan: ({ more }) => messageKey("moreThan", { more }),
33
- positive: messageKey("positive"),
34
- negative: messageKey("negative"),
35
- integer: messageKey("integer")
33
+ min: messageOf("numberMin", "min", ({ min }) => ({ min })),
34
+ max: messageOf("numberMax", "max", ({ max }) => ({ max })),
35
+ lessThan: messageOf("lessThan", "lessThan", ({ less }) => ({ less })),
36
+ moreThan: messageOf("moreThan", "moreThan", ({ more }) => ({ more })),
37
+ positive: messageOf("positive", "positive"),
38
+ negative: messageOf("negative", "negative"),
39
+ integer: messageOf("integer", "integer")
36
40
  },
37
41
  date: {
38
- min: ({ min }) => messageKey("dateMin", { min: String(min) }),
39
- max: ({ max }) => messageKey("dateMax", { max: String(max) })
42
+ min: messageOf("dateMin", "min", ({ min }) => ({ min: String(min) })),
43
+ max: messageOf("dateMax", "max", ({ max }) => ({ max: String(max) }))
40
44
  },
41
45
  array: {
42
- min: ({ min }) => messageKey("arrayMin", { count: min }),
43
- max: ({ max }) => messageKey("arrayMax", { count: max }),
44
- length: ({ length }) => messageKey("arrayLength", { count: length })
46
+ min: messageOf("arrayMin", "min", ({ min }) => ({ count: min })),
47
+ max: messageOf("arrayMax", "max", ({ max }) => ({ count: max })),
48
+ length: messageOf("arrayLength", "length", ({ length }) => ({ count: length }))
45
49
  }
46
50
  });
47
51
  function buildYupLocale() {
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","sources":["../../src/forms/validation.js"],"sourcesContent":["// Mensajes por defecto de yup como LLAVES de i18n y no como texto.\n//\n// Por qué llaves: setLocale es global y se llama una sola vez. Con el texto en español, al cambiar a inglés los\n// errores seguirían en español hasta recargar. Con {key, values} el esquema no cambia y el texto se traduce al\n// PINTARLO (translateValidationMessage, lo usa FormTextField) en el idioma que esté activo en ese momento.\n//\n// Uso en un esquema: Yup.string().required().email() → sin textos pegados.\n// Mensaje propio de un campo: .required({key: 'auth:login.emailRequired'}) o .test('x', {key: 'modulo:llave'}, fn).\n//\n// IMPORTANTE: toda llave de aquí existe en los textos del paquete, namespace validation de locales/{es,en}.js (lo revisa\n// validation.test.js). La validación de aquí es para no gastar un viaje al servidor en lo obvio; la que protege es la\n// del backend.\n//\n// buildYupLocale() se llama UNA vez en la entrada de la aplicación, antes del primer esquema.\n//\n// Funciones puras, no renderizan: function (regla de la casa). Solo importa yup (se prueba con node --test).\nimport * as Yup from 'yup';\n\nconst NAMESPACE = 'validation';\n\n/** {key: 'validation:<nombre>', values} */\nfunction messageKey(name, values) {\n return values === undefined ? {key: `${NAMESPACE}:${name}`} : {key: `${NAMESPACE}:${name}`, values};\n}\n\n/** El locale de yup: cada mensaje por defecto es una llave del namespace validation. */\nexport const YUP_LOCALE = Object.freeze({\n mixed: {\n default: messageKey('default'),\n required: messageKey('required'),\n defined: messageKey('required'),\n notNull: messageKey('required'),\n notType: messageKey('notType'),\n oneOf: ({values}) => messageKey('oneOf', {values: String(values)}),\n notOneOf: ({values}) => messageKey('notOneOf', {values: String(values)}),\n },\n string: {\n length: ({length}) => messageKey('stringLength', {count: length}),\n min: ({min}) => messageKey('stringMin', {count: min}),\n max: ({max}) => messageKey('stringMax', {count: max}),\n matches: messageKey('matches'),\n email: messageKey('email'),\n url: messageKey('url'),\n uuid: messageKey('uuid'),\n trim: messageKey('trim'),\n lowercase: messageKey('lowercase'),\n uppercase: messageKey('uppercase'),\n },\n number: {\n min: ({min}) => messageKey('numberMin', {min}),\n max: ({max}) => messageKey('numberMax', {max}),\n lessThan: ({less}) => messageKey('lessThan', {less}),\n moreThan: ({more}) => messageKey('moreThan', {more}),\n positive: messageKey('positive'),\n negative: messageKey('negative'),\n integer: messageKey('integer'),\n },\n date: {\n min: ({min}) => messageKey('dateMin', {min: String(min)}),\n max: ({max}) => messageKey('dateMax', {max: String(max)}),\n },\n array: {\n min: ({min}) => messageKey('arrayMin', {count: min}),\n max: ({max}) => messageKey('arrayMax', {count: max}),\n length: ({length}) => messageKey('arrayLength', {count: length}),\n },\n});\n\n/**\n * Instala el locale de llaves en yup. Se llama una vez en la entrada de la aplicación, antes del primer esquema.\n */\nexport function buildYupLocale() {\n Yup.setLocale(YUP_LOCALE);\n}\n\nexport {Yup};\n\n// el texto de un error en el idioma activo vive aparte (sin yup) para los campos sueltos; aquí se re-exporta\nexport {translateValidationMessage} from '@/forms/validationMessages.js';\n"],"names":[],"mappings":";AAkBA,MAAM,YAAY;AAGlB,SAAS,WAAW,MAAM,QAAQ;AAC9B,SAAO,WAAW,SAAY,EAAC,KAAK,GAAG,SAAS,IAAI,IAAI,GAAE,IAAI,EAAC,KAAK,GAAG,SAAS,IAAI,IAAI,IAAI,OAAM;AACtG;AAGY,MAAC,aAAa,OAAO,OAAO;AAAA,EACpC,OAAO;AAAA,IACH,SAAS,WAAW,SAAS;AAAA,IAC7B,UAAU,WAAW,UAAU;AAAA,IAC/B,SAAS,WAAW,UAAU;AAAA,IAC9B,SAAS,WAAW,UAAU;AAAA,IAC9B,SAAS,WAAW,SAAS;AAAA,IAC7B,OAAO,CAAC,EAAC,OAAM,MAAM,WAAW,SAAS,EAAC,QAAQ,OAAO,MAAM,EAAC,CAAC;AAAA,IACjE,UAAU,CAAC,EAAC,OAAM,MAAM,WAAW,YAAY,EAAC,QAAQ,OAAO,MAAM,EAAC,CAAC;AAAA,EAC/E;AAAA,EACI,QAAQ;AAAA,IACJ,QAAQ,CAAC,EAAC,OAAM,MAAM,WAAW,gBAAgB,EAAC,OAAO,OAAM,CAAC;AAAA,IAChE,KAAK,CAAC,EAAC,IAAG,MAAM,WAAW,aAAa,EAAC,OAAO,IAAG,CAAC;AAAA,IACpD,KAAK,CAAC,EAAC,IAAG,MAAM,WAAW,aAAa,EAAC,OAAO,IAAG,CAAC;AAAA,IACpD,SAAS,WAAW,SAAS;AAAA,IAC7B,OAAO,WAAW,OAAO;AAAA,IACzB,KAAK,WAAW,KAAK;AAAA,IACrB,MAAM,WAAW,MAAM;AAAA,IACvB,MAAM,WAAW,MAAM;AAAA,IACvB,WAAW,WAAW,WAAW;AAAA,IACjC,WAAW,WAAW,WAAW;AAAA,EACzC;AAAA,EACI,QAAQ;AAAA,IACJ,KAAK,CAAC,EAAC,IAAG,MAAM,WAAW,aAAa,EAAC,IAAG,CAAC;AAAA,IAC7C,KAAK,CAAC,EAAC,IAAG,MAAM,WAAW,aAAa,EAAC,IAAG,CAAC;AAAA,IAC7C,UAAU,CAAC,EAAC,KAAI,MAAM,WAAW,YAAY,EAAC,KAAI,CAAC;AAAA,IACnD,UAAU,CAAC,EAAC,KAAI,MAAM,WAAW,YAAY,EAAC,KAAI,CAAC;AAAA,IACnD,UAAU,WAAW,UAAU;AAAA,IAC/B,UAAU,WAAW,UAAU;AAAA,IAC/B,SAAS,WAAW,SAAS;AAAA,EACrC;AAAA,EACI,MAAM;AAAA,IACF,KAAK,CAAC,EAAC,IAAG,MAAM,WAAW,WAAW,EAAC,KAAK,OAAO,GAAG,EAAC,CAAC;AAAA,IACxD,KAAK,CAAC,EAAC,IAAG,MAAM,WAAW,WAAW,EAAC,KAAK,OAAO,GAAG,EAAC,CAAC;AAAA,EAChE;AAAA,EACI,OAAO;AAAA,IACH,KAAK,CAAC,EAAC,IAAG,MAAM,WAAW,YAAY,EAAC,OAAO,IAAG,CAAC;AAAA,IACnD,KAAK,CAAC,EAAC,IAAG,MAAM,WAAW,YAAY,EAAC,OAAO,IAAG,CAAC;AAAA,IACnD,QAAQ,CAAC,EAAC,OAAM,MAAM,WAAW,eAAe,EAAC,OAAO,OAAM,CAAC;AAAA,EACvE;AACA,CAAC;AAKM,SAAS,iBAAiB;AAC7B,MAAI,UAAU,UAAU;AAC5B;"}
1
+ {"version":3,"file":"validation.js","sources":["../../src/forms/validation.js"],"sourcesContent":["// Mensajes por defecto de yup como LLAVES de i18n y no como texto.\n//\n// Por qué llaves: setLocale es global y se llama una sola vez. Con el texto en español, al cambiar a inglés los\n// errores seguirían en español hasta recargar. Con {key, values} el esquema no cambia y el texto se traduce al\n// PINTARLO (translateValidationMessage, lo usa FormTextField) en el idioma que esté activo en ese momento.\n//\n// Uso en un esquema: Yup.string().required().email() → sin textos pegados.\n// Mensaje propio de un campo: .required({key: 'auth:login.emailRequired'}) o .test('x', {key: 'modulo:llave'}, fn).\n// O sin tocar el esquema: cada mensaje lleva su regla y su campo, y la pantalla (messages del campo) o los textos del\n// proyecto (validation:fields.<campo>.<regla>) ponen el suyo (translateValidationMessage, en validationMessages.js).\n//\n// IMPORTANTE: toda llave de aquí existe en los textos del paquete, namespace validation de locales/{es,en}.js (lo revisa\n// validation.test.js). La validación de aquí es para no gastar un viaje al servidor en lo obvio; la que protege es la\n// del backend.\n//\n// buildYupLocale() se llama UNA vez en la entrada de la aplicación, antes del primer esquema.\n//\n// Funciones puras, no renderizan: function (regla de la casa). Solo importa yup (se prueba con node --test).\nimport * as Yup from 'yup';\n\nconst NAMESPACE = 'validation';\n\n/**\n * Un mensaje de yup como llave: {key: 'validation:<nombre>', values, rule, path}.\n *\n * `rule` (la regla de yup que falló: required, min, matches…) y `path` (el campo) dejan que la pantalla o los textos del\n * proyecto pongan un mensaje propio para ese campo y esa regla sin tocar el esquema (translateValidationMessage). `label`\n * (el de .label('RFC') del esquema) va en los valores, para los textos que dicen el nombre del campo.\n *\n * @param {string} name el nombre del texto en el namespace validation\n * @param {string} rule la regla de yup\n * @param {(params: object) => object} [valuesOf] los valores del texto, sacados de lo que da yup (min, max…)\n * @returns {(params?: object) => {key: string, values: object, rule: string, path?: string}}\n */\nfunction messageOf(name, rule, valuesOf) {\n return (params = {}) => {\n const values = {...(valuesOf ? valuesOf(params) : {}), ...(params.label ? {label: params.label} : {})};\n // OJO: con .label('RFC') yup cambia params.path por el nombre visible; el campo de verdad viene en originalPath\n const fieldPath = params.originalPath ?? params.path;\n return {key: `${NAMESPACE}:${name}`, values, rule, ...(fieldPath ? {path: fieldPath} : {})};\n };\n}\n\n/** El locale de yup: cada mensaje por defecto es una llave del namespace validation, con su regla y su campo. */\nexport const YUP_LOCALE = Object.freeze({\n mixed: {\n default: messageOf('default', 'default'),\n required: messageOf('required', 'required'),\n defined: messageOf('required', 'defined'),\n notNull: messageOf('required', 'notNull'),\n notType: messageOf('notType', 'notType'),\n oneOf: messageOf('oneOf', 'oneOf', ({values}) => ({values: String(values)})),\n notOneOf: messageOf('notOneOf', 'notOneOf', ({values}) => ({values: String(values)})),\n },\n string: {\n length: messageOf('stringLength', 'length', ({length}) => ({count: length})),\n min: messageOf('stringMin', 'min', ({min}) => ({count: min})),\n max: messageOf('stringMax', 'max', ({max}) => ({count: max})),\n matches: messageOf('matches', 'matches'),\n email: messageOf('email', 'email'),\n url: messageOf('url', 'url'),\n uuid: messageOf('uuid', 'uuid'),\n trim: messageOf('trim', 'trim'),\n lowercase: messageOf('lowercase', 'lowercase'),\n uppercase: messageOf('uppercase', 'uppercase'),\n },\n number: {\n min: messageOf('numberMin', 'min', ({min}) => ({min})),\n max: messageOf('numberMax', 'max', ({max}) => ({max})),\n lessThan: messageOf('lessThan', 'lessThan', ({less}) => ({less})),\n moreThan: messageOf('moreThan', 'moreThan', ({more}) => ({more})),\n positive: messageOf('positive', 'positive'),\n negative: messageOf('negative', 'negative'),\n integer: messageOf('integer', 'integer'),\n },\n date: {\n min: messageOf('dateMin', 'min', ({min}) => ({min: String(min)})),\n max: messageOf('dateMax', 'max', ({max}) => ({max: String(max)})),\n },\n array: {\n min: messageOf('arrayMin', 'min', ({min}) => ({count: min})),\n max: messageOf('arrayMax', 'max', ({max}) => ({count: max})),\n length: messageOf('arrayLength', 'length', ({length}) => ({count: length})),\n },\n});\n\n/**\n * Instala el locale de llaves en yup. Se llama una vez en la entrada de la aplicación, antes del primer esquema.\n */\nexport function buildYupLocale() {\n Yup.setLocale(YUP_LOCALE);\n}\n\nexport {Yup};\n\n// el texto de un error en el idioma activo vive aparte (sin yup) para los campos sueltos; aquí se re-exporta\nexport {translateValidationMessage} from '@/forms/validationMessages.js';\n"],"names":[],"mappings":"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"}
@@ -1,16 +1,73 @@
1
- function translateValidationMessage(translate, error) {
2
- if (!error) {
1
+ import { createLogger } from "../observability/logger.js";
2
+ const NAMESPACE = "validation";
3
+ const DEFAULT_MESSAGE_KEY = `${NAMESPACE}:default`;
4
+ const log = createLogger("forms");
5
+ const warnedShapes = /* @__PURE__ */ new Set();
6
+ function fieldKeyOf(path) {
7
+ return String(path).replace(/\[\d+\]/g, "").split(".").filter((step) => step !== "" && !/^\d+$/.test(step)).join(".");
8
+ }
9
+ function normalizedValidationMessage(error) {
10
+ if (typeof error === "string") {
11
+ return { text: error };
12
+ }
13
+ if (!error || typeof error !== "object") {
14
+ return null;
15
+ }
16
+ const key = typeof error.key === "string" ? error.key : typeof error.msg === "string" ? error.msg : null;
17
+ if (key) {
18
+ return { key, values: error.values ?? error.params ?? {}, rule: error.rule, path: error.path };
19
+ }
20
+ if (typeof error.message === "string") {
21
+ return { text: error.message };
22
+ }
23
+ if (error.message && typeof error.message === "object") {
24
+ const inner = normalizedValidationMessage(error.message);
25
+ return inner && "key" in inner && !inner.rule && error.type ? { ...inner, rule: error.type } : inner;
26
+ }
27
+ return null;
28
+ }
29
+ function warnUnknownShape(error) {
30
+ const shape = Object.keys(error).sort().join(",");
31
+ if (warnedShapes.has(shape)) {
32
+ return;
33
+ }
34
+ warnedShapes.add(shape);
35
+ log.warn(`Un mensaje de validación con forma desconocida ({${shape}}): se enseña el mensaje general. Conéctelo con readValidationMessage de ToolkitProvider.`);
36
+ }
37
+ function translateValidationMessage(translate, error, { label, messages, readMessage, fieldName } = {}) {
38
+ if (error === void 0 || error === null || error === "" || error === false) {
3
39
  return void 0;
4
40
  }
5
- if (typeof error === "string") {
6
- return error;
41
+ const read = readMessage ? readMessage(error) : void 0;
42
+ const message = normalizedValidationMessage(read === void 0 || read === null ? error : read);
43
+ if (!message) {
44
+ warnUnknownShape(typeof error === "object" ? error : { value: error });
45
+ return translate(DEFAULT_MESSAGE_KEY);
7
46
  }
8
- if (typeof error === "object" && error.key) {
9
- return translate(error.key, error.values);
47
+ if ("text" in message) {
48
+ return message.text;
10
49
  }
11
- return String(error);
50
+ const values = label && message.values.label === void 0 ? { ...message.values, label } : message.values;
51
+ const ownMessage = message.rule ? messages?.[message.rule] : void 0;
52
+ if (ownMessage !== void 0 && ownMessage !== null) {
53
+ return translateValidationMessage(translate, ownMessage, { label });
54
+ }
55
+ const path = message.path ?? fieldName;
56
+ if (message.rule && path) {
57
+ const fieldText = translate(`${NAMESPACE}:fields.${fieldKeyOf(path)}.${message.rule}`, { ...values, defaultValue: "" });
58
+ if (fieldText) {
59
+ return fieldText;
60
+ }
61
+ }
62
+ return translate(message.key, values);
63
+ }
64
+ function ruleMessageOf(key, rule, values = {}) {
65
+ return { key, values, rule };
12
66
  }
13
67
  export {
68
+ fieldKeyOf,
69
+ normalizedValidationMessage,
70
+ ruleMessageOf,
14
71
  translateValidationMessage
15
72
  };
16
73
  //# sourceMappingURL=validationMessages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validationMessages.js","sources":["../../src/forms/validationMessages.js"],"sourcesContent":["// El texto de un error de validación en el idioma activo. Aparte de validation.js a propósito: no importa yup, así lo usan\n// los campos sueltos de la puerta principal (inputs/) sin cargar yup en un proyecto que no valida con él.\n//\n// Función pura, no renderiza: function (regla de la casa).\n\n/**\n * Texto de un error de validación en el idioma activo.\n * Acepta las dos formas que llegan: {key, values} de yup (buildYupLocale), o un texto ya traducido (los del backend).\n *\n * @param {(key: string, values?: object) => string} translate el t de useToolkitTranslation\n * @param {string|{key: string, values?: object}|undefined|null} error\n * @returns {string|undefined}\n */\nexport function translateValidationMessage(translate, error) {\n if (!error) {\n return undefined;\n }\n if (typeof error === 'string') {\n return error;\n }\n if (typeof error === 'object' && error.key) {\n return translate(error.key, error.values);\n }\n return String(error);\n}\n"],"names":[],"mappings":"AAaO,SAAS,2BAA2B,WAAW,OAAO;AACzD,MAAI,CAAC,OAAO;AACR,WAAO;AAAA,EACX;AACA,MAAI,OAAO,UAAU,UAAU;AAC3B,WAAO;AAAA,EACX;AACA,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK;AACxC,WAAO,UAAU,MAAM,KAAK,MAAM,MAAM;AAAA,EAC5C;AACA,SAAO,OAAO,KAAK;AACvB;"}
1
+ {"version":3,"file":"validationMessages.js","sources":["../../src/forms/validationMessages.js"],"sourcesContent":["// El texto de un error de validación en el idioma activo. Aparte de validation.js a propósito: no importa yup, así lo usan\n// los campos sueltos de la puerta principal (inputs/) sin cargar yup en un proyecto que no valida con él.\n//\n// De dónde sale el texto, en este orden (el primero que exista gana):\n// 1. el de la pantalla para ese campo y esa regla: <TextInput messages={{matches: 'El RFC lleva 12 o 13 caracteres'}} />\n// 2. el de los textos del proyecto para ese campo y esa regla: validation:fields.<campo>.<regla>\n// ({es: {validation: {fields: {rfc: {matches: '…'}}}}}); el campo sin índices de lista (contacts[2].email → contacts.email)\n// 3. el del mensaje mismo: la llave que puso Calcita (buildYupLocale) o el esquema ({key: 'clientes:rfcLargo'})\n// Así el negocio pide un mensaje muy específico y se agrega un texto, sin tocar el esquema ni los mensajes de Calcita.\n//\n// Las formas de mensaje que entiende (readValidationMessage de ToolkitProvider lee cualquier otra, la de un sistema que ya\n// existe):\n// 'El correo ya existe.' un texto ya escrito (el del backend): tal cual\n// {key, values} la de Calcita (y rule y path, que pone buildYupLocale)\n// {msg, values} la de muchos sistemas con i18next (su setLocale de yup)\n// {message: 'texto'} un texto dentro de un objeto\n// {message: {…}, type} el error entero de react-hook-form: se lee su message\n// Una forma que no entiende NO se pinta como «[object Object]»: sale el mensaje general y se avisa en la consola.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\nimport {createLogger} from '@/observability/logger.js';\n\nconst NAMESPACE = 'validation';\nconst DEFAULT_MESSAGE_KEY = `${NAMESPACE}:default`;\nconst log = createLogger('forms');\n// las formas de mensaje que no se entendieron y de las que ya se avisó (una vez por forma)\nconst warnedShapes = new Set();\n\n/**\n * El campo sin índices de lista, para buscar su texto propio: 'contacts[2].email' y 'contacts.2.email' son 'contacts.email'.\n *\n * @param {string} path\n * @returns {string}\n */\nexport function fieldKeyOf(path) {\n return String(path)\n .replace(/\\[\\d+\\]/g, '')\n .split('.')\n .filter((step) => step !== '' && !/^\\d+$/.test(step))\n .join('.');\n}\n\n/**\n * Un mensaje en la forma de Calcita, venga como venga.\n *\n * @param {unknown} error\n * @returns {{text: string}|{key: string, values: object, rule?: string, path?: string}|null} null: no se entendió\n */\nexport function normalizedValidationMessage(error) {\n if (typeof error === 'string') {\n return {text: error};\n }\n if (!error || typeof error !== 'object') {\n return null;\n }\n const key = typeof error.key === 'string' ? error.key : (typeof error.msg === 'string' ? error.msg : null);\n if (key) {\n return {key, values: error.values ?? error.params ?? {}, rule: error.rule, path: error.path};\n }\n if (typeof error.message === 'string') {\n return {text: error.message};\n }\n if (error.message && typeof error.message === 'object') {\n const inner = normalizedValidationMessage(error.message);\n // el error de react-hook-form trae la regla en `type`\n return inner && 'key' in inner && !inner.rule && error.type ? {...inner, rule: error.type} : inner;\n }\n return null;\n}\n\n/**\n * Avisa una vez por forma de un mensaje que no se entendió (sus llaves), en vez de pintar «[object Object]».\n *\n * @param {object} error\n * @returns {void}\n */\nfunction warnUnknownShape(error) {\n const shape = Object.keys(error).sort().join(',');\n if (warnedShapes.has(shape)) {\n return;\n }\n warnedShapes.add(shape);\n log.warn(`Un mensaje de validación con forma desconocida ({${shape}}): se enseña el mensaje general. Conéctelo con readValidationMessage de ToolkitProvider.`);\n}\n\n/**\n * Texto de un error de validación en el idioma activo.\n *\n * @param {(key: string, values?: object) => string} translate el t de useToolkitTranslation (respeta `defaultValue`, como el\n * de i18next: con él busca los textos opcionales sin avisar que faltan)\n * @param {unknown} error lo que dejó la validación en el campo\n * @param {object} [options]\n * @param {string} [options.label] el nombre del campo, para los textos que lo dicen ({{label}}: «Escriba {{label}}»)\n * @param {Record<string, string|object>} [options.messages] los textos de la pantalla para este campo, por regla\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}); ya traducidos o como {key, values}\n * @param {((error: unknown) => unknown)|null} [options.readMessage] cómo leer el mensaje de un sistema que ya existe\n * (readValidationMessage de ToolkitProvider): regresa un texto, {key, values} o undefined para la lectura de siempre\n * @param {string} [options.fieldName] el name del campo que pinta el error: para el texto propio de ese campo cuando el\n * mensaje no trae su campo (las reglas propias, los de un sistema que ya existe)\n * @returns {string|undefined}\n */\nexport function translateValidationMessage(translate, error, {label, messages, readMessage, fieldName} = {}) {\n if (error === undefined || error === null || error === '' || error === false) {\n return undefined;\n }\n const read = readMessage ? readMessage(error) : undefined;\n const message = normalizedValidationMessage(read === undefined || read === null ? error : read);\n if (!message) {\n warnUnknownShape(typeof error === 'object' ? error : {value: error});\n return translate(DEFAULT_MESSAGE_KEY);\n }\n if ('text' in message) {\n return message.text;\n }\n const values = label && message.values.label === undefined ? {...message.values, label} : message.values;\n\n // 1. el de la pantalla para esta regla\n const ownMessage = message.rule ? messages?.[message.rule] : undefined;\n if (ownMessage !== undefined && ownMessage !== null) {\n return translateValidationMessage(translate, ownMessage, {label});\n }\n // 2. el de los textos del proyecto para este campo y esta regla (opcional: sin él no se avisa que falta)\n const path = message.path ?? fieldName;\n if (message.rule && path) {\n const fieldText = translate(`${NAMESPACE}:fields.${fieldKeyOf(path)}.${message.rule}`, {...values, defaultValue: ''});\n if (fieldText) {\n return fieldText;\n }\n }\n // 3. el del mensaje\n return translate(message.key, values);\n}\n\n/**\n * El mensaje de una regla propia (.test) como lo dejan las de Calcita: su llave, sus valores y el nombre de la regla, para\n * que la pantalla (messages del campo) o los textos del proyecto (validation:fields.<campo>.<regla>) pongan el suyo sin\n * tocar el esquema. Es un objeto fijo: quien lo lea (rule.message.key) lo encuentra como siempre.\n *\n * {name: 'percent', message: ruleMessageOf('validation:percent', 'percent', {min: 0, max: 100}), test: …}\n *\n * @param {string} key la llave del texto ('validation:percent')\n * @param {string} rule el nombre de la regla\n * @param {object} [values] los valores del texto\n * @returns {{key: string, values: object, rule: string}}\n */\nexport function ruleMessageOf(key, rule, values = {}) {\n return {key, values, rule};\n}\n"],"names":[],"mappings":";AAsBA,MAAM,YAAY;AAClB,MAAM,sBAAsB,GAAG,SAAS;AACxC,MAAM,MAAM,aAAa,OAAO;AAEhC,MAAM,eAAe,oBAAI,IAAG;AAQrB,SAAS,WAAW,MAAM;AAC7B,SAAO,OAAO,IAAI,EACb,QAAQ,YAAY,EAAE,EACtB,MAAM,GAAG,EACT,OAAO,CAAC,SAAS,SAAS,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,EACnD,KAAK,GAAG;AACjB;AAQO,SAAS,4BAA4B,OAAO;AAC/C,MAAI,OAAO,UAAU,UAAU;AAC3B,WAAO,EAAC,MAAM,MAAK;AAAA,EACvB;AACA,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACrC,WAAO;AAAA,EACX;AACA,QAAM,MAAM,OAAO,MAAM,QAAQ,WAAW,MAAM,MAAO,OAAO,MAAM,QAAQ,WAAW,MAAM,MAAM;AACrG,MAAI,KAAK;AACL,WAAO,EAAC,KAAK,QAAQ,MAAM,UAAU,MAAM,UAAU,CAAA,GAAI,MAAM,MAAM,MAAM,MAAM,MAAM,KAAI;AAAA,EAC/F;AACA,MAAI,OAAO,MAAM,YAAY,UAAU;AACnC,WAAO,EAAC,MAAM,MAAM,QAAO;AAAA,EAC/B;AACA,MAAI,MAAM,WAAW,OAAO,MAAM,YAAY,UAAU;AACpD,UAAM,QAAQ,4BAA4B,MAAM,OAAO;AAEvD,WAAO,SAAS,SAAS,SAAS,CAAC,MAAM,QAAQ,MAAM,OAAO,EAAC,GAAG,OAAO,MAAM,MAAM,KAAI,IAAI;AAAA,EACjG;AACA,SAAO;AACX;AAQA,SAAS,iBAAiB,OAAO;AAC7B,QAAM,QAAQ,OAAO,KAAK,KAAK,EAAE,KAAI,EAAG,KAAK,GAAG;AAChD,MAAI,aAAa,IAAI,KAAK,GAAG;AACzB;AAAA,EACJ;AACA,eAAa,IAAI,KAAK;AACtB,MAAI,KAAK,oDAAoD,KAAK,2FAA2F;AACjK;AAkBO,SAAS,2BAA2B,WAAW,OAAO,EAAC,OAAO,UAAU,aAAa,UAAS,IAAI,IAAI;AACzG,MAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,MAAM,UAAU,OAAO;AAC1E,WAAO;AAAA,EACX;AACA,QAAM,OAAO,cAAc,YAAY,KAAK,IAAI;AAChD,QAAM,UAAU,4BAA4B,SAAS,UAAa,SAAS,OAAO,QAAQ,IAAI;AAC9F,MAAI,CAAC,SAAS;AACV,qBAAiB,OAAO,UAAU,WAAW,QAAQ,EAAC,OAAO,MAAK,CAAC;AACnE,WAAO,UAAU,mBAAmB;AAAA,EACxC;AACA,MAAI,UAAU,SAAS;AACnB,WAAO,QAAQ;AAAA,EACnB;AACA,QAAM,SAAS,SAAS,QAAQ,OAAO,UAAU,SAAY,EAAC,GAAG,QAAQ,QAAQ,MAAK,IAAI,QAAQ;AAGlG,QAAM,aAAa,QAAQ,OAAO,WAAW,QAAQ,IAAI,IAAI;AAC7D,MAAI,eAAe,UAAa,eAAe,MAAM;AACjD,WAAO,2BAA2B,WAAW,YAAY,EAAC,MAAK,CAAC;AAAA,EACpE;AAEA,QAAM,OAAO,QAAQ,QAAQ;AAC7B,MAAI,QAAQ,QAAQ,MAAM;AACtB,UAAM,YAAY,UAAU,GAAG,SAAS,WAAW,WAAW,IAAI,CAAC,IAAI,QAAQ,IAAI,IAAI,EAAC,GAAG,QAAQ,cAAc,GAAE,CAAC;AACpH,QAAI,WAAW;AACX,aAAO;AAAA,IACX;AAAA,EACJ;AAEA,SAAO,UAAU,QAAQ,KAAK,MAAM;AACxC;AAcO,SAAS,cAAc,KAAK,MAAM,SAAS,CAAA,GAAI;AAClD,SAAO,EAAC,KAAK,QAAQ,KAAI;AAC7B;"}
package/dist/forms.js CHANGED
@@ -13,6 +13,7 @@ import { default as default11 } from "./forms/FormProblemAlert.js";
13
13
  import { default as default12 } from "./forms/FormRepeatingFields.js";
14
14
  import { default as default13 } from "./forms/FormTransferListField.js";
15
15
  import { listTotalAtMostRule, listTotalOf, orderedInListRule, uniqueInListRule } from "./forms/listRules.js";
16
+ import { percentRule, sameAsFieldRule } from "./forms/fieldRules.js";
16
17
  import { default as default14 } from "./forms/FormSelectField.js";
17
18
  import { default as default15 } from "./forms/FormServerProblem.js";
18
19
  import { default as default16 } from "./forms/FormTextField.js";
@@ -68,6 +69,8 @@ export {
68
69
  normalizeRecoveryCode,
69
70
  normalizeTotpCode,
70
71
  orderedInListRule,
72
+ percentRule,
73
+ sameAsFieldRule,
71
74
  splitRowFieldErrors,
72
75
  splitServerFieldErrors,
73
76
  translateValidationMessage,
package/dist/forms.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"forms.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"forms.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2,11 +2,11 @@
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { useFormContext, useFormState } from "react-hook-form";
4
4
  import Alert from "@mui/material/Alert";
5
- import { piecePart } from "../theme/themePieces.js";
5
+ import { piecePart, withPieceSlots } from "../theme/themePieces.js";
6
6
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
7
7
  const THEME_NAME = "CalcitaFormProblemAlert";
8
8
  const ProblemAlert = piecePart(THEME_NAME, "Root", Alert);
9
- function FormProblemAlert({ control, sx, ...unknownProps }) {
9
+ function FormProblemAlertContent({ control, sx, ...unknownProps }) {
10
10
  warnUnknownProps("FormProblemAlert", unknownProps);
11
11
  const formContext = useFormContext();
12
12
  const { errors } = useFormState({ control: control ?? formContext?.control });
@@ -16,6 +16,7 @@ function FormProblemAlert({ control, sx, ...unknownProps }) {
16
16
  }
17
17
  return /* @__PURE__ */ jsx(ProblemAlert, { severity: "error", role: "alert", sx, children: message });
18
18
  }
19
+ const FormProblemAlert = withPieceSlots(FormProblemAlertContent, THEME_NAME);
19
20
  export {
20
21
  FormProblemAlert as default
21
22
  };
@@ -1 +1 @@
1
- {"version":3,"file":"FormProblemAlert.js","sources":["../../src/hookForm/FormProblemAlert.jsx"],"sourcesContent":["// El aviso de arriba del formulario de react-hook-form: lo que el servidor dijo que no es de un campo. applyServerProblem\n// lo deja en errors.root.server; aquí se pinta. Sin mensaje no pinta nada ni ocupa lugar.\n//\n// Se cambia desde el tema del proyecto: components.CalcitaFormProblemAlert con styleOverrides.root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormContext, useFormState} from 'react-hook-form';\nimport Alert from '@mui/material/Alert';\nimport {piecePart} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaFormProblemAlert): el estilo del proyecto va\n// después del de MUI y el sx de la pantalla al final\nconst THEME_NAME = 'CalcitaFormProblemAlert';\nconst ProblemAlert = piecePart(THEME_NAME, 'Root', Alert);\n\n/**\n * @param {{control?: object, sx?: object}} props control: el de useForm, si la pantalla no usa FormProvider\n */\nexport default function FormProblemAlert({control, sx, ...unknownProps}) {\n warnUnknownProps('FormProblemAlert', unknownProps);\n const formContext = useFormContext();\n const {errors} = useFormState({control: control ?? formContext?.control});\n const message = errors.root?.server?.message;\n\n // guard clause: sin aviso del servidor\n if (!message) {\n return null;\n }\n return <ProblemAlert severity=\"error\" role=\"alert\" sx={sx}>{message}</ProblemAlert>;\n}\n"],"names":[],"mappings":";;;;;;AAaA,MAAM,aAAa;AACnB,MAAM,eAAe,UAAU,YAAY,QAAQ,KAAK;AAKxD,SAAwB,iBAAiB,EAAC,SAAS,IAAI,GAAG,gBAAe;AACrE,mBAAiB,oBAAoB,YAAY;AACjD,QAAM,cAAc,eAAA;AACpB,QAAM,EAAC,WAAU,aAAa,EAAC,SAAS,WAAW,aAAa,SAAQ;AACxE,QAAM,UAAU,OAAO,MAAM,QAAQ;AAGrC,MAAI,CAAC,SAAS;AACV,WAAO;AAAA,EACX;AACA,6BAAQ,cAAA,EAAa,UAAS,SAAQ,MAAK,SAAQ,IAAS,UAAA,SAAQ;AACxE;"}
1
+ {"version":3,"file":"FormProblemAlert.js","sources":["../../src/hookForm/FormProblemAlert.jsx"],"sourcesContent":["// El aviso de arriba del formulario de react-hook-form: lo que el servidor dijo que no es de un campo. applyServerProblem\n// lo deja en errors.root.server; aquí se pinta. Sin mensaje no pinta nada ni ocupa lugar.\n//\n// Se cambia desde el tema del proyecto: components.CalcitaFormProblemAlert con styleOverrides.root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormContext, useFormState} from 'react-hook-form';\nimport Alert from '@mui/material/Alert';\nimport {piecePart, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaFormProblemAlert): el estilo del proyecto va\n// después del de MUI y el sx de la pantalla al final\nconst THEME_NAME = 'CalcitaFormProblemAlert';\nconst ProblemAlert = piecePart(THEME_NAME, 'Root', Alert);\n\n/**\n * @param {{control?: object, sx?: object}} props control: el de useForm, si la pantalla no usa FormProvider\n */\nfunction FormProblemAlertContent({control, sx, ...unknownProps}) {\n warnUnknownProps('FormProblemAlert', unknownProps);\n const formContext = useFormContext();\n const {errors} = useFormState({control: control ?? formContext?.control});\n const message = errors.root?.server?.message;\n\n // guard clause: sin aviso del servidor\n if (!message) {\n return null;\n }\n return <ProblemAlert severity=\"error\" role=\"alert\" sx={sx}>{message}</ProblemAlert>;\n}\n\nconst FormProblemAlert = withPieceSlots(FormProblemAlertContent, THEME_NAME);\nexport default FormProblemAlert;\n"],"names":[],"mappings":";;;;;;AAaA,MAAM,aAAa;AACnB,MAAM,eAAe,UAAU,YAAY,QAAQ,KAAK;AAKxD,SAAS,wBAAwB,EAAC,SAAS,IAAI,GAAG,gBAAe;AAC7D,mBAAiB,oBAAoB,YAAY;AACjD,QAAM,cAAc,eAAA;AACpB,QAAM,EAAC,WAAU,aAAa,EAAC,SAAS,WAAW,aAAa,SAAQ;AACxE,QAAM,UAAU,OAAO,MAAM,QAAQ;AAGrC,MAAI,CAAC,SAAS;AACV,WAAO;AAAA,EACX;AACA,6BAAQ,cAAA,EAAa,UAAS,SAAQ,MAAK,SAAQ,IAAS,UAAA,SAAQ;AACxE;AAEA,MAAM,mBAAmB,eAAe,yBAAyB,UAAU;"}
@@ -3,12 +3,17 @@ import { jsx } from "react/jsx-runtime";
3
3
  import { useFormContext, useFormState } from "react-hook-form";
4
4
  import Button from "@mui/material/Button";
5
5
  import CircularProgress from "@mui/material/CircularProgress";
6
- function SubmitButton({ children, disabled, isPending, control, ...buttonProps }) {
6
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
7
+ const THEME_NAME = "CalcitaSubmitButton";
8
+ const SubmitButtonRoot = piecePart(THEME_NAME, "Root", Button);
9
+ function SubmitButtonContent(props) {
10
+ const { children, disabled, isPending, control, ...buttonProps } = usePieceProps(props, THEME_NAME);
7
11
  const formContext = useFormContext();
8
12
  const { isSubmitting } = useFormState({ control: control ?? formContext?.control });
9
13
  const isBusy = Boolean(isPending ?? isSubmitting);
10
- return /* @__PURE__ */ jsx(Button, { type: "submit", variant: "contained", size: "large", disabled: disabled || isBusy, "aria-busy": isBusy, ...buttonProps, children: isBusy ? /* @__PURE__ */ jsx(CircularProgress, { size: 22, color: "inherit" }) : children });
14
+ return /* @__PURE__ */ jsx(SubmitButtonRoot, { type: "submit", variant: "contained", size: "large", disabled: disabled || isBusy, "aria-busy": isBusy, ...buttonProps, children: isBusy ? /* @__PURE__ */ jsx(CircularProgress, { size: 22, color: "inherit" }) : children });
11
15
  }
16
+ const SubmitButton = withPieceSlots(SubmitButtonContent, THEME_NAME);
12
17
  export {
13
18
  SubmitButton as default
14
19
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SubmitButton.js","sources":["../../src/hookForm/SubmitButton.jsx"],"sourcesContent":["// Botón de enviar de react-hook-form: se bloquea y muestra su indicador mientras se envía (un doble clic no manda dos\n// peticiones). Mismo look que el SubmitButton de formik.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormContext, useFormState} from 'react-hook-form';\nimport Button from '@mui/material/Button';\nimport CircularProgress from '@mui/material/CircularProgress';\n\n/**\n * @param {object} props\n * @param {import('react').ReactNode} props.children\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.isPending] cuando el envío lo lleva una máquina de estados y no el handleSubmit\n * @param {object} [props.control] el de useForm, si la pantalla no usa FormProvider\n * @param {object} [props.sx] (y lo demás del Button de MUI: size, fullWidth, startIcon…)\n * @param {'small'|'medium'|'large'} [props.size]\n * @param {boolean} [props.fullWidth]\n * @param {import('react').ReactNode} [props.startIcon]\n */\nexport default function SubmitButton({children, disabled, isPending, control, ...buttonProps}) {\n const formContext = useFormContext();\n const {isSubmitting} = useFormState({control: control ?? formContext?.control});\n const isBusy = Boolean(isPending ?? isSubmitting);\n\n return (\n <Button type=\"submit\" variant=\"contained\" size=\"large\" disabled={disabled || isBusy} aria-busy={isBusy} {...buttonProps}>\n {isBusy ? <CircularProgress size={22} color=\"inherit\" /> : children}\n </Button>\n );\n}\n"],"names":[],"mappings":";;;;;AAmBA,SAAwB,aAAa,EAAC,UAAU,UAAU,WAAW,SAAS,GAAG,eAAc;AAC3F,QAAM,cAAc,eAAA;AACpB,QAAM,EAAC,iBAAgB,aAAa,EAAC,SAAS,WAAW,aAAa,SAAQ;AAC9E,QAAM,SAAS,QAAQ,aAAa,YAAY;AAEhD,SACI,oBAAC,UAAO,MAAK,UAAS,SAAQ,aAAY,MAAK,SAAQ,UAAU,YAAY,QAAQ,aAAW,QAAS,GAAG,aACvG,UAAA,SAAS,oBAAC,kBAAA,EAAiB,MAAM,IAAI,OAAM,WAAU,IAAK,SAAA,CAC/D;AAER;"}
1
+ {"version":3,"file":"SubmitButton.js","sources":["../../src/hookForm/SubmitButton.jsx"],"sourcesContent":["// Botón de enviar de react-hook-form: se bloquea y muestra su indicador mientras se envía (un doble clic no manda dos\n// peticiones). Mismo look que el SubmitButton de formik.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSubmitButton con defaultProps, styleOverrides de\n// sus partes (root) y slots/slotProps para cambiarlas.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormContext, useFormState} from 'react-hook-form';\nimport Button from '@mui/material/Button';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaSubmitButton)\nconst THEME_NAME = 'CalcitaSubmitButton';\nconst SubmitButtonRoot = piecePart(THEME_NAME, 'Root', Button);\n\n/**\n * @param {object} props\n * @param {import('react').ReactNode} props.children\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.isPending] cuando el envío lo lleva una máquina de estados y no el handleSubmit\n * @param {object} [props.control] el de useForm, si la pantalla no usa FormProvider\n * @param {object} [props.sx] (y lo demás del Button de MUI: size, fullWidth, startIcon…)\n * @param {'small'|'medium'|'large'} [props.size]\n * @param {boolean} [props.fullWidth]\n * @param {import('react').ReactNode} [props.startIcon]\n */\nfunction SubmitButtonContent(props) {\n const {children, disabled, isPending, control, ...buttonProps} = usePieceProps(props, THEME_NAME);\n const formContext = useFormContext();\n const {isSubmitting} = useFormState({control: control ?? formContext?.control});\n const isBusy = Boolean(isPending ?? isSubmitting);\n\n return (\n <SubmitButtonRoot type=\"submit\" variant=\"contained\" size=\"large\" disabled={disabled || isBusy} aria-busy={isBusy} {...buttonProps}>\n {isBusy ? <CircularProgress size={22} color=\"inherit\" /> : children}\n </SubmitButtonRoot>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst SubmitButton = withPieceSlots(SubmitButtonContent, THEME_NAME);\nexport default SubmitButton;\n"],"names":[],"mappings":";;;;;;AAaA,MAAM,aAAa;AACnB,MAAM,mBAAmB,UAAU,YAAY,QAAQ,MAAM;AAa7D,SAAS,oBAAoB,OAAO;AAChC,QAAM,EAAC,UAAU,UAAU,WAAW,SAAS,GAAG,gBAAe,cAAc,OAAO,UAAU;AAChG,QAAM,cAAc,eAAA;AACpB,QAAM,EAAC,iBAAgB,aAAa,EAAC,SAAS,WAAW,aAAa,SAAQ;AAC9E,QAAM,SAAS,QAAQ,aAAa,YAAY;AAEhD,SACI,oBAAC,oBAAiB,MAAK,UAAS,SAAQ,aAAY,MAAK,SAAQ,UAAU,YAAY,QAAQ,aAAW,QAAS,GAAG,aACjH,UAAA,SAAS,oBAAC,kBAAA,EAAiB,MAAM,IAAI,OAAM,WAAU,IAAK,SAAA,CAC/D;AAER;AAGA,MAAM,eAAe,eAAe,qBAAqB,UAAU;"}
@@ -15,7 +15,7 @@ import Typography from "@mui/material/Typography";
15
15
  import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded";
16
16
  import { PHONE_MEDIA_QUERY, DESKTOP_MEDIA_QUERY } from "../appShell/shellSizes.js";
17
17
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
18
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
18
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
19
19
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
20
20
  const THEME_NAME = "CalcitaInboxLayout";
21
21
  const InboxLabelDot = piecePart(THEME_NAME, "LabelDot", Box);
@@ -52,7 +52,7 @@ function FolderRow({ folder, isSelected, onSelect, t }) {
52
52
  unreadCount > 0 && /* @__PURE__ */ jsx(InboxFolderCount, { variant: "caption", ownSx: { fontWeight: 700 }, "aria-label": t("unreadCount", { count: unreadCount }), children: unreadCount })
53
53
  ] });
54
54
  }
55
- function InboxLayout(props) {
55
+ function InboxLayoutContent(props) {
56
56
  const {
57
57
  folders,
58
58
  labels = [],
@@ -119,6 +119,7 @@ function InboxLayout(props) {
119
119
  ] })
120
120
  ] });
121
121
  }
122
+ const InboxLayout = withPieceSlots(InboxLayoutContent, THEME_NAME);
122
123
  export {
123
124
  InboxLayout as default
124
125
  };