@stackcraftmx/calcita 0.47.0 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (488) hide show
  1. package/README.md +173 -12
  2. package/cli/calcita.js +15 -0
  3. package/cli/checkTexts.js +209 -0
  4. package/cli/packageVersions.js +6 -1
  5. package/cli/projectFiles.js +4 -2
  6. package/cli/templates/project/README.md.tpl +21 -1
  7. package/cli/templates/project/eslint.config.js.tpl +27 -0
  8. package/cli/templates/project/src/app/appTexts.js.tpl +2 -1
  9. package/cli/templates/project/src/core/publicPaths.js.tpl +10 -2
  10. package/cli/templates/project/vite.config.js.tpl +8 -1
  11. package/dist/DataTable/AuditTrailDialog.js +3 -2
  12. package/dist/DataTable/AuditTrailDialog.js.map +1 -1
  13. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +3 -2
  14. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
  15. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +3 -2
  16. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
  17. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +3 -2
  18. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
  19. package/dist/DataTable/EmptyState.js +3 -2
  20. package/dist/DataTable/EmptyState.js.map +1 -1
  21. package/dist/DataTable/FilterChips.js +3 -2
  22. package/dist/DataTable/FilterChips.js.map +1 -1
  23. package/dist/DataTable/GoToPage.js +3 -2
  24. package/dist/DataTable/GoToPage.js.map +1 -1
  25. package/dist/DataTable/ServerTable.js +95 -28
  26. package/dist/DataTable/ServerTable.js.map +1 -1
  27. package/dist/DataTable/ServerTableFilterDrawer.js +8 -3
  28. package/dist/DataTable/ServerTableFilterDrawer.js.map +1 -1
  29. package/dist/DataTable/StackedCell.js +60 -0
  30. package/dist/DataTable/StackedCell.js.map +1 -0
  31. package/dist/DataTable/TableCardsView.js +88 -0
  32. package/dist/DataTable/TableCardsView.js.map +1 -0
  33. package/dist/DataTable/columnWidths.js +30 -0
  34. package/dist/DataTable/columnWidths.js.map +1 -0
  35. package/dist/DataTable/columns.js +47 -1
  36. package/dist/DataTable/columns.js.map +1 -1
  37. package/dist/DataTable/fixedColumns.js +24 -0
  38. package/dist/DataTable/fixedColumns.js.map +1 -0
  39. package/dist/DataTable/useTableView.js +29 -0
  40. package/dist/DataTable/useTableView.js.map +1 -0
  41. package/dist/access/PermissionMatrix.js +3 -2
  42. package/dist/access/PermissionMatrix.js.map +1 -1
  43. package/dist/account/AccountProvider.js +1 -1
  44. package/dist/account/AccountSecuritySection.js +3 -2
  45. package/dist/account/AccountSecuritySection.js.map +1 -1
  46. package/dist/account/DemoTotpCodeButton.js +3 -2
  47. package/dist/account/DemoTotpCodeButton.js.map +1 -1
  48. package/dist/account/ProfileScreen.js +3 -2
  49. package/dist/account/ProfileScreen.js.map +1 -1
  50. package/dist/account/SignInScreen.js +3 -2
  51. package/dist/account/SignInScreen.js.map +1 -1
  52. package/dist/appShell/AccountMenu.js +3 -2
  53. package/dist/appShell/AccountMenu.js.map +1 -1
  54. package/dist/appShell/AppLayout.js +3 -2
  55. package/dist/appShell/AppLayout.js.map +1 -1
  56. package/dist/appShell/AppearanceSettings.js +3 -2
  57. package/dist/appShell/AppearanceSettings.js.map +1 -1
  58. package/dist/appShell/AuthLayout.js +3 -2
  59. package/dist/appShell/AuthLayout.js.map +1 -1
  60. package/dist/appShell/BarActionButton.js +11 -4
  61. package/dist/appShell/BarActionButton.js.map +1 -1
  62. package/dist/appShell/BarActions.js +3 -2
  63. package/dist/appShell/BarActions.js.map +1 -1
  64. package/dist/appShell/BarCapsule.js +3 -2
  65. package/dist/appShell/BarCapsule.js.map +1 -1
  66. package/dist/appShell/BarSearch.js +3 -2
  67. package/dist/appShell/BarSearch.js.map +1 -1
  68. package/dist/appShell/HeaderTools.js +3 -2
  69. package/dist/appShell/HeaderTools.js.map +1 -1
  70. package/dist/appShell/MobileTabBar.js +3 -2
  71. package/dist/appShell/MobileTabBar.js.map +1 -1
  72. package/dist/appShell/SettingsMenu.js +3 -2
  73. package/dist/appShell/SettingsMenu.js.map +1 -1
  74. package/dist/appShell/SideMenu.js +3 -2
  75. package/dist/appShell/SideMenu.js.map +1 -1
  76. package/dist/appShell/SideMenuEntry.js +3 -2
  77. package/dist/appShell/SideMenuEntry.js.map +1 -1
  78. package/dist/appShell/SubmenuActionsMenu.js +3 -2
  79. package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
  80. package/dist/appShell/TabBarEditor.js +3 -2
  81. package/dist/appShell/TabBarEditor.js.map +1 -1
  82. package/dist/appShell/TopMenu.js +3 -2
  83. package/dist/appShell/TopMenu.js.map +1 -1
  84. package/dist/appShell/Wordmark.js +3 -2
  85. package/dist/appShell/Wordmark.js.map +1 -1
  86. package/dist/auth/PasswordChecklist.js +3 -2
  87. package/dist/auth/PasswordChecklist.js.map +1 -1
  88. package/dist/calendar/EventCalendar.js +3 -2
  89. package/dist/calendar/EventCalendar.js.map +1 -1
  90. package/dist/calendar/EventDetails.js +3 -2
  91. package/dist/calendar/EventDetails.js.map +1 -1
  92. package/dist/datePickers/DateInput.js +28 -22
  93. package/dist/datePickers/DateInput.js.map +1 -1
  94. package/dist/datePickers/DateTimeInput.js +33 -27
  95. package/dist/datePickers/DateTimeInput.js.map +1 -1
  96. package/dist/datePickers/MonthInput.js +27 -21
  97. package/dist/datePickers/MonthInput.js.map +1 -1
  98. package/dist/datePickers/TimeInput.js +26 -20
  99. package/dist/datePickers/TimeInput.js.map +1 -1
  100. package/dist/datePickers/usePickerField.js +5 -4
  101. package/dist/datePickers/usePickerField.js.map +1 -1
  102. package/dist/downloads/DownloadManager.js +3 -2
  103. package/dist/downloads/DownloadManager.js.map +1 -1
  104. package/dist/feedback/ConfirmDialog.js +3 -2
  105. package/dist/feedback/ConfirmDialog.js.map +1 -1
  106. package/dist/feedback/ModalWaiting.js +3 -2
  107. package/dist/feedback/ModalWaiting.js.map +1 -1
  108. package/dist/feedback/NewBuildNotice.js +3 -2
  109. package/dist/feedback/NewBuildNotice.js.map +1 -1
  110. package/dist/filepond/FileDropzone.js +3 -2
  111. package/dist/filepond/FileDropzone.js.map +1 -1
  112. package/dist/forms/FormProblemAlert.js +3 -2
  113. package/dist/forms/FormProblemAlert.js.map +1 -1
  114. package/dist/forms/SubmitButton.js +7 -2
  115. package/dist/forms/SubmitButton.js.map +1 -1
  116. package/dist/forms/auth/SignInForm.js +3 -2
  117. package/dist/forms/auth/SignInForm.js.map +1 -1
  118. package/dist/forms/fieldRules.js +30 -0
  119. package/dist/forms/fieldRules.js.map +1 -0
  120. package/dist/forms/security/SecondStepForm.js +3 -2
  121. package/dist/forms/security/SecondStepForm.js.map +1 -1
  122. package/dist/forms/security/TwoStepVerificationCard.js +3 -2
  123. package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
  124. package/dist/forms/useValidationText.js +18 -0
  125. package/dist/forms/useValidationText.js.map +1 -0
  126. package/dist/forms/validation.js +35 -31
  127. package/dist/forms/validation.js.map +1 -1
  128. package/dist/forms/validationMessages.js +64 -7
  129. package/dist/forms/validationMessages.js.map +1 -1
  130. package/dist/forms.js +3 -0
  131. package/dist/forms.js.map +1 -1
  132. package/dist/hookForm/FormProblemAlert.js +3 -2
  133. package/dist/hookForm/FormProblemAlert.js.map +1 -1
  134. package/dist/hookForm/SubmitButton.js +7 -2
  135. package/dist/hookForm/SubmitButton.js.map +1 -1
  136. package/dist/inbox/InboxLayout.js +3 -2
  137. package/dist/inbox/InboxLayout.js.map +1 -1
  138. package/dist/inbox/MessageList.js +3 -2
  139. package/dist/inbox/MessageList.js.map +1 -1
  140. package/dist/inbox/MessageView.js +3 -2
  141. package/dist/inbox/MessageView.js.map +1 -1
  142. package/dist/index.js +186 -163
  143. package/dist/index.js.map +1 -1
  144. package/dist/inputs/CatalogInput.js +32 -25
  145. package/dist/inputs/CatalogInput.js.map +1 -1
  146. package/dist/inputs/CheckboxGroupInput.js +8 -5
  147. package/dist/inputs/CheckboxGroupInput.js.map +1 -1
  148. package/dist/inputs/ColorInput.js +7 -4
  149. package/dist/inputs/ColorInput.js.map +1 -1
  150. package/dist/inputs/FieldFrame.js +10 -4
  151. package/dist/inputs/FieldFrame.js.map +1 -1
  152. package/dist/inputs/FormSection.js +1 -1
  153. package/dist/inputs/MaskedInput.js +1 -0
  154. package/dist/inputs/MaskedInput.js.map +1 -1
  155. package/dist/inputs/NumberInput.js +29 -24
  156. package/dist/inputs/NumberInput.js.map +1 -1
  157. package/dist/inputs/RepeatingFields.js +8 -5
  158. package/dist/inputs/RepeatingFields.js.map +1 -1
  159. package/dist/inputs/SelectInput.js +8 -5
  160. package/dist/inputs/SelectInput.js.map +1 -1
  161. package/dist/inputs/TextInput.js +5 -3
  162. package/dist/inputs/TextInput.js.map +1 -1
  163. package/dist/inputs/TransferListInput.js +8 -5
  164. package/dist/inputs/TransferListInput.js.map +1 -1
  165. package/dist/inputs/WizardLayout.js +3 -2
  166. package/dist/inputs/WizardLayout.js.map +1 -1
  167. package/dist/kanban/KanbanBoard.js +3 -2
  168. package/dist/kanban/KanbanBoard.js.map +1 -1
  169. package/dist/legal/CookieNotice.js +3 -2
  170. package/dist/legal/CookieNotice.js.map +1 -1
  171. package/dist/legal/TermsAcceptanceDialog.js +3 -2
  172. package/dist/legal/TermsAcceptanceDialog.js.map +1 -1
  173. package/dist/locales/en.js +24 -0
  174. package/dist/locales/en.js.map +1 -1
  175. package/dist/locales/es.js +24 -0
  176. package/dist/locales/es.js.map +1 -1
  177. package/dist/maps/MapView.js +3 -2
  178. package/dist/maps/MapView.js.map +1 -1
  179. package/dist/mexico/CfdiSummary.js +3 -2
  180. package/dist/mexico/CfdiSummary.js.map +1 -1
  181. package/dist/mexico/EfirmaFields.js +3 -2
  182. package/dist/mexico/EfirmaFields.js.map +1 -1
  183. package/dist/mexico/mexicoIdentifiers.js +5 -0
  184. package/dist/mexico/mexicoIdentifiers.js.map +1 -1
  185. package/dist/mexico/mexicoRules.js +9 -4
  186. package/dist/mexico/mexicoRules.js.map +1 -1
  187. package/dist/mexico.js +4 -2
  188. package/dist/pwa/InstallAppSetting.js +3 -2
  189. package/dist/pwa/InstallAppSetting.js.map +1 -1
  190. package/dist/pwa/InstallInstructionsDialog.js +3 -2
  191. package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
  192. package/dist/pwa/InstallPromptBanner.js +3 -2
  193. package/dist/pwa/InstallPromptBanner.js.map +1 -1
  194. package/dist/react-hook-form.js +3 -0
  195. package/dist/react-hook-form.js.map +1 -1
  196. package/dist/richText/RichTextEditor.js +7 -4
  197. package/dist/richText/RichTextEditor.js.map +1 -1
  198. package/dist/richText/RichTextView.js +3 -2
  199. package/dist/richText/RichTextView.js.map +1 -1
  200. package/dist/security/ActivityLog.js +3 -2
  201. package/dist/security/ActivityLog.js.map +1 -1
  202. package/dist/security/RecoveryCodesDialog.js +3 -2
  203. package/dist/security/RecoveryCodesDialog.js.map +1 -1
  204. package/dist/security/SessionsCard.js +3 -2
  205. package/dist/security/SessionsCard.js.map +1 -1
  206. package/dist/table.js +21 -2
  207. package/dist/table.js.map +1 -1
  208. package/dist/theme/themePieces.js +70 -4
  209. package/dist/theme/themePieces.js.map +1 -1
  210. package/dist/toolkit/ToolkitProvider.js +8 -1
  211. package/dist/toolkit/ToolkitProvider.js.map +1 -1
  212. package/dist/toolkit/browserNavigation.js +19 -4
  213. package/dist/toolkit/browserNavigation.js.map +1 -1
  214. package/dist/toolkit/combineTexts.js +32 -0
  215. package/dist/toolkit/combineTexts.js.map +1 -0
  216. package/dist/toolkit/hashNavigation.js +17 -3
  217. package/dist/toolkit/hashNavigation.js.map +1 -1
  218. package/dist/toolkit/navigationPaths.js +15 -0
  219. package/dist/toolkit/navigationPaths.js.map +1 -1
  220. package/dist/toolkit/pathIndex.js +66 -0
  221. package/dist/toolkit/pathIndex.js.map +1 -0
  222. package/dist/toolkit/toolkitSettings.js +19 -1
  223. package/dist/toolkit/toolkitSettings.js.map +1 -1
  224. package/dist/types/DataTable/AuditTrailDialog.d.ts +6 -17
  225. package/dist/types/DataTable/ColumnFilters/HeaderFilterPopover.d.ts +6 -5
  226. package/dist/types/DataTable/ColumnFilters/MultiSelectColumnFilter.d.ts +6 -9
  227. package/dist/types/DataTable/ColumnFilters/SortableFilterHeader.d.ts +6 -14
  228. package/dist/types/DataTable/EmptyState.d.ts +6 -9
  229. package/dist/types/DataTable/FilterChips.d.ts +6 -11
  230. package/dist/types/DataTable/GoToPage.d.ts +6 -9
  231. package/dist/types/DataTable/ServerTable.d.ts +16 -80
  232. package/dist/types/DataTable/ServerTableFilterDrawer.d.ts +6 -13
  233. package/dist/types/DataTable/StackedCell.d.ts +12 -0
  234. package/dist/types/DataTable/TableCardsView.d.ts +27 -0
  235. package/dist/types/DataTable/columnWidths.d.ts +21 -0
  236. package/dist/types/DataTable/columns.d.ts +111 -0
  237. package/dist/types/DataTable/fixedColumns.d.ts +29 -0
  238. package/dist/types/DataTable/index.d.ts +6 -1
  239. package/dist/types/DataTable/useTableView.d.ts +22 -0
  240. package/dist/types/access/PermissionMatrix.d.ts +6 -10
  241. package/dist/types/account/AccountSecuritySection.d.ts +6 -7
  242. package/dist/types/account/DemoTotpCodeButton.d.ts +6 -5
  243. package/dist/types/account/ProfileScreen.d.ts +6 -18
  244. package/dist/types/account/SignInScreen.d.ts +6 -13
  245. package/dist/types/appShell/AccountMenu.d.ts +6 -11
  246. package/dist/types/appShell/AppLayout.d.ts +3 -40
  247. package/dist/types/appShell/AppearanceSettings.d.ts +6 -12
  248. package/dist/types/appShell/AuthLayout.d.ts +3 -11
  249. package/dist/types/appShell/BarActionButton.d.ts +6 -10
  250. package/dist/types/appShell/BarActions.d.ts +6 -15
  251. package/dist/types/appShell/BarCapsule.d.ts +6 -9
  252. package/dist/types/appShell/BarSearch.d.ts +6 -15
  253. package/dist/types/appShell/HeaderTools.d.ts +6 -16
  254. package/dist/types/appShell/MobileTabBar.d.ts +6 -13
  255. package/dist/types/appShell/SettingsMenu.d.ts +6 -10
  256. package/dist/types/appShell/SideMenu.d.ts +6 -20
  257. package/dist/types/appShell/SideMenuEntry.d.ts +6 -11
  258. package/dist/types/appShell/SubmenuActionsMenu.d.ts +6 -12
  259. package/dist/types/appShell/TabBarEditor.d.ts +6 -9
  260. package/dist/types/appShell/TopMenu.d.ts +6 -5
  261. package/dist/types/appShell/Wordmark.d.ts +6 -7
  262. package/dist/types/auth/PasswordChecklist.d.ts +6 -9
  263. package/dist/types/calendar/EventCalendar.d.ts +6 -23
  264. package/dist/types/calendar/EventDetails.d.ts +6 -10
  265. package/dist/types/datePickers/DateInput.d.ts +7 -22
  266. package/dist/types/datePickers/DateTimeInput.d.ts +7 -27
  267. package/dist/types/datePickers/MonthInput.d.ts +7 -21
  268. package/dist/types/datePickers/TimeInput.d.ts +7 -21
  269. package/dist/types/datePickers/usePickerField.d.ts +5 -1
  270. package/dist/types/downloads/DownloadManager.d.ts +6 -6
  271. package/dist/types/feedback/ConfirmDialog.d.ts +6 -18
  272. package/dist/types/feedback/ModalWaiting.d.ts +6 -9
  273. package/dist/types/feedback/NewBuildNotice.d.ts +6 -10
  274. package/dist/types/filepond/FileDropzone.d.ts +6 -29
  275. package/dist/types/forms/FormProblemAlert.d.ts +6 -5
  276. package/dist/types/forms/SubmitButton.d.ts +6 -6
  277. package/dist/types/forms/auth/SignInForm.d.ts +6 -11
  278. package/dist/types/forms/fieldRules.d.ts +44 -0
  279. package/dist/types/forms/index.d.ts +1 -0
  280. package/dist/types/forms/security/SecondStepForm.d.ts +6 -14
  281. package/dist/types/forms/security/TwoStepVerificationCard.d.ts +6 -21
  282. package/dist/types/forms/useValidationText.d.ts +12 -0
  283. package/dist/types/forms/validation.d.ts +117 -174
  284. package/dist/types/forms/validationMessages.d.ts +54 -6
  285. package/dist/types/forms.d.ts +1 -1
  286. package/dist/types/hookForm/FormProblemAlert.d.ts +6 -5
  287. package/dist/types/hookForm/SubmitButton.d.ts +6 -13
  288. package/dist/types/inbox/InboxLayout.d.ts +6 -17
  289. package/dist/types/inbox/MessageList.d.ts +6 -18
  290. package/dist/types/inbox/MessageView.d.ts +6 -14
  291. package/dist/types/index.d.ts +8 -1
  292. package/dist/types/inputs/CatalogInput.d.ts +7 -24
  293. package/dist/types/inputs/CheckboxGroupInput.d.ts +7 -18
  294. package/dist/types/inputs/ColorInput.d.ts +7 -16
  295. package/dist/types/inputs/FieldFrame.d.ts +6 -10
  296. package/dist/types/inputs/MaskedInput.d.ts +3 -0
  297. package/dist/types/inputs/NumberInput.d.ts +7 -20
  298. package/dist/types/inputs/RepeatingFields.d.ts +7 -28
  299. package/dist/types/inputs/SelectInput.d.ts +7 -20
  300. package/dist/types/inputs/TextInput.d.ts +3 -0
  301. package/dist/types/inputs/TransferListInput.d.ts +7 -20
  302. package/dist/types/inputs/WizardLayout.d.ts +6 -19
  303. package/dist/types/kanban/KanbanBoard.d.ts +6 -25
  304. package/dist/types/legal/CookieNotice.d.ts +6 -16
  305. package/dist/types/legal/TermsAcceptanceDialog.d.ts +6 -18
  306. package/dist/types/locales/en.d.ts +24 -0
  307. package/dist/types/locales/es.d.ts +24 -0
  308. package/dist/types/maps/MapView.d.ts +6 -17
  309. package/dist/types/mexico/CfdiSummary.d.ts +6 -11
  310. package/dist/types/mexico/EfirmaFields.d.ts +6 -16
  311. package/dist/types/mexico/mexicoIdentifiers.d.ts +7 -0
  312. package/dist/types/mexico/mexicoRules.d.ts +19 -3
  313. package/dist/types/mexico.d.ts +2 -2
  314. package/dist/types/pwa/InstallAppSetting.d.ts +6 -6
  315. package/dist/types/pwa/InstallInstructionsDialog.d.ts +6 -9
  316. package/dist/types/pwa/InstallPromptBanner.d.ts +6 -11
  317. package/dist/types/react-hook-form.d.ts +1 -0
  318. package/dist/types/richText/RichTextEditor.d.ts +7 -22
  319. package/dist/types/richText/RichTextView.d.ts +6 -9
  320. package/dist/types/security/ActivityLog.d.ts +6 -9
  321. package/dist/types/security/RecoveryCodesDialog.d.ts +6 -11
  322. package/dist/types/security/SessionsCard.d.ts +6 -11
  323. package/dist/types/table.d.ts +3 -1
  324. package/dist/types/theme/themePieces.d.ts +55 -3
  325. package/dist/types/toolkit/ToolkitProvider.d.ts +13 -1
  326. package/dist/types/toolkit/browserNavigation.d.ts +7 -3
  327. package/dist/types/toolkit/combineTexts.d.ts +6 -0
  328. package/dist/types/toolkit/hashNavigation.d.ts +4 -2
  329. package/dist/types/toolkit/navigationPaths.d.ts +35 -0
  330. package/dist/types/toolkit/pathIndex.d.ts +27 -0
  331. package/dist/types/toolkit/toolkitSettings.d.ts +7 -4
  332. package/dist/types/ui/actions/ActionsMenu.d.ts +9 -11
  333. package/dist/types/ui/actions/CopyButton.d.ts +6 -12
  334. package/dist/types/ui/actions/DownloadMenu.d.ts +6 -29
  335. package/dist/types/ui/actions/SecretField.d.ts +6 -11
  336. package/dist/types/ui/actions/SelectionActions.d.ts +6 -13
  337. package/dist/types/ui/cards/RecordCard.d.ts +6 -31
  338. package/dist/types/ui/cards/RecordCardSkeleton.d.ts +6 -11
  339. package/dist/types/ui/countdown/Countdown.d.ts +6 -15
  340. package/dist/types/ui/documents/PdfViewerDialog.d.ts +6 -13
  341. package/dist/types/ui/filters/DateRangeFilter.d.ts +6 -10
  342. package/dist/types/ui/filters/FilterDrawer.d.ts +6 -17
  343. package/dist/types/ui/filters/PeriodRangeSelector.d.ts +6 -13
  344. package/dist/types/ui/filters/QuickFilters.d.ts +6 -12
  345. package/dist/types/ui/help/HelpButton.d.ts +6 -10
  346. package/dist/types/ui/help/HelpCarouselDialog.d.ts +6 -14
  347. package/dist/types/ui/labels/MarkedText.d.ts +10 -0
  348. package/dist/types/ui/labels/Tag.d.ts +6 -12
  349. package/dist/types/ui/labels/markedTextPieces.d.ts +22 -0
  350. package/dist/types/ui/layout/CollapsibleSection.d.ts +6 -12
  351. package/dist/types/ui/layout/ContentDialog.d.ts +6 -10
  352. package/dist/types/ui/layout/DefinitionList.d.ts +6 -9
  353. package/dist/types/ui/layout/DetailHeader.d.ts +6 -10
  354. package/dist/types/ui/layout/ErrorPage.d.ts +6 -17
  355. package/dist/types/ui/layout/FullPageLoader.d.ts +6 -6
  356. package/dist/types/ui/layout/GlassPanel.d.ts +6 -8
  357. package/dist/types/ui/layout/PageHeader.d.ts +6 -10
  358. package/dist/types/ui/layout/PageHeading.d.ts +6 -11
  359. package/dist/types/ui/layout/ProfileHeader.d.ts +6 -11
  360. package/dist/types/ui/layout/ScrollableRow.d.ts +6 -13
  361. package/dist/types/ui/layout/SectionCard.d.ts +6 -8
  362. package/dist/types/ui/metrics/BarList.d.ts +6 -12
  363. package/dist/types/ui/metrics/CalendarHeatmap.d.ts +6 -19
  364. package/dist/types/ui/metrics/ChartTooltip.d.ts +6 -6
  365. package/dist/types/ui/metrics/ColumnChart.d.ts +6 -25
  366. package/dist/types/ui/metrics/LineChart.d.ts +6 -20
  367. package/dist/types/ui/metrics/MetricCard.d.ts +6 -17
  368. package/dist/types/ui/metrics/TableToggle.d.ts +6 -6
  369. package/dist/types/ui/metrics/chartParts.d.ts +15 -30
  370. package/dist/types/ui/navigation/BackButton.d.ts +6 -9
  371. package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +6 -9
  372. package/dist/types/ui/navigation/FontSizeToggle.d.ts +6 -8
  373. package/dist/types/ui/navigation/LanguageToggle.d.ts +6 -8
  374. package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +6 -7
  375. package/dist/types/ui/navigation/RouteTabs.d.ts +7 -12
  376. package/dist/types/ui/timeline/GroupedTimeline.d.ts +6 -23
  377. package/dist/types/upload/AttachmentsInput.d.ts +11 -1
  378. package/dist/types/upload/FileDropzone.d.ts +6 -21
  379. package/dist/types/upload/FileInput.d.ts +7 -24
  380. package/dist/types/upload/FileUploadInput.d.ts +7 -31
  381. package/dist/types/upload/ImageInput.d.ts +7 -25
  382. package/dist/types/upload/TemplateDownloadButton.d.ts +6 -18
  383. package/dist/ui/actions/ActionsMenu.js +14 -5
  384. package/dist/ui/actions/ActionsMenu.js.map +1 -1
  385. package/dist/ui/actions/CopyButton.js +8 -3
  386. package/dist/ui/actions/CopyButton.js.map +1 -1
  387. package/dist/ui/actions/DownloadMenu.js +3 -2
  388. package/dist/ui/actions/DownloadMenu.js.map +1 -1
  389. package/dist/ui/actions/SecretField.js +8 -3
  390. package/dist/ui/actions/SecretField.js.map +1 -1
  391. package/dist/ui/actions/SelectionActions.js +3 -2
  392. package/dist/ui/actions/SelectionActions.js.map +1 -1
  393. package/dist/ui/cards/RecordCard.js +4 -3
  394. package/dist/ui/cards/RecordCard.js.map +1 -1
  395. package/dist/ui/cards/RecordCardSkeleton.js +8 -3
  396. package/dist/ui/cards/RecordCardSkeleton.js.map +1 -1
  397. package/dist/ui/countdown/Countdown.js +3 -2
  398. package/dist/ui/countdown/Countdown.js.map +1 -1
  399. package/dist/ui/documents/PdfViewerDialog.js +3 -2
  400. package/dist/ui/documents/PdfViewerDialog.js.map +1 -1
  401. package/dist/ui/filters/DateRangeFilter.js +3 -2
  402. package/dist/ui/filters/DateRangeFilter.js.map +1 -1
  403. package/dist/ui/filters/FilterDrawer.js +3 -2
  404. package/dist/ui/filters/FilterDrawer.js.map +1 -1
  405. package/dist/ui/filters/PeriodRangeSelector.js +3 -2
  406. package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
  407. package/dist/ui/filters/QuickFilters.js +3 -2
  408. package/dist/ui/filters/QuickFilters.js.map +1 -1
  409. package/dist/ui/help/HelpButton.js +8 -3
  410. package/dist/ui/help/HelpButton.js.map +1 -1
  411. package/dist/ui/help/HelpCarouselDialog.js +3 -2
  412. package/dist/ui/help/HelpCarouselDialog.js.map +1 -1
  413. package/dist/ui/labels/MarkedText.js +31 -0
  414. package/dist/ui/labels/MarkedText.js.map +1 -0
  415. package/dist/ui/labels/Tag.js +3 -2
  416. package/dist/ui/labels/Tag.js.map +1 -1
  417. package/dist/ui/labels/markedTextPieces.js +64 -0
  418. package/dist/ui/labels/markedTextPieces.js.map +1 -0
  419. package/dist/ui/layout/CollapsibleSection.js +3 -2
  420. package/dist/ui/layout/CollapsibleSection.js.map +1 -1
  421. package/dist/ui/layout/ContentDialog.js +3 -2
  422. package/dist/ui/layout/ContentDialog.js.map +1 -1
  423. package/dist/ui/layout/DefinitionList.js +3 -2
  424. package/dist/ui/layout/DefinitionList.js.map +1 -1
  425. package/dist/ui/layout/DetailHeader.js +3 -2
  426. package/dist/ui/layout/DetailHeader.js.map +1 -1
  427. package/dist/ui/layout/ErrorPage.js +3 -2
  428. package/dist/ui/layout/ErrorPage.js.map +1 -1
  429. package/dist/ui/layout/FullPageLoader.js +3 -2
  430. package/dist/ui/layout/FullPageLoader.js.map +1 -1
  431. package/dist/ui/layout/GlassPanel.js +3 -2
  432. package/dist/ui/layout/GlassPanel.js.map +1 -1
  433. package/dist/ui/layout/PageHeader.js +3 -2
  434. package/dist/ui/layout/PageHeader.js.map +1 -1
  435. package/dist/ui/layout/PageHeading.js +3 -2
  436. package/dist/ui/layout/PageHeading.js.map +1 -1
  437. package/dist/ui/layout/ProfileHeader.js +3 -2
  438. package/dist/ui/layout/ProfileHeader.js.map +1 -1
  439. package/dist/ui/layout/ScrollableRow.js +3 -2
  440. package/dist/ui/layout/ScrollableRow.js.map +1 -1
  441. package/dist/ui/layout/SectionCard.js +3 -2
  442. package/dist/ui/layout/SectionCard.js.map +1 -1
  443. package/dist/ui/metrics/BarList.js +3 -2
  444. package/dist/ui/metrics/BarList.js.map +1 -1
  445. package/dist/ui/metrics/CalendarHeatmap.js +3 -2
  446. package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
  447. package/dist/ui/metrics/ChartTooltip.js +3 -2
  448. package/dist/ui/metrics/ChartTooltip.js.map +1 -1
  449. package/dist/ui/metrics/ColumnChart.js +3 -2
  450. package/dist/ui/metrics/ColumnChart.js.map +1 -1
  451. package/dist/ui/metrics/LineChart.js +3 -2
  452. package/dist/ui/metrics/LineChart.js.map +1 -1
  453. package/dist/ui/metrics/MetricCard.js +3 -2
  454. package/dist/ui/metrics/MetricCard.js.map +1 -1
  455. package/dist/ui/metrics/TableToggle.js +3 -2
  456. package/dist/ui/metrics/TableToggle.js.map +1 -1
  457. package/dist/ui/metrics/chartParts.js +7 -4
  458. package/dist/ui/metrics/chartParts.js.map +1 -1
  459. package/dist/ui/navigation/BackButton.js +7 -2
  460. package/dist/ui/navigation/BackButton.js.map +1 -1
  461. package/dist/ui/navigation/ColorSchemeToggle.js +3 -2
  462. package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
  463. package/dist/ui/navigation/FontSizeToggle.js +3 -2
  464. package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
  465. package/dist/ui/navigation/LanguageToggle.js +3 -2
  466. package/dist/ui/navigation/LanguageToggle.js.map +1 -1
  467. package/dist/ui/navigation/PageBreadcrumbs.js +3 -2
  468. package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
  469. package/dist/ui/navigation/RouteTabs.js +8 -4
  470. package/dist/ui/navigation/RouteTabs.js.map +1 -1
  471. package/dist/ui/timeline/GroupedTimeline.js +3 -2
  472. package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
  473. package/dist/upload/AttachmentsInput.js +9 -6
  474. package/dist/upload/AttachmentsInput.js.map +1 -1
  475. package/dist/upload/FileChip.js +2 -1
  476. package/dist/upload/FileChip.js.map +1 -1
  477. package/dist/upload/FileDropzone.js +5 -4
  478. package/dist/upload/FileDropzone.js.map +1 -1
  479. package/dist/upload/FileInput.js +9 -6
  480. package/dist/upload/FileInput.js.map +1 -1
  481. package/dist/upload/FileUploadInput.js +9 -6
  482. package/dist/upload/FileUploadInput.js.map +1 -1
  483. package/dist/upload/ImageInput.js +8 -5
  484. package/dist/upload/ImageInput.js.map +1 -1
  485. package/dist/upload/TemplateDownloadButton.js +3 -2
  486. package/dist/upload/TemplateDownloadButton.js.map +1 -1
  487. package/package.json +1 -1
  488. package/cli/templates/project/src/app/combineTexts.js.tpl +0 -31
@@ -1 +1 @@
1
- {"version":3,"file":"FileUploadInput.js","sources":["../../src/upload/FileUploadInput.jsx"],"sourcesContent":["// El cargador MINI: un archivo que se SUBE en cuanto se elige, del tamaño de un renglón. Para una lista de documentos (el\n// expediente de un cliente, lo que pide una solicitud): a la izquierda el nombre del documento (la etiqueta del renglón) y a\n// la derecha el nombre del archivo, su estado y el botón.\n//\n// estado Por cargar · Subiendo 40 % · Procesando · Cargado · No se cargó\n// botón Cargar (lleno) → ya cargado, Sustituir (con borde); mientras sube, Cancelar\n// íconos bajar el que ya subió (si la pantalla da download) y quitarlo\n// abajo el avance en palabras («1.2 MB de 3 MB · 350 kB/s · faltan 5 segundos»; el porcentaje ya va en el estado) o el\n// motivo del error\n//\n// Al formulario llega SOLO lo que el servidor da para reconocer el archivo (su id, por omisión result.id): el formulario\n// manda ese id junto con lo demás y el backend lo liga a su registro. Mientras sube, el valor es '' (no se puede guardar\n// con el id del anterior). Subir es de la pantalla: `upload` recibe el archivo con su señal para cancelar, su avance y una\n// llave por archivo elegido (si la red se cae a media subida, el servidor no deja dos copias). Con uploadWithProgress o\n// con axios, igual.\n//\n// Lo que es del negocio (Aprobado, Falta información) no va aquí: la pantalla lo pinta junto, con `actions`, y sabe en\n// qué va cada uno con onStatusChange (para «3 de 5 cargados»). Tipo y peso se revisan ANTES de subir (accept, maxSize): no\n// se gastan minutos subiendo lo que el servidor va a rechazar; el motivo sale abajo, en rojo.\n//\n// Dentro de una FormSection se vuelve renglón, como los demás campos. También se puede soltar el archivo encima.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaFileUploadInput con defaultProps y\n// styleOverrides de sus partes: root, fileName, status, button, helper.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useId, useRef, useState} from 'react';\nimport {useMachine} from '@xstate/react';\nimport Button from '@mui/material/Button';\nimport Chip from '@mui/material/Chip';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport IconButton from '@mui/material/IconButton';\nimport Stack from '@mui/material/Stack';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded';\nimport CloseRoundedIcon from '@mui/icons-material/CloseRounded';\nimport FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';\nimport FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined';\n\nimport {startDownload} from '@/downloads/downloadQueue.js';\nimport {translateValidationMessage} from '@/forms/validationMessages.js';\nimport {newIdentifier} from '@/identifiers.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {fieldErrorsOf} from '@/problems.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\nimport {FILE_REJECTION} from '@/upload/fileRules.js';\nimport {transferProgressOf} from '@/upload/transferProgress.js';\nimport {buildUploadActors, uploadMachine} from '@/upload/uploadMachine.js';\nimport {useFilePicker} from '@/upload/useFilePicker.js';\n\n/** En qué va el archivo de un renglón (onStatusChange). */\nexport const FILE_UPLOAD_STATUS = Object.freeze({\n pending: 'pending', uploading: 'uploading', processing: 'processing', uploaded: 'uploaded', failed: 'failed',\n});\n\n// el color de la etiqueta de cada estado (el color es información)\nconst STATUS_COLORS = Object.freeze({\n [FILE_UPLOAD_STATUS.pending]: 'default',\n [FILE_UPLOAD_STATUS.uploading]: 'info',\n [FILE_UPLOAD_STATUS.processing]: 'info',\n [FILE_UPLOAD_STATUS.uploaded]: 'success',\n [FILE_UPLOAD_STATUS.failed]: 'error',\n});\n\n// entre las partes del avance en palabras\nconst PROGRESS_SEPARATOR = ' · ';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaFileUploadInput)\nconst THEME_NAME = 'CalcitaFileUploadInput';\nconst FileUploadRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst FileUploadName = piecePart(THEME_NAME, 'FileName', Typography);\nconst FileUploadStatus = piecePart(THEME_NAME, 'Status', Chip);\nconst FileUploadButton = piecePart(THEME_NAME, 'Button', Button);\nconst FileUploadHelper = piecePart(THEME_NAME, 'Helper', FormHelperText);\n\n/**\n * El texto de un error de la subida: el del campo si el servidor mandó un 422 con su lista, si no su detail, y si no hubo\n * respuesta, el genérico.\n *\n * @param {unknown} error\n * @returns {string|null}\n */\nfunction uploadErrorTextOf(error) {\n const problem = /** @type {{problem?: object, message?: string}} */ (error)?.problem;\n const firstFieldMessage = Object.values(fieldErrorsOf(problem ?? null)).flat()[0];\n return firstFieldMessage ?? problem?.detail ?? null;\n}\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {import('react').ReactNode} [props.label] ya traducida: el nombre del documento; sin ella, el renglón va solo\n * @param {string|null} [props.value] lo que el servidor dio para reconocer el archivo subido ('' o null = ninguno)\n * @param {(value: string) => void} props.onChange recibe el id al terminar de subir, '' al quitarlo o mientras sube otro\n * @param {() => void} [props.onBlur] se llama al elegir o quitar (para que el formulario lo marque como tocado)\n * @param {(file: File, options: {signal: AbortSignal, idempotencyKey: string, onUploadProgress: (transfer: {loaded: number, total: number, rate?: number, estimated?: number}) => void}) => Promise<any>} props.upload\n * sube el archivo (con uploadWithProgress, axios o el cliente del proyecto) y regresa lo que conteste el servidor\n * @param {(result: any) => string} [props.idOf] de la respuesta, lo que se guarda en el formulario; por omisión result.id\n * @param {{name: string, size?: number}|null} [props.uploadedFile] el que ya estaba subido, para enseñar su nombre al editar\n * @param {(value: string, transferOptions: object) => Promise<{blob: Blob, fileName: string}>} [props.download] baja el\n * que ya subió (pasa por el panel de descargas); sin él no sale el ícono\n * @param {string|string[]} [props.accept] 'pdf' | ['pdf', 'image'] | '.xlsx,.xls' | 'image/*'\n * @param {number|string} [props.maxSize] bytes o '10 MB'\n * @param {string} [props.limitsText] ya traducido: qué acepta, en palabras («PDF o foto, hasta 5 MB»); sale al pasar sobre\n * el botón. Por omisión solo el peso máximo\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ya traducida\n * @param {boolean} [props.disabled]\n * @param {import('react').ReactNode} [props.actions] lo del negocio junto al estado (Aprobado, Falta información)\n * @param {(result: any) => void} [props.onUploaded] terminó de subir (p. ej. para enseñar el folio de la respuesta)\n * @param {(error: unknown) => void} [props.onUploadFailed] no se pudo subir (el motivo ya sale abajo)\n * @param {() => void} [props.onCancel] la persona canceló a media subida\n * @param {() => void} [props.onRemove] la persona quitó el archivo\n * @param {(status: string) => void} [props.onStatusChange] uno de FILE_UPLOAD_STATUS, cada vez que cambia\n * @param {object} [props.sx] ajustes del renglón\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function FileUploadInput(props) {\n const {\n name, label, value = '', onChange, onBlur, upload, idOf = (result) => result?.id, uploadedFile = null, download, accept, maxSize,\n limitsText, error, helperText = ' ', disabled = false, actions, onUploaded, onUploadFailed, onCancel, onRemove, onStatusChange,\n sx, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const {formatFileSize} = useFormatters();\n const generatedId = useId();\n const inputId = `${name ?? 'file-upload'}-${generatedId}`;\n const labelId = `${inputId}-label`;\n const buttonTextId = `${inputId}-button`;\n const [chosenFile, setChosenFile] = useState(null);\n const [rejectedText, setRejectedText] = useState(null);\n const startedAtRef = useRef(0);\n const [uploadSnapshot, sendToUpload] = useMachine(uploadMachine.provide({\n actors: buildUploadActors(({file, idempotencyKey}, onProgress, signal) => upload(file, {\n signal,\n idempotencyKey,\n onUploadProgress: (transfer) => {\n const total = transfer.total ?? file.size;\n onProgress(total ? Math.round((transfer.loaded * 100) / total) : 0, {...transfer, total});\n },\n })),\n }));\n const {progress, transfer, result, problem} = uploadSnapshot.context;\n const isSending = uploadSnapshot.matches({uploading: 'sending'});\n const isProcessing = uploadSnapshot.matches({uploading: 'processing'});\n const isUploading = isSending || isProcessing;\n const isFailed = uploadSnapshot.matches('failed') || Boolean(rejectedText);\n const isUploaded = Boolean(value) && !isUploading && !isFailed;\n let status = FILE_UPLOAD_STATUS.pending;\n if (isSending) {\n status = FILE_UPLOAD_STATUS.uploading;\n } else if (isProcessing) {\n status = FILE_UPLOAD_STATUS.processing;\n } else if (isFailed) {\n status = FILE_UPLOAD_STATUS.failed;\n } else if (isUploaded) {\n status = FILE_UPLOAD_STATUS.uploaded;\n }\n\n // al terminar, el formulario se queda con el id; quien usa el campo puede enseñar lo demás de la respuesta\n useEffect(() => {\n if (!result) {\n return;\n }\n onChange(idOf(result) ?? '');\n onUploaded?.(result);\n // OJO: solo cuando llega una respuesta nueva; onChange, idOf y onUploaded cambian en cada render\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [result]);\n useEffect(() => {\n if (problem) {\n onUploadFailed?.(problem);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [problem]);\n useEffect(() => {\n onStatusChange?.(status);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [status]);\n // si el formulario se limpia (después de guardar), el renglón también regresa a «por cargar»\n useEffect(() => {\n if (!value && uploadSnapshot.matches('done')) {\n setChosenFile(null);\n sendToUpload({type: 'RESET'});\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value]);\n\n const startUpload = (file) => {\n onBlur?.();\n setRejectedText(null);\n setChosenFile(file);\n // mientras sube, el formulario no tiene archivo: no se puede guardar con el id del anterior\n onChange('');\n startedAtRef.current = Date.now();\n sendToUpload({type: 'UPLOAD', input: {file, idempotencyKey: newIdentifier()}});\n };\n const picker = useFilePicker({\n accept, maxSize, disabled: disabled || isUploading, onAccept: startUpload, texts,\n onReject: (file, reason) => {\n onBlur?.();\n setRejectedText(reason === FILE_REJECTION.size\n ? t('upload.tooLarge', {name: file.name, max: formatFileSize(picker.maxBytes)})\n : t('upload.invalidType', {name: file.name, accept: picker.resolvedAccept}));\n },\n });\n const remove = () => {\n setChosenFile(null);\n setRejectedText(null);\n onChange('');\n onBlur?.();\n sendToUpload({type: 'RESET'});\n onRemove?.();\n };\n const cancel = () => {\n sendToUpload({type: 'CANCEL'});\n onCancel?.();\n };\n\n const shownFile = chosenFile ?? (value ? uploadedFile : null);\n const statusLabel = status === FILE_UPLOAD_STATUS.uploading\n ? t('upload.status.uploading', {percent: progress ?? 0})\n : t(`upload.status.${status}`);\n const validationText = translateValidationMessage(t, error);\n const errorText = rejectedText\n ?? (uploadSnapshot.matches('failed') ? uploadErrorTextOf(problem) ?? t('upload.failed') : null)\n ?? (isUploading ? null : validationText);\n let progressText = null;\n if (isProcessing) {\n progressText = t('upload.processing');\n } else if (isSending) {\n // «1.2 MB de 3 MB · 350 kB/s · faltan 5 segundos»: la velocidad y lo que falta, cuando ya se pueden decir (el\n // porcentaje ya va en la etiqueta del estado)\n const now = transfer ? transferProgressOf(transfer, startedAtRef.current) : null;\n progressText = now ? [\n t('upload.amount', {loaded: formatFileSize(now.loaded), total: formatFileSize(now.total)}),\n now.bytesPerSecond ? t('upload.speed', {size: formatFileSize(now.bytesPerSecond)}) : null,\n now.remainingSeconds != null ? t('upload.remaining', {count: now.remainingSeconds}) : null,\n ].filter(Boolean).join(PROGRESS_SEPARATOR) : t('upload.starting');\n } else if (uploadSnapshot.matches('cancelled')) {\n progressText = t('upload.cancelled');\n }\n const buttonHint = limitsText ?? (picker.maxBytes ? t('upload.maxSizeHint', {max: formatFileSize(picker.maxBytes)}) : '');\n const downloadUploaded = () => startDownload({\n label: shownFile?.name ?? t('upload.download'),\n request: (transferOptions) => download(value, transferOptions),\n });\n\n const row = (\n <div>\n <FileUploadRoot\n direction=\"row\"\n aria-busy={isUploading}\n {...picker.dropHandlers}\n ownSx={{\n // en el teléfono el nombre baja a su renglón; en escritorio se corta con «…» y el botón no se mueve\n alignItems: 'center', justifyContent: 'flex-end', flexWrap: {xs: 'wrap', sm: 'nowrap'}, gap: 1, minWidth: 0, minHeight: 40,\n px: 0.5, mx: -0.5, borderRadius: 1,\n outline: picker.isDragging ? 2 : 0, outlineStyle: 'dashed', outlineColor: 'primary.main',\n bgcolor: picker.isDragging ? 'action.hover' : 'transparent',\n ...sx,\n }}\n >\n <input {...picker.inputProps} id={inputId} name={name} aria-labelledby={label ? labelId : undefined} />\n {shownFile && (\n // el nombre cortado si es largo y completo al pasar el cursor; en el teléfono baja a su renglón\n <Tooltip title={shownFile.size != null ? `${shownFile.name} · ${formatFileSize(shownFile.size)}` : shownFile.name}>\n <FileUploadName variant=\"caption\" color=\"text.secondary\" noWrap\n ownSx={{minWidth: 0, flexShrink: 1, flexBasis: {xs: '100%', sm: 'auto'}, textAlign: {xs: 'right', sm: 'left'}}}>\n {shownFile.name}\n </FileUploadName>\n </Tooltip>\n )}\n {actions}\n <FileUploadStatus\n size=\"small\"\n color={STATUS_COLORS[status]}\n variant={status === FILE_UPLOAD_STATUS.pending ? 'filled' : 'outlined'}\n label={statusLabel}\n icon={(isUploading && (\n <CircularProgress size={12} color=\"inherit\" variant={isProcessing ? 'indeterminate' : 'determinate'} value={progress ?? 0} />\n )) || (isUploaded && <CheckCircleRoundedIcon />) || undefined}\n ownSx={{flexShrink: 0}}\n />\n {isUploading ? (\n <FileUploadButton size=\"small\" color=\"inherit\" onClick={cancel} ownSx={{flexShrink: 0}}>{t('upload.cancel')}</FileUploadButton>\n ) : (\n // describeChild: lo que acepta se lee como descripción; el nombre sigue siendo «Cargar» y el documento\n <Tooltip title={buttonHint} describeChild>\n <FileUploadButton\n size=\"small\"\n variant={isUploaded ? 'outlined' : 'contained'}\n startIcon={<FileUploadOutlinedIcon />}\n disabled={disabled}\n onClick={picker.open}\n aria-labelledby={label ? `${buttonTextId} ${labelId}` : undefined}\n ownSx={{flexShrink: 0}}\n >\n <span id={buttonTextId}>{isUploaded ? t('upload.replace') : t('upload.upload')}</span>\n </FileUploadButton>\n </Tooltip>\n )}\n {isUploaded && download && (\n <Tooltip title={t('upload.download')}>\n <IconButton size=\"small\" aria-label={t('upload.download')} onClick={downloadUploaded}>\n <FileDownloadOutlinedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n {isUploaded && !disabled && (\n <Tooltip title={t('upload.remove', {name: shownFile?.name ?? ''})}>\n <IconButton size=\"small\" aria-label={t('upload.remove', {name: shownFile?.name ?? ''})} onClick={remove}>\n <CloseRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </FileUploadRoot>\n {/* abajo: el error manda; si no, el avance; si no, la ayuda de la pantalla */}\n <FileUploadHelper error={Boolean(errorText)} role={errorText ? 'alert' : (progressText ? 'status' : undefined)}\n ownSx={{textAlign: 'right', mx: 0}}>\n {errorText ?? progressText ?? helperText}\n </FileUploadHelper>\n </div>\n );\n\n // sin etiqueta, el renglón va solo (la pantalla pone el título del documento a su manera)\n if (!label) {\n return row;\n }\n return <FieldFrame inputId={inputId} labelId={labelId} label={label}>{row}</FieldFrame>;\n}\n"],"names":["result","transfer"],"mappings":"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"}
1
+ {"version":3,"file":"FileUploadInput.js","sources":["../../src/upload/FileUploadInput.jsx"],"sourcesContent":["// El cargador MINI: un archivo que se SUBE en cuanto se elige, del tamaño de un renglón. Para una lista de documentos (el\n// expediente de un cliente, lo que pide una solicitud): a la izquierda el nombre del documento (la etiqueta del renglón) y a\n// la derecha el nombre del archivo, su estado y el botón.\n//\n// estado Por cargar · Subiendo 40 % · Procesando · Cargado · No se cargó\n// botón Cargar (lleno) → ya cargado, Sustituir (con borde); mientras sube, Cancelar\n// íconos bajar el que ya subió (si la pantalla da download) y quitarlo\n// abajo el avance en palabras («1.2 MB de 3 MB · 350 kB/s · faltan 5 segundos»; el porcentaje ya va en el estado) o el\n// motivo del error\n//\n// Al formulario llega SOLO lo que el servidor da para reconocer el archivo (su id, por omisión result.id): el formulario\n// manda ese id junto con lo demás y el backend lo liga a su registro. Mientras sube, el valor es '' (no se puede guardar\n// con el id del anterior). Subir es de la pantalla: `upload` recibe el archivo con su señal para cancelar, su avance y una\n// llave por archivo elegido (si la red se cae a media subida, el servidor no deja dos copias). Con uploadWithProgress o\n// con axios, igual.\n//\n// Lo que es del negocio (Aprobado, Falta información) no va aquí: la pantalla lo pinta junto, con `actions`, y sabe en\n// qué va cada uno con onStatusChange (para «3 de 5 cargados»). Tipo y peso se revisan ANTES de subir (accept, maxSize): no\n// se gastan minutos subiendo lo que el servidor va a rechazar; el motivo sale abajo, en rojo.\n//\n// Dentro de una FormSection se vuelve renglón, como los demás campos. También se puede soltar el archivo encima.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaFileUploadInput con defaultProps y\n// styleOverrides de sus partes: root, fileName, status, button, helper.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useId, useRef, useState} from 'react';\nimport {useMachine} from '@xstate/react';\nimport Button from '@mui/material/Button';\nimport Chip from '@mui/material/Chip';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport IconButton from '@mui/material/IconButton';\nimport Stack from '@mui/material/Stack';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded';\nimport CloseRoundedIcon from '@mui/icons-material/CloseRounded';\nimport FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';\nimport FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined';\n\nimport {startDownload} from '@/downloads/downloadQueue.js';\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport {newIdentifier} from '@/identifiers.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {fieldErrorsOf} from '@/problems.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\nimport {FILE_REJECTION} from '@/upload/fileRules.js';\nimport {transferProgressOf} from '@/upload/transferProgress.js';\nimport {buildUploadActors, uploadMachine} from '@/upload/uploadMachine.js';\nimport {useFilePicker} from '@/upload/useFilePicker.js';\n\n/** En qué va el archivo de un renglón (onStatusChange). */\nexport const FILE_UPLOAD_STATUS = Object.freeze({\n pending: 'pending', uploading: 'uploading', processing: 'processing', uploaded: 'uploaded', failed: 'failed',\n});\n\n// el color de la etiqueta de cada estado (el color es información)\nconst STATUS_COLORS = Object.freeze({\n [FILE_UPLOAD_STATUS.pending]: 'default',\n [FILE_UPLOAD_STATUS.uploading]: 'info',\n [FILE_UPLOAD_STATUS.processing]: 'info',\n [FILE_UPLOAD_STATUS.uploaded]: 'success',\n [FILE_UPLOAD_STATUS.failed]: 'error',\n});\n\n// entre las partes del avance en palabras\nconst PROGRESS_SEPARATOR = ' · ';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaFileUploadInput)\nconst THEME_NAME = 'CalcitaFileUploadInput';\nconst FileUploadRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst FileUploadName = piecePart(THEME_NAME, 'FileName', Typography);\nconst FileUploadStatus = piecePart(THEME_NAME, 'Status', Chip);\nconst FileUploadButton = piecePart(THEME_NAME, 'Button', Button);\nconst FileUploadHelper = piecePart(THEME_NAME, 'Helper', FormHelperText);\n\n/**\n * El texto de un error de la subida: el del campo si el servidor mandó un 422 con su lista, si no su detail, y si no hubo\n * respuesta, el genérico.\n *\n * @param {unknown} error\n * @returns {string|null}\n */\nfunction uploadErrorTextOf(error) {\n const problem = /** @type {{problem?: object, message?: string}} */ (error)?.problem;\n const firstFieldMessage = Object.values(fieldErrorsOf(problem ?? null)).flat()[0];\n return firstFieldMessage ?? problem?.detail ?? null;\n}\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {import('react').ReactNode} [props.label] ya traducida: el nombre del documento; sin ella, el renglón va solo\n * @param {string|null} [props.value] lo que el servidor dio para reconocer el archivo subido ('' o null = ninguno)\n * @param {(value: string) => void} props.onChange recibe el id al terminar de subir, '' al quitarlo o mientras sube otro\n * @param {() => void} [props.onBlur] se llama al elegir o quitar (para que el formulario lo marque como tocado)\n * @param {(file: File, options: {signal: AbortSignal, idempotencyKey: string, onUploadProgress: (transfer: {loaded: number, total: number, rate?: number, estimated?: number}) => void}) => Promise<any>} props.upload\n * sube el archivo (con uploadWithProgress, axios o el cliente del proyecto) y regresa lo que conteste el servidor\n * @param {(result: any) => string} [props.idOf] de la respuesta, lo que se guarda en el formulario; por omisión result.id\n * @param {{name: string, size?: number}|null} [props.uploadedFile] el que ya estaba subido, para enseñar su nombre al editar\n * @param {(value: string, transferOptions: object) => Promise<{blob: Blob, fileName: string}>} [props.download] baja el\n * que ya subió (pasa por el panel de descargas); sin él no sale el ícono\n * @param {string|string[]} [props.accept] 'pdf' | ['pdf', 'image'] | '.xlsx,.xls' | 'image/*'\n * @param {number|string} [props.maxSize] bytes o '10 MB'\n * @param {string} [props.limitsText] ya traducido: qué acepta, en palabras («PDF o foto, hasta 5 MB»); sale al pasar sobre\n * el botón. Por omisión solo el peso máximo\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ya traducida\n * @param {boolean} [props.disabled]\n * @param {import('react').ReactNode} [props.actions] lo del negocio junto al estado (Aprobado, Falta información)\n * @param {(result: any) => void} [props.onUploaded] terminó de subir (p. ej. para enseñar el folio de la respuesta)\n * @param {(error: unknown) => void} [props.onUploadFailed] no se pudo subir (el motivo ya sale abajo)\n * @param {() => void} [props.onCancel] la persona canceló a media subida\n * @param {() => void} [props.onRemove] la persona quitó el archivo\n * @param {(status: string) => void} [props.onStatusChange] uno de FILE_UPLOAD_STATUS, cada vez que cambia\n * @param {object} [props.sx] ajustes del rengló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 FileUploadInputContent(props) {\n const {\n name, label, value = '', onChange, onBlur, upload, idOf = (result) => result?.id, uploadedFile = null, download, accept, maxSize,\n limitsText, error, helperText = ' ', disabled = false, actions, onUploaded, onUploadFailed, onCancel, onRemove, onStatusChange,\n 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({name, label, messages});\n const {formatFileSize} = useFormatters();\n const generatedId = useId();\n const inputId = `${name ?? 'file-upload'}-${generatedId}`;\n const labelId = `${inputId}-label`;\n const buttonTextId = `${inputId}-button`;\n const [chosenFile, setChosenFile] = useState(null);\n const [rejectedText, setRejectedText] = useState(null);\n const startedAtRef = useRef(0);\n const [uploadSnapshot, sendToUpload] = useMachine(uploadMachine.provide({\n actors: buildUploadActors(({file, idempotencyKey}, onProgress, signal) => upload(file, {\n signal,\n idempotencyKey,\n onUploadProgress: (transfer) => {\n const total = transfer.total ?? file.size;\n onProgress(total ? Math.round((transfer.loaded * 100) / total) : 0, {...transfer, total});\n },\n })),\n }));\n const {progress, transfer, result, problem} = uploadSnapshot.context;\n const isSending = uploadSnapshot.matches({uploading: 'sending'});\n const isProcessing = uploadSnapshot.matches({uploading: 'processing'});\n const isUploading = isSending || isProcessing;\n const isFailed = uploadSnapshot.matches('failed') || Boolean(rejectedText);\n const isUploaded = Boolean(value) && !isUploading && !isFailed;\n let status = FILE_UPLOAD_STATUS.pending;\n if (isSending) {\n status = FILE_UPLOAD_STATUS.uploading;\n } else if (isProcessing) {\n status = FILE_UPLOAD_STATUS.processing;\n } else if (isFailed) {\n status = FILE_UPLOAD_STATUS.failed;\n } else if (isUploaded) {\n status = FILE_UPLOAD_STATUS.uploaded;\n }\n\n // al terminar, el formulario se queda con el id; quien usa el campo puede enseñar lo demás de la respuesta\n useEffect(() => {\n if (!result) {\n return;\n }\n onChange(idOf(result) ?? '');\n onUploaded?.(result);\n // OJO: solo cuando llega una respuesta nueva; onChange, idOf y onUploaded cambian en cada render\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [result]);\n useEffect(() => {\n if (problem) {\n onUploadFailed?.(problem);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [problem]);\n useEffect(() => {\n onStatusChange?.(status);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [status]);\n // si el formulario se limpia (después de guardar), el renglón también regresa a «por cargar»\n useEffect(() => {\n if (!value && uploadSnapshot.matches('done')) {\n setChosenFile(null);\n sendToUpload({type: 'RESET'});\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value]);\n\n const startUpload = (file) => {\n onBlur?.();\n setRejectedText(null);\n setChosenFile(file);\n // mientras sube, el formulario no tiene archivo: no se puede guardar con el id del anterior\n onChange('');\n startedAtRef.current = Date.now();\n sendToUpload({type: 'UPLOAD', input: {file, idempotencyKey: newIdentifier()}});\n };\n const picker = useFilePicker({\n accept, maxSize, disabled: disabled || isUploading, onAccept: startUpload, texts,\n onReject: (file, reason) => {\n onBlur?.();\n setRejectedText(reason === FILE_REJECTION.size\n ? t('upload.tooLarge', {name: file.name, max: formatFileSize(picker.maxBytes)})\n : t('upload.invalidType', {name: file.name, accept: picker.resolvedAccept}));\n },\n });\n const remove = () => {\n setChosenFile(null);\n setRejectedText(null);\n onChange('');\n onBlur?.();\n sendToUpload({type: 'RESET'});\n onRemove?.();\n };\n const cancel = () => {\n sendToUpload({type: 'CANCEL'});\n onCancel?.();\n };\n\n const shownFile = chosenFile ?? (value ? uploadedFile : null);\n const statusLabel = status === FILE_UPLOAD_STATUS.uploading\n ? t('upload.status.uploading', {percent: progress ?? 0})\n : t(`upload.status.${status}`);\n const validationText = validationTextOf(error);\n const errorText = rejectedText\n ?? (uploadSnapshot.matches('failed') ? uploadErrorTextOf(problem) ?? t('upload.failed') : null)\n ?? (isUploading ? null : validationText);\n let progressText = null;\n if (isProcessing) {\n progressText = t('upload.processing');\n } else if (isSending) {\n // «1.2 MB de 3 MB · 350 kB/s · faltan 5 segundos»: la velocidad y lo que falta, cuando ya se pueden decir (el\n // porcentaje ya va en la etiqueta del estado)\n const now = transfer ? transferProgressOf(transfer, startedAtRef.current) : null;\n progressText = now ? [\n t('upload.amount', {loaded: formatFileSize(now.loaded), total: formatFileSize(now.total)}),\n now.bytesPerSecond ? t('upload.speed', {size: formatFileSize(now.bytesPerSecond)}) : null,\n now.remainingSeconds != null ? t('upload.remaining', {count: now.remainingSeconds}) : null,\n ].filter(Boolean).join(PROGRESS_SEPARATOR) : t('upload.starting');\n } else if (uploadSnapshot.matches('cancelled')) {\n progressText = t('upload.cancelled');\n }\n const buttonHint = limitsText ?? (picker.maxBytes ? t('upload.maxSizeHint', {max: formatFileSize(picker.maxBytes)}) : '');\n const downloadUploaded = () => startDownload({\n label: shownFile?.name ?? t('upload.download'),\n request: (transferOptions) => download(value, transferOptions),\n });\n\n const row = (\n <div>\n <FileUploadRoot\n direction=\"row\"\n aria-busy={isUploading}\n {...picker.dropHandlers}\n ownSx={{\n // en el teléfono el nombre baja a su renglón; en escritorio se corta con «…» y el botón no se mueve\n alignItems: 'center', justifyContent: 'flex-end', flexWrap: {xs: 'wrap', sm: 'nowrap'}, gap: 1, minWidth: 0, minHeight: 40,\n px: 0.5, mx: -0.5, borderRadius: 1,\n outline: picker.isDragging ? 2 : 0, outlineStyle: 'dashed', outlineColor: 'primary.main',\n bgcolor: picker.isDragging ? 'action.hover' : 'transparent',\n }}\n sx={sx}\n >\n <input {...picker.inputProps} id={inputId} name={name} aria-labelledby={label ? labelId : undefined} />\n {shownFile && (\n // el nombre cortado si es largo y completo al pasar el cursor; en el teléfono baja a su renglón\n <Tooltip title={shownFile.size != null ? `${shownFile.name} · ${formatFileSize(shownFile.size)}` : shownFile.name}>\n <FileUploadName variant=\"caption\" color=\"text.secondary\" noWrap\n ownSx={{minWidth: 0, flexShrink: 1, flexBasis: {xs: '100%', sm: 'auto'}, textAlign: {xs: 'right', sm: 'left'}}}>\n {shownFile.name}\n </FileUploadName>\n </Tooltip>\n )}\n {actions}\n <FileUploadStatus\n size=\"small\"\n color={STATUS_COLORS[status]}\n variant={status === FILE_UPLOAD_STATUS.pending ? 'filled' : 'outlined'}\n label={statusLabel}\n icon={(isUploading && (\n <CircularProgress size={12} color=\"inherit\" variant={isProcessing ? 'indeterminate' : 'determinate'} value={progress ?? 0} />\n )) || (isUploaded && <CheckCircleRoundedIcon />) || undefined}\n ownSx={{flexShrink: 0}}\n />\n {isUploading ? (\n <FileUploadButton size=\"small\" color=\"inherit\" onClick={cancel} ownSx={{flexShrink: 0}}>{t('upload.cancel')}</FileUploadButton>\n ) : (\n // describeChild: lo que acepta se lee como descripción; el nombre sigue siendo «Cargar» y el documento\n <Tooltip title={buttonHint} describeChild>\n <FileUploadButton\n size=\"small\"\n variant={isUploaded ? 'outlined' : 'contained'}\n startIcon={<FileUploadOutlinedIcon />}\n disabled={disabled}\n onClick={picker.open}\n aria-labelledby={label ? `${buttonTextId} ${labelId}` : undefined}\n ownSx={{flexShrink: 0}}\n >\n <span id={buttonTextId}>{isUploaded ? t('upload.replace') : t('upload.upload')}</span>\n </FileUploadButton>\n </Tooltip>\n )}\n {isUploaded && download && (\n <Tooltip title={t('upload.download')}>\n <IconButton size=\"small\" aria-label={t('upload.download')} onClick={downloadUploaded}>\n <FileDownloadOutlinedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n {isUploaded && !disabled && (\n <Tooltip title={t('upload.remove', {name: shownFile?.name ?? ''})}>\n <IconButton size=\"small\" aria-label={t('upload.remove', {name: shownFile?.name ?? ''})} onClick={remove}>\n <CloseRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </FileUploadRoot>\n {/* abajo: el error manda; si no, el avance; si no, la ayuda de la pantalla */}\n <FileUploadHelper error={Boolean(errorText)} role={errorText ? 'alert' : (progressText ? 'status' : undefined)}\n ownSx={{textAlign: 'right', mx: 0}}>\n {errorText ?? progressText ?? helperText}\n </FileUploadHelper>\n </div>\n );\n\n // sin etiqueta, el renglón va solo (la pantalla pone el título del documento a su manera)\n if (!label) {\n return row;\n }\n return <FieldFrame inputId={inputId} labelId={labelId} label={label}>{row}</FieldFrame>;\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst FileUploadInput = withPieceSlots(FileUploadInputContent, THEME_NAME);\nexport default FileUploadInput;\n"],"names":["result","transfer"],"mappings":"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"}
@@ -7,9 +7,9 @@ import ButtonBase from "@mui/material/ButtonBase";
7
7
  import FormHelperText from "@mui/material/FormHelperText";
8
8
  import Stack from "@mui/material/Stack";
9
9
  import AddPhotoAlternateOutlinedIcon from "@mui/icons-material/AddPhotoAlternateOutlined";
10
- import { translateValidationMessage } from "../forms/validationMessages.js";
10
+ import { useValidationText } from "../forms/useValidationText.js";
11
11
  import FieldFrame from "../inputs/FieldFrame.js";
12
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
12
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
13
13
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
14
14
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
15
15
  import { useFilePicker } from "./useFilePicker.js";
@@ -38,7 +38,7 @@ function usePreviewUrl(value) {
38
38
  }
39
39
  return typeof value === "string" && value ? value : null;
40
40
  }
41
- function ImageInput(props) {
41
+ function ImageInputContent(props) {
42
42
  const {
43
43
  name,
44
44
  label,
@@ -59,14 +59,16 @@ function ImageInput(props) {
59
59
  busy = false,
60
60
  onReject,
61
61
  sx,
62
+ messages,
62
63
  texts,
63
64
  ...unknownProps
64
65
  } = usePieceProps(props, THEME_NAME);
65
66
  warnUnknownProps(THEME_NAME, unknownProps);
66
67
  const { t } = useToolkitTranslation("common", texts);
68
+ const validationTextOf = useValidationText({ name, label, messages });
67
69
  const generatedId = useId();
68
70
  const previewId = `${name ?? "image"}-${generatedId}`;
69
- const errorText = translateValidationMessage(t, error);
71
+ const errorText = validationTextOf(error);
70
72
  const isLocked = disabled || busy;
71
73
  const previewUrl = usePreviewUrl(value);
72
74
  const change = (file) => {
@@ -76,7 +78,7 @@ function ImageInput(props) {
76
78
  const picker = useFilePicker({ accept, maxSize, disabled: isLocked, onAccept: change, onReject, texts });
77
79
  const pickText = chooseLabel ?? t(value ? "upload.changeImage" : "upload.chooseImage");
78
80
  return /* @__PURE__ */ jsx(FieldFrame, { inputId: previewId, label, children: /* @__PURE__ */ jsxs("div", { children: [
79
- /* @__PURE__ */ jsxs(ImageRoot, { direction: "row", "aria-busy": busy, ownSx: { alignItems: "center", gap: 2, ...sx }, children: [
81
+ /* @__PURE__ */ jsxs(ImageRoot, { direction: "row", "aria-busy": busy, ownSx: { alignItems: "center", gap: 2 }, sx, children: [
80
82
  /* @__PURE__ */ jsx("input", { ...picker.inputProps, name, "aria-hidden": "true", tabIndex: -1 }),
81
83
  /* @__PURE__ */ jsx(
82
84
  ImagePreview,
@@ -118,6 +120,7 @@ function ImageInput(props) {
118
120
  /* @__PURE__ */ jsx(FormHelperText, { error: Boolean(errorText), children: errorText ?? helperText })
119
121
  ] }) });
120
122
  }
123
+ const ImageInput = withPieceSlots(ImageInputContent, THEME_NAME);
121
124
  export {
122
125
  IMAGE_SHAPE,
123
126
  ImageInput as default
@@ -1 +1 @@
1
- {"version":3,"file":"ImageInput.js","sources":["../../src/upload/ImageInput.jsx"],"sourcesContent":["// Una imagen con su vista previa: la foto de un perfil (círculo) o la de un producto o una sucursal (recuadro). Se pica la\n// vista previa o «Elegir imagen» para abrir la ventana de archivos, o se suelta la imagen encima; «Quitar la imagen» la\n// borra. Dentro de una FormSection se vuelve renglón, como los demás campos.\n//\n// Solo ELIGE (controlado), con las reglas de los demás cargadores (accept, por omisión imágenes; maxSize; useFilePicker).\n// value es la imagen nueva (File), la que ya está guardada (su dirección, en texto) o null; onChange recibe File o null.\n// Enviarla es de la pantalla.\n//\n// La vista previa de un archivo nuevo se pinta en el navegador, sin subirlo (URL.createObjectURL); se libera al cambiarla.\n//\n// Huecos: shape (IMAGE_SHAPE), size, placeholder (lo que se ve sin imagen: las iniciales de la persona, por ejemplo), alt,\n// los textos de los botones y texts. Con formik: FormImageField; con react-hook-form, el del mismo nombre.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaImageInput con defaultProps y\n// styleOverrides de sus partes: root, preview, image, placeholder, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useId, useState} from 'react';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport Stack from '@mui/material/Stack';\nimport AddPhotoAlternateOutlinedIcon from '@mui/icons-material/AddPhotoAlternateOutlined';\n\nimport {translateValidationMessage} from '@/forms/validationMessages.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\nimport {useFilePicker} from '@/upload/useFilePicker.js';\n\n/** La forma de la vista previa: círculo para una persona, recuadro para lo demás. */\nexport const IMAGE_SHAPE = Object.freeze({circle: 'circle', rounded: 'rounded'});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaImageInput)\nconst THEME_NAME = 'CalcitaImageInput';\nconst ImageRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst ImagePreview = piecePart(THEME_NAME, 'Preview', ButtonBase);\nconst ImagePicture = piecePart(THEME_NAME, 'Image', 'img');\nconst ImagePlaceholder = piecePart(THEME_NAME, 'Placeholder', Box);\nconst ImageActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n// el tamaño de la vista previa si la pantalla no dice otro (como un avatar grande de perfil)\nconst DEFAULT_PREVIEW_SIZE = 96;\n\n/**\n * La dirección de la vista previa: la de un archivo nuevo se crea en el navegador y se libera al cambiar; la guardada se\n * usa tal cual.\n *\n * @param {File|string|null} value\n * @returns {string|null}\n */\nfunction usePreviewUrl(value) {\n const [fileUrl, setFileUrl] = useState(null);\n const isFile = typeof File !== 'undefined' && value instanceof File;\n\n useEffect(() => {\n if (!isFile) {\n setFileUrl(null);\n return undefined;\n }\n const url = URL.createObjectURL(value);\n setFileUrl(url);\n return () => URL.revokeObjectURL(url);\n }, [isFile, value]);\n\n if (isFile) {\n return fileUrl;\n }\n return typeof value === 'string' && value ? value : null;\n}\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {import('react').ReactNode} [props.label] ya traducida\n * @param {File|string|null} [props.value] la imagen nueva, la dirección de la que ya está guardada o null\n * @param {(file: File|null) => void} props.onChange null al quitarla\n * @param {() => void} [props.onBlur] se llama al elegir o quitar (para que el formulario lo marque como tocado)\n * @param {'circle'|'rounded'} [props.shape] IMAGE_SHAPE; por omisión, círculo\n * @param {number} [props.size] el lado de la vista previa en px; por omisión 96\n * @param {string} [props.alt] ya traducido: qué se ve en la imagen (por omisión, la etiqueta)\n * @param {import('react').ReactNode} [props.placeholder] lo que se ve sin imagen; por omisión, un ícono\n * @param {string|string[]} [props.accept] por omisión, cualquier imagen\n * @param {number|string} [props.maxSize] bytes o '2 MB'\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ya traducida (p. ej. «JPG o PNG, cuadrada, hasta 2 MB»)\n * @param {string} [props.chooseLabel] ya traducido; por omisión «Elegir imagen» (o «Cambiar la imagen» si ya hay una)\n * @param {string} [props.removeLabel] ya traducido; por omisión «Quitar la imagen»\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.busy] candado mientras se sube\n * @param {(file: File, reason: string) => void} [props.onReject] reason es uno de FILE_REJECTION; sin él, un aviso\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 ImageInput(props) {\n const {\n name, label, value = null, onChange, onBlur, shape = IMAGE_SHAPE.circle, size = DEFAULT_PREVIEW_SIZE, alt, placeholder,\n accept = 'image', maxSize, error, helperText = ' ', chooseLabel, removeLabel, disabled = false, busy = false, onReject, sx, 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 previewId = `${name ?? 'image'}-${generatedId}`;\n const errorText = translateValidationMessage(t, error);\n const isLocked = disabled || busy;\n const previewUrl = usePreviewUrl(value);\n const change = (file) => {\n onChange(file);\n onBlur?.();\n };\n const picker = useFilePicker({accept, maxSize, disabled: isLocked, onAccept: change, onReject, texts});\n const pickText = chooseLabel ?? t(value ? 'upload.changeImage' : 'upload.chooseImage');\n\n return (\n <FieldFrame inputId={previewId} label={label}>\n <div>\n <ImageRoot direction=\"row\" aria-busy={busy} ownSx={{alignItems: 'center', gap: 2, ...sx}}>\n <input {...picker.inputProps} name={name} aria-hidden=\"true\" tabIndex={-1} />\n <ImagePreview\n id={previewId}\n onClick={picker.open}\n disabled={isLocked}\n aria-label={pickText}\n {...picker.dropHandlers}\n ownSx={{\n width: size, height: size, flexShrink: 0, overflow: 'hidden',\n borderRadius: shape === IMAGE_SHAPE.circle ? '50%' : 2,\n bgcolor: 'action.hover', color: 'text.secondary',\n outline: picker.isDragging ? 2 : 0, outlineStyle: 'dashed', outlineColor: 'primary.main', outlineOffset: 2,\n '&.Mui-focusVisible': {outline: 2, outlineStyle: 'solid', outlineColor: 'primary.main', outlineOffset: 2},\n }}\n >\n {previewUrl ? (\n <ImagePicture src={previewUrl} alt={alt ?? (typeof label === 'string' ? label : '')}\n ownSx={{width: '100%', height: '100%', objectFit: 'cover', display: 'block'}} />\n ) : (\n <ImagePlaceholder ownSx={{display: 'grid', placeItems: 'center', width: '100%', height: '100%'}}>\n {placeholder ?? <AddPhotoAlternateOutlinedIcon />}\n </ImagePlaceholder>\n )}\n </ImagePreview>\n <ImageActions ownSx={{alignItems: 'flex-start', gap: 0.5}}>\n <Button size=\"small\" variant=\"outlined\" onClick={picker.open} disabled={isLocked}>{pickText}</Button>\n {value && (\n <Button size=\"small\" color=\"error\" onClick={() => change(null)} disabled={isLocked}>\n {removeLabel ?? t('upload.removeImage')}\n </Button>\n )}\n </ImageActions>\n </ImageRoot>\n <FormHelperText error={Boolean(errorText)}>{errorText ?? helperText}</FormHelperText>\n </div>\n </FieldFrame>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ImageInput.js","sources":["../../src/upload/ImageInput.jsx"],"sourcesContent":["// Una imagen con su vista previa: la foto de un perfil (círculo) o la de un producto o una sucursal (recuadro). Se pica la\n// vista previa o «Elegir imagen» para abrir la ventana de archivos, o se suelta la imagen encima; «Quitar la imagen» la\n// borra. Dentro de una FormSection se vuelve renglón, como los demás campos.\n//\n// Solo ELIGE (controlado), con las reglas de los demás cargadores (accept, por omisión imágenes; maxSize; useFilePicker).\n// value es la imagen nueva (File), la que ya está guardada (su dirección, en texto) o null; onChange recibe File o null.\n// Enviarla es de la pantalla.\n//\n// La vista previa de un archivo nuevo se pinta en el navegador, sin subirlo (URL.createObjectURL); se libera al cambiarla.\n//\n// Huecos: shape (IMAGE_SHAPE), size, placeholder (lo que se ve sin imagen: las iniciales de la persona, por ejemplo), alt,\n// los textos de los botones y texts. Con formik: FormImageField; con react-hook-form, el del mismo nombre.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaImageInput con defaultProps y\n// styleOverrides de sus partes: root, preview, image, placeholder, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useId, useState} from 'react';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport Stack from '@mui/material/Stack';\nimport AddPhotoAlternateOutlinedIcon from '@mui/icons-material/AddPhotoAlternateOutlined';\n\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\nimport {useFilePicker} from '@/upload/useFilePicker.js';\n\n/** La forma de la vista previa: círculo para una persona, recuadro para lo demás. */\nexport const IMAGE_SHAPE = Object.freeze({circle: 'circle', rounded: 'rounded'});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaImageInput)\nconst THEME_NAME = 'CalcitaImageInput';\nconst ImageRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst ImagePreview = piecePart(THEME_NAME, 'Preview', ButtonBase);\nconst ImagePicture = piecePart(THEME_NAME, 'Image', 'img');\nconst ImagePlaceholder = piecePart(THEME_NAME, 'Placeholder', Box);\nconst ImageActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n// el tamaño de la vista previa si la pantalla no dice otro (como un avatar grande de perfil)\nconst DEFAULT_PREVIEW_SIZE = 96;\n\n/**\n * La dirección de la vista previa: la de un archivo nuevo se crea en el navegador y se libera al cambiar; la guardada se\n * usa tal cual.\n *\n * @param {File|string|null} value\n * @returns {string|null}\n */\nfunction usePreviewUrl(value) {\n const [fileUrl, setFileUrl] = useState(null);\n const isFile = typeof File !== 'undefined' && value instanceof File;\n\n useEffect(() => {\n if (!isFile) {\n setFileUrl(null);\n return undefined;\n }\n const url = URL.createObjectURL(value);\n setFileUrl(url);\n return () => URL.revokeObjectURL(url);\n }, [isFile, value]);\n\n if (isFile) {\n return fileUrl;\n }\n return typeof value === 'string' && value ? value : null;\n}\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {import('react').ReactNode} [props.label] ya traducida\n * @param {File|string|null} [props.value] la imagen nueva, la dirección de la que ya está guardada o null\n * @param {(file: File|null) => void} props.onChange null al quitarla\n * @param {() => void} [props.onBlur] se llama al elegir o quitar (para que el formulario lo marque como tocado)\n * @param {'circle'|'rounded'} [props.shape] IMAGE_SHAPE; por omisión, círculo\n * @param {number} [props.size] el lado de la vista previa en px; por omisión 96\n * @param {string} [props.alt] ya traducido: qué se ve en la imagen (por omisión, la etiqueta)\n * @param {import('react').ReactNode} [props.placeholder] lo que se ve sin imagen; por omisión, un ícono\n * @param {string|string[]} [props.accept] por omisión, cualquier imagen\n * @param {number|string} [props.maxSize] bytes o '2 MB'\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ya traducida (p. ej. «JPG o PNG, cuadrada, hasta 2 MB»)\n * @param {string} [props.chooseLabel] ya traducido; por omisión «Elegir imagen» (o «Cambiar la imagen» si ya hay una)\n * @param {string} [props.removeLabel] ya traducido; por omisión «Quitar la imagen»\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.busy] candado mientras se sube\n * @param {(file: File, reason: string) => void} [props.onReject] reason es uno de FILE_REJECTION; sin él, un aviso\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 ImageInputContent(props) {\n const {\n name, label, value = null, onChange, onBlur, shape = IMAGE_SHAPE.circle, size = DEFAULT_PREVIEW_SIZE, alt, placeholder,\n accept = 'image', maxSize, error, helperText = ' ', chooseLabel, removeLabel, disabled = false, busy = false, onReject, 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({name, label, messages});\n const generatedId = useId();\n const previewId = `${name ?? 'image'}-${generatedId}`;\n const errorText = validationTextOf(error);\n const isLocked = disabled || busy;\n const previewUrl = usePreviewUrl(value);\n const change = (file) => {\n onChange(file);\n onBlur?.();\n };\n const picker = useFilePicker({accept, maxSize, disabled: isLocked, onAccept: change, onReject, texts});\n const pickText = chooseLabel ?? t(value ? 'upload.changeImage' : 'upload.chooseImage');\n\n return (\n <FieldFrame inputId={previewId} label={label}>\n <div>\n <ImageRoot direction=\"row\" aria-busy={busy} ownSx={{alignItems: 'center', gap: 2}} sx={sx}>\n <input {...picker.inputProps} name={name} aria-hidden=\"true\" tabIndex={-1} />\n <ImagePreview\n id={previewId}\n onClick={picker.open}\n disabled={isLocked}\n aria-label={pickText}\n {...picker.dropHandlers}\n ownSx={{\n width: size, height: size, flexShrink: 0, overflow: 'hidden',\n borderRadius: shape === IMAGE_SHAPE.circle ? '50%' : 2,\n bgcolor: 'action.hover', color: 'text.secondary',\n outline: picker.isDragging ? 2 : 0, outlineStyle: 'dashed', outlineColor: 'primary.main', outlineOffset: 2,\n '&.Mui-focusVisible': {outline: 2, outlineStyle: 'solid', outlineColor: 'primary.main', outlineOffset: 2},\n }}\n >\n {previewUrl ? (\n <ImagePicture src={previewUrl} alt={alt ?? (typeof label === 'string' ? label : '')}\n ownSx={{width: '100%', height: '100%', objectFit: 'cover', display: 'block'}} />\n ) : (\n <ImagePlaceholder ownSx={{display: 'grid', placeItems: 'center', width: '100%', height: '100%'}}>\n {placeholder ?? <AddPhotoAlternateOutlinedIcon />}\n </ImagePlaceholder>\n )}\n </ImagePreview>\n <ImageActions ownSx={{alignItems: 'flex-start', gap: 0.5}}>\n <Button size=\"small\" variant=\"outlined\" onClick={picker.open} disabled={isLocked}>{pickText}</Button>\n {value && (\n <Button size=\"small\" color=\"error\" onClick={() => change(null)} disabled={isLocked}>\n {removeLabel ?? t('upload.removeImage')}\n </Button>\n )}\n </ImageActions>\n </ImageRoot>\n <FormHelperText error={Boolean(errorText)}>{errorText ?? helperText}</FormHelperText>\n </div>\n </FieldFrame>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst ImageInput = withPieceSlots(ImageInputContent, THEME_NAME);\nexport default ImageInput;\n"],"names":[],"mappings":"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"}
@@ -3,12 +3,12 @@ import { jsx } from "react/jsx-runtime";
3
3
  import Button from "@mui/material/Button";
4
4
  import FileDownloadOutlinedIcon from "@mui/icons-material/FileDownloadOutlined";
5
5
  import { startDownload } from "../downloads/downloadQueue.js";
6
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
6
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
7
7
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
8
8
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
9
9
  const THEME_NAME = "CalcitaTemplateDownloadButton";
10
10
  const TemplateButtonRoot = piecePart(THEME_NAME, "Root", Button);
11
- function TemplateDownloadButton(props) {
11
+ function TemplateDownloadButtonContent(props) {
12
12
  const {
13
13
  href,
14
14
  fileName,
@@ -61,6 +61,7 @@ function TemplateDownloadButton(props) {
61
61
  }
62
62
  );
63
63
  }
64
+ const TemplateDownloadButton = withPieceSlots(TemplateDownloadButtonContent, THEME_NAME);
64
65
  export {
65
66
  TemplateDownloadButton as default
66
67
  };
@@ -1 +1 @@
1
- {"version":3,"file":"TemplateDownloadButton.js","sources":["../../src/upload/TemplateDownloadButton.jsx"],"sourcesContent":["// «Descargar la plantilla»: el botón que va junto a un cargador para bajar el formato que el archivo debe seguir (el Excel\n// con sus columnas, el CSV de ejemplo). Los cargadores del paquete lo ponen en su lugar con su prop `template`; también se\n// usa suelto.\n//\n// Dos formas de bajarlo:\n// href un archivo fijo (public/plantillas/inventario.xlsx): un enlace de descarga, sin pasar por el panel.\n// request lo arma o lo da el API: va por startDownload, así sale en el panel de descargas con su avance y, si el\n// servidor dice que no, su motivo.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTemplateDownloadButton con defaultProps y\n// styleOverrides de su parte root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport Button from '@mui/material/Button';\nimport FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';\n\nimport {startDownload} from '@/downloads/downloadQueue.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaTemplateDownloadButton)\nconst THEME_NAME = 'CalcitaTemplateDownloadButton';\nconst TemplateButtonRoot = piecePart(THEME_NAME, 'Root', Button);\n\n/**\n * @param {object} props\n * @param {string} [props.href] un archivo fijo; se baja con un enlace\n * @param {string} [props.fileName] con href: con qué nombre se guarda (por omisión, el del archivo)\n * @param {(transferOptions: {signal: AbortSignal, onDownloadProgress: (progress: {loaded: number, total?: number|null}) => void}) => Promise<{blob: Blob, fileName: string}>} [props.request]\n * lo pide al API y va al panel de descargas (startDownload)\n * @param {string} [props.format] con request: el tipo de archivo, para su ícono en el panel (xlsx, csv…)\n * @param {string} [props.label] ya traducido; por omisión «Descargar la plantilla»\n * @param {() => void} [props.onDownload] al empezar la descarga (para medir cuántos la bajan, por ejemplo)\n * @param {'text'|'outlined'|'contained'} [props.variant]\n * @param {'small'|'medium'|'large'} [props.size]\n * @param {boolean} [props.disabled]\n * @param {import('react').ReactNode} [props.startIcon] por omisión, la flecha de descarga\n * @param {object} [props.sx]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common`\n */\nexport default function TemplateDownloadButton(props) {\n const {\n href, fileName, request, format, label, onDownload, variant = 'text', size, disabled = false, startIcon, sx, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const text = label ?? t('upload.template');\n const icon = startIcon ?? <FileDownloadOutlinedIcon />;\n\n // un archivo fijo: el enlace del navegador (download con su nombre)\n if (href) {\n return (\n <TemplateButtonRoot component=\"a\" href={href} download={fileName ?? true} variant={variant} size={size} disabled={disabled} startIcon={icon}\n onClick={onDownload} sx={sx}>\n {text}\n </TemplateButtonRoot>\n );\n }\n\n return (\n <TemplateButtonRoot\n variant={variant}\n size={size}\n disabled={disabled || !request}\n startIcon={icon}\n sx={sx}\n onClick={() => {\n onDownload?.();\n startDownload({label: text, format, request});\n }}\n >\n {text}\n </TemplateButtonRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAsBA,MAAM,aAAa;AACnB,MAAM,qBAAqB,UAAU,YAAY,QAAQ,MAAM;AAkB/D,SAAwB,uBAAuB,OAAO;AAClD,QAAM;AAAA,IACF;AAAA,IAAM;AAAA,IAAU;AAAA,IAAS;AAAA,IAAQ;AAAA,IAAO;AAAA,IAAY,UAAU;AAAA,IAAQ;AAAA,IAAM,WAAW;AAAA,IAAO;AAAA,IAAW;AAAA,IAAI;AAAA,IAC7G,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AACnC,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,OAAO,SAAS,EAAE,iBAAiB;AACzC,QAAM,OAAO,aAAa,oBAAC,0BAAA,CAAA,CAAyB;AAGpD,MAAI,MAAM;AACN,WACI;AAAA,MAAC;AAAA,MAAA;AAAA,QAAmB,WAAU;AAAA,QAAI;AAAA,QAAY,UAAU,YAAY;AAAA,QAAM;AAAA,QAAkB;AAAA,QAAY;AAAA,QAAoB,WAAW;AAAA,QACnH,SAAS;AAAA,QAAY;AAAA,QACpC,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGb;AAEA,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACG;AAAA,MACA;AAAA,MACA,UAAU,YAAY,CAAC;AAAA,MACvB,WAAW;AAAA,MACX;AAAA,MACA,SAAS,MAAM;AACX,qBAAA;AACA,sBAAc,EAAC,OAAO,MAAM,QAAQ,SAAQ;AAAA,MAChD;AAAA,MAEC,UAAA;AAAA,IAAA;AAAA,EAAA;AAGb;"}
1
+ {"version":3,"file":"TemplateDownloadButton.js","sources":["../../src/upload/TemplateDownloadButton.jsx"],"sourcesContent":["// «Descargar la plantilla»: el botón que va junto a un cargador para bajar el formato que el archivo debe seguir (el Excel\n// con sus columnas, el CSV de ejemplo). Los cargadores del paquete lo ponen en su lugar con su prop `template`; también se\n// usa suelto.\n//\n// Dos formas de bajarlo:\n// href un archivo fijo (public/plantillas/inventario.xlsx): un enlace de descarga, sin pasar por el panel.\n// request lo arma o lo da el API: va por startDownload, así sale en el panel de descargas con su avance y, si el\n// servidor dice que no, su motivo.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTemplateDownloadButton con defaultProps y\n// styleOverrides de su parte root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport Button from '@mui/material/Button';\nimport FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';\n\nimport {startDownload} from '@/downloads/downloadQueue.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaTemplateDownloadButton)\nconst THEME_NAME = 'CalcitaTemplateDownloadButton';\nconst TemplateButtonRoot = piecePart(THEME_NAME, 'Root', Button);\n\n/**\n * @param {object} props\n * @param {string} [props.href] un archivo fijo; se baja con un enlace\n * @param {string} [props.fileName] con href: con qué nombre se guarda (por omisión, el del archivo)\n * @param {(transferOptions: {signal: AbortSignal, onDownloadProgress: (progress: {loaded: number, total?: number|null}) => void}) => Promise<{blob: Blob, fileName: string}>} [props.request]\n * lo pide al API y va al panel de descargas (startDownload)\n * @param {string} [props.format] con request: el tipo de archivo, para su ícono en el panel (xlsx, csv…)\n * @param {string} [props.label] ya traducido; por omisión «Descargar la plantilla»\n * @param {() => void} [props.onDownload] al empezar la descarga (para medir cuántos la bajan, por ejemplo)\n * @param {'text'|'outlined'|'contained'} [props.variant]\n * @param {'small'|'medium'|'large'} [props.size]\n * @param {boolean} [props.disabled]\n * @param {import('react').ReactNode} [props.startIcon] por omisión, la flecha de descarga\n * @param {object} [props.sx]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common`\n */\nfunction TemplateDownloadButtonContent(props) {\n const {\n href, fileName, request, format, label, onDownload, variant = 'text', size, disabled = false, startIcon, sx, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const text = label ?? t('upload.template');\n const icon = startIcon ?? <FileDownloadOutlinedIcon />;\n\n // un archivo fijo: el enlace del navegador (download con su nombre)\n if (href) {\n return (\n <TemplateButtonRoot component=\"a\" href={href} download={fileName ?? true} variant={variant} size={size} disabled={disabled} startIcon={icon}\n onClick={onDownload} sx={sx}>\n {text}\n </TemplateButtonRoot>\n );\n }\n\n return (\n <TemplateButtonRoot\n variant={variant}\n size={size}\n disabled={disabled || !request}\n startIcon={icon}\n sx={sx}\n onClick={() => {\n onDownload?.();\n startDownload({label: text, format, request});\n }}\n >\n {text}\n </TemplateButtonRoot>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst TemplateDownloadButton = withPieceSlots(TemplateDownloadButtonContent, THEME_NAME);\nexport default TemplateDownloadButton;\n"],"names":[],"mappings":";;;;;;;;AAsBA,MAAM,aAAa;AACnB,MAAM,qBAAqB,UAAU,YAAY,QAAQ,MAAM;AAkB/D,SAAS,8BAA8B,OAAO;AAC1C,QAAM;AAAA,IACF;AAAA,IAAM;AAAA,IAAU;AAAA,IAAS;AAAA,IAAQ;AAAA,IAAO;AAAA,IAAY,UAAU;AAAA,IAAQ;AAAA,IAAM,WAAW;AAAA,IAAO;AAAA,IAAW;AAAA,IAAI;AAAA,IAC7G,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AACnC,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,OAAO,SAAS,EAAE,iBAAiB;AACzC,QAAM,OAAO,aAAa,oBAAC,0BAAA,CAAA,CAAyB;AAGpD,MAAI,MAAM;AACN,WACI;AAAA,MAAC;AAAA,MAAA;AAAA,QAAmB,WAAU;AAAA,QAAI;AAAA,QAAY,UAAU,YAAY;AAAA,QAAM;AAAA,QAAkB;AAAA,QAAY;AAAA,QAAoB,WAAW;AAAA,QACnH,SAAS;AAAA,QAAY;AAAA,QACpC,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGb;AAEA,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACG;AAAA,MACA;AAAA,MACA,UAAU,YAAY,CAAC;AAAA,MACvB,WAAW;AAAA,MACX;AAAA,MACA,SAAS,MAAM;AACX,qBAAA;AACA,sBAAc,EAAC,OAAO,MAAM,QAAQ,SAAQ;AAAA,MAChD;AAAA,MAEC,UAAA;AAAA,IAAA;AAAA,EAAA;AAGb;AAGA,MAAM,yBAAyB,eAAe,+BAA+B,UAAU;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackcraftmx/calcita",
3
- "version": "0.47.0",
3
+ "version": "0.51.0",
4
4
  "description": "Componentes y utilidades de React con MUI para arrancar proyectos rápido: tabla de servidor, diálogos, avisos, descargas, formularios, formatos y reportes en Excel.",
5
5
  "license": "FSL-1.1-MIT",
6
6
  "author": "calcifux",
@@ -1,31 +0,0 @@
1
- // Junta los textos de cada módulo en el objeto `texts` que recibe ToolkitProvider: {es: {namespace: {...}}, en: {...}}.
2
- //
3
- // Cada módulo trae sus archivos de textos (*Texts.js) con su namespace. Aquí se juntan por idioma y por namespace; dos
4
- // archivos con el mismo namespace suman sus llaves, y si repiten una llave truena: un texto pisado en silencio saldría en
5
- // la pantalla equivocada.
6
- //
7
- // Funciones puras, sin React: function (regla de la casa).
8
-
9
- /**
10
- * @param {Array<Record<string, Record<string, object>>>} textFiles los textos de cada archivo, por idioma
11
- * @returns {Record<string, Record<string, object>>} todos los textos, por idioma y namespace
12
- */
13
- export function combineTexts(textFiles) {
14
- const combined = {};
15
-
16
- for (const fileTexts of textFiles) {
17
- for (const [language, namespaces] of Object.entries(fileTexts)) {
18
- combined[language] ??= {};
19
- for (const [namespace, keys] of Object.entries(namespaces)) {
20
- const currentKeys = combined[language][namespace] ?? {};
21
- const repeatedKey = Object.keys(keys).find((key) => Object.hasOwn(currentKeys, key));
22
- if (repeatedKey) {
23
- throw new Error(`Dos archivos definen el texto «${namespace}:${repeatedKey}» en «${language}»`);
24
- }
25
- combined[language][namespace] = {...currentKeys, ...keys};
26
- }
27
- }
28
- }
29
-
30
- return combined;
31
- }