@stackcraftmx/calcita 0.32.2 → 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 (680) hide show
  1. package/README.md +426 -4
  2. package/cli/calcita.js +15 -0
  3. package/cli/checkTexts.js +209 -0
  4. package/cli/packageVersions.js +17 -3
  5. package/cli/projectFiles.js +7 -2
  6. package/cli/templates/module/__Name__Page.test.jsx.tpl +24 -0
  7. package/cli/templates/project/README.md.tpl +35 -2
  8. package/cli/templates/project/eslint.config.js.tpl +27 -0
  9. package/cli/templates/project/src/app/appRouter.jsx.tpl +5 -2
  10. package/cli/templates/project/src/app/appTexts.js.tpl +2 -1
  11. package/cli/templates/project/src/core/accountConnector.js.tpl +4 -2
  12. package/cli/templates/project/src/core/publicPaths.js.tpl +10 -2
  13. package/cli/templates/project/src/modules/auth/SignInPage.test.jsx.tpl +20 -0
  14. package/cli/templates/project/src/modules/home/HomePage.test.jsx.tpl +16 -0
  15. package/cli/templates/project/src/testing/browserGaps.js.tpl +70 -0
  16. package/cli/templates/project/src/testing/openScreen.jsx.tpl +58 -0
  17. package/cli/templates/project/src/testing/setup.js.tpl +25 -0
  18. package/cli/templates/project/vite.config.js.tpl +20 -1
  19. package/dist/DataTable/AuditTrailDialog.js +3 -2
  20. package/dist/DataTable/AuditTrailDialog.js.map +1 -1
  21. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +3 -2
  22. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
  23. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +3 -2
  24. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
  25. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +3 -2
  26. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
  27. package/dist/DataTable/EmptyState.js +3 -2
  28. package/dist/DataTable/EmptyState.js.map +1 -1
  29. package/dist/DataTable/FilterChips.js +3 -2
  30. package/dist/DataTable/FilterChips.js.map +1 -1
  31. package/dist/DataTable/GoToPage.js +71 -14
  32. package/dist/DataTable/GoToPage.js.map +1 -1
  33. package/dist/DataTable/ServerTable.js +97 -28
  34. package/dist/DataTable/ServerTable.js.map +1 -1
  35. package/dist/DataTable/ServerTableFilterDrawer.js +57 -0
  36. package/dist/DataTable/ServerTableFilterDrawer.js.map +1 -0
  37. package/dist/DataTable/StackedCell.js +60 -0
  38. package/dist/DataTable/StackedCell.js.map +1 -0
  39. package/dist/DataTable/TableCardsView.js +88 -0
  40. package/dist/DataTable/TableCardsView.js.map +1 -0
  41. package/dist/DataTable/columnWidths.js +30 -0
  42. package/dist/DataTable/columnWidths.js.map +1 -0
  43. package/dist/DataTable/columns.js +47 -1
  44. package/dist/DataTable/columns.js.map +1 -1
  45. package/dist/DataTable/filterContext.js.map +1 -1
  46. package/dist/DataTable/fixedColumns.js +24 -0
  47. package/dist/DataTable/fixedColumns.js.map +1 -0
  48. package/dist/DataTable/goToPageOptions.js +17 -0
  49. package/dist/DataTable/goToPageOptions.js.map +1 -0
  50. package/dist/DataTable/useTableView.js +29 -0
  51. package/dist/DataTable/useTableView.js.map +1 -0
  52. package/dist/access/PermissionMatrix.js +3 -2
  53. package/dist/access/PermissionMatrix.js.map +1 -1
  54. package/dist/account/AccountProvider.js +1 -1
  55. package/dist/account/AccountSecuritySection.js +3 -2
  56. package/dist/account/AccountSecuritySection.js.map +1 -1
  57. package/dist/account/DemoTotpCodeButton.js +3 -2
  58. package/dist/account/DemoTotpCodeButton.js.map +1 -1
  59. package/dist/account/ProfileScreen.js +3 -2
  60. package/dist/account/ProfileScreen.js.map +1 -1
  61. package/dist/account/SignInScreen.js +3 -2
  62. package/dist/account/SignInScreen.js.map +1 -1
  63. package/dist/appShell/AccountMenu.js +3 -2
  64. package/dist/appShell/AccountMenu.js.map +1 -1
  65. package/dist/appShell/AppLayout.js +3 -2
  66. package/dist/appShell/AppLayout.js.map +1 -1
  67. package/dist/appShell/AppearanceSettings.js +3 -2
  68. package/dist/appShell/AppearanceSettings.js.map +1 -1
  69. package/dist/appShell/AuthLayout.js +3 -2
  70. package/dist/appShell/AuthLayout.js.map +1 -1
  71. package/dist/appShell/BarActionButton.js +11 -4
  72. package/dist/appShell/BarActionButton.js.map +1 -1
  73. package/dist/appShell/BarActions.js +3 -2
  74. package/dist/appShell/BarActions.js.map +1 -1
  75. package/dist/appShell/BarCapsule.js +3 -2
  76. package/dist/appShell/BarCapsule.js.map +1 -1
  77. package/dist/appShell/BarSearch.js +3 -2
  78. package/dist/appShell/BarSearch.js.map +1 -1
  79. package/dist/appShell/HeaderTools.js +3 -2
  80. package/dist/appShell/HeaderTools.js.map +1 -1
  81. package/dist/appShell/MobileTabBar.js +3 -2
  82. package/dist/appShell/MobileTabBar.js.map +1 -1
  83. package/dist/appShell/SettingsMenu.js +3 -2
  84. package/dist/appShell/SettingsMenu.js.map +1 -1
  85. package/dist/appShell/SideMenu.js +3 -2
  86. package/dist/appShell/SideMenu.js.map +1 -1
  87. package/dist/appShell/SideMenuEntry.js +3 -2
  88. package/dist/appShell/SideMenuEntry.js.map +1 -1
  89. package/dist/appShell/SubmenuActionsMenu.js +3 -2
  90. package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
  91. package/dist/appShell/TabBarEditor.js +3 -2
  92. package/dist/appShell/TabBarEditor.js.map +1 -1
  93. package/dist/appShell/TopMenu.js +3 -2
  94. package/dist/appShell/TopMenu.js.map +1 -1
  95. package/dist/appShell/Wordmark.js +3 -2
  96. package/dist/appShell/Wordmark.js.map +1 -1
  97. package/dist/auth/PasswordChecklist.js +3 -2
  98. package/dist/auth/PasswordChecklist.js.map +1 -1
  99. package/dist/calendar/EventCalendar.js +3 -2
  100. package/dist/calendar/EventCalendar.js.map +1 -1
  101. package/dist/calendar/EventDetails.js +3 -2
  102. package/dist/calendar/EventDetails.js.map +1 -1
  103. package/dist/date-pickers.js +28 -2
  104. package/dist/date-pickers.js.map +1 -1
  105. package/dist/datePickers/DateInput.js +41 -54
  106. package/dist/datePickers/DateInput.js.map +1 -1
  107. package/dist/datePickers/DateTimeInput.js +81 -0
  108. package/dist/datePickers/DateTimeInput.js.map +1 -0
  109. package/dist/datePickers/FormDateTimeField.js +12 -0
  110. package/dist/datePickers/FormDateTimeField.js.map +1 -0
  111. package/dist/datePickers/FormMonthField.js +12 -0
  112. package/dist/datePickers/FormMonthField.js.map +1 -0
  113. package/dist/datePickers/FormTimeField.js +12 -0
  114. package/dist/datePickers/FormTimeField.js.map +1 -0
  115. package/dist/datePickers/MonthInput.js +64 -0
  116. package/dist/datePickers/MonthInput.js.map +1 -0
  117. package/dist/datePickers/PickerFrame.js +27 -0
  118. package/dist/datePickers/PickerFrame.js.map +1 -0
  119. package/dist/datePickers/TimeInput.js +61 -0
  120. package/dist/datePickers/TimeInput.js.map +1 -0
  121. package/dist/datePickers/dateTimeRules.js +24 -0
  122. package/dist/datePickers/dateTimeRules.js.map +1 -0
  123. package/dist/datePickers/pickerValues.js +106 -0
  124. package/dist/datePickers/pickerValues.js.map +1 -0
  125. package/dist/datePickers/useCurrentMinute.js +28 -0
  126. package/dist/datePickers/useCurrentMinute.js.map +1 -0
  127. package/dist/datePickers/usePickerField.js +23 -0
  128. package/dist/datePickers/usePickerField.js.map +1 -0
  129. package/dist/dictionaries/dictionaries.js +3 -1
  130. package/dist/dictionaries/dictionaries.js.map +1 -1
  131. package/dist/downloads/DownloadManager.js +3 -2
  132. package/dist/downloads/DownloadManager.js.map +1 -1
  133. package/dist/feedback/ConfirmDialog.js +3 -2
  134. package/dist/feedback/ConfirmDialog.js.map +1 -1
  135. package/dist/feedback/ModalWaiting.js +3 -2
  136. package/dist/feedback/ModalWaiting.js.map +1 -1
  137. package/dist/feedback/NewBuildNotice.js +3 -2
  138. package/dist/feedback/NewBuildNotice.js.map +1 -1
  139. package/dist/filepond/FileDropzone.js +3 -2
  140. package/dist/filepond/FileDropzone.js.map +1 -1
  141. package/dist/forms/FormAttachmentsField.js +12 -0
  142. package/dist/forms/FormAttachmentsField.js.map +1 -0
  143. package/dist/forms/FormCheckboxGroupField.js +12 -0
  144. package/dist/forms/FormCheckboxGroupField.js.map +1 -0
  145. package/dist/forms/FormFileField.js +12 -0
  146. package/dist/forms/FormFileField.js.map +1 -0
  147. package/dist/forms/FormFileUploadField.js +12 -0
  148. package/dist/forms/FormFileUploadField.js.map +1 -0
  149. package/dist/forms/FormImageField.js +12 -0
  150. package/dist/forms/FormImageField.js.map +1 -0
  151. package/dist/forms/FormMaskedField.js +12 -0
  152. package/dist/forms/FormMaskedField.js.map +1 -0
  153. package/dist/forms/FormProblemAlert.js +3 -2
  154. package/dist/forms/FormProblemAlert.js.map +1 -1
  155. package/dist/forms/FormRepeatingFields.js +54 -0
  156. package/dist/forms/FormRepeatingFields.js.map +1 -0
  157. package/dist/forms/FormTransferListField.js +12 -0
  158. package/dist/forms/FormTransferListField.js.map +1 -0
  159. package/dist/forms/SubmitButton.js +7 -2
  160. package/dist/forms/SubmitButton.js.map +1 -1
  161. package/dist/forms/applyServerProblem.js +10 -3
  162. package/dist/forms/applyServerProblem.js.map +1 -1
  163. package/dist/forms/auth/SignInForm.js +3 -2
  164. package/dist/forms/auth/SignInForm.js.map +1 -1
  165. package/dist/forms/fieldRules.js +30 -0
  166. package/dist/forms/fieldRules.js.map +1 -0
  167. package/dist/forms/listRules.js +111 -0
  168. package/dist/forms/listRules.js.map +1 -0
  169. package/dist/forms/security/SecondStepForm.js +3 -2
  170. package/dist/forms/security/SecondStepForm.js.map +1 -1
  171. package/dist/forms/security/TwoStepVerificationCard.js +3 -2
  172. package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
  173. package/dist/forms/serverProblemFields.js +17 -0
  174. package/dist/forms/serverProblemFields.js.map +1 -1
  175. package/dist/forms/useValidationText.js +18 -0
  176. package/dist/forms/useValidationText.js.map +1 -0
  177. package/dist/forms/validation.js +35 -31
  178. package/dist/forms/validation.js.map +1 -1
  179. package/dist/forms/validationMessages.js +64 -7
  180. package/dist/forms/validationMessages.js.map +1 -1
  181. package/dist/forms.js +54 -29
  182. package/dist/forms.js.map +1 -1
  183. package/dist/hookForm/FormAttachmentsField.js +12 -0
  184. package/dist/hookForm/FormAttachmentsField.js.map +1 -0
  185. package/dist/hookForm/FormCheckboxGroupField.js +12 -0
  186. package/dist/hookForm/FormCheckboxGroupField.js.map +1 -0
  187. package/dist/hookForm/FormFileField.js +12 -0
  188. package/dist/hookForm/FormFileField.js.map +1 -0
  189. package/dist/hookForm/FormFileUploadField.js +12 -0
  190. package/dist/hookForm/FormFileUploadField.js.map +1 -0
  191. package/dist/hookForm/FormImageField.js +12 -0
  192. package/dist/hookForm/FormImageField.js.map +1 -0
  193. package/dist/hookForm/FormMaskedField.js +12 -0
  194. package/dist/hookForm/FormMaskedField.js.map +1 -0
  195. package/dist/hookForm/FormProblemAlert.js +3 -2
  196. package/dist/hookForm/FormProblemAlert.js.map +1 -1
  197. package/dist/hookForm/FormRepeatingFields.js +44 -0
  198. package/dist/hookForm/FormRepeatingFields.js.map +1 -0
  199. package/dist/hookForm/FormTransferListField.js +12 -0
  200. package/dist/hookForm/FormTransferListField.js.map +1 -0
  201. package/dist/hookForm/SubmitButton.js +7 -2
  202. package/dist/hookForm/SubmitButton.js.map +1 -1
  203. package/dist/hookForm/applyServerProblem.js +8 -3
  204. package/dist/hookForm/applyServerProblem.js.map +1 -1
  205. package/dist/inbox/InboxLayout.js +3 -2
  206. package/dist/inbox/InboxLayout.js.map +1 -1
  207. package/dist/inbox/MessageList.js +3 -2
  208. package/dist/inbox/MessageList.js.map +1 -1
  209. package/dist/inbox/MessageView.js +3 -2
  210. package/dist/inbox/MessageView.js.map +1 -1
  211. package/dist/index.js +235 -124
  212. package/dist/index.js.map +1 -1
  213. package/dist/inputs/CatalogInput.js +103 -29
  214. package/dist/inputs/CatalogInput.js.map +1 -1
  215. package/dist/inputs/CheckboxGroupInput.js +103 -0
  216. package/dist/inputs/CheckboxGroupInput.js.map +1 -0
  217. package/dist/inputs/ColorInput.js +7 -4
  218. package/dist/inputs/ColorInput.js.map +1 -1
  219. package/dist/inputs/FieldFrame.js +10 -4
  220. package/dist/inputs/FieldFrame.js.map +1 -1
  221. package/dist/inputs/FormSection.js +1 -1
  222. package/dist/inputs/MaskedInput.js +87 -0
  223. package/dist/inputs/MaskedInput.js.map +1 -0
  224. package/dist/inputs/NumberInput.js +41 -25
  225. package/dist/inputs/NumberInput.js.map +1 -1
  226. package/dist/inputs/RepeatingFields.js +180 -0
  227. package/dist/inputs/RepeatingFields.js.map +1 -0
  228. package/dist/inputs/SelectInput.js +50 -9
  229. package/dist/inputs/SelectInput.js.map +1 -1
  230. package/dist/inputs/TextInput.js +5 -3
  231. package/dist/inputs/TextInput.js.map +1 -1
  232. package/dist/inputs/TransferListInput.js +218 -0
  233. package/dist/inputs/TransferListInput.js.map +1 -0
  234. package/dist/inputs/WizardLayout.js +3 -2
  235. package/dist/inputs/WizardLayout.js.map +1 -1
  236. package/dist/inputs/inputMasks.js +84 -0
  237. package/dist/inputs/inputMasks.js.map +1 -0
  238. package/dist/inputs/selectAllState.js +20 -0
  239. package/dist/inputs/selectAllState.js.map +1 -0
  240. package/dist/inputs/useRowKeys.js +26 -0
  241. package/dist/inputs/useRowKeys.js.map +1 -0
  242. package/dist/kanban/KanbanBoard.js +3 -2
  243. package/dist/kanban/KanbanBoard.js.map +1 -1
  244. package/dist/legal/CookieNotice.js +80 -0
  245. package/dist/legal/CookieNotice.js.map +1 -0
  246. package/dist/legal/TermsAcceptanceDialog.js +130 -0
  247. package/dist/legal/TermsAcceptanceDialog.js.map +1 -0
  248. package/dist/legal/consentStorage.js +18 -0
  249. package/dist/legal/consentStorage.js.map +1 -0
  250. package/dist/legal/useCookieConsent.js +17 -0
  251. package/dist/legal/useCookieConsent.js.map +1 -0
  252. package/dist/locales/en.js +257 -1
  253. package/dist/locales/en.js.map +1 -1
  254. package/dist/locales/es.js +257 -1
  255. package/dist/locales/es.js.map +1 -1
  256. package/dist/maps/MapView.js +3 -2
  257. package/dist/maps/MapView.js.map +1 -1
  258. package/dist/mexico/CfdiSummary.js +82 -0
  259. package/dist/mexico/CfdiSummary.js.map +1 -0
  260. package/dist/mexico/EfirmaFields.js +168 -0
  261. package/dist/mexico/EfirmaFields.js.map +1 -0
  262. package/dist/mexico/certificateReader.js +79 -0
  263. package/dist/mexico/certificateReader.js.map +1 -0
  264. package/dist/mexico/cfdiReader.js +81 -0
  265. package/dist/mexico/cfdiReader.js.map +1 -0
  266. package/dist/mexico/derReader.js +81 -0
  267. package/dist/mexico/derReader.js.map +1 -0
  268. package/dist/mexico/efirmaKey.js +51 -0
  269. package/dist/mexico/efirmaKey.js.map +1 -0
  270. package/dist/mexico/mexicoIdentifiers.js +91 -0
  271. package/dist/mexico/mexicoIdentifiers.js.map +1 -0
  272. package/dist/mexico/mexicoRules.js +21 -0
  273. package/dist/mexico/mexicoRules.js.map +1 -0
  274. package/dist/mexico.js +34 -0
  275. package/dist/mexico.js.map +1 -0
  276. package/dist/pwa/InstallAppSetting.js +3 -2
  277. package/dist/pwa/InstallAppSetting.js.map +1 -1
  278. package/dist/pwa/InstallInstructionsDialog.js +3 -2
  279. package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
  280. package/dist/pwa/InstallPromptBanner.js +3 -2
  281. package/dist/pwa/InstallPromptBanner.js.map +1 -1
  282. package/dist/react-hook-form.js +43 -17
  283. package/dist/react-hook-form.js.map +1 -1
  284. package/dist/rich-text.js +19 -0
  285. package/dist/rich-text.js.map +1 -0
  286. package/dist/richText/FormRichTextField.js +12 -0
  287. package/dist/richText/FormRichTextField.js.map +1 -0
  288. package/dist/richText/RichTextEditor.js +111 -0
  289. package/dist/richText/RichTextEditor.js.map +1 -0
  290. package/dist/richText/RichTextLinkPopover.js +57 -0
  291. package/dist/richText/RichTextLinkPopover.js.map +1 -0
  292. package/dist/richText/RichTextToolbar.js +189 -0
  293. package/dist/richText/RichTextToolbar.js.map +1 -0
  294. package/dist/richText/RichTextView.js +27 -0
  295. package/dist/richText/RichTextView.js.map +1 -0
  296. package/dist/richText/richTextContentSx.js +42 -0
  297. package/dist/richText/richTextContentSx.js.map +1 -0
  298. package/dist/richText/richTextExtensions.js +44 -0
  299. package/dist/richText/richTextExtensions.js.map +1 -0
  300. package/dist/richText/richTextRules.js +46 -0
  301. package/dist/richText/richTextRules.js.map +1 -0
  302. package/dist/security/ActivityLog.js +3 -2
  303. package/dist/security/ActivityLog.js.map +1 -1
  304. package/dist/security/RecoveryCodesDialog.js +3 -2
  305. package/dist/security/RecoveryCodesDialog.js.map +1 -1
  306. package/dist/security/SessionsCard.js +3 -2
  307. package/dist/security/SessionsCard.js.map +1 -1
  308. package/dist/table.js +23 -2
  309. package/dist/table.js.map +1 -1
  310. package/dist/theme/components/glassComponents.js +27 -0
  311. package/dist/theme/components/glassComponents.js.map +1 -1
  312. package/dist/theme/components/minimalComponents.js +12 -0
  313. package/dist/theme/components/minimalComponents.js.map +1 -1
  314. package/dist/theme/themePieces.js +70 -4
  315. package/dist/theme/themePieces.js.map +1 -1
  316. package/dist/toolkit/ToolkitProvider.js +8 -1
  317. package/dist/toolkit/ToolkitProvider.js.map +1 -1
  318. package/dist/toolkit/browserNavigation.js +19 -4
  319. package/dist/toolkit/browserNavigation.js.map +1 -1
  320. package/dist/toolkit/combineTexts.js +32 -0
  321. package/dist/toolkit/combineTexts.js.map +1 -0
  322. package/dist/toolkit/hashNavigation.js +17 -3
  323. package/dist/toolkit/hashNavigation.js.map +1 -1
  324. package/dist/toolkit/navigationPaths.js +15 -0
  325. package/dist/toolkit/navigationPaths.js.map +1 -1
  326. package/dist/toolkit/pathIndex.js +66 -0
  327. package/dist/toolkit/pathIndex.js.map +1 -0
  328. package/dist/toolkit/toolkitSettings.js +19 -1
  329. package/dist/toolkit/toolkitSettings.js.map +1 -1
  330. package/dist/types/DataTable/AuditTrailDialog.d.ts +6 -17
  331. package/dist/types/DataTable/ColumnFilters/HeaderFilterPopover.d.ts +6 -5
  332. package/dist/types/DataTable/ColumnFilters/MultiSelectColumnFilter.d.ts +6 -9
  333. package/dist/types/DataTable/ColumnFilters/SortableFilterHeader.d.ts +6 -14
  334. package/dist/types/DataTable/EmptyState.d.ts +6 -9
  335. package/dist/types/DataTable/FilterChips.d.ts +6 -11
  336. package/dist/types/DataTable/GoToPage.d.ts +6 -9
  337. package/dist/types/DataTable/ServerTable.d.ts +16 -80
  338. package/dist/types/DataTable/ServerTableFilterDrawer.d.ts +14 -0
  339. package/dist/types/DataTable/StackedCell.d.ts +12 -0
  340. package/dist/types/DataTable/TableCardsView.d.ts +27 -0
  341. package/dist/types/DataTable/columnWidths.d.ts +21 -0
  342. package/dist/types/DataTable/columns.d.ts +111 -0
  343. package/dist/types/DataTable/filterContext.d.ts +2 -1
  344. package/dist/types/DataTable/fixedColumns.d.ts +29 -0
  345. package/dist/types/DataTable/goToPageOptions.d.ts +15 -0
  346. package/dist/types/DataTable/index.d.ts +7 -1
  347. package/dist/types/DataTable/useTableView.d.ts +22 -0
  348. package/dist/types/access/PermissionMatrix.d.ts +6 -10
  349. package/dist/types/account/AccountSecuritySection.d.ts +6 -7
  350. package/dist/types/account/DemoTotpCodeButton.d.ts +6 -5
  351. package/dist/types/account/ProfileScreen.d.ts +6 -18
  352. package/dist/types/account/SignInScreen.d.ts +6 -13
  353. package/dist/types/appShell/AccountMenu.d.ts +6 -11
  354. package/dist/types/appShell/AppLayout.d.ts +3 -40
  355. package/dist/types/appShell/AppearanceSettings.d.ts +6 -12
  356. package/dist/types/appShell/AuthLayout.d.ts +3 -11
  357. package/dist/types/appShell/BarActionButton.d.ts +6 -10
  358. package/dist/types/appShell/BarActions.d.ts +6 -15
  359. package/dist/types/appShell/BarCapsule.d.ts +6 -9
  360. package/dist/types/appShell/BarSearch.d.ts +6 -15
  361. package/dist/types/appShell/HeaderTools.d.ts +6 -16
  362. package/dist/types/appShell/MobileTabBar.d.ts +6 -13
  363. package/dist/types/appShell/SettingsMenu.d.ts +6 -10
  364. package/dist/types/appShell/SideMenu.d.ts +6 -20
  365. package/dist/types/appShell/SideMenuEntry.d.ts +6 -11
  366. package/dist/types/appShell/SubmenuActionsMenu.d.ts +6 -12
  367. package/dist/types/appShell/TabBarEditor.d.ts +6 -9
  368. package/dist/types/appShell/TopMenu.d.ts +6 -5
  369. package/dist/types/appShell/Wordmark.d.ts +6 -7
  370. package/dist/types/auth/PasswordChecklist.d.ts +6 -9
  371. package/dist/types/calendar/EventCalendar.d.ts +6 -23
  372. package/dist/types/calendar/EventDetails.d.ts +6 -10
  373. package/dist/types/date-pickers.d.ts +10 -1
  374. package/dist/types/datePickers/DateInput.d.ts +10 -23
  375. package/dist/types/datePickers/DateTimeInput.d.ts +30 -0
  376. package/dist/types/datePickers/FormDateTimeField.d.ts +7 -0
  377. package/dist/types/datePickers/FormMonthField.d.ts +7 -0
  378. package/dist/types/datePickers/FormTimeField.d.ts +7 -0
  379. package/dist/types/datePickers/MonthInput.d.ts +25 -0
  380. package/dist/types/datePickers/PickerFrame.d.ts +22 -0
  381. package/dist/types/datePickers/TimeInput.d.ts +24 -0
  382. package/dist/types/datePickers/dateTimeRules.d.ts +31 -0
  383. package/dist/types/datePickers/pickerValues.d.ts +114 -0
  384. package/dist/types/datePickers/useCurrentMinute.d.ts +5 -0
  385. package/dist/types/datePickers/usePickerField.d.ts +28 -0
  386. package/dist/types/dictionaries/dictionaries.d.ts +6 -3
  387. package/dist/types/downloads/DownloadManager.d.ts +6 -6
  388. package/dist/types/feedback/ConfirmDialog.d.ts +6 -18
  389. package/dist/types/feedback/ModalWaiting.d.ts +6 -9
  390. package/dist/types/feedback/NewBuildNotice.d.ts +6 -10
  391. package/dist/types/filepond/FileDropzone.d.ts +6 -29
  392. package/dist/types/forms/FormAttachmentsField.d.ts +7 -0
  393. package/dist/types/forms/FormCheckboxGroupField.d.ts +7 -0
  394. package/dist/types/forms/FormFileField.d.ts +7 -0
  395. package/dist/types/forms/FormFileUploadField.d.ts +7 -0
  396. package/dist/types/forms/FormImageField.d.ts +7 -0
  397. package/dist/types/forms/FormMaskedField.d.ts +7 -0
  398. package/dist/types/forms/FormProblemAlert.d.ts +6 -5
  399. package/dist/types/forms/FormRepeatingFields.d.ts +25 -0
  400. package/dist/types/forms/FormTransferListField.d.ts +7 -0
  401. package/dist/types/forms/SubmitButton.d.ts +6 -6
  402. package/dist/types/forms/auth/SignInForm.d.ts +6 -11
  403. package/dist/types/forms/fieldRules.d.ts +44 -0
  404. package/dist/types/forms/index.d.ts +11 -1
  405. package/dist/types/forms/listRules.d.ts +48 -0
  406. package/dist/types/forms/security/SecondStepForm.d.ts +6 -14
  407. package/dist/types/forms/security/TwoStepVerificationCard.d.ts +6 -21
  408. package/dist/types/forms/serverProblemFields.d.ts +13 -0
  409. package/dist/types/forms/useValidationText.d.ts +12 -0
  410. package/dist/types/forms/validation.d.ts +117 -174
  411. package/dist/types/forms/validationMessages.d.ts +54 -6
  412. package/dist/types/forms.d.ts +1 -1
  413. package/dist/types/hookForm/FormAttachmentsField.d.ts +8 -0
  414. package/dist/types/hookForm/FormCheckboxGroupField.d.ts +8 -0
  415. package/dist/types/hookForm/FormFileField.d.ts +8 -0
  416. package/dist/types/hookForm/FormFileUploadField.d.ts +8 -0
  417. package/dist/types/hookForm/FormImageField.d.ts +8 -0
  418. package/dist/types/hookForm/FormMaskedField.d.ts +9 -0
  419. package/dist/types/hookForm/FormProblemAlert.d.ts +6 -5
  420. package/dist/types/hookForm/FormRepeatingFields.d.ts +27 -0
  421. package/dist/types/hookForm/FormTransferListField.d.ts +8 -0
  422. package/dist/types/hookForm/SubmitButton.d.ts +6 -13
  423. package/dist/types/inbox/InboxLayout.d.ts +6 -17
  424. package/dist/types/inbox/MessageList.d.ts +6 -18
  425. package/dist/types/inbox/MessageView.d.ts +6 -14
  426. package/dist/types/index.d.ts +33 -4
  427. package/dist/types/inputs/CatalogInput.d.ts +10 -21
  428. package/dist/types/inputs/CheckboxGroupInput.d.ts +28 -0
  429. package/dist/types/inputs/ColorInput.d.ts +7 -16
  430. package/dist/types/inputs/FieldFrame.d.ts +6 -10
  431. package/dist/types/inputs/MaskedInput.d.ts +38 -0
  432. package/dist/types/inputs/NumberInput.d.ts +7 -20
  433. package/dist/types/inputs/RepeatingFields.d.ts +31 -0
  434. package/dist/types/inputs/SelectInput.d.ts +10 -18
  435. package/dist/types/inputs/TextInput.d.ts +3 -0
  436. package/dist/types/inputs/TransferListInput.d.ts +30 -0
  437. package/dist/types/inputs/WizardLayout.d.ts +6 -19
  438. package/dist/types/inputs/inputMasks.d.ts +52 -0
  439. package/dist/types/inputs/selectAllState.d.ts +11 -0
  440. package/dist/types/inputs/useRowKeys.d.ts +11 -0
  441. package/dist/types/kanban/KanbanBoard.d.ts +6 -25
  442. package/dist/types/legal/CookieNotice.d.ts +20 -0
  443. package/dist/types/legal/TermsAcceptanceDialog.d.ts +20 -0
  444. package/dist/types/legal/consentStorage.d.ts +16 -0
  445. package/dist/types/legal/useCookieConsent.d.ts +13 -0
  446. package/dist/types/locales/en.d.ts +256 -0
  447. package/dist/types/locales/es.d.ts +256 -0
  448. package/dist/types/maps/MapView.d.ts +6 -17
  449. package/dist/types/mexico/CfdiSummary.d.ts +12 -0
  450. package/dist/types/mexico/EfirmaFields.d.ts +28 -0
  451. package/dist/types/mexico/certificateReader.d.ts +37 -0
  452. package/dist/types/mexico/cfdiReader.d.ts +95 -0
  453. package/dist/types/mexico/derReader.d.ts +54 -0
  454. package/dist/types/mexico/efirmaKey.d.ts +26 -0
  455. package/dist/types/mexico/mexicoIdentifiers.d.ts +68 -0
  456. package/dist/types/mexico/mexicoRules.d.ts +45 -0
  457. package/dist/types/mexico.d.ts +11 -0
  458. package/dist/types/pwa/InstallAppSetting.d.ts +6 -6
  459. package/dist/types/pwa/InstallInstructionsDialog.d.ts +6 -9
  460. package/dist/types/pwa/InstallPromptBanner.d.ts +6 -11
  461. package/dist/types/react-hook-form.d.ts +11 -1
  462. package/dist/types/rich-text.d.ts +5 -0
  463. package/dist/types/richText/FormRichTextField.d.ts +7 -0
  464. package/dist/types/richText/RichTextEditor.d.ts +27 -0
  465. package/dist/types/richText/RichTextLinkPopover.d.ts +17 -0
  466. package/dist/types/richText/RichTextToolbar.d.ts +15 -0
  467. package/dist/types/richText/RichTextView.d.ts +10 -0
  468. package/dist/types/richText/richTextContentSx.d.ts +7 -0
  469. package/dist/types/richText/richTextExtensions.d.ts +15 -0
  470. package/dist/types/richText/richTextRules.d.ts +41 -0
  471. package/dist/types/security/ActivityLog.d.ts +6 -9
  472. package/dist/types/security/RecoveryCodesDialog.d.ts +6 -11
  473. package/dist/types/security/SessionsCard.d.ts +6 -11
  474. package/dist/types/table.d.ts +3 -1
  475. package/dist/types/theme/themePieces.d.ts +55 -3
  476. package/dist/types/toolkit/ToolkitProvider.d.ts +13 -1
  477. package/dist/types/toolkit/browserNavigation.d.ts +7 -3
  478. package/dist/types/toolkit/combineTexts.d.ts +6 -0
  479. package/dist/types/toolkit/hashNavigation.d.ts +4 -2
  480. package/dist/types/toolkit/navigationPaths.d.ts +35 -0
  481. package/dist/types/toolkit/pathIndex.d.ts +27 -0
  482. package/dist/types/toolkit/toolkitSettings.d.ts +7 -4
  483. package/dist/types/ui/actions/ActionsMenu.d.ts +24 -11
  484. package/dist/types/ui/actions/CopyButton.d.ts +8 -11
  485. package/dist/types/ui/actions/DownloadMenu.d.ts +6 -29
  486. package/dist/types/ui/actions/SecretField.d.ts +6 -11
  487. package/dist/types/ui/actions/SelectionActions.d.ts +6 -13
  488. package/dist/types/ui/actions/tableRowText.d.ts +6 -0
  489. package/dist/types/ui/cards/RecordCard.d.ts +40 -0
  490. package/dist/types/ui/cards/RecordCardSkeleton.d.ts +12 -0
  491. package/dist/types/ui/countdown/Countdown.d.ts +22 -0
  492. package/dist/types/ui/countdown/countdownParts.d.ts +39 -0
  493. package/dist/types/ui/countdown/useCountdown.d.ts +14 -0
  494. package/dist/types/ui/documents/PdfViewerDialog.d.ts +14 -0
  495. package/dist/types/ui/filters/DateRangeFilter.d.ts +6 -10
  496. package/dist/types/ui/filters/FilterDrawer.d.ts +23 -0
  497. package/dist/types/ui/filters/PeriodRangeSelector.d.ts +6 -13
  498. package/dist/types/ui/filters/QuickFilters.d.ts +6 -12
  499. package/dist/types/ui/filters/filterDrawerFields.d.ts +139 -0
  500. package/dist/types/ui/help/HelpButton.d.ts +11 -0
  501. package/dist/types/ui/help/HelpCarouselDialog.d.ts +27 -0
  502. package/dist/types/ui/help/useHelpCarousel.d.ts +21 -0
  503. package/dist/types/ui/index.d.ts +10 -0
  504. package/dist/types/ui/labels/IconBadge.d.ts +34 -0
  505. package/dist/types/ui/labels/MarkedText.d.ts +10 -0
  506. package/dist/types/ui/labels/Tag.d.ts +6 -12
  507. package/dist/types/ui/labels/markedTextPieces.d.ts +22 -0
  508. package/dist/types/ui/layout/CollapsibleSection.d.ts +6 -12
  509. package/dist/types/ui/layout/ContentDialog.d.ts +6 -10
  510. package/dist/types/ui/layout/DefinitionList.d.ts +6 -9
  511. package/dist/types/ui/layout/DetailHeader.d.ts +6 -10
  512. package/dist/types/ui/layout/ErrorPage.d.ts +6 -17
  513. package/dist/types/ui/layout/FullPageLoader.d.ts +6 -6
  514. package/dist/types/ui/layout/GlassPanel.d.ts +6 -8
  515. package/dist/types/ui/layout/PageHeader.d.ts +6 -10
  516. package/dist/types/ui/layout/PageHeading.d.ts +6 -11
  517. package/dist/types/ui/layout/ProfileHeader.d.ts +6 -11
  518. package/dist/types/ui/layout/ScrollableRow.d.ts +6 -13
  519. package/dist/types/ui/layout/SectionCard.d.ts +6 -8
  520. package/dist/types/ui/metrics/BarList.d.ts +6 -12
  521. package/dist/types/ui/metrics/CalendarHeatmap.d.ts +6 -19
  522. package/dist/types/ui/metrics/ChartTooltip.d.ts +6 -6
  523. package/dist/types/ui/metrics/ColumnChart.d.ts +6 -25
  524. package/dist/types/ui/metrics/LineChart.d.ts +6 -20
  525. package/dist/types/ui/metrics/MetricCard.d.ts +6 -17
  526. package/dist/types/ui/metrics/TableToggle.d.ts +6 -6
  527. package/dist/types/ui/metrics/chartParts.d.ts +15 -30
  528. package/dist/types/ui/navigation/BackButton.d.ts +6 -9
  529. package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +6 -9
  530. package/dist/types/ui/navigation/FontSizeToggle.d.ts +6 -8
  531. package/dist/types/ui/navigation/LanguageToggle.d.ts +6 -8
  532. package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +6 -7
  533. package/dist/types/ui/navigation/RouteTabs.d.ts +39 -0
  534. package/dist/types/ui/navigation/routeTabMatching.d.ts +27 -0
  535. package/dist/types/ui/timeline/GroupedTimeline.d.ts +6 -23
  536. package/dist/types/upload/AttachmentsInput.d.ts +72 -0
  537. package/dist/types/upload/FileChip.d.ts +18 -0
  538. package/dist/types/upload/FileDropzone.d.ts +7 -19
  539. package/dist/types/upload/FileInput.d.ts +31 -0
  540. package/dist/types/upload/FileUploadInput.d.ts +56 -0
  541. package/dist/types/upload/ImageInput.d.ts +35 -0
  542. package/dist/types/upload/TemplateDownloadButton.d.ts +27 -0
  543. package/dist/types/upload/fileAppearance.d.ts +8 -0
  544. package/dist/types/upload/fileRules.d.ts +38 -0
  545. package/dist/types/upload/transferProgress.d.ts +18 -0
  546. package/dist/types/upload/uploadMachine.d.ts +6 -2
  547. package/dist/types/upload/uploadWithProgress.d.ts +6 -2
  548. package/dist/types/upload/useFilePicker.d.ts +39 -0
  549. package/dist/ui/actions/ActionsMenu.js +109 -17
  550. package/dist/ui/actions/ActionsMenu.js.map +1 -1
  551. package/dist/ui/actions/CopyButton.js +37 -12
  552. package/dist/ui/actions/CopyButton.js.map +1 -1
  553. package/dist/ui/actions/DownloadMenu.js +3 -2
  554. package/dist/ui/actions/DownloadMenu.js.map +1 -1
  555. package/dist/ui/actions/SecretField.js +8 -3
  556. package/dist/ui/actions/SecretField.js.map +1 -1
  557. package/dist/ui/actions/SelectionActions.js +3 -2
  558. package/dist/ui/actions/SelectionActions.js.map +1 -1
  559. package/dist/ui/actions/tableRowText.js +7 -0
  560. package/dist/ui/actions/tableRowText.js.map +1 -0
  561. package/dist/ui/cards/RecordCard.js +146 -0
  562. package/dist/ui/cards/RecordCard.js.map +1 -0
  563. package/dist/ui/cards/RecordCardSkeleton.js +38 -0
  564. package/dist/ui/cards/RecordCardSkeleton.js.map +1 -0
  565. package/dist/ui/countdown/Countdown.js +39 -0
  566. package/dist/ui/countdown/Countdown.js.map +1 -0
  567. package/dist/ui/countdown/countdownParts.js +34 -0
  568. package/dist/ui/countdown/countdownParts.js.map +1 -0
  569. package/dist/ui/countdown/useCountdown.js +35 -0
  570. package/dist/ui/countdown/useCountdown.js.map +1 -0
  571. package/dist/ui/documents/PdfViewerDialog.js +82 -0
  572. package/dist/ui/documents/PdfViewerDialog.js.map +1 -0
  573. package/dist/ui/filters/DateRangeFilter.js +3 -2
  574. package/dist/ui/filters/DateRangeFilter.js.map +1 -1
  575. package/dist/ui/filters/FilterDrawer.js +212 -0
  576. package/dist/ui/filters/FilterDrawer.js.map +1 -0
  577. package/dist/ui/filters/PeriodRangeSelector.js +3 -2
  578. package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
  579. package/dist/ui/filters/QuickFilters.js +3 -2
  580. package/dist/ui/filters/QuickFilters.js.map +1 -1
  581. package/dist/ui/filters/filterDrawerFields.js +119 -0
  582. package/dist/ui/filters/filterDrawerFields.js.map +1 -0
  583. package/dist/ui/help/HelpButton.js +22 -0
  584. package/dist/ui/help/HelpButton.js.map +1 -0
  585. package/dist/ui/help/HelpCarouselDialog.js +155 -0
  586. package/dist/ui/help/HelpCarouselDialog.js.map +1 -0
  587. package/dist/ui/help/useHelpCarousel.js +25 -0
  588. package/dist/ui/help/useHelpCarousel.js.map +1 -0
  589. package/dist/ui/labels/IconBadge.js +82 -0
  590. package/dist/ui/labels/IconBadge.js.map +1 -0
  591. package/dist/ui/labels/MarkedText.js +31 -0
  592. package/dist/ui/labels/MarkedText.js.map +1 -0
  593. package/dist/ui/labels/Tag.js +3 -2
  594. package/dist/ui/labels/Tag.js.map +1 -1
  595. package/dist/ui/labels/markedTextPieces.js +64 -0
  596. package/dist/ui/labels/markedTextPieces.js.map +1 -0
  597. package/dist/ui/layout/CollapsibleSection.js +3 -2
  598. package/dist/ui/layout/CollapsibleSection.js.map +1 -1
  599. package/dist/ui/layout/ContentDialog.js +3 -2
  600. package/dist/ui/layout/ContentDialog.js.map +1 -1
  601. package/dist/ui/layout/DefinitionList.js +3 -2
  602. package/dist/ui/layout/DefinitionList.js.map +1 -1
  603. package/dist/ui/layout/DetailHeader.js +3 -2
  604. package/dist/ui/layout/DetailHeader.js.map +1 -1
  605. package/dist/ui/layout/ErrorPage.js +3 -2
  606. package/dist/ui/layout/ErrorPage.js.map +1 -1
  607. package/dist/ui/layout/FullPageLoader.js +3 -2
  608. package/dist/ui/layout/FullPageLoader.js.map +1 -1
  609. package/dist/ui/layout/GlassPanel.js +3 -2
  610. package/dist/ui/layout/GlassPanel.js.map +1 -1
  611. package/dist/ui/layout/PageHeader.js +3 -2
  612. package/dist/ui/layout/PageHeader.js.map +1 -1
  613. package/dist/ui/layout/PageHeading.js +3 -2
  614. package/dist/ui/layout/PageHeading.js.map +1 -1
  615. package/dist/ui/layout/ProfileHeader.js +3 -2
  616. package/dist/ui/layout/ProfileHeader.js.map +1 -1
  617. package/dist/ui/layout/ScrollableRow.js +3 -2
  618. package/dist/ui/layout/ScrollableRow.js.map +1 -1
  619. package/dist/ui/layout/SectionCard.js +3 -2
  620. package/dist/ui/layout/SectionCard.js.map +1 -1
  621. package/dist/ui/metrics/BarList.js +3 -2
  622. package/dist/ui/metrics/BarList.js.map +1 -1
  623. package/dist/ui/metrics/CalendarHeatmap.js +3 -2
  624. package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
  625. package/dist/ui/metrics/ChartTooltip.js +3 -2
  626. package/dist/ui/metrics/ChartTooltip.js.map +1 -1
  627. package/dist/ui/metrics/ColumnChart.js +3 -2
  628. package/dist/ui/metrics/ColumnChart.js.map +1 -1
  629. package/dist/ui/metrics/LineChart.js +3 -2
  630. package/dist/ui/metrics/LineChart.js.map +1 -1
  631. package/dist/ui/metrics/MetricCard.js +3 -2
  632. package/dist/ui/metrics/MetricCard.js.map +1 -1
  633. package/dist/ui/metrics/TableToggle.js +3 -2
  634. package/dist/ui/metrics/TableToggle.js.map +1 -1
  635. package/dist/ui/metrics/chartParts.js +7 -4
  636. package/dist/ui/metrics/chartParts.js.map +1 -1
  637. package/dist/ui/navigation/BackButton.js +7 -2
  638. package/dist/ui/navigation/BackButton.js.map +1 -1
  639. package/dist/ui/navigation/ColorSchemeToggle.js +3 -2
  640. package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
  641. package/dist/ui/navigation/FontSizeToggle.js +3 -2
  642. package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
  643. package/dist/ui/navigation/LanguageToggle.js +3 -2
  644. package/dist/ui/navigation/LanguageToggle.js.map +1 -1
  645. package/dist/ui/navigation/PageBreadcrumbs.js +3 -2
  646. package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
  647. package/dist/ui/navigation/RouteTabs.js +79 -0
  648. package/dist/ui/navigation/RouteTabs.js.map +1 -0
  649. package/dist/ui/navigation/routeTabMatching.js +23 -0
  650. package/dist/ui/navigation/routeTabMatching.js.map +1 -0
  651. package/dist/ui/timeline/GroupedTimeline.js +3 -2
  652. package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
  653. package/dist/upload/AttachmentsInput.js +130 -0
  654. package/dist/upload/AttachmentsInput.js.map +1 -0
  655. package/dist/upload/FileChip.js +28 -0
  656. package/dist/upload/FileChip.js.map +1 -0
  657. package/dist/upload/FileDropzone.js +23 -87
  658. package/dist/upload/FileDropzone.js.map +1 -1
  659. package/dist/upload/FileInput.js +115 -0
  660. package/dist/upload/FileInput.js.map +1 -0
  661. package/dist/upload/FileUploadInput.js +288 -0
  662. package/dist/upload/FileUploadInput.js.map +1 -0
  663. package/dist/upload/ImageInput.js +128 -0
  664. package/dist/upload/ImageInput.js.map +1 -0
  665. package/dist/upload/TemplateDownloadButton.js +68 -0
  666. package/dist/upload/TemplateDownloadButton.js.map +1 -0
  667. package/dist/upload/fileAppearance.js +21 -0
  668. package/dist/upload/fileAppearance.js.map +1 -0
  669. package/dist/upload/fileRules.js +27 -1
  670. package/dist/upload/fileRules.js.map +1 -1
  671. package/dist/upload/transferProgress.js +23 -0
  672. package/dist/upload/transferProgress.js.map +1 -0
  673. package/dist/upload/uploadMachine.js +8 -8
  674. package/dist/upload/uploadMachine.js.map +1 -1
  675. package/dist/upload/uploadWithProgress.js +1 -1
  676. package/dist/upload/uploadWithProgress.js.map +1 -1
  677. package/dist/upload/useFilePicker.js +101 -0
  678. package/dist/upload/useFilePicker.js.map +1 -0
  679. package/package.json +44 -1
  680. package/cli/templates/project/src/app/combineTexts.js.tpl +0 -31
@@ -1,42 +1,46 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { useId, useState } from "react";
4
- import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
5
4
  import InputAdornment from "@mui/material/InputAdornment";
6
5
  import TextField from "@mui/material/TextField";
7
- import { translateValidationMessage } from "../forms/validationMessages.js";
6
+ import { useValidationText } from "../forms/useValidationText.js";
8
7
  import FieldFrame from "./FieldFrame.js";
9
8
  import { groupThousands, completeDecimals, cleanNumberText } from "./numberText.js";
10
9
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
10
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
11
+ const THEME_NAME = "CalcitaNumberInput";
12
+ const NumberInputField = piecePart(THEME_NAME, "Field", TextField);
11
13
  const SEPARATORS_ROOM = 6;
12
- function NumberInput({
13
- name,
14
- label,
15
- value,
16
- onChange,
17
- onBlur,
18
- error,
19
- helperText = " ",
20
- decimals = 2,
21
- allowNegative = false,
22
- prefix,
23
- suffix,
24
- maxDigits = 17,
25
- disabled = false,
26
- inputRef,
27
- texts,
28
- ...unknownProps
29
- }) {
30
- warnUnknownProps("NumberInput", unknownProps);
31
- const { t } = useToolkitTranslation("common", texts);
14
+ function NumberInputContent(props) {
15
+ const {
16
+ name,
17
+ label,
18
+ value,
19
+ onChange,
20
+ onBlur,
21
+ error,
22
+ helperText = " ",
23
+ decimals = 2,
24
+ allowNegative = false,
25
+ prefix,
26
+ suffix,
27
+ maxDigits = 17,
28
+ disabled = false,
29
+ inputRef,
30
+ messages,
31
+ texts: unusedTexts,
32
+ ...unknownProps
33
+ } = usePieceProps(props, THEME_NAME);
34
+ warnUnknownProps(THEME_NAME, unknownProps);
35
+ const validationTextOf = useValidationText({ name, label, messages });
32
36
  const generatedId = useId();
33
37
  const inputId = `${name ?? "number"}-${generatedId}`;
34
38
  const [isTyping, setIsTyping] = useState(false);
35
- const errorText = translateValidationMessage(t, error);
39
+ const errorText = validationTextOf(error);
36
40
  const valueText = value === null || value === void 0 ? "" : String(value);
37
41
  const shownText = groupThousands(isTyping ? valueText : completeDecimals(valueText, decimals));
38
42
  return /* @__PURE__ */ jsx(FieldFrame, { inputId, label, children: /* @__PURE__ */ jsx(
39
- TextField,
43
+ NumberInputField,
40
44
  {
41
45
  name,
42
46
  id: inputId,
@@ -47,7 +51,18 @@ function NumberInput({
47
51
  fullWidth: true,
48
52
  error: Boolean(errorText),
49
53
  helperText: errorText ?? helperText,
50
- onFocus: () => setIsTyping(true),
54
+ onFocus: (event) => {
55
+ const input = event.target;
56
+ const wasAllSelected = input.value.length > 0 && input.selectionStart === 0 && input.selectionEnd === input.value.length;
57
+ setIsTyping(true);
58
+ if (wasAllSelected) {
59
+ requestAnimationFrame(() => {
60
+ if (document.activeElement === input) {
61
+ input.select();
62
+ }
63
+ });
64
+ }
65
+ },
51
66
  onChange: (event) => onChange(cleanNumberText(event.target.value, decimals, allowNegative)),
52
67
  onBlur: () => {
53
68
  setIsTyping(false);
@@ -67,6 +82,7 @@ function NumberInput({
67
82
  }
68
83
  ) });
69
84
  }
85
+ const NumberInput = withPieceSlots(NumberInputContent, THEME_NAME);
70
86
  export {
71
87
  NumberInput as default
72
88
  };
@@ -1 +1 @@
1
- {"version":3,"file":"NumberInput.js","sources":["../../src/inputs/NumberInput.jsx"],"sourcesContent":["// Campo de NÚMERO suelto: se escribe y se lee con separador de miles («2,850,000.50») y al formulario (y al servidor)\n// llega el texto limpio («2850000.50»), que es lo que lee Money.fromString sin pasar por decimales.\n//\n// Por qué no type=\"number\": pinta flechitas que nadie usa, no agrupa miles, acepta «e» y en el teléfono deja escribir\n// cosas raras. Este usa el teclado numérico (inputMode decimal) y alinea a la derecha, como en una hoja de cálculo.\n//\n// Mientras se escribe se respeta lo tecleado (no completa decimales a medias); al salir se completan con ceros.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport TextField from '@mui/material/TextField';\n\nimport {translateValidationMessage} from '@/forms/validationMessages.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {cleanNumberText, completeDecimals, groupThousands} from '@/inputs/numberText.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// lo que caben los separadores y el punto además de los dígitos\nconst SEPARATORS_ROOM = 6;\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|number|null|undefined} props.value el texto limpio ('2850000.50'); '' = vacío\n * @param {(value: string) => void} props.onChange recibe el texto limpio\n * @param {() => void} [props.onBlur]\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText]\n * @param {number} [props.decimals] por omisión 2\n * @param {boolean} [props.allowNegative]\n * @param {import('react').ReactNode} [props.prefix] p. ej. «$»\n * @param {import('react').ReactNode} [props.suffix] p. ej. «MXN» o «%»\n * @param {number} [props.maxDigits] tope de dígitos (por omisión 17)\n * @param {boolean} [props.disabled]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function NumberInput({\n name, label, value, onChange, onBlur, error, helperText = ' ', decimals = 2, allowNegative = false, prefix, suffix, maxDigits = 17,\n disabled = false, inputRef, texts,\n ...unknownProps\n}) {\n warnUnknownProps('NumberInput', unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const generatedId = useId();\n const inputId = `${name ?? 'number'}-${generatedId}`;\n const [isTyping, setIsTyping] = useState(false);\n const errorText = translateValidationMessage(t, error);\n const valueText = value === null || value === undefined ? '' : String(value);\n // escribiendo: lo que hay; fuera del campo: con sus decimales completos\n const shownText = groupThousands(isTyping ? valueText : completeDecimals(valueText, decimals));\n\n return (\n <FieldFrame inputId={inputId} label={label}>\n <TextField\n name={name}\n id={inputId}\n inputRef={inputRef}\n value={shownText}\n disabled={disabled}\n size=\"small\"\n fullWidth\n error={Boolean(errorText)}\n helperText={errorText ?? helperText}\n onFocus={() => setIsTyping(true)}\n onChange={(event) => onChange(cleanNumberText(event.target.value, decimals, allowNegative))}\n onBlur={() => {\n setIsTyping(false);\n const completedText = completeDecimals(cleanNumberText(valueText, decimals, allowNegative), decimals);\n if (completedText !== valueText) {\n onChange(completedText);\n }\n onBlur?.();\n }}\n slotProps={{\n htmlInput: {inputMode: 'decimal', maxLength: maxDigits + SEPARATORS_ROOM, style: {textAlign: 'right'}},\n input: {\n startAdornment: prefix ? <InputAdornment position=\"start\">{prefix}</InputAdornment> : undefined,\n endAdornment: suffix ? <InputAdornment position=\"end\">{suffix}</InputAdornment> : undefined,\n },\n }}\n />\n </FieldFrame>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAoBA,MAAM,kBAAkB;AAoBxB,SAAwB,YAAY;AAAA,EAChC;AAAA,EAAM;AAAA,EAAO;AAAA,EAAO;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAO,aAAa;AAAA,EAAK,WAAW;AAAA,EAAG,gBAAgB;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ,YAAY;AAAA,EAChI,WAAW;AAAA,EAAO;AAAA,EAAU;AAAA,EAC5B,GAAG;AACP,GAAG;AACC,mBAAiB,eAAe,YAAY;AAC5C,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,cAAc,MAAA;AACpB,QAAM,UAAU,GAAG,QAAQ,QAAQ,IAAI,WAAW;AAClD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,YAAY,2BAA2B,GAAG,KAAK;AACrD,QAAM,YAAY,UAAU,QAAQ,UAAU,SAAY,KAAK,OAAO,KAAK;AAE3E,QAAM,YAAY,eAAe,WAAW,YAAY,iBAAiB,WAAW,QAAQ,CAAC;AAE7F,SACI,oBAAC,YAAA,EAAW,SAAkB,OAC1B,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACG;AAAA,MACA,IAAI;AAAA,MACJ;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,MAAK;AAAA,MACL,WAAS;AAAA,MACT,OAAO,QAAQ,SAAS;AAAA,MACxB,YAAY,aAAa;AAAA,MACzB,SAAS,MAAM,YAAY,IAAI;AAAA,MAC/B,UAAU,CAAC,UAAU,SAAS,gBAAgB,MAAM,OAAO,OAAO,UAAU,aAAa,CAAC;AAAA,MAC1F,QAAQ,MAAM;AACV,oBAAY,KAAK;AACjB,cAAM,gBAAgB,iBAAiB,gBAAgB,WAAW,UAAU,aAAa,GAAG,QAAQ;AACpG,YAAI,kBAAkB,WAAW;AAC7B,mBAAS,aAAa;AAAA,QAC1B;AACA,iBAAA;AAAA,MACJ;AAAA,MACA,WAAW;AAAA,QACP,WAAW,EAAC,WAAW,WAAW,WAAW,YAAY,iBAAiB,OAAO,EAAC,WAAW,UAAO;AAAA,QACpG,OAAO;AAAA,UACH,gBAAgB,SAAS,oBAAC,kBAAe,UAAS,SAAS,kBAAO,IAAoB;AAAA,UACtF,cAAc,SAAS,oBAAC,kBAAe,UAAS,OAAO,kBAAO,IAAoB;AAAA,QAAA;AAAA,MACtF;AAAA,IACJ;AAAA,EAAA,GAER;AAER;"}
1
+ {"version":3,"file":"NumberInput.js","sources":["../../src/inputs/NumberInput.jsx"],"sourcesContent":["// Campo de NÚMERO suelto: se escribe y se lee con separador de miles («2,850,000.50») y al formulario (y al servidor)\n// llega el texto limpio («2850000.50»), que es lo que lee Money.fromString sin pasar por decimales.\n//\n// Por qué no type=\"number\": pinta flechitas que nadie usa, no agrupa miles, acepta «e» y en el teléfono deja escribir\n// cosas raras. Este usa el teclado numérico (inputMode decimal) y alinea a la derecha, como en una hoja de cálculo.\n//\n// Mientras se escribe se respeta lo tecleado (no completa decimales a medias); al salir se completan con ceros.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaNumberInput con defaultProps, styleOverrides de\n// sus partes (field) y slots/slotProps para cambiarlas.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport TextField from '@mui/material/TextField';\n\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {cleanNumberText, completeDecimals, groupThousands} from '@/inputs/numberText.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaNumberInput)\nconst THEME_NAME = 'CalcitaNumberInput';\nconst NumberInputField = piecePart(THEME_NAME, 'Field', TextField);\n\n// lo que caben los separadores y el punto además de los dígitos\nconst SEPARATORS_ROOM = 6;\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|number|null|undefined} props.value el texto limpio ('2850000.50'); '' = vacío\n * @param {(value: string) => void} props.onChange recibe el texto limpio\n * @param {() => void} [props.onBlur]\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText]\n * @param {number} [props.decimals] por omisión 2\n * @param {boolean} [props.allowNegative]\n * @param {import('react').ReactNode} [props.prefix] p. ej. «$»\n * @param {import('react').ReactNode} [props.suffix] p. ej. «MXN» o «%»\n * @param {number} [props.maxDigits] tope de dígitos (por omisión 17)\n * @param {boolean} [props.disabled]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef]\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] se acepta como en los demás campos; este no tiene textos propios (su error usa `messages`)\n */\nfunction NumberInputContent(props) {\n const {\n name, label, value, onChange, onBlur, error, helperText = ' ', decimals = 2, allowNegative = false, prefix, suffix, maxDigits = 17,\n disabled = false, inputRef, messages, texts: unusedTexts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n // el texto del error: el de la pantalla (messages), el del proyecto para este campo o el de Calcita\n const validationTextOf = useValidationText({name, label, messages});\n const generatedId = useId();\n const inputId = `${name ?? 'number'}-${generatedId}`;\n const [isTyping, setIsTyping] = useState(false);\n const errorText = validationTextOf(error);\n const valueText = value === null || value === undefined ? '' : String(value);\n // escribiendo: lo que hay; fuera del campo: con sus decimales completos\n const shownText = groupThousands(isTyping ? valueText : completeDecimals(valueText, decimals));\n\n return (\n <FieldFrame inputId={inputId} label={label}>\n <NumberInputField\n name={name}\n id={inputId}\n inputRef={inputRef}\n value={shownText}\n disabled={disabled}\n size=\"small\"\n fullWidth\n error={Boolean(errorText)}\n helperText={errorText ?? helperText}\n onFocus={(event) => {\n const input = event.target;\n // OJO: al entrar, el texto cambia («50,000.00» → «50,000») y el navegador pierde lo seleccionado; al entrar\n // con Tab estaba todo seleccionado y lo tecleado se pegaba al final (50,000,100,000). Si estaba todo\n // seleccionado, se vuelve a seleccionar ya pintado; con un clic (el cursor en un lugar) no se toca\n const wasAllSelected = input.value.length > 0 && input.selectionStart === 0 && input.selectionEnd === input.value.length;\n setIsTyping(true);\n if (wasAllSelected) {\n requestAnimationFrame(() => {\n if (document.activeElement === input) {\n input.select();\n }\n });\n }\n }}\n onChange={(event) => onChange(cleanNumberText(event.target.value, decimals, allowNegative))}\n onBlur={() => {\n setIsTyping(false);\n const completedText = completeDecimals(cleanNumberText(valueText, decimals, allowNegative), decimals);\n if (completedText !== valueText) {\n onChange(completedText);\n }\n onBlur?.();\n }}\n slotProps={{\n htmlInput: {inputMode: 'decimal', maxLength: maxDigits + SEPARATORS_ROOM, style: {textAlign: 'right'}},\n input: {\n startAdornment: prefix ? <InputAdornment position=\"start\">{prefix}</InputAdornment> : undefined,\n endAdornment: suffix ? <InputAdornment position=\"end\">{suffix}</InputAdornment> : undefined,\n },\n }}\n />\n </FieldFrame>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst NumberInput = withPieceSlots(NumberInputContent, THEME_NAME);\nexport default NumberInput;\n"],"names":[],"mappings":";;;;;;;;;;AAuBA,MAAM,aAAa;AACnB,MAAM,mBAAmB,UAAU,YAAY,SAAS,SAAS;AAGjE,MAAM,kBAAkB;AAsBxB,SAAS,mBAAmB,OAAO;AAC/B,QAAM;AAAA,IACF;AAAA,IAAM;AAAA,IAAO;AAAA,IAAO;AAAA,IAAU;AAAA,IAAQ;AAAA,IAAO,aAAa;AAAA,IAAK,WAAW;AAAA,IAAG,gBAAgB;AAAA,IAAO;AAAA,IAAQ;AAAA,IAAQ,YAAY;AAAA,IAChI,WAAW;AAAA,IAAO;AAAA,IAAU;AAAA,IAAU,OAAO;AAAA,IAC7C,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AACnC,mBAAiB,YAAY,YAAY;AAEzC,QAAM,mBAAmB,kBAAkB,EAAC,MAAM,OAAO,UAAS;AAClE,QAAM,cAAc,MAAA;AACpB,QAAM,UAAU,GAAG,QAAQ,QAAQ,IAAI,WAAW;AAClD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,YAAY,iBAAiB,KAAK;AACxC,QAAM,YAAY,UAAU,QAAQ,UAAU,SAAY,KAAK,OAAO,KAAK;AAE3E,QAAM,YAAY,eAAe,WAAW,YAAY,iBAAiB,WAAW,QAAQ,CAAC;AAE7F,SACI,oBAAC,YAAA,EAAW,SAAkB,OAC1B,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACG;AAAA,MACA,IAAI;AAAA,MACJ;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,MAAK;AAAA,MACL,WAAS;AAAA,MACT,OAAO,QAAQ,SAAS;AAAA,MACxB,YAAY,aAAa;AAAA,MACzB,SAAS,CAAC,UAAU;AAChB,cAAM,QAAQ,MAAM;AAIpB,cAAM,iBAAiB,MAAM,MAAM,SAAS,KAAK,MAAM,mBAAmB,KAAK,MAAM,iBAAiB,MAAM,MAAM;AAClH,oBAAY,IAAI;AAChB,YAAI,gBAAgB;AAChB,gCAAsB,MAAM;AACxB,gBAAI,SAAS,kBAAkB,OAAO;AAClC,oBAAM,OAAA;AAAA,YACV;AAAA,UACJ,CAAC;AAAA,QACL;AAAA,MACJ;AAAA,MACA,UAAU,CAAC,UAAU,SAAS,gBAAgB,MAAM,OAAO,OAAO,UAAU,aAAa,CAAC;AAAA,MAC1F,QAAQ,MAAM;AACV,oBAAY,KAAK;AACjB,cAAM,gBAAgB,iBAAiB,gBAAgB,WAAW,UAAU,aAAa,GAAG,QAAQ;AACpG,YAAI,kBAAkB,WAAW;AAC7B,mBAAS,aAAa;AAAA,QAC1B;AACA,iBAAA;AAAA,MACJ;AAAA,MACA,WAAW;AAAA,QACP,WAAW,EAAC,WAAW,WAAW,WAAW,YAAY,iBAAiB,OAAO,EAAC,WAAW,UAAO;AAAA,QACpG,OAAO;AAAA,UACH,gBAAgB,SAAS,oBAAC,kBAAe,UAAS,SAAS,kBAAO,IAAoB;AAAA,UACtF,cAAc,SAAS,oBAAC,kBAAe,UAAS,OAAO,kBAAO,IAAoB;AAAA,QAAA;AAAA,MACtF;AAAA,IACJ;AAAA,EAAA,GAER;AAER;AAGA,MAAM,cAAc,eAAe,oBAAoB,UAAU;"}
@@ -0,0 +1,180 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import { useState, useId } from "react";
4
+ import Box from "@mui/material/Box";
5
+ import Button from "@mui/material/Button";
6
+ import Dialog from "@mui/material/Dialog";
7
+ import DialogActions from "@mui/material/DialogActions";
8
+ import DialogContent from "@mui/material/DialogContent";
9
+ import DialogTitle from "@mui/material/DialogTitle";
10
+ import FormHelperText from "@mui/material/FormHelperText";
11
+ import Paper from "@mui/material/Paper";
12
+ import Stack from "@mui/material/Stack";
13
+ import Typography from "@mui/material/Typography";
14
+ import AddRoundedIcon from "@mui/icons-material/AddRounded";
15
+ import DeleteOutlineRoundedIcon from "@mui/icons-material/DeleteOutlineRounded";
16
+ import RestartAltRoundedIcon from "@mui/icons-material/RestartAltRounded";
17
+ import ConfirmDialog from "../feedback/ConfirmDialog.js";
18
+ import { useValidationText } from "../forms/useValidationText.js";
19
+ import { FormSectionContext } from "./formLayoutContext.js";
20
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
21
+ import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
22
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
23
+ const DEFAULT_COLUMNS = Object.freeze({ xs: 1, sm: 2, md: 3 });
24
+ const THEME_NAME = "CalcitaRepeatingFields";
25
+ const RepeatingRoot = piecePart(THEME_NAME, "Root", Stack);
26
+ const RepeatingRow = piecePart(THEME_NAME, "Row", Paper);
27
+ const RepeatingRowHeader = piecePart(THEME_NAME, "RowHeader", Stack);
28
+ const RepeatingRowContent = piecePart(THEME_NAME, "RowContent", Box);
29
+ const RepeatingAddButton = piecePart(THEME_NAME, "AddButton", Button);
30
+ const RepeatingHelper = piecePart(THEME_NAME, "Helper", FormHelperText);
31
+ function gridColumnsOf(columns) {
32
+ const templateOf = (count) => `repeat(${count}, minmax(0, 1fr))`;
33
+ if (typeof columns === "number") {
34
+ return templateOf(columns);
35
+ }
36
+ return Object.fromEntries(Object.entries(columns).map(([breakpoint, count]) => [breakpoint, templateOf(count)]));
37
+ }
38
+ function RepeatingFieldsContent(props) {
39
+ const {
40
+ label,
41
+ rowKeys,
42
+ renderRow,
43
+ rowLabelOf,
44
+ rowActionsOf,
45
+ columns = DEFAULT_COLUMNS,
46
+ minRows = 1,
47
+ maxRows = null,
48
+ onAdd,
49
+ onRemove,
50
+ onClear,
51
+ removeBlockedReasonOf,
52
+ confirmRemoveOf,
53
+ rowHasErrorOf,
54
+ error,
55
+ helperText,
56
+ footer,
57
+ addLabel,
58
+ disabled = false,
59
+ sx,
60
+ messages,
61
+ texts,
62
+ ...unknownProps
63
+ } = usePieceProps(props, THEME_NAME);
64
+ warnUnknownProps(THEME_NAME, unknownProps);
65
+ const { t } = useToolkitTranslation("common", texts);
66
+ const validationTextOf = useValidationText({ label, messages });
67
+ const [pendingRemoval, setPendingRemoval] = useState(null);
68
+ const blockedTitleId = `${useId()}-blocked-title`;
69
+ const rowCount = rowKeys.length;
70
+ const isAtMinimum = rowCount <= minRows;
71
+ const isAtMaximum = maxRows != null && rowCount >= maxRows;
72
+ const errorText = validationTextOf(error);
73
+ const titleOf = (index) => rowLabelOf?.(index) ?? t("repeating.row", { number: index + 1 });
74
+ const requestRemove = (index) => {
75
+ const blockedReason = removeBlockedReasonOf?.(index) ?? null;
76
+ if (blockedReason) {
77
+ setPendingRemoval({ index, kind: "blocked", reason: blockedReason });
78
+ return;
79
+ }
80
+ if (confirmRemoveOf?.(index)) {
81
+ setPendingRemoval({ index, kind: "confirm" });
82
+ return;
83
+ }
84
+ removeOrClear(index);
85
+ };
86
+ const removeOrClear = (index) => {
87
+ if (isAtMinimum) {
88
+ onClear(index);
89
+ } else {
90
+ onRemove(index);
91
+ }
92
+ };
93
+ return /* @__PURE__ */ jsxs(RepeatingRoot, { spacing: 1.5, ownSx: { minWidth: 0 }, sx, children: [
94
+ label && /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", component: "h3", children: label }),
95
+ rowKeys.map((rowKey, index) => {
96
+ const removeText = isAtMinimum ? t("repeating.clear", { row: titleOf(index) }) : t("repeating.remove", { row: titleOf(index) });
97
+ return /* @__PURE__ */ jsxs(
98
+ RepeatingRow,
99
+ {
100
+ variant: "outlined",
101
+ role: "group",
102
+ "aria-label": titleOf(index),
103
+ ownSx: { p: { xs: 1.5, sm: 2 }, ...rowHasErrorOf?.(index) && { borderColor: "error.main" } },
104
+ children: [
105
+ /* @__PURE__ */ jsxs(RepeatingRowHeader, { direction: "row", ownSx: { alignItems: "center", gap: 1, mb: 1.5 }, children: [
106
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", sx: { flexGrow: 1, minWidth: 0 }, color: rowHasErrorOf?.(index) ? "error" : "text.primary", children: titleOf(index) }),
107
+ rowActionsOf?.(index),
108
+ /* @__PURE__ */ jsx(
109
+ Button,
110
+ {
111
+ size: "small",
112
+ color: "inherit",
113
+ disabled,
114
+ onClick: () => requestRemove(index),
115
+ "aria-label": removeText,
116
+ startIcon: isAtMinimum ? /* @__PURE__ */ jsx(RestartAltRoundedIcon, {}) : /* @__PURE__ */ jsx(DeleteOutlineRoundedIcon, {}),
117
+ children: isAtMinimum ? t("repeating.clearShort") : t("repeating.removeShort")
118
+ }
119
+ )
120
+ ] }),
121
+ /* @__PURE__ */ jsx(FormSectionContext.Provider, { value: false, children: /* @__PURE__ */ jsx(RepeatingRowContent, { ownSx: { display: "grid", gap: 2, gridTemplateColumns: gridColumnsOf(columns), alignItems: "start" }, children: renderRow(index) }) })
122
+ ]
123
+ },
124
+ rowKey
125
+ );
126
+ }),
127
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", sx: { alignItems: "center", gap: 2, flexWrap: "wrap" }, children: [
128
+ /* @__PURE__ */ jsx(
129
+ RepeatingAddButton,
130
+ {
131
+ variant: "outlined",
132
+ startIcon: /* @__PURE__ */ jsx(AddRoundedIcon, {}),
133
+ onClick: onAdd,
134
+ disabled: disabled || isAtMaximum,
135
+ ownSx: { alignSelf: "flex-start" },
136
+ children: addLabel ?? t("repeating.add")
137
+ }
138
+ ),
139
+ maxRows != null && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", children: t("repeating.maxRows", { count: maxRows }) }),
140
+ footer
141
+ ] }),
142
+ (errorText || helperText) && /* @__PURE__ */ jsx(RepeatingHelper, { error: Boolean(errorText), role: errorText ? "alert" : void 0, ownSx: { mx: 0 }, children: errorText ?? helperText }),
143
+ /* @__PURE__ */ jsx(
144
+ ConfirmDialog,
145
+ {
146
+ open: pendingRemoval?.kind === "confirm",
147
+ title: t("repeating.confirmTitle", { row: pendingRemoval ? titleOf(pendingRemoval.index) : "" }),
148
+ description: t("repeating.confirmText"),
149
+ confirmLabel: t("repeating.removeShort"),
150
+ tone: "error",
151
+ onConfirm: () => {
152
+ removeOrClear(pendingRemoval.index);
153
+ setPendingRemoval(null);
154
+ },
155
+ onClose: () => setPendingRemoval(null),
156
+ texts
157
+ }
158
+ ),
159
+ /* @__PURE__ */ jsxs(
160
+ Dialog,
161
+ {
162
+ open: pendingRemoval?.kind === "blocked",
163
+ onClose: () => setPendingRemoval(null),
164
+ maxWidth: "xs",
165
+ fullWidth: true,
166
+ "aria-labelledby": blockedTitleId,
167
+ children: [
168
+ /* @__PURE__ */ jsx(DialogTitle, { id: blockedTitleId, children: t("repeating.blockedTitle") }),
169
+ /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx(Typography, { children: pendingRemoval?.reason }) }),
170
+ /* @__PURE__ */ jsx(DialogActions, { children: /* @__PURE__ */ jsx(Button, { variant: "contained", onClick: () => setPendingRemoval(null), autoFocus: true, children: t("repeating.understood") }) })
171
+ ]
172
+ }
173
+ )
174
+ ] });
175
+ }
176
+ const RepeatingFields = withPieceSlots(RepeatingFieldsContent, THEME_NAME);
177
+ export {
178
+ RepeatingFields as default
179
+ };
180
+ //# sourceMappingURL=RepeatingFields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RepeatingFields.js","sources":["../../src/inputs/RepeatingFields.jsx"],"sourcesContent":["// Renglones de campos que se repiten (los contactos de un cliente, los precios por volumen, el reparto de un presupuesto):\n// cada renglón con su número y «Quitar», y «Agregar» al final. Es solo la VISTA: los renglones los guarda el formulario\n// (FormRepeatingFields de formik o de react-hook-form los conecta por name).\n//\n// Reglas de la vista:\n// - minRows (por omisión 1): con el mínimo, «Quitar» se vuelve «Limpiar» y deja el renglón vacío (nunca queda la\n// lista sin renglones para escribir);\n// - maxRows: con el máximo, «Agregar» se apaga y dice hasta cuántos;\n// - quitar un renglón lo decide la pantalla: removeBlockedReasonOf(index) da el motivo si NO se puede (sale en una\n// ventana con «Entendido»), y confirmRemoveOf(index) pide confirmar antes (un renglón ya guardado);\n// - el renglón con un error se marca en rojo, para encontrarlo en una lista larga.\n//\n// En escritorio los campos de un renglón van lado a lado (columns); en el teléfono, uno debajo de otro, como tarjetas.\n// Dentro de un renglón los campos van con su etiqueta arriba aunque la lista esté dentro de una FormSection.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaRepeatingFields con defaultProps y\n// styleOverrides de sus partes: root, row, rowHeader, rowContent, addButton, helper.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\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 DialogTitle from '@mui/material/DialogTitle';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded';\nimport RestartAltRoundedIcon from '@mui/icons-material/RestartAltRounded';\n\nimport ConfirmDialog from '@/feedback/ConfirmDialog.jsx';\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport {FormSectionContext} from '@/inputs/formLayoutContext.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// por omisión: uno en el teléfono, dos en tableta, tres en escritorio\nconst DEFAULT_COLUMNS = Object.freeze({xs: 1, sm: 2, md: 3});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaRepeatingFields)\nconst THEME_NAME = 'CalcitaRepeatingFields';\nconst RepeatingRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst RepeatingRow = piecePart(THEME_NAME, 'Row', Paper);\nconst RepeatingRowHeader = piecePart(THEME_NAME, 'RowHeader', Stack);\nconst RepeatingRowContent = piecePart(THEME_NAME, 'RowContent', Box);\nconst RepeatingAddButton = piecePart(THEME_NAME, 'AddButton', Button);\nconst RepeatingHelper = piecePart(THEME_NAME, 'Helper', FormHelperText);\n\n/**\n * El número de columnas de la rejilla como CSS: {xs: 1, md: 3} → {xs: 'repeat(1, minmax(0, 1fr))', …}.\n *\n * @param {number|Record<string, number>} columns\n * @returns {string|Record<string, string>}\n */\nfunction gridColumnsOf(columns) {\n const templateOf = (count) => `repeat(${count}, minmax(0, 1fr))`;\n if (typeof columns === 'number') {\n return templateOf(columns);\n }\n return Object.fromEntries(Object.entries(columns).map(([breakpoint, count]) => [breakpoint, templateOf(count)]));\n}\n\n/**\n * @param {object} props\n * @param {import('react').ReactNode} [props.label] ya traducido: el título de la lista («Contactos»)\n * @param {string[]} props.rowKeys una llave estable por renglón (no el índice: al quitar uno, los de abajo no deben\n * confundirse con el que se fue)\n * @param {(index: number) => import('react').ReactNode} props.renderRow los campos del renglón\n * @param {(index: number) => string} [props.rowLabelOf] el título de cada renglón; por omisión «Renglón 1», «Renglón 2»…\n * @param {(index: number) => import('react').ReactNode} [props.rowActionsOf] botones suyos en el título del renglón\n * @param {number|Record<string, number>} [props.columns] cuántos campos lado a lado: 2 o {xs: 1, sm: 2, md: 3}\n * @param {number} [props.minRows] cuántos renglones quedan siempre (por omisión 1); con 0 se puede quedar vacía\n * @param {number|null} [props.maxRows] hasta cuántos; sin él, los que quiera\n * @param {() => void} props.onAdd agrega un renglón vacío al final\n * @param {(index: number) => void} props.onRemove quita ese renglón\n * @param {(index: number) => void} props.onClear deja ese renglón vacío (cuando ya no se puede quitar por el mínimo)\n * @param {(index: number) => string|null} [props.removeBlockedReasonOf] si ese renglón NO se puede quitar, el motivo ya\n * traducido (sale en una ventana)\n * @param {(index: number) => boolean} [props.confirmRemoveOf] true si hay que confirmar antes de quitarlo\n * @param {(index: number) => boolean} [props.rowHasErrorOf] true si el renglón tiene un error (se marca en rojo)\n * @param {string|{key: string, values?: object}} [props.error] el error de toda la lista (la suma no alcanza, faltan renglones)\n * @param {import('react').ReactNode} [props.helperText] ya traducida\n * @param {import('react').ReactNode} [props.footer] lo que va junto a «Agregar» (p. ej. «Suman $40,000 de $50,000»)\n * @param {string} [props.addLabel] ya traducido; por omisión «Agregar»\n * @param {boolean} [props.disabled]\n * @param {object} [props.sx]\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction RepeatingFieldsContent(props) {\n const {\n label, rowKeys, renderRow, rowLabelOf, rowActionsOf, columns = DEFAULT_COLUMNS, minRows = 1, maxRows = null, onAdd, onRemove,\n onClear, removeBlockedReasonOf, confirmRemoveOf, rowHasErrorOf, error, helperText, footer, addLabel, disabled = false, sx, messages, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // el texto del error: el de la pantalla (messages), el del proyecto para este campo o el de Calcita\n const validationTextOf = useValidationText({label, messages});\n // el renglón que se va a quitar y por qué se pregunta: {index, kind: 'confirm' | 'blocked', reason}\n const [pendingRemoval, setPendingRemoval] = useState(null);\n const blockedTitleId = `${useId()}-blocked-title`;\n const rowCount = rowKeys.length;\n const isAtMinimum = rowCount <= minRows;\n const isAtMaximum = maxRows != null && rowCount >= maxRows;\n const errorText = validationTextOf(error);\n const titleOf = (index) => rowLabelOf?.(index) ?? t('repeating.row', {number: index + 1});\n\n // quitar (o limpiar, si ya está en el mínimo): primero lo que diga la pantalla\n const requestRemove = (index) => {\n const blockedReason = removeBlockedReasonOf?.(index) ?? null;\n if (blockedReason) {\n setPendingRemoval({index, kind: 'blocked', reason: blockedReason});\n return;\n }\n if (confirmRemoveOf?.(index)) {\n setPendingRemoval({index, kind: 'confirm'});\n return;\n }\n removeOrClear(index);\n };\n const removeOrClear = (index) => {\n if (isAtMinimum) {\n onClear(index);\n } else {\n onRemove(index);\n }\n };\n\n return (\n <RepeatingRoot spacing={1.5} ownSx={{minWidth: 0}} sx={sx}>\n {label && <Typography variant=\"subtitle2\" component=\"h3\">{label}</Typography>}\n {rowKeys.map((rowKey, index) => {\n const removeText = isAtMinimum ? t('repeating.clear', {row: titleOf(index)}) : t('repeating.remove', {row: titleOf(index)});\n return (\n <RepeatingRow\n key={rowKey}\n variant=\"outlined\"\n role=\"group\"\n aria-label={titleOf(index)}\n ownSx={{p: {xs: 1.5, sm: 2}, ...(rowHasErrorOf?.(index) && {borderColor: 'error.main'})}}\n >\n <RepeatingRowHeader direction=\"row\" ownSx={{alignItems: 'center', gap: 1, mb: 1.5}}>\n <Typography variant=\"subtitle2\" sx={{flexGrow: 1, minWidth: 0}} color={rowHasErrorOf?.(index) ? 'error' : 'text.primary'}>\n {titleOf(index)}\n </Typography>\n {rowActionsOf?.(index)}\n <Button size=\"small\" color=\"inherit\" disabled={disabled} onClick={() => requestRemove(index)} aria-label={removeText}\n startIcon={isAtMinimum ? <RestartAltRoundedIcon /> : <DeleteOutlineRoundedIcon />}>\n {isAtMinimum ? t('repeating.clearShort') : t('repeating.removeShort')}\n </Button>\n </RepeatingRowHeader>\n {/* los campos del renglón llevan su etiqueta arriba aunque la lista esté dentro de una FormSection */}\n <FormSectionContext.Provider value={false}>\n <RepeatingRowContent ownSx={{display: 'grid', gap: 2, gridTemplateColumns: gridColumnsOf(columns), alignItems: 'start'}}>\n {renderRow(index)}\n </RepeatingRowContent>\n </FormSectionContext.Provider>\n </RepeatingRow>\n );\n })}\n <Stack direction=\"row\" sx={{alignItems: 'center', gap: 2, flexWrap: 'wrap'}}>\n <RepeatingAddButton variant=\"outlined\" startIcon={<AddRoundedIcon />} onClick={onAdd} disabled={disabled || isAtMaximum}\n ownSx={{alignSelf: 'flex-start'}}>\n {addLabel ?? t('repeating.add')}\n </RepeatingAddButton>\n {maxRows != null && (\n <Typography variant=\"caption\" color=\"text.secondary\">{t('repeating.maxRows', {count: maxRows})}</Typography>\n )}\n {footer}\n </Stack>\n {(errorText || helperText) && (\n <RepeatingHelper error={Boolean(errorText)} role={errorText ? 'alert' : undefined} ownSx={{mx: 0}}>\n {errorText ?? helperText}\n </RepeatingHelper>\n )}\n\n <ConfirmDialog\n open={pendingRemoval?.kind === 'confirm'}\n title={t('repeating.confirmTitle', {row: pendingRemoval ? titleOf(pendingRemoval.index) : ''})}\n description={t('repeating.confirmText')}\n confirmLabel={t('repeating.removeShort')}\n tone=\"error\"\n onConfirm={() => {\n removeOrClear(pendingRemoval.index);\n setPendingRemoval(null);\n }}\n onClose={() => setPendingRemoval(null)}\n texts={texts}\n />\n <Dialog open={pendingRemoval?.kind === 'blocked'} onClose={() => setPendingRemoval(null)} maxWidth=\"xs\" fullWidth\n aria-labelledby={blockedTitleId}>\n <DialogTitle id={blockedTitleId}>{t('repeating.blockedTitle')}</DialogTitle>\n <DialogContent><Typography>{pendingRemoval?.reason}</Typography></DialogContent>\n <DialogActions>\n <Button variant=\"contained\" onClick={() => setPendingRemoval(null)} autoFocus>{t('repeating.understood')}</Button>\n </DialogActions>\n </Dialog>\n </RepeatingRoot>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst RepeatingFields = withPieceSlots(RepeatingFieldsContent, THEME_NAME);\nexport default RepeatingFields;\n"],"names":[],"mappings":"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"}
@@ -3,17 +3,21 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useId } from "react";
4
4
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
5
5
  import Box from "@mui/material/Box";
6
+ import Checkbox from "@mui/material/Checkbox";
6
7
  import MenuItem from "@mui/material/MenuItem";
7
8
  import TextField from "@mui/material/TextField";
8
9
  import Typography from "@mui/material/Typography";
9
- import { translateValidationMessage } from "../forms/validationMessages.js";
10
+ import { useValidationText } from "../forms/useValidationText.js";
10
11
  import FieldFrame from "./FieldFrame.js";
11
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
12
+ import { selectAllStateOf } from "./selectAllState.js";
13
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
12
14
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
13
15
  const THEME_NAME = "CalcitaSelectInput";
14
16
  const SelectOption = piecePart(THEME_NAME, "Option", MenuItem);
15
17
  const SelectOptionText = piecePart(THEME_NAME, "OptionText", Box);
16
- function SelectInput(props) {
18
+ const SELECT_ALL_VALUE = "__calcita_select_all__";
19
+ const WITHOUT_CHECKMARK = Object.freeze({ "&.Mui-selected::after": { content: "none" } });
20
+ function SelectInputContent(props) {
17
21
  const {
18
22
  name,
19
23
  label,
@@ -27,15 +31,19 @@ function SelectInput(props) {
27
31
  disabled = false,
28
32
  inputRef,
29
33
  multiple = false,
34
+ selectAll = false,
35
+ checkboxes = false,
36
+ messages,
30
37
  texts,
31
38
  ...unknownProps
32
39
  } = usePieceProps(props, THEME_NAME);
33
40
  warnUnknownProps(THEME_NAME, unknownProps);
34
41
  const { t } = useToolkitTranslation("common", texts);
42
+ const validationTextOf = useValidationText({ name, label, messages });
35
43
  const generatedId = useId();
36
44
  const inputId = `${name ?? "select"}-${generatedId}`;
37
45
  const labelId = `${inputId}-label`;
38
- const errorText = translateValidationMessage(t, error);
46
+ const errorText = validationTextOf(error);
39
47
  const placeholderText = /* @__PURE__ */ jsx(
40
48
  Typography,
41
49
  {
@@ -52,9 +60,15 @@ function SelectInput(props) {
52
60
  return options.find((option) => option.value === selectedValue)?.label ?? placeholderText;
53
61
  };
54
62
  const currentValue = multiple ? Array.isArray(value) ? value : [] : value ?? "";
63
+ const selectAllState = multiple ? selectAllStateOf(currentValue, options.filter((option) => !option.disabled).map((option) => option.value)) : null;
55
64
  const handleChange = (event) => {
56
65
  const nextValue = event.target.value;
57
- onChange(multiple && typeof nextValue === "string" ? nextValue.split(",") : nextValue);
66
+ const values = multiple && typeof nextValue === "string" ? nextValue.split(",") : nextValue;
67
+ if (multiple && values.includes(SELECT_ALL_VALUE)) {
68
+ onChange(selectAllState.toggled());
69
+ return;
70
+ }
71
+ onChange(values);
58
72
  };
59
73
  return /* @__PURE__ */ jsx(FieldFrame, { inputId, labelId, label, children: /* @__PURE__ */ jsxs(
60
74
  TextField,
@@ -74,18 +88,45 @@ function SelectInput(props) {
74
88
  slotProps: { select: { multiple, displayEmpty: true, renderValue: renderSelectedValue, labelId } },
75
89
  children: [
76
90
  !multiple && /* @__PURE__ */ jsx(MenuItem, { value: "", disabled: true, children: placeholderText }),
91
+ multiple && selectAll && /* @__PURE__ */ jsxs(SelectOption, { value: SELECT_ALL_VALUE, ownSx: { fontWeight: 600, ...WITHOUT_CHECKMARK }, children: [
92
+ /* @__PURE__ */ jsx(
93
+ Checkbox,
94
+ {
95
+ size: "small",
96
+ tabIndex: -1,
97
+ disableRipple: true,
98
+ sx: { p: 0, mr: 1 },
99
+ checked: selectAllState.allChosen,
100
+ indeterminate: selectAllState.someChosen
101
+ }
102
+ ),
103
+ selectAllState.allChosen ? t("form.unselectAll") : t("form.selectAll", { count: options.length })
104
+ ] }),
77
105
  options.map((option) => (
78
106
  // la opción en renglón y su nombre con su explicación en un bloque: con la opción en columna, la palomita del
79
107
  // elegido (el tema la pinta al final) se bajaba a otro renglón (lo cachó una captura de Tareas)
80
- /* @__PURE__ */ jsx(SelectOption, { value: option.value, ownSx: { whiteSpace: "normal" }, children: /* @__PURE__ */ jsxs(SelectOptionText, { component: "span", ownSx: { display: "flex", flexDirection: "column", minWidth: 0, flexGrow: 1 }, children: [
81
- /* @__PURE__ */ jsx(Typography, { component: "span", variant: "body2", children: option.label }),
82
- option.description && /* @__PURE__ */ jsx(Typography, { component: "span", variant: "caption", color: "text.secondary", children: option.description })
83
- ] }) }, option.value)
108
+ /* @__PURE__ */ jsxs(
109
+ SelectOption,
110
+ {
111
+ value: option.value,
112
+ disabled: option.disabled,
113
+ ownSx: { whiteSpace: "normal", ...multiple && checkboxes && WITHOUT_CHECKMARK },
114
+ children: [
115
+ multiple && checkboxes && /* @__PURE__ */ jsx(Checkbox, { size: "small", tabIndex: -1, disableRipple: true, sx: { p: 0, mr: 1 }, checked: currentValue.includes(option.value) }),
116
+ /* @__PURE__ */ jsxs(SelectOptionText, { component: "span", ownSx: { display: "flex", flexDirection: "column", minWidth: 0, flexGrow: 1 }, children: [
117
+ /* @__PURE__ */ jsx(Typography, { component: "span", variant: "body2", children: option.label }),
118
+ option.description && /* @__PURE__ */ jsx(Typography, { component: "span", variant: "caption", color: "text.secondary", children: option.description })
119
+ ] })
120
+ ]
121
+ },
122
+ option.value
123
+ )
84
124
  ))
85
125
  ]
86
126
  }
87
127
  ) });
88
128
  }
129
+ const SelectInput = withPieceSlots(SelectInputContent, THEME_NAME);
89
130
  export {
90
131
  SelectInput as default
91
132
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SelectInput.js","sources":["../../src/inputs/SelectInput.jsx"],"sourcesContent":["// Lista desplegable suelta, con la etiqueta arriba (mismo look que TextInput): la que pintan FormSelectField (formik) y la\n// de react-hook-form, y la que se usa sin formulario.\n//\n// Cada opción puede traer una explicación (description) que se lee en la lista para escoger; en la caja queda solo el\n// nombre de lo elegido. OJO: sin renderValue, MUI copiaba la opción completa a la caja y se leía «MenudeoCompra por pieza…».\n//\n// Con `multiple` se eligen varias: la lista se queda abierta, cada elegida lleva su palomita y en la caja quedan sus nombres\n// separados por coma, en el orden de las opciones. Al formulario llega la lista de valores (Yup.array().min(1) la valida).\n// Para catálogos largos, CatalogInput con `multiple` (busca y deja chips).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSelectInput con defaultProps y\n// styleOverrides de sus partes: option, optionText.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport MenuItem from '@mui/material/MenuItem';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\n\nimport {translateValidationMessage} from '@/forms/validationMessages.js';\nimport FieldFrame from '@/inputs/FieldFrame.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.CalcitaSelectInput)\nconst THEME_NAME = 'CalcitaSelectInput';\nconst SelectOption = piecePart(THEME_NAME, 'Option', MenuItem);\nconst SelectOptionText = piecePart(THEME_NAME, 'OptionText', Box);\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|number|Array<string|number>|null|undefined} props.value '' = sin elegir; con multiple, la lista ([] = ninguna)\n * @param {(value: any) => void} props.onChange recibe el valor elegido (con multiple, la lista), no el evento\n * @param {() => void} [props.onBlur]\n * @param {Array<{value: string|number, label: string, description?: string}>} props.options\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ayuda fija; el error la reemplaza\n * @param {string} [props.placeholder] texto de la opción vacía\n * @param {boolean} [props.disabled]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef]\n * @param {boolean} [props.multiple] elegir varias opciones\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function SelectInput(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSelectInput.defaultProps) y encima lo que llega aquí\n const {\n name, label, value, onChange, onBlur, options, error, helperText = ' ', placeholder, disabled = false, inputRef, multiple = false, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const generatedId = useId();\n const inputId = `${name ?? 'select'}-${generatedId}`;\n // OJO: la lista desplegable de MUI es un div y no un <input>: el `for` de la etiqueta no la une. Se nombra con su etiqueta\n // por aria-labelledby (labelId); sin esto el lector de pantalla no decía «Ciudad», solo lo elegido\n const labelId = `${inputId}-label`;\n const errorText = translateValidationMessage(t, error);\n const placeholderText = (\n <Typography component=\"span\"\n // OJO: el placeholder de un select activo se lee (text.secondary); text.disabled solo con el campo inactivo\n color={disabled ? 'text.disabled' : 'text.secondary'}>{placeholder ?? t('form.selectPlaceholder')}</Typography>\n );\n const renderSelectedValue = (selectedValue) => {\n if (multiple) {\n const selectedLabels = options.filter((option) => selectedValue.includes(option.value)).map((option) => option.label);\n return selectedLabels.length > 0 ? selectedLabels.join(', ') : placeholderText;\n }\n return options.find((option) => option.value === selectedValue)?.label ?? placeholderText;\n };\n const currentValue = multiple ? (Array.isArray(value) ? value : []) : (value ?? '');\n // OJO: con multiple, el autollenado del navegador puede mandar el valor como texto separado por comas (lo dice MUI)\n const handleChange = (event) => {\n const nextValue = event.target.value;\n onChange(multiple && typeof nextValue === 'string' ? nextValue.split(',') : nextValue);\n };\n\n return (\n <FieldFrame inputId={inputId} labelId={labelId} label={label}>\n <TextField\n name={name}\n id={inputId}\n inputRef={inputRef}\n select\n size=\"small\"\n fullWidth\n disabled={disabled}\n value={currentValue}\n onChange={handleChange}\n onBlur={onBlur}\n error={Boolean(errorText)}\n helperText={errorText ?? helperText}\n slotProps={{select: {multiple, displayEmpty: true, renderValue: renderSelectedValue, labelId}}}>\n {/* la opción vacía solo con una: con varias, se quitan picándolas otra vez */}\n {!multiple && <MenuItem value=\"\" disabled>{placeholderText}</MenuItem>}\n {options.map((option) => (\n // la opción en renglón y su nombre con su explicación en un bloque: con la opción en columna, la palomita del\n // elegido (el tema la pinta al final) se bajaba a otro renglón (lo cachó una captura de Tareas)\n <SelectOption key={option.value} value={option.value} ownSx={{whiteSpace: 'normal'}}>\n <SelectOptionText component=\"span\" ownSx={{display: 'flex', flexDirection: 'column', minWidth: 0, flexGrow: 1}}>\n <Typography component=\"span\" variant=\"body2\">{option.label}</Typography>\n {option.description && (\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\">{option.description}</Typography>\n )}\n </SelectOptionText>\n </SelectOption>\n ))}\n </TextField>\n </FieldFrame>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AA2BA,MAAM,aAAa;AACnB,MAAM,eAAe,UAAU,YAAY,UAAU,QAAQ;AAC7D,MAAM,mBAAmB,UAAU,YAAY,cAAc,GAAG;AAkBhE,SAAwB,YAAY,OAAO;AAEvC,QAAM;AAAA,IACN;AAAA,IAAM;AAAA,IAAO;AAAA,IAAO;AAAA,IAAU;AAAA,IAAQ;AAAA,IAAS;AAAA,IAAO,aAAa;AAAA,IAAK;AAAA,IAAa,WAAW;AAAA,IAAO;AAAA,IAAU,WAAW;AAAA,IAAO;AAAA,IACnI,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,cAAc,MAAA;AACpB,QAAM,UAAU,GAAG,QAAQ,QAAQ,IAAI,WAAW;AAGlD,QAAM,UAAU,GAAG,OAAO;AAC1B,QAAM,YAAY,2BAA2B,GAAG,KAAK;AACrD,QAAM,kBACF;AAAA,IAAC;AAAA,IAAA;AAAA,MAAW,WAAU;AAAA,MAEV,OAAO,WAAW,kBAAkB;AAAA,MAAmB,UAAA,eAAe,EAAE,wBAAwB;AAAA,IAAA;AAAA,EAAA;AAEhH,QAAM,sBAAsB,CAAC,kBAAkB;AAC3C,QAAI,UAAU;AACV,YAAM,iBAAiB,QAAQ,OAAO,CAAC,WAAW,cAAc,SAAS,OAAO,KAAK,CAAC,EAAE,IAAI,CAAC,WAAW,OAAO,KAAK;AACpH,aAAO,eAAe,SAAS,IAAI,eAAe,KAAK,IAAI,IAAI;AAAA,IACnE;AACA,WAAO,QAAQ,KAAK,CAAC,WAAW,OAAO,UAAU,aAAa,GAAG,SAAS;AAAA,EAC9E;AACA,QAAM,eAAe,WAAY,MAAM,QAAQ,KAAK,IAAI,QAAQ,KAAO,SAAS;AAEhF,QAAM,eAAe,CAAC,UAAU;AAC5B,UAAM,YAAY,MAAM,OAAO;AAC/B,aAAS,YAAY,OAAO,cAAc,WAAW,UAAU,MAAM,GAAG,IAAI,SAAS;AAAA,EACzF;AAEA,SACI,oBAAC,YAAA,EAAW,SAAkB,SAAkB,OAC5C,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACG;AAAA,MACA,IAAI;AAAA,MACJ;AAAA,MACA,QAAM;AAAA,MACN,MAAK;AAAA,MACL,WAAS;AAAA,MACT;AAAA,MACA,OAAO;AAAA,MACP,UAAU;AAAA,MACV;AAAA,MACA,OAAO,QAAQ,SAAS;AAAA,MACxB,YAAY,aAAa;AAAA,MACzB,WAAW,EAAC,QAAQ,EAAC,UAAU,cAAc,MAAM,aAAa,qBAAqB,UAAO;AAAA,MAE3F,UAAA;AAAA,QAAA,CAAC,YAAY,oBAAC,UAAA,EAAS,OAAM,IAAG,UAAQ,MAAE,UAAA,iBAAgB;AAAA,QAC1D,QAAQ,IAAI,CAAC;AAAA;AAAA;AAAA,UAGV,oBAAC,cAAA,EAAgC,OAAO,OAAO,OAAO,OAAO,EAAC,YAAY,SAAA,GACtE,UAAA,qBAAC,kBAAA,EAAiB,WAAU,QAAO,OAAO,EAAC,SAAS,QAAQ,eAAe,UAAU,UAAU,GAAG,UAAU,EAAA,GACxG,UAAA;AAAA,YAAA,oBAAC,cAAW,WAAU,QAAO,SAAQ,SAAS,iBAAO,OAAM;AAAA,YAC1D,OAAO,eACJ,oBAAC,YAAA,EAAW,WAAU,QAAO,SAAQ,WAAU,OAAM,kBAAkB,UAAA,OAAO,YAAA,CAAY;AAAA,UAAA,GAElG,EAAA,GANe,OAAO,KAO1B;AAAA,SACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,GAET;AAER;"}
1
+ {"version":3,"file":"SelectInput.js","sources":["../../src/inputs/SelectInput.jsx"],"sourcesContent":["// Lista desplegable suelta, con la etiqueta arriba (mismo look que TextInput): la que pintan FormSelectField (formik) y la\n// de react-hook-form, y la que se usa sin formulario.\n//\n// Cada opción puede traer una explicación (description) que se lee en la lista para escoger; en la caja queda solo el\n// nombre de lo elegido. OJO: sin renderValue, MUI copiaba la opción completa a la caja y se leía «MenudeoCompra por pieza…».\n//\n// Con `multiple` se eligen varias: la lista se queda abierta, cada elegida lleva su palomita y en la caja quedan sus nombres\n// separados por coma, en el orden de las opciones. Al formulario llega la lista de valores (Yup.array().min(1) la valida).\n// Para catálogos largos, CatalogInput con `multiple` (busca y deja chips). Con varias, además: selectAll («Elegir todos»\n// arriba, con su casilla a medias si hay algunos) y checkboxes (una casilla en cada opción en lugar de la palomita).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSelectInput con defaultProps y\n// styleOverrides de sus partes: option, optionText.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Checkbox from '@mui/material/Checkbox';\nimport MenuItem from '@mui/material/MenuItem';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\n\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {selectAllStateOf} from '@/inputs/selectAllState.js';\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.CalcitaSelectInput)\nconst THEME_NAME = 'CalcitaSelectInput';\nconst SelectOption = piecePart(THEME_NAME, 'Option', MenuItem);\nconst SelectOptionText = piecePart(THEME_NAME, 'OptionText', Box);\n// la opción de «Elegir todos»: no es de la lista y nunca llega al formulario\nconst SELECT_ALL_VALUE = '__calcita_select_all__';\n// con casillas, la palomita que el tema le pone al elegido sobra\nconst WITHOUT_CHECKMARK = Object.freeze({'&.Mui-selected::after': {content: 'none'}});\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|number|Array<string|number>|null|undefined} props.value '' = sin elegir; con multiple, la lista ([] = ninguna)\n * @param {(value: any) => void} props.onChange recibe el valor elegido (con multiple, la lista), no el evento\n * @param {() => void} [props.onBlur]\n * @param {Array<{value: string|number, label: string, description?: string, disabled?: boolean}>} props.options\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ayuda fija; el error la reemplaza\n * @param {string} [props.placeholder] texto de la opción vacía\n * @param {boolean} [props.disabled]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef]\n * @param {boolean} [props.multiple] elegir varias opciones\n * @param {boolean} [props.selectAll] con multiple: «Elegir todos» arriba de la lista\n * @param {boolean} [props.checkboxes] con multiple: una casilla en cada opción\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction SelectInputContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSelectInput.defaultProps) y encima lo que llega aquí\n const {\n name, label, value, onChange, onBlur, options, error, helperText = ' ', placeholder, disabled = false, inputRef, multiple = false,\n selectAll = false, checkboxes = false, messages, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // el texto del error: el de la pantalla (messages), el del proyecto para este campo o el de Calcita\n const validationTextOf = useValidationText({name, label, messages});\n const generatedId = useId();\n const inputId = `${name ?? 'select'}-${generatedId}`;\n // OJO: la lista desplegable de MUI es un div y no un <input>: el `for` de la etiqueta no la une. Se nombra con su etiqueta\n // por aria-labelledby (labelId); sin esto el lector de pantalla no decía «Ciudad», solo lo elegido\n const labelId = `${inputId}-label`;\n const errorText = validationTextOf(error);\n const placeholderText = (\n <Typography component=\"span\"\n // OJO: el placeholder de un select activo se lee (text.secondary); text.disabled solo con el campo inactivo\n color={disabled ? 'text.disabled' : 'text.secondary'}>{placeholder ?? t('form.selectPlaceholder')}</Typography>\n );\n const renderSelectedValue = (selectedValue) => {\n if (multiple) {\n const selectedLabels = options.filter((option) => selectedValue.includes(option.value)).map((option) => option.label);\n return selectedLabels.length > 0 ? selectedLabels.join(', ') : placeholderText;\n }\n return options.find((option) => option.value === selectedValue)?.label ?? placeholderText;\n };\n const currentValue = multiple ? (Array.isArray(value) ? value : []) : (value ?? '');\n // «Elegir todos» solo existe con varias. OJO, trampa pagada: se calculaba también con una sola, y un valor que es número\n // (un recordatorio de 60 minutos) tumbaba la pantalla: new Set(60) no es una lista\n const selectAllState = multiple\n ? selectAllStateOf(currentValue, options.filter((option) => !option.disabled).map((option) => option.value))\n : null;\n // OJO: con multiple, el autollenado del navegador puede mandar el valor como texto separado por comas (lo dice MUI)\n const handleChange = (event) => {\n const nextValue = event.target.value;\n const values = multiple && typeof nextValue === 'string' ? nextValue.split(',') : nextValue;\n // «Elegir todos» llega como una opción más: se cambia por todos (o por ninguno, si ya estaban todos)\n if (multiple && values.includes(SELECT_ALL_VALUE)) {\n onChange(selectAllState.toggled());\n return;\n }\n onChange(values);\n };\n\n return (\n <FieldFrame inputId={inputId} labelId={labelId} label={label}>\n <TextField\n name={name}\n id={inputId}\n inputRef={inputRef}\n select\n size=\"small\"\n fullWidth\n disabled={disabled}\n value={currentValue}\n onChange={handleChange}\n onBlur={onBlur}\n error={Boolean(errorText)}\n helperText={errorText ?? helperText}\n slotProps={{select: {multiple, displayEmpty: true, renderValue: renderSelectedValue, labelId}}}>\n {/* la opción vacía solo con una: con varias, se quitan picándolas otra vez */}\n {!multiple && <MenuItem value=\"\" disabled>{placeholderText}</MenuItem>}\n {multiple && selectAll && (\n <SelectOption value={SELECT_ALL_VALUE} ownSx={{fontWeight: 600, ...WITHOUT_CHECKMARK}}>\n <Checkbox size=\"small\" tabIndex={-1} disableRipple sx={{p: 0, mr: 1}}\n checked={selectAllState.allChosen} indeterminate={selectAllState.someChosen} />\n {selectAllState.allChosen ? t('form.unselectAll') : t('form.selectAll', {count: options.length})}\n </SelectOption>\n )}\n {options.map((option) => (\n // la opción en renglón y su nombre con su explicación en un bloque: con la opción en columna, la palomita del\n // elegido (el tema la pinta al final) se bajaba a otro renglón (lo cachó una captura de Tareas)\n <SelectOption key={option.value} value={option.value} disabled={option.disabled}\n ownSx={{whiteSpace: 'normal', ...(multiple && checkboxes && WITHOUT_CHECKMARK)}}>\n {multiple && checkboxes && (\n <Checkbox size=\"small\" tabIndex={-1} disableRipple sx={{p: 0, mr: 1}} checked={currentValue.includes(option.value)} />\n )}\n <SelectOptionText component=\"span\" ownSx={{display: 'flex', flexDirection: 'column', minWidth: 0, flexGrow: 1}}>\n <Typography component=\"span\" variant=\"body2\">{option.label}</Typography>\n {option.description && (\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\">{option.description}</Typography>\n )}\n </SelectOptionText>\n </SelectOption>\n ))}\n </TextField>\n </FieldFrame>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst SelectInput = withPieceSlots(SelectInputContent, THEME_NAME);\nexport default SelectInput;\n"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@ import Tooltip from "@mui/material/Tooltip";
9
9
  import CancelIcon from "@mui/icons-material/Cancel";
10
10
  import VisibilityOffOutlinedIcon from "@mui/icons-material/VisibilityOffOutlined";
11
11
  import VisibilityOutlinedIcon from "@mui/icons-material/VisibilityOutlined";
12
- import { translateValidationMessage } from "../forms/validationMessages.js";
12
+ import { useValidationText } from "../forms/useValidationText.js";
13
13
  import FieldFrame from "./FieldFrame.js";
14
14
  import { piecePart, usePieceProps } from "../theme/themePieces.js";
15
15
  const THEME_NAME = "CalcitaTextInput";
@@ -38,14 +38,16 @@ function TextInput(props) {
38
38
  normalizeOnBlur,
39
39
  inputRef,
40
40
  clearable = true,
41
+ messages,
41
42
  texts,
42
43
  ...textFieldProps
43
- } = usePieceProps(props, THEME_NAME);
44
+ } = usePieceProps(props, THEME_NAME, { ownSlotProps: true });
44
45
  const { t } = useToolkitTranslation("common", texts);
46
+ const validationTextOf = useValidationText({ name, label, messages });
45
47
  const [isRevealed, setIsRevealed] = useState(false);
46
48
  const generatedId = useId();
47
49
  const inputId = textFieldProps.id ?? `${name ?? "text"}-${generatedId}`;
48
- const errorText = translateValidationMessage(t, error);
50
+ const errorText = validationTextOf(error);
49
51
  const isPassword = type === "password";
50
52
  const revealLabel = isRevealed ? t("form.hidePassword") : t("form.showPassword");
51
53
  const passwordAdornment = isPassword ? /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(Tooltip, { title: revealLabel, children: /* @__PURE__ */ jsx(IconButton, { size: "small", edge: "end", "aria-label": revealLabel, onClick: () => setIsRevealed((currentValue) => !currentValue), children: isRevealed ? /* @__PURE__ */ jsx(VisibilityOffOutlinedIcon, { fontSize: "small" }) : /* @__PURE__ */ jsx(VisibilityOutlinedIcon, { fontSize: "small" }) }) }) }) : void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"TextInput.js","sources":["../../src/inputs/TextInput.jsx"],"sourcesContent":["// Campo de texto suelto, con la etiqueta arriba: el que pintan FormTextField (formik) y el de react-hook-form, y el que se\n// usa sin formulario (controlado: value / onChange).\n//\n// Lo que resuelve, y por lo que existe en vez de un <TextField> suelto:\n// - el renglón de ayuda está reservado desde el principio, así la tarjeta no brinca cuando aparece un error;\n// - las contraseñas traen el ojo para revelarlas (con aria-label traducido);\n// - con texto, la ⓧ para borrarlo de un toque, como los campos de Apple («Display a Clear button in the trailing end of\n// a text field», HIG «Text fields»). Sale con el cursor encima o al escribir, para que un formulario lleno no se vea\n// lleno de ⓧ; no entra al recorrido del teclado (con el teclado se borra seleccionando el texto);\n// - normalizeOnBlur deja el valor como lo va a mandar el formulario (el correo en minúsculas y sin espacios) al salir del\n// campo: la persona ve lo que se envía;\n// - uppercase normaliza a mayúsculas mientras se escribe (claves, RFC);\n// - el error llega como LLAVE de yup ({key, values}) o como texto ya traducido (el del servidor) y se pinta en el idioma\n// activo. Cuándo enseñarlo (ya se tocó, ya se envió) lo decide quien lo conecta al formulario.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTextInput con defaultProps y\n// styleOverrides.field (el TextField). El sx de la pantalla sigue ganando a todo.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport IconButton from '@mui/material/IconButton';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport CancelIcon from '@mui/icons-material/Cancel';\nimport VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';\nimport VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';\n\nimport {translateValidationMessage} from '@/forms/validationMessages.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaTextInput): el campo de MUI con lo de Calcita abajo,\n// el tema del proyecto encima y el sx de la pantalla al final\nconst THEME_NAME = 'CalcitaTextInput';\nconst InputField = piecePart(THEME_NAME, 'Field', TextField);\n\n// la ⓧ de borrar: escondida hasta que el campo tiene el cursor encima o se está escribiendo en él\nconst CLEAR_BUTTON_CLASS = 'calcita-clear-button';\nconst CLEAR_BUTTON_SX = Object.freeze({\n [`& .${CLEAR_BUTTON_CLASS}`]: {visibility: 'hidden', color: 'text.secondary'},\n [`& .MuiInputBase-root:hover .${CLEAR_BUTTON_CLASS}, & .MuiInputBase-root.Mui-focused .${CLEAR_BUTTON_CLASS}`]: {visibility: 'visible'},\n // un campo de búsqueda (type=\"search\") trae la × del navegador: con la ⓧ de la casa salían dos para lo mismo (lo cachó\n // una captura de Tareas). Se esconde la del navegador; la de la casa es la que se ve igual en todos\n '& input[type=\"search\"]::-webkit-search-cancel-button': {WebkitAppearance: 'none', display: 'none'},\n});\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|null|undefined} props.value\n * @param {(value: string) => void} props.onChange recibe el texto, no el evento\n * @param {() => void} [props.onBlur]\n * @param {string|{key: string, values?: object}} [props.error] el error a enseñar (undefined = sin error)\n * @param {string} [props.type] 'password' agrega el ojo\n * @param {string} [props.helperText] ayuda fija; el error la reemplaza. Por omisión el campo deja su renglón vacío para que\n * no brinque al salir un error; con helperText=\"\" no lo deja (un campo con botones al lado en el mismo renglón)\n * @param {string} [props.placeholder] ya traducido; el ejemplo de qué escribir (se va al escribir)\n * @param {import('react').ReactNode} [props.startAdornment]\n * @param {import('react').ReactNode} [props.endAdornment] adorno al final (en contraseñas manda el ojo)\n * @param {boolean} [props.uppercase] normaliza a mayúsculas mientras se escribe\n * @param {(value: string) => string} [props.normalizeOnBlur]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef] para enfocar el campo (react-hook-form lo usa)\n * @param {boolean} [props.clearable] la ⓧ para borrar el texto; por omisión sí (no en contraseñas ni con adorno propio)\n * @param {boolean} [props.multiline] (y lo demás de TextField de MUI: minRows, autoComplete, autoFocus, slotProps, sx…)\n * @param {number} [props.minRows]\n * @param {number} [props.maxRows]\n * @param {string} [props.autoComplete]\n * @param {boolean} [props.autoFocus]\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.required]\n * @param {boolean} [props.fullWidth]\n * @param {string} [props.id]\n * @param {object} [props.slotProps]\n * @param {object} [props.sx]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function TextInput(props) {\n // lo que el proyecto puso en su tema (components.CalcitaTextInput.defaultProps) y encima lo que llega aquí\n const {\n name, label, value, onChange, onBlur, error, type = 'text', helperText = ' ', startAdornment, endAdornment: customEndAdornment,\n uppercase = false, normalizeOnBlur, inputRef, clearable = true, texts, ...textFieldProps\n } = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('common', texts);\n const [isRevealed, setIsRevealed] = useState(false);\n const generatedId = useId();\n const inputId = textFieldProps.id ?? `${name ?? 'text'}-${generatedId}`;\n const errorText = translateValidationMessage(t, error);\n const isPassword = type === 'password';\n const revealLabel = isRevealed ? t('form.hidePassword') : t('form.showPassword');\n\n const passwordAdornment = isPassword ? (\n <InputAdornment position=\"end\">\n <Tooltip title={revealLabel}>\n <IconButton size=\"small\" edge=\"end\" aria-label={revealLabel} onClick={() => setIsRevealed((currentValue) => !currentValue)}>\n {isRevealed ? <VisibilityOffOutlinedIcon fontSize=\"small\" /> : <VisibilityOutlinedIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </InputAdornment>\n ) : undefined;\n const isEditable = !textFieldProps.disabled && !textFieldProps.slotProps?.htmlInput?.readOnly;\n const canClear = clearable && !isPassword && !customEndAdornment && isEditable && Boolean(value);\n // onMouseDown sin acción: el foco se queda en el campo al borrar (si no, el campo pierde el foco y se valida de más)\n const clearAdornment = canClear ? (\n <InputAdornment position=\"end\">\n <IconButton size=\"small\" edge=\"end\" tabIndex={-1} aria-label={t('form.clear')} className={CLEAR_BUTTON_CLASS}\n onMouseDown={(event) => event.preventDefault()} onClick={() => onChange('')}>\n <CancelIcon fontSize=\"small\" />\n </IconButton>\n </InputAdornment>\n ) : undefined;\n const endAdornment = customEndAdornment ? <InputAdornment position=\"end\">{customEndAdornment}</InputAdornment> : (passwordAdornment ?? clearAdornment);\n\n const handleBlur = () => {\n if (normalizeOnBlur) {\n const normalizedValue = normalizeOnBlur(value ?? '');\n // solo si cambió: un cambio de más dispara una validación de más\n if (normalizedValue !== value) {\n onChange(normalizedValue);\n }\n }\n onBlur?.();\n };\n\n return (\n <FieldFrame inputId={inputId} label={label}>\n <InputField\n {...textFieldProps}\n name={name}\n id={inputId}\n inputRef={inputRef}\n value={value ?? ''}\n onChange={(event) => onChange(uppercase ? event.target.value.toUpperCase() : event.target.value)}\n onBlur={handleBlur}\n type={isPassword && isRevealed ? 'text' : type}\n ownSx={CLEAR_BUTTON_SX}\n sx={textFieldProps.sx}\n error={Boolean(errorText)}\n helperText={errorText ?? helperText}\n fullWidth\n size=\"small\"\n // OJO: lo que el proyecto pasó en slotProps (htmlInput: {maxLength}) se suma a los adornos de la casa. Antes se\n // pisaba entero y el tope de caracteres de una pantalla se perdía sin avisar\n slotProps={{\n ...textFieldProps.slotProps,\n input: {\n ...textFieldProps.slotProps?.input,\n startAdornment: startAdornment ? <InputAdornment position=\"start\">{startAdornment}</InputAdornment> : undefined,\n endAdornment,\n },\n }}\n />\n </FieldFrame>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TextInput.js","sources":["../../src/inputs/TextInput.jsx"],"sourcesContent":["// Campo de texto suelto, con la etiqueta arriba: el que pintan FormTextField (formik) y el de react-hook-form, y el que se\n// usa sin formulario (controlado: value / onChange).\n//\n// Lo que resuelve, y por lo que existe en vez de un <TextField> suelto:\n// - el renglón de ayuda está reservado desde el principio, así la tarjeta no brinca cuando aparece un error;\n// - las contraseñas traen el ojo para revelarlas (con aria-label traducido);\n// - con texto, la ⓧ para borrarlo de un toque, como los campos de Apple («Display a Clear button in the trailing end of\n// a text field», HIG «Text fields»). Sale con el cursor encima o al escribir, para que un formulario lleno no se vea\n// lleno de ⓧ; no entra al recorrido del teclado (con el teclado se borra seleccionando el texto);\n// - normalizeOnBlur deja el valor como lo va a mandar el formulario (el correo en minúsculas y sin espacios) al salir del\n// campo: la persona ve lo que se envía;\n// - uppercase normaliza a mayúsculas mientras se escribe (claves, RFC);\n// - el error llega como LLAVE de yup ({key, values}) o como texto ya traducido (el del servidor) y se pinta en el idioma\n// activo. Cuándo enseñarlo (ya se tocó, ya se envió) lo decide quien lo conecta al formulario.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTextInput con defaultProps y\n// styleOverrides.field (el TextField). El sx de la pantalla sigue ganando a todo.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport IconButton from '@mui/material/IconButton';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport CancelIcon from '@mui/icons-material/Cancel';\nimport VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';\nimport VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';\n\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaTextInput): el campo de MUI con lo de Calcita abajo,\n// el tema del proyecto encima y el sx de la pantalla al final\nconst THEME_NAME = 'CalcitaTextInput';\nconst InputField = piecePart(THEME_NAME, 'Field', TextField);\n\n// la ⓧ de borrar: escondida hasta que el campo tiene el cursor encima o se está escribiendo en él\nconst CLEAR_BUTTON_CLASS = 'calcita-clear-button';\nconst CLEAR_BUTTON_SX = Object.freeze({\n [`& .${CLEAR_BUTTON_CLASS}`]: {visibility: 'hidden', color: 'text.secondary'},\n [`& .MuiInputBase-root:hover .${CLEAR_BUTTON_CLASS}, & .MuiInputBase-root.Mui-focused .${CLEAR_BUTTON_CLASS}`]: {visibility: 'visible'},\n // un campo de búsqueda (type=\"search\") trae la × del navegador: con la ⓧ de la casa salían dos para lo mismo (lo cachó\n // una captura de Tareas). Se esconde la del navegador; la de la casa es la que se ve igual en todos\n '& input[type=\"search\"]::-webkit-search-cancel-button': {WebkitAppearance: 'none', display: 'none'},\n});\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|null|undefined} props.value\n * @param {(value: string) => void} props.onChange recibe el texto, no el evento\n * @param {() => void} [props.onBlur]\n * @param {string|{key: string, values?: object}} [props.error] el error a enseñar (undefined = sin error)\n * @param {string} [props.type] 'password' agrega el ojo\n * @param {string} [props.helperText] ayuda fija; el error la reemplaza. Por omisión el campo deja su renglón vacío para que\n * no brinque al salir un error; con helperText=\"\" no lo deja (un campo con botones al lado en el mismo renglón)\n * @param {string} [props.placeholder] ya traducido; el ejemplo de qué escribir (se va al escribir)\n * @param {import('react').ReactNode} [props.startAdornment]\n * @param {import('react').ReactNode} [props.endAdornment] adorno al final (en contraseñas manda el ojo)\n * @param {boolean} [props.uppercase] normaliza a mayúsculas mientras se escribe\n * @param {(value: string) => string} [props.normalizeOnBlur]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef] para enfocar el campo (react-hook-form lo usa)\n * @param {boolean} [props.clearable] la ⓧ para borrar el texto; por omisión sí (no en contraseñas ni con adorno propio)\n * @param {boolean} [props.multiline] (y lo demás de TextField de MUI: minRows, autoComplete, autoFocus, slotProps, sx…)\n * @param {number} [props.minRows]\n * @param {number} [props.maxRows]\n * @param {string} [props.autoComplete]\n * @param {boolean} [props.autoFocus]\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.required]\n * @param {boolean} [props.fullWidth]\n * @param {string} [props.id]\n * @param {object} [props.slotProps]\n * @param {object} [props.sx]\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function TextInput(props) {\n // lo que el proyecto puso en su tema (components.CalcitaTextInput.defaultProps) y encima lo que llega aquí\n const {\n name, label, value, onChange, onBlur, error, type = 'text', helperText = ' ', startAdornment, endAdornment: customEndAdornment,\n uppercase = false, normalizeOnBlur, inputRef, clearable = true, messages, texts, ...textFieldProps\n } = usePieceProps(props, THEME_NAME, {ownSlotProps: true}); // su slotProps es el del TextField de MUI (input, htmlInput…)\n const {t} = useToolkitTranslation('common', texts);\n // el texto del error: el de la pantalla (messages), el del proyecto para este campo o el de Calcita\n const validationTextOf = useValidationText({name, label, messages});\n const [isRevealed, setIsRevealed] = useState(false);\n const generatedId = useId();\n const inputId = textFieldProps.id ?? `${name ?? 'text'}-${generatedId}`;\n const errorText = validationTextOf(error);\n const isPassword = type === 'password';\n const revealLabel = isRevealed ? t('form.hidePassword') : t('form.showPassword');\n\n const passwordAdornment = isPassword ? (\n <InputAdornment position=\"end\">\n <Tooltip title={revealLabel}>\n <IconButton size=\"small\" edge=\"end\" aria-label={revealLabel} onClick={() => setIsRevealed((currentValue) => !currentValue)}>\n {isRevealed ? <VisibilityOffOutlinedIcon fontSize=\"small\" /> : <VisibilityOutlinedIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </InputAdornment>\n ) : undefined;\n const isEditable = !textFieldProps.disabled && !textFieldProps.slotProps?.htmlInput?.readOnly;\n const canClear = clearable && !isPassword && !customEndAdornment && isEditable && Boolean(value);\n // onMouseDown sin acción: el foco se queda en el campo al borrar (si no, el campo pierde el foco y se valida de más)\n const clearAdornment = canClear ? (\n <InputAdornment position=\"end\">\n <IconButton size=\"small\" edge=\"end\" tabIndex={-1} aria-label={t('form.clear')} className={CLEAR_BUTTON_CLASS}\n onMouseDown={(event) => event.preventDefault()} onClick={() => onChange('')}>\n <CancelIcon fontSize=\"small\" />\n </IconButton>\n </InputAdornment>\n ) : undefined;\n const endAdornment = customEndAdornment ? <InputAdornment position=\"end\">{customEndAdornment}</InputAdornment> : (passwordAdornment ?? clearAdornment);\n\n const handleBlur = () => {\n if (normalizeOnBlur) {\n const normalizedValue = normalizeOnBlur(value ?? '');\n // solo si cambió: un cambio de más dispara una validación de más\n if (normalizedValue !== value) {\n onChange(normalizedValue);\n }\n }\n onBlur?.();\n };\n\n return (\n <FieldFrame inputId={inputId} label={label}>\n <InputField\n {...textFieldProps}\n name={name}\n id={inputId}\n inputRef={inputRef}\n value={value ?? ''}\n onChange={(event) => onChange(uppercase ? event.target.value.toUpperCase() : event.target.value)}\n onBlur={handleBlur}\n type={isPassword && isRevealed ? 'text' : type}\n ownSx={CLEAR_BUTTON_SX}\n sx={textFieldProps.sx}\n error={Boolean(errorText)}\n helperText={errorText ?? helperText}\n fullWidth\n size=\"small\"\n // OJO: lo que el proyecto pasó en slotProps (htmlInput: {maxLength}) se suma a los adornos de la casa. Antes se\n // pisaba entero y el tope de caracteres de una pantalla se perdía sin avisar\n slotProps={{\n ...textFieldProps.slotProps,\n input: {\n ...textFieldProps.slotProps?.input,\n startAdornment: startAdornment ? <InputAdornment position=\"start\">{startAdornment}</InputAdornment> : undefined,\n endAdornment,\n },\n }}\n />\n </FieldFrame>\n );\n}\n"],"names":[],"mappings":"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"}