@stackcraftmx/calcita 0.32.2 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (680) hide show
  1. package/README.md +426 -4
  2. package/cli/calcita.js +15 -0
  3. package/cli/checkTexts.js +209 -0
  4. package/cli/packageVersions.js +17 -3
  5. package/cli/projectFiles.js +7 -2
  6. package/cli/templates/module/__Name__Page.test.jsx.tpl +24 -0
  7. package/cli/templates/project/README.md.tpl +35 -2
  8. package/cli/templates/project/eslint.config.js.tpl +27 -0
  9. package/cli/templates/project/src/app/appRouter.jsx.tpl +5 -2
  10. package/cli/templates/project/src/app/appTexts.js.tpl +2 -1
  11. package/cli/templates/project/src/core/accountConnector.js.tpl +4 -2
  12. package/cli/templates/project/src/core/publicPaths.js.tpl +10 -2
  13. package/cli/templates/project/src/modules/auth/SignInPage.test.jsx.tpl +20 -0
  14. package/cli/templates/project/src/modules/home/HomePage.test.jsx.tpl +16 -0
  15. package/cli/templates/project/src/testing/browserGaps.js.tpl +70 -0
  16. package/cli/templates/project/src/testing/openScreen.jsx.tpl +58 -0
  17. package/cli/templates/project/src/testing/setup.js.tpl +25 -0
  18. package/cli/templates/project/vite.config.js.tpl +20 -1
  19. package/dist/DataTable/AuditTrailDialog.js +3 -2
  20. package/dist/DataTable/AuditTrailDialog.js.map +1 -1
  21. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +3 -2
  22. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
  23. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +3 -2
  24. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
  25. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +3 -2
  26. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
  27. package/dist/DataTable/EmptyState.js +3 -2
  28. package/dist/DataTable/EmptyState.js.map +1 -1
  29. package/dist/DataTable/FilterChips.js +3 -2
  30. package/dist/DataTable/FilterChips.js.map +1 -1
  31. package/dist/DataTable/GoToPage.js +71 -14
  32. package/dist/DataTable/GoToPage.js.map +1 -1
  33. package/dist/DataTable/ServerTable.js +97 -28
  34. package/dist/DataTable/ServerTable.js.map +1 -1
  35. package/dist/DataTable/ServerTableFilterDrawer.js +57 -0
  36. package/dist/DataTable/ServerTableFilterDrawer.js.map +1 -0
  37. package/dist/DataTable/StackedCell.js +60 -0
  38. package/dist/DataTable/StackedCell.js.map +1 -0
  39. package/dist/DataTable/TableCardsView.js +88 -0
  40. package/dist/DataTable/TableCardsView.js.map +1 -0
  41. package/dist/DataTable/columnWidths.js +30 -0
  42. package/dist/DataTable/columnWidths.js.map +1 -0
  43. package/dist/DataTable/columns.js +47 -1
  44. package/dist/DataTable/columns.js.map +1 -1
  45. package/dist/DataTable/filterContext.js.map +1 -1
  46. package/dist/DataTable/fixedColumns.js +24 -0
  47. package/dist/DataTable/fixedColumns.js.map +1 -0
  48. package/dist/DataTable/goToPageOptions.js +17 -0
  49. package/dist/DataTable/goToPageOptions.js.map +1 -0
  50. package/dist/DataTable/useTableView.js +29 -0
  51. package/dist/DataTable/useTableView.js.map +1 -0
  52. package/dist/access/PermissionMatrix.js +3 -2
  53. package/dist/access/PermissionMatrix.js.map +1 -1
  54. package/dist/account/AccountProvider.js +1 -1
  55. package/dist/account/AccountSecuritySection.js +3 -2
  56. package/dist/account/AccountSecuritySection.js.map +1 -1
  57. package/dist/account/DemoTotpCodeButton.js +3 -2
  58. package/dist/account/DemoTotpCodeButton.js.map +1 -1
  59. package/dist/account/ProfileScreen.js +3 -2
  60. package/dist/account/ProfileScreen.js.map +1 -1
  61. package/dist/account/SignInScreen.js +3 -2
  62. package/dist/account/SignInScreen.js.map +1 -1
  63. package/dist/appShell/AccountMenu.js +3 -2
  64. package/dist/appShell/AccountMenu.js.map +1 -1
  65. package/dist/appShell/AppLayout.js +3 -2
  66. package/dist/appShell/AppLayout.js.map +1 -1
  67. package/dist/appShell/AppearanceSettings.js +3 -2
  68. package/dist/appShell/AppearanceSettings.js.map +1 -1
  69. package/dist/appShell/AuthLayout.js +3 -2
  70. package/dist/appShell/AuthLayout.js.map +1 -1
  71. package/dist/appShell/BarActionButton.js +11 -4
  72. package/dist/appShell/BarActionButton.js.map +1 -1
  73. package/dist/appShell/BarActions.js +3 -2
  74. package/dist/appShell/BarActions.js.map +1 -1
  75. package/dist/appShell/BarCapsule.js +3 -2
  76. package/dist/appShell/BarCapsule.js.map +1 -1
  77. package/dist/appShell/BarSearch.js +3 -2
  78. package/dist/appShell/BarSearch.js.map +1 -1
  79. package/dist/appShell/HeaderTools.js +3 -2
  80. package/dist/appShell/HeaderTools.js.map +1 -1
  81. package/dist/appShell/MobileTabBar.js +3 -2
  82. package/dist/appShell/MobileTabBar.js.map +1 -1
  83. package/dist/appShell/SettingsMenu.js +3 -2
  84. package/dist/appShell/SettingsMenu.js.map +1 -1
  85. package/dist/appShell/SideMenu.js +3 -2
  86. package/dist/appShell/SideMenu.js.map +1 -1
  87. package/dist/appShell/SideMenuEntry.js +3 -2
  88. package/dist/appShell/SideMenuEntry.js.map +1 -1
  89. package/dist/appShell/SubmenuActionsMenu.js +3 -2
  90. package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
  91. package/dist/appShell/TabBarEditor.js +3 -2
  92. package/dist/appShell/TabBarEditor.js.map +1 -1
  93. package/dist/appShell/TopMenu.js +3 -2
  94. package/dist/appShell/TopMenu.js.map +1 -1
  95. package/dist/appShell/Wordmark.js +3 -2
  96. package/dist/appShell/Wordmark.js.map +1 -1
  97. package/dist/auth/PasswordChecklist.js +3 -2
  98. package/dist/auth/PasswordChecklist.js.map +1 -1
  99. package/dist/calendar/EventCalendar.js +3 -2
  100. package/dist/calendar/EventCalendar.js.map +1 -1
  101. package/dist/calendar/EventDetails.js +3 -2
  102. package/dist/calendar/EventDetails.js.map +1 -1
  103. package/dist/date-pickers.js +28 -2
  104. package/dist/date-pickers.js.map +1 -1
  105. package/dist/datePickers/DateInput.js +41 -54
  106. package/dist/datePickers/DateInput.js.map +1 -1
  107. package/dist/datePickers/DateTimeInput.js +81 -0
  108. package/dist/datePickers/DateTimeInput.js.map +1 -0
  109. package/dist/datePickers/FormDateTimeField.js +12 -0
  110. package/dist/datePickers/FormDateTimeField.js.map +1 -0
  111. package/dist/datePickers/FormMonthField.js +12 -0
  112. package/dist/datePickers/FormMonthField.js.map +1 -0
  113. package/dist/datePickers/FormTimeField.js +12 -0
  114. package/dist/datePickers/FormTimeField.js.map +1 -0
  115. package/dist/datePickers/MonthInput.js +64 -0
  116. package/dist/datePickers/MonthInput.js.map +1 -0
  117. package/dist/datePickers/PickerFrame.js +27 -0
  118. package/dist/datePickers/PickerFrame.js.map +1 -0
  119. package/dist/datePickers/TimeInput.js +61 -0
  120. package/dist/datePickers/TimeInput.js.map +1 -0
  121. package/dist/datePickers/dateTimeRules.js +24 -0
  122. package/dist/datePickers/dateTimeRules.js.map +1 -0
  123. package/dist/datePickers/pickerValues.js +106 -0
  124. package/dist/datePickers/pickerValues.js.map +1 -0
  125. package/dist/datePickers/useCurrentMinute.js +28 -0
  126. package/dist/datePickers/useCurrentMinute.js.map +1 -0
  127. package/dist/datePickers/usePickerField.js +23 -0
  128. package/dist/datePickers/usePickerField.js.map +1 -0
  129. package/dist/dictionaries/dictionaries.js +3 -1
  130. package/dist/dictionaries/dictionaries.js.map +1 -1
  131. package/dist/downloads/DownloadManager.js +3 -2
  132. package/dist/downloads/DownloadManager.js.map +1 -1
  133. package/dist/feedback/ConfirmDialog.js +3 -2
  134. package/dist/feedback/ConfirmDialog.js.map +1 -1
  135. package/dist/feedback/ModalWaiting.js +3 -2
  136. package/dist/feedback/ModalWaiting.js.map +1 -1
  137. package/dist/feedback/NewBuildNotice.js +3 -2
  138. package/dist/feedback/NewBuildNotice.js.map +1 -1
  139. package/dist/filepond/FileDropzone.js +3 -2
  140. package/dist/filepond/FileDropzone.js.map +1 -1
  141. package/dist/forms/FormAttachmentsField.js +12 -0
  142. package/dist/forms/FormAttachmentsField.js.map +1 -0
  143. package/dist/forms/FormCheckboxGroupField.js +12 -0
  144. package/dist/forms/FormCheckboxGroupField.js.map +1 -0
  145. package/dist/forms/FormFileField.js +12 -0
  146. package/dist/forms/FormFileField.js.map +1 -0
  147. package/dist/forms/FormFileUploadField.js +12 -0
  148. package/dist/forms/FormFileUploadField.js.map +1 -0
  149. package/dist/forms/FormImageField.js +12 -0
  150. package/dist/forms/FormImageField.js.map +1 -0
  151. package/dist/forms/FormMaskedField.js +12 -0
  152. package/dist/forms/FormMaskedField.js.map +1 -0
  153. package/dist/forms/FormProblemAlert.js +3 -2
  154. package/dist/forms/FormProblemAlert.js.map +1 -1
  155. package/dist/forms/FormRepeatingFields.js +54 -0
  156. package/dist/forms/FormRepeatingFields.js.map +1 -0
  157. package/dist/forms/FormTransferListField.js +12 -0
  158. package/dist/forms/FormTransferListField.js.map +1 -0
  159. package/dist/forms/SubmitButton.js +7 -2
  160. package/dist/forms/SubmitButton.js.map +1 -1
  161. package/dist/forms/applyServerProblem.js +10 -3
  162. package/dist/forms/applyServerProblem.js.map +1 -1
  163. package/dist/forms/auth/SignInForm.js +3 -2
  164. package/dist/forms/auth/SignInForm.js.map +1 -1
  165. package/dist/forms/fieldRules.js +30 -0
  166. package/dist/forms/fieldRules.js.map +1 -0
  167. package/dist/forms/listRules.js +111 -0
  168. package/dist/forms/listRules.js.map +1 -0
  169. package/dist/forms/security/SecondStepForm.js +3 -2
  170. package/dist/forms/security/SecondStepForm.js.map +1 -1
  171. package/dist/forms/security/TwoStepVerificationCard.js +3 -2
  172. package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
  173. package/dist/forms/serverProblemFields.js +17 -0
  174. package/dist/forms/serverProblemFields.js.map +1 -1
  175. package/dist/forms/useValidationText.js +18 -0
  176. package/dist/forms/useValidationText.js.map +1 -0
  177. package/dist/forms/validation.js +35 -31
  178. package/dist/forms/validation.js.map +1 -1
  179. package/dist/forms/validationMessages.js +64 -7
  180. package/dist/forms/validationMessages.js.map +1 -1
  181. package/dist/forms.js +54 -29
  182. package/dist/forms.js.map +1 -1
  183. package/dist/hookForm/FormAttachmentsField.js +12 -0
  184. package/dist/hookForm/FormAttachmentsField.js.map +1 -0
  185. package/dist/hookForm/FormCheckboxGroupField.js +12 -0
  186. package/dist/hookForm/FormCheckboxGroupField.js.map +1 -0
  187. package/dist/hookForm/FormFileField.js +12 -0
  188. package/dist/hookForm/FormFileField.js.map +1 -0
  189. package/dist/hookForm/FormFileUploadField.js +12 -0
  190. package/dist/hookForm/FormFileUploadField.js.map +1 -0
  191. package/dist/hookForm/FormImageField.js +12 -0
  192. package/dist/hookForm/FormImageField.js.map +1 -0
  193. package/dist/hookForm/FormMaskedField.js +12 -0
  194. package/dist/hookForm/FormMaskedField.js.map +1 -0
  195. package/dist/hookForm/FormProblemAlert.js +3 -2
  196. package/dist/hookForm/FormProblemAlert.js.map +1 -1
  197. package/dist/hookForm/FormRepeatingFields.js +44 -0
  198. package/dist/hookForm/FormRepeatingFields.js.map +1 -0
  199. package/dist/hookForm/FormTransferListField.js +12 -0
  200. package/dist/hookForm/FormTransferListField.js.map +1 -0
  201. package/dist/hookForm/SubmitButton.js +7 -2
  202. package/dist/hookForm/SubmitButton.js.map +1 -1
  203. package/dist/hookForm/applyServerProblem.js +8 -3
  204. package/dist/hookForm/applyServerProblem.js.map +1 -1
  205. package/dist/inbox/InboxLayout.js +3 -2
  206. package/dist/inbox/InboxLayout.js.map +1 -1
  207. package/dist/inbox/MessageList.js +3 -2
  208. package/dist/inbox/MessageList.js.map +1 -1
  209. package/dist/inbox/MessageView.js +3 -2
  210. package/dist/inbox/MessageView.js.map +1 -1
  211. package/dist/index.js +235 -124
  212. package/dist/index.js.map +1 -1
  213. package/dist/inputs/CatalogInput.js +103 -29
  214. package/dist/inputs/CatalogInput.js.map +1 -1
  215. package/dist/inputs/CheckboxGroupInput.js +103 -0
  216. package/dist/inputs/CheckboxGroupInput.js.map +1 -0
  217. package/dist/inputs/ColorInput.js +7 -4
  218. package/dist/inputs/ColorInput.js.map +1 -1
  219. package/dist/inputs/FieldFrame.js +10 -4
  220. package/dist/inputs/FieldFrame.js.map +1 -1
  221. package/dist/inputs/FormSection.js +1 -1
  222. package/dist/inputs/MaskedInput.js +87 -0
  223. package/dist/inputs/MaskedInput.js.map +1 -0
  224. package/dist/inputs/NumberInput.js +41 -25
  225. package/dist/inputs/NumberInput.js.map +1 -1
  226. package/dist/inputs/RepeatingFields.js +180 -0
  227. package/dist/inputs/RepeatingFields.js.map +1 -0
  228. package/dist/inputs/SelectInput.js +50 -9
  229. package/dist/inputs/SelectInput.js.map +1 -1
  230. package/dist/inputs/TextInput.js +5 -3
  231. package/dist/inputs/TextInput.js.map +1 -1
  232. package/dist/inputs/TransferListInput.js +218 -0
  233. package/dist/inputs/TransferListInput.js.map +1 -0
  234. package/dist/inputs/WizardLayout.js +3 -2
  235. package/dist/inputs/WizardLayout.js.map +1 -1
  236. package/dist/inputs/inputMasks.js +84 -0
  237. package/dist/inputs/inputMasks.js.map +1 -0
  238. package/dist/inputs/selectAllState.js +20 -0
  239. package/dist/inputs/selectAllState.js.map +1 -0
  240. package/dist/inputs/useRowKeys.js +26 -0
  241. package/dist/inputs/useRowKeys.js.map +1 -0
  242. package/dist/kanban/KanbanBoard.js +3 -2
  243. package/dist/kanban/KanbanBoard.js.map +1 -1
  244. package/dist/legal/CookieNotice.js +80 -0
  245. package/dist/legal/CookieNotice.js.map +1 -0
  246. package/dist/legal/TermsAcceptanceDialog.js +130 -0
  247. package/dist/legal/TermsAcceptanceDialog.js.map +1 -0
  248. package/dist/legal/consentStorage.js +18 -0
  249. package/dist/legal/consentStorage.js.map +1 -0
  250. package/dist/legal/useCookieConsent.js +17 -0
  251. package/dist/legal/useCookieConsent.js.map +1 -0
  252. package/dist/locales/en.js +257 -1
  253. package/dist/locales/en.js.map +1 -1
  254. package/dist/locales/es.js +257 -1
  255. package/dist/locales/es.js.map +1 -1
  256. package/dist/maps/MapView.js +3 -2
  257. package/dist/maps/MapView.js.map +1 -1
  258. package/dist/mexico/CfdiSummary.js +82 -0
  259. package/dist/mexico/CfdiSummary.js.map +1 -0
  260. package/dist/mexico/EfirmaFields.js +168 -0
  261. package/dist/mexico/EfirmaFields.js.map +1 -0
  262. package/dist/mexico/certificateReader.js +79 -0
  263. package/dist/mexico/certificateReader.js.map +1 -0
  264. package/dist/mexico/cfdiReader.js +81 -0
  265. package/dist/mexico/cfdiReader.js.map +1 -0
  266. package/dist/mexico/derReader.js +81 -0
  267. package/dist/mexico/derReader.js.map +1 -0
  268. package/dist/mexico/efirmaKey.js +51 -0
  269. package/dist/mexico/efirmaKey.js.map +1 -0
  270. package/dist/mexico/mexicoIdentifiers.js +91 -0
  271. package/dist/mexico/mexicoIdentifiers.js.map +1 -0
  272. package/dist/mexico/mexicoRules.js +21 -0
  273. package/dist/mexico/mexicoRules.js.map +1 -0
  274. package/dist/mexico.js +34 -0
  275. package/dist/mexico.js.map +1 -0
  276. package/dist/pwa/InstallAppSetting.js +3 -2
  277. package/dist/pwa/InstallAppSetting.js.map +1 -1
  278. package/dist/pwa/InstallInstructionsDialog.js +3 -2
  279. package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
  280. package/dist/pwa/InstallPromptBanner.js +3 -2
  281. package/dist/pwa/InstallPromptBanner.js.map +1 -1
  282. package/dist/react-hook-form.js +43 -17
  283. package/dist/react-hook-form.js.map +1 -1
  284. package/dist/rich-text.js +19 -0
  285. package/dist/rich-text.js.map +1 -0
  286. package/dist/richText/FormRichTextField.js +12 -0
  287. package/dist/richText/FormRichTextField.js.map +1 -0
  288. package/dist/richText/RichTextEditor.js +111 -0
  289. package/dist/richText/RichTextEditor.js.map +1 -0
  290. package/dist/richText/RichTextLinkPopover.js +57 -0
  291. package/dist/richText/RichTextLinkPopover.js.map +1 -0
  292. package/dist/richText/RichTextToolbar.js +189 -0
  293. package/dist/richText/RichTextToolbar.js.map +1 -0
  294. package/dist/richText/RichTextView.js +27 -0
  295. package/dist/richText/RichTextView.js.map +1 -0
  296. package/dist/richText/richTextContentSx.js +42 -0
  297. package/dist/richText/richTextContentSx.js.map +1 -0
  298. package/dist/richText/richTextExtensions.js +44 -0
  299. package/dist/richText/richTextExtensions.js.map +1 -0
  300. package/dist/richText/richTextRules.js +46 -0
  301. package/dist/richText/richTextRules.js.map +1 -0
  302. package/dist/security/ActivityLog.js +3 -2
  303. package/dist/security/ActivityLog.js.map +1 -1
  304. package/dist/security/RecoveryCodesDialog.js +3 -2
  305. package/dist/security/RecoveryCodesDialog.js.map +1 -1
  306. package/dist/security/SessionsCard.js +3 -2
  307. package/dist/security/SessionsCard.js.map +1 -1
  308. package/dist/table.js +23 -2
  309. package/dist/table.js.map +1 -1
  310. package/dist/theme/components/glassComponents.js +27 -0
  311. package/dist/theme/components/glassComponents.js.map +1 -1
  312. package/dist/theme/components/minimalComponents.js +12 -0
  313. package/dist/theme/components/minimalComponents.js.map +1 -1
  314. package/dist/theme/themePieces.js +70 -4
  315. package/dist/theme/themePieces.js.map +1 -1
  316. package/dist/toolkit/ToolkitProvider.js +8 -1
  317. package/dist/toolkit/ToolkitProvider.js.map +1 -1
  318. package/dist/toolkit/browserNavigation.js +19 -4
  319. package/dist/toolkit/browserNavigation.js.map +1 -1
  320. package/dist/toolkit/combineTexts.js +32 -0
  321. package/dist/toolkit/combineTexts.js.map +1 -0
  322. package/dist/toolkit/hashNavigation.js +17 -3
  323. package/dist/toolkit/hashNavigation.js.map +1 -1
  324. package/dist/toolkit/navigationPaths.js +15 -0
  325. package/dist/toolkit/navigationPaths.js.map +1 -1
  326. package/dist/toolkit/pathIndex.js +66 -0
  327. package/dist/toolkit/pathIndex.js.map +1 -0
  328. package/dist/toolkit/toolkitSettings.js +19 -1
  329. package/dist/toolkit/toolkitSettings.js.map +1 -1
  330. package/dist/types/DataTable/AuditTrailDialog.d.ts +6 -17
  331. package/dist/types/DataTable/ColumnFilters/HeaderFilterPopover.d.ts +6 -5
  332. package/dist/types/DataTable/ColumnFilters/MultiSelectColumnFilter.d.ts +6 -9
  333. package/dist/types/DataTable/ColumnFilters/SortableFilterHeader.d.ts +6 -14
  334. package/dist/types/DataTable/EmptyState.d.ts +6 -9
  335. package/dist/types/DataTable/FilterChips.d.ts +6 -11
  336. package/dist/types/DataTable/GoToPage.d.ts +6 -9
  337. package/dist/types/DataTable/ServerTable.d.ts +16 -80
  338. package/dist/types/DataTable/ServerTableFilterDrawer.d.ts +14 -0
  339. package/dist/types/DataTable/StackedCell.d.ts +12 -0
  340. package/dist/types/DataTable/TableCardsView.d.ts +27 -0
  341. package/dist/types/DataTable/columnWidths.d.ts +21 -0
  342. package/dist/types/DataTable/columns.d.ts +111 -0
  343. package/dist/types/DataTable/filterContext.d.ts +2 -1
  344. package/dist/types/DataTable/fixedColumns.d.ts +29 -0
  345. package/dist/types/DataTable/goToPageOptions.d.ts +15 -0
  346. package/dist/types/DataTable/index.d.ts +7 -1
  347. package/dist/types/DataTable/useTableView.d.ts +22 -0
  348. package/dist/types/access/PermissionMatrix.d.ts +6 -10
  349. package/dist/types/account/AccountSecuritySection.d.ts +6 -7
  350. package/dist/types/account/DemoTotpCodeButton.d.ts +6 -5
  351. package/dist/types/account/ProfileScreen.d.ts +6 -18
  352. package/dist/types/account/SignInScreen.d.ts +6 -13
  353. package/dist/types/appShell/AccountMenu.d.ts +6 -11
  354. package/dist/types/appShell/AppLayout.d.ts +3 -40
  355. package/dist/types/appShell/AppearanceSettings.d.ts +6 -12
  356. package/dist/types/appShell/AuthLayout.d.ts +3 -11
  357. package/dist/types/appShell/BarActionButton.d.ts +6 -10
  358. package/dist/types/appShell/BarActions.d.ts +6 -15
  359. package/dist/types/appShell/BarCapsule.d.ts +6 -9
  360. package/dist/types/appShell/BarSearch.d.ts +6 -15
  361. package/dist/types/appShell/HeaderTools.d.ts +6 -16
  362. package/dist/types/appShell/MobileTabBar.d.ts +6 -13
  363. package/dist/types/appShell/SettingsMenu.d.ts +6 -10
  364. package/dist/types/appShell/SideMenu.d.ts +6 -20
  365. package/dist/types/appShell/SideMenuEntry.d.ts +6 -11
  366. package/dist/types/appShell/SubmenuActionsMenu.d.ts +6 -12
  367. package/dist/types/appShell/TabBarEditor.d.ts +6 -9
  368. package/dist/types/appShell/TopMenu.d.ts +6 -5
  369. package/dist/types/appShell/Wordmark.d.ts +6 -7
  370. package/dist/types/auth/PasswordChecklist.d.ts +6 -9
  371. package/dist/types/calendar/EventCalendar.d.ts +6 -23
  372. package/dist/types/calendar/EventDetails.d.ts +6 -10
  373. package/dist/types/date-pickers.d.ts +10 -1
  374. package/dist/types/datePickers/DateInput.d.ts +10 -23
  375. package/dist/types/datePickers/DateTimeInput.d.ts +30 -0
  376. package/dist/types/datePickers/FormDateTimeField.d.ts +7 -0
  377. package/dist/types/datePickers/FormMonthField.d.ts +7 -0
  378. package/dist/types/datePickers/FormTimeField.d.ts +7 -0
  379. package/dist/types/datePickers/MonthInput.d.ts +25 -0
  380. package/dist/types/datePickers/PickerFrame.d.ts +22 -0
  381. package/dist/types/datePickers/TimeInput.d.ts +24 -0
  382. package/dist/types/datePickers/dateTimeRules.d.ts +31 -0
  383. package/dist/types/datePickers/pickerValues.d.ts +114 -0
  384. package/dist/types/datePickers/useCurrentMinute.d.ts +5 -0
  385. package/dist/types/datePickers/usePickerField.d.ts +28 -0
  386. package/dist/types/dictionaries/dictionaries.d.ts +6 -3
  387. package/dist/types/downloads/DownloadManager.d.ts +6 -6
  388. package/dist/types/feedback/ConfirmDialog.d.ts +6 -18
  389. package/dist/types/feedback/ModalWaiting.d.ts +6 -9
  390. package/dist/types/feedback/NewBuildNotice.d.ts +6 -10
  391. package/dist/types/filepond/FileDropzone.d.ts +6 -29
  392. package/dist/types/forms/FormAttachmentsField.d.ts +7 -0
  393. package/dist/types/forms/FormCheckboxGroupField.d.ts +7 -0
  394. package/dist/types/forms/FormFileField.d.ts +7 -0
  395. package/dist/types/forms/FormFileUploadField.d.ts +7 -0
  396. package/dist/types/forms/FormImageField.d.ts +7 -0
  397. package/dist/types/forms/FormMaskedField.d.ts +7 -0
  398. package/dist/types/forms/FormProblemAlert.d.ts +6 -5
  399. package/dist/types/forms/FormRepeatingFields.d.ts +25 -0
  400. package/dist/types/forms/FormTransferListField.d.ts +7 -0
  401. package/dist/types/forms/SubmitButton.d.ts +6 -6
  402. package/dist/types/forms/auth/SignInForm.d.ts +6 -11
  403. package/dist/types/forms/fieldRules.d.ts +44 -0
  404. package/dist/types/forms/index.d.ts +11 -1
  405. package/dist/types/forms/listRules.d.ts +48 -0
  406. package/dist/types/forms/security/SecondStepForm.d.ts +6 -14
  407. package/dist/types/forms/security/TwoStepVerificationCard.d.ts +6 -21
  408. package/dist/types/forms/serverProblemFields.d.ts +13 -0
  409. package/dist/types/forms/useValidationText.d.ts +12 -0
  410. package/dist/types/forms/validation.d.ts +117 -174
  411. package/dist/types/forms/validationMessages.d.ts +54 -6
  412. package/dist/types/forms.d.ts +1 -1
  413. package/dist/types/hookForm/FormAttachmentsField.d.ts +8 -0
  414. package/dist/types/hookForm/FormCheckboxGroupField.d.ts +8 -0
  415. package/dist/types/hookForm/FormFileField.d.ts +8 -0
  416. package/dist/types/hookForm/FormFileUploadField.d.ts +8 -0
  417. package/dist/types/hookForm/FormImageField.d.ts +8 -0
  418. package/dist/types/hookForm/FormMaskedField.d.ts +9 -0
  419. package/dist/types/hookForm/FormProblemAlert.d.ts +6 -5
  420. package/dist/types/hookForm/FormRepeatingFields.d.ts +27 -0
  421. package/dist/types/hookForm/FormTransferListField.d.ts +8 -0
  422. package/dist/types/hookForm/SubmitButton.d.ts +6 -13
  423. package/dist/types/inbox/InboxLayout.d.ts +6 -17
  424. package/dist/types/inbox/MessageList.d.ts +6 -18
  425. package/dist/types/inbox/MessageView.d.ts +6 -14
  426. package/dist/types/index.d.ts +33 -4
  427. package/dist/types/inputs/CatalogInput.d.ts +10 -21
  428. package/dist/types/inputs/CheckboxGroupInput.d.ts +28 -0
  429. package/dist/types/inputs/ColorInput.d.ts +7 -16
  430. package/dist/types/inputs/FieldFrame.d.ts +6 -10
  431. package/dist/types/inputs/MaskedInput.d.ts +38 -0
  432. package/dist/types/inputs/NumberInput.d.ts +7 -20
  433. package/dist/types/inputs/RepeatingFields.d.ts +31 -0
  434. package/dist/types/inputs/SelectInput.d.ts +10 -18
  435. package/dist/types/inputs/TextInput.d.ts +3 -0
  436. package/dist/types/inputs/TransferListInput.d.ts +30 -0
  437. package/dist/types/inputs/WizardLayout.d.ts +6 -19
  438. package/dist/types/inputs/inputMasks.d.ts +52 -0
  439. package/dist/types/inputs/selectAllState.d.ts +11 -0
  440. package/dist/types/inputs/useRowKeys.d.ts +11 -0
  441. package/dist/types/kanban/KanbanBoard.d.ts +6 -25
  442. package/dist/types/legal/CookieNotice.d.ts +20 -0
  443. package/dist/types/legal/TermsAcceptanceDialog.d.ts +20 -0
  444. package/dist/types/legal/consentStorage.d.ts +16 -0
  445. package/dist/types/legal/useCookieConsent.d.ts +13 -0
  446. package/dist/types/locales/en.d.ts +256 -0
  447. package/dist/types/locales/es.d.ts +256 -0
  448. package/dist/types/maps/MapView.d.ts +6 -17
  449. package/dist/types/mexico/CfdiSummary.d.ts +12 -0
  450. package/dist/types/mexico/EfirmaFields.d.ts +28 -0
  451. package/dist/types/mexico/certificateReader.d.ts +37 -0
  452. package/dist/types/mexico/cfdiReader.d.ts +95 -0
  453. package/dist/types/mexico/derReader.d.ts +54 -0
  454. package/dist/types/mexico/efirmaKey.d.ts +26 -0
  455. package/dist/types/mexico/mexicoIdentifiers.d.ts +68 -0
  456. package/dist/types/mexico/mexicoRules.d.ts +45 -0
  457. package/dist/types/mexico.d.ts +11 -0
  458. package/dist/types/pwa/InstallAppSetting.d.ts +6 -6
  459. package/dist/types/pwa/InstallInstructionsDialog.d.ts +6 -9
  460. package/dist/types/pwa/InstallPromptBanner.d.ts +6 -11
  461. package/dist/types/react-hook-form.d.ts +11 -1
  462. package/dist/types/rich-text.d.ts +5 -0
  463. package/dist/types/richText/FormRichTextField.d.ts +7 -0
  464. package/dist/types/richText/RichTextEditor.d.ts +27 -0
  465. package/dist/types/richText/RichTextLinkPopover.d.ts +17 -0
  466. package/dist/types/richText/RichTextToolbar.d.ts +15 -0
  467. package/dist/types/richText/RichTextView.d.ts +10 -0
  468. package/dist/types/richText/richTextContentSx.d.ts +7 -0
  469. package/dist/types/richText/richTextExtensions.d.ts +15 -0
  470. package/dist/types/richText/richTextRules.d.ts +41 -0
  471. package/dist/types/security/ActivityLog.d.ts +6 -9
  472. package/dist/types/security/RecoveryCodesDialog.d.ts +6 -11
  473. package/dist/types/security/SessionsCard.d.ts +6 -11
  474. package/dist/types/table.d.ts +3 -1
  475. package/dist/types/theme/themePieces.d.ts +55 -3
  476. package/dist/types/toolkit/ToolkitProvider.d.ts +13 -1
  477. package/dist/types/toolkit/browserNavigation.d.ts +7 -3
  478. package/dist/types/toolkit/combineTexts.d.ts +6 -0
  479. package/dist/types/toolkit/hashNavigation.d.ts +4 -2
  480. package/dist/types/toolkit/navigationPaths.d.ts +35 -0
  481. package/dist/types/toolkit/pathIndex.d.ts +27 -0
  482. package/dist/types/toolkit/toolkitSettings.d.ts +7 -4
  483. package/dist/types/ui/actions/ActionsMenu.d.ts +24 -11
  484. package/dist/types/ui/actions/CopyButton.d.ts +8 -11
  485. package/dist/types/ui/actions/DownloadMenu.d.ts +6 -29
  486. package/dist/types/ui/actions/SecretField.d.ts +6 -11
  487. package/dist/types/ui/actions/SelectionActions.d.ts +6 -13
  488. package/dist/types/ui/actions/tableRowText.d.ts +6 -0
  489. package/dist/types/ui/cards/RecordCard.d.ts +40 -0
  490. package/dist/types/ui/cards/RecordCardSkeleton.d.ts +12 -0
  491. package/dist/types/ui/countdown/Countdown.d.ts +22 -0
  492. package/dist/types/ui/countdown/countdownParts.d.ts +39 -0
  493. package/dist/types/ui/countdown/useCountdown.d.ts +14 -0
  494. package/dist/types/ui/documents/PdfViewerDialog.d.ts +14 -0
  495. package/dist/types/ui/filters/DateRangeFilter.d.ts +6 -10
  496. package/dist/types/ui/filters/FilterDrawer.d.ts +23 -0
  497. package/dist/types/ui/filters/PeriodRangeSelector.d.ts +6 -13
  498. package/dist/types/ui/filters/QuickFilters.d.ts +6 -12
  499. package/dist/types/ui/filters/filterDrawerFields.d.ts +139 -0
  500. package/dist/types/ui/help/HelpButton.d.ts +11 -0
  501. package/dist/types/ui/help/HelpCarouselDialog.d.ts +27 -0
  502. package/dist/types/ui/help/useHelpCarousel.d.ts +21 -0
  503. package/dist/types/ui/index.d.ts +10 -0
  504. package/dist/types/ui/labels/IconBadge.d.ts +34 -0
  505. package/dist/types/ui/labels/MarkedText.d.ts +10 -0
  506. package/dist/types/ui/labels/Tag.d.ts +6 -12
  507. package/dist/types/ui/labels/markedTextPieces.d.ts +22 -0
  508. package/dist/types/ui/layout/CollapsibleSection.d.ts +6 -12
  509. package/dist/types/ui/layout/ContentDialog.d.ts +6 -10
  510. package/dist/types/ui/layout/DefinitionList.d.ts +6 -9
  511. package/dist/types/ui/layout/DetailHeader.d.ts +6 -10
  512. package/dist/types/ui/layout/ErrorPage.d.ts +6 -17
  513. package/dist/types/ui/layout/FullPageLoader.d.ts +6 -6
  514. package/dist/types/ui/layout/GlassPanel.d.ts +6 -8
  515. package/dist/types/ui/layout/PageHeader.d.ts +6 -10
  516. package/dist/types/ui/layout/PageHeading.d.ts +6 -11
  517. package/dist/types/ui/layout/ProfileHeader.d.ts +6 -11
  518. package/dist/types/ui/layout/ScrollableRow.d.ts +6 -13
  519. package/dist/types/ui/layout/SectionCard.d.ts +6 -8
  520. package/dist/types/ui/metrics/BarList.d.ts +6 -12
  521. package/dist/types/ui/metrics/CalendarHeatmap.d.ts +6 -19
  522. package/dist/types/ui/metrics/ChartTooltip.d.ts +6 -6
  523. package/dist/types/ui/metrics/ColumnChart.d.ts +6 -25
  524. package/dist/types/ui/metrics/LineChart.d.ts +6 -20
  525. package/dist/types/ui/metrics/MetricCard.d.ts +6 -17
  526. package/dist/types/ui/metrics/TableToggle.d.ts +6 -6
  527. package/dist/types/ui/metrics/chartParts.d.ts +15 -30
  528. package/dist/types/ui/navigation/BackButton.d.ts +6 -9
  529. package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +6 -9
  530. package/dist/types/ui/navigation/FontSizeToggle.d.ts +6 -8
  531. package/dist/types/ui/navigation/LanguageToggle.d.ts +6 -8
  532. package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +6 -7
  533. package/dist/types/ui/navigation/RouteTabs.d.ts +39 -0
  534. package/dist/types/ui/navigation/routeTabMatching.d.ts +27 -0
  535. package/dist/types/ui/timeline/GroupedTimeline.d.ts +6 -23
  536. package/dist/types/upload/AttachmentsInput.d.ts +72 -0
  537. package/dist/types/upload/FileChip.d.ts +18 -0
  538. package/dist/types/upload/FileDropzone.d.ts +7 -19
  539. package/dist/types/upload/FileInput.d.ts +31 -0
  540. package/dist/types/upload/FileUploadInput.d.ts +56 -0
  541. package/dist/types/upload/ImageInput.d.ts +35 -0
  542. package/dist/types/upload/TemplateDownloadButton.d.ts +27 -0
  543. package/dist/types/upload/fileAppearance.d.ts +8 -0
  544. package/dist/types/upload/fileRules.d.ts +38 -0
  545. package/dist/types/upload/transferProgress.d.ts +18 -0
  546. package/dist/types/upload/uploadMachine.d.ts +6 -2
  547. package/dist/types/upload/uploadWithProgress.d.ts +6 -2
  548. package/dist/types/upload/useFilePicker.d.ts +39 -0
  549. package/dist/ui/actions/ActionsMenu.js +109 -17
  550. package/dist/ui/actions/ActionsMenu.js.map +1 -1
  551. package/dist/ui/actions/CopyButton.js +37 -12
  552. package/dist/ui/actions/CopyButton.js.map +1 -1
  553. package/dist/ui/actions/DownloadMenu.js +3 -2
  554. package/dist/ui/actions/DownloadMenu.js.map +1 -1
  555. package/dist/ui/actions/SecretField.js +8 -3
  556. package/dist/ui/actions/SecretField.js.map +1 -1
  557. package/dist/ui/actions/SelectionActions.js +3 -2
  558. package/dist/ui/actions/SelectionActions.js.map +1 -1
  559. package/dist/ui/actions/tableRowText.js +7 -0
  560. package/dist/ui/actions/tableRowText.js.map +1 -0
  561. package/dist/ui/cards/RecordCard.js +146 -0
  562. package/dist/ui/cards/RecordCard.js.map +1 -0
  563. package/dist/ui/cards/RecordCardSkeleton.js +38 -0
  564. package/dist/ui/cards/RecordCardSkeleton.js.map +1 -0
  565. package/dist/ui/countdown/Countdown.js +39 -0
  566. package/dist/ui/countdown/Countdown.js.map +1 -0
  567. package/dist/ui/countdown/countdownParts.js +34 -0
  568. package/dist/ui/countdown/countdownParts.js.map +1 -0
  569. package/dist/ui/countdown/useCountdown.js +35 -0
  570. package/dist/ui/countdown/useCountdown.js.map +1 -0
  571. package/dist/ui/documents/PdfViewerDialog.js +82 -0
  572. package/dist/ui/documents/PdfViewerDialog.js.map +1 -0
  573. package/dist/ui/filters/DateRangeFilter.js +3 -2
  574. package/dist/ui/filters/DateRangeFilter.js.map +1 -1
  575. package/dist/ui/filters/FilterDrawer.js +212 -0
  576. package/dist/ui/filters/FilterDrawer.js.map +1 -0
  577. package/dist/ui/filters/PeriodRangeSelector.js +3 -2
  578. package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
  579. package/dist/ui/filters/QuickFilters.js +3 -2
  580. package/dist/ui/filters/QuickFilters.js.map +1 -1
  581. package/dist/ui/filters/filterDrawerFields.js +119 -0
  582. package/dist/ui/filters/filterDrawerFields.js.map +1 -0
  583. package/dist/ui/help/HelpButton.js +22 -0
  584. package/dist/ui/help/HelpButton.js.map +1 -0
  585. package/dist/ui/help/HelpCarouselDialog.js +155 -0
  586. package/dist/ui/help/HelpCarouselDialog.js.map +1 -0
  587. package/dist/ui/help/useHelpCarousel.js +25 -0
  588. package/dist/ui/help/useHelpCarousel.js.map +1 -0
  589. package/dist/ui/labels/IconBadge.js +82 -0
  590. package/dist/ui/labels/IconBadge.js.map +1 -0
  591. package/dist/ui/labels/MarkedText.js +31 -0
  592. package/dist/ui/labels/MarkedText.js.map +1 -0
  593. package/dist/ui/labels/Tag.js +3 -2
  594. package/dist/ui/labels/Tag.js.map +1 -1
  595. package/dist/ui/labels/markedTextPieces.js +64 -0
  596. package/dist/ui/labels/markedTextPieces.js.map +1 -0
  597. package/dist/ui/layout/CollapsibleSection.js +3 -2
  598. package/dist/ui/layout/CollapsibleSection.js.map +1 -1
  599. package/dist/ui/layout/ContentDialog.js +3 -2
  600. package/dist/ui/layout/ContentDialog.js.map +1 -1
  601. package/dist/ui/layout/DefinitionList.js +3 -2
  602. package/dist/ui/layout/DefinitionList.js.map +1 -1
  603. package/dist/ui/layout/DetailHeader.js +3 -2
  604. package/dist/ui/layout/DetailHeader.js.map +1 -1
  605. package/dist/ui/layout/ErrorPage.js +3 -2
  606. package/dist/ui/layout/ErrorPage.js.map +1 -1
  607. package/dist/ui/layout/FullPageLoader.js +3 -2
  608. package/dist/ui/layout/FullPageLoader.js.map +1 -1
  609. package/dist/ui/layout/GlassPanel.js +3 -2
  610. package/dist/ui/layout/GlassPanel.js.map +1 -1
  611. package/dist/ui/layout/PageHeader.js +3 -2
  612. package/dist/ui/layout/PageHeader.js.map +1 -1
  613. package/dist/ui/layout/PageHeading.js +3 -2
  614. package/dist/ui/layout/PageHeading.js.map +1 -1
  615. package/dist/ui/layout/ProfileHeader.js +3 -2
  616. package/dist/ui/layout/ProfileHeader.js.map +1 -1
  617. package/dist/ui/layout/ScrollableRow.js +3 -2
  618. package/dist/ui/layout/ScrollableRow.js.map +1 -1
  619. package/dist/ui/layout/SectionCard.js +3 -2
  620. package/dist/ui/layout/SectionCard.js.map +1 -1
  621. package/dist/ui/metrics/BarList.js +3 -2
  622. package/dist/ui/metrics/BarList.js.map +1 -1
  623. package/dist/ui/metrics/CalendarHeatmap.js +3 -2
  624. package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
  625. package/dist/ui/metrics/ChartTooltip.js +3 -2
  626. package/dist/ui/metrics/ChartTooltip.js.map +1 -1
  627. package/dist/ui/metrics/ColumnChart.js +3 -2
  628. package/dist/ui/metrics/ColumnChart.js.map +1 -1
  629. package/dist/ui/metrics/LineChart.js +3 -2
  630. package/dist/ui/metrics/LineChart.js.map +1 -1
  631. package/dist/ui/metrics/MetricCard.js +3 -2
  632. package/dist/ui/metrics/MetricCard.js.map +1 -1
  633. package/dist/ui/metrics/TableToggle.js +3 -2
  634. package/dist/ui/metrics/TableToggle.js.map +1 -1
  635. package/dist/ui/metrics/chartParts.js +7 -4
  636. package/dist/ui/metrics/chartParts.js.map +1 -1
  637. package/dist/ui/navigation/BackButton.js +7 -2
  638. package/dist/ui/navigation/BackButton.js.map +1 -1
  639. package/dist/ui/navigation/ColorSchemeToggle.js +3 -2
  640. package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
  641. package/dist/ui/navigation/FontSizeToggle.js +3 -2
  642. package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
  643. package/dist/ui/navigation/LanguageToggle.js +3 -2
  644. package/dist/ui/navigation/LanguageToggle.js.map +1 -1
  645. package/dist/ui/navigation/PageBreadcrumbs.js +3 -2
  646. package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
  647. package/dist/ui/navigation/RouteTabs.js +79 -0
  648. package/dist/ui/navigation/RouteTabs.js.map +1 -0
  649. package/dist/ui/navigation/routeTabMatching.js +23 -0
  650. package/dist/ui/navigation/routeTabMatching.js.map +1 -0
  651. package/dist/ui/timeline/GroupedTimeline.js +3 -2
  652. package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
  653. package/dist/upload/AttachmentsInput.js +130 -0
  654. package/dist/upload/AttachmentsInput.js.map +1 -0
  655. package/dist/upload/FileChip.js +28 -0
  656. package/dist/upload/FileChip.js.map +1 -0
  657. package/dist/upload/FileDropzone.js +23 -87
  658. package/dist/upload/FileDropzone.js.map +1 -1
  659. package/dist/upload/FileInput.js +115 -0
  660. package/dist/upload/FileInput.js.map +1 -0
  661. package/dist/upload/FileUploadInput.js +288 -0
  662. package/dist/upload/FileUploadInput.js.map +1 -0
  663. package/dist/upload/ImageInput.js +128 -0
  664. package/dist/upload/ImageInput.js.map +1 -0
  665. package/dist/upload/TemplateDownloadButton.js +68 -0
  666. package/dist/upload/TemplateDownloadButton.js.map +1 -0
  667. package/dist/upload/fileAppearance.js +21 -0
  668. package/dist/upload/fileAppearance.js.map +1 -0
  669. package/dist/upload/fileRules.js +27 -1
  670. package/dist/upload/fileRules.js.map +1 -1
  671. package/dist/upload/transferProgress.js +23 -0
  672. package/dist/upload/transferProgress.js.map +1 -0
  673. package/dist/upload/uploadMachine.js +8 -8
  674. package/dist/upload/uploadMachine.js.map +1 -1
  675. package/dist/upload/uploadWithProgress.js +1 -1
  676. package/dist/upload/uploadWithProgress.js.map +1 -1
  677. package/dist/upload/useFilePicker.js +101 -0
  678. package/dist/upload/useFilePicker.js.map +1 -0
  679. package/package.json +44 -1
  680. package/cli/templates/project/src/app/combineTexts.js.tpl +0 -31
@@ -52,11 +52,37 @@ function parseFileSize(size) {
52
52
  }
53
53
  return Math.round(Number(match[1]) * BYTES_BY_UNIT[(match[2] ?? "b").toLowerCase()]);
54
54
  }
55
+ function screenFiles(pickedFiles, { resolvedAccept, maxBytes = null, maxFiles, maxTotalBytes = null, keptFiles = [] } = {}) {
56
+ const kept = keptFiles.filter((keptFile) => !pickedFiles.some((picked) => picked.name === keptFile.name));
57
+ const accepted = [];
58
+ const rejected = [];
59
+ let totalBytes = kept.reduce((sum, keptFile) => sum + (keptFile.size ?? 0), 0);
60
+ for (const file of pickedFiles) {
61
+ let reason = null;
62
+ if (!matchesAccept(file, resolvedAccept)) {
63
+ reason = FILE_REJECTION.type;
64
+ } else if (maxBytes && file.size > maxBytes) {
65
+ reason = FILE_REJECTION.size;
66
+ } else if (maxFiles && kept.length + accepted.length >= maxFiles) {
67
+ reason = FILE_REJECTION.count;
68
+ } else if (maxTotalBytes && totalBytes + (file.size ?? 0) > maxTotalBytes) {
69
+ reason = FILE_REJECTION.total;
70
+ }
71
+ if (reason) {
72
+ rejected.push({ file, reason });
73
+ } else {
74
+ accepted.push(file);
75
+ totalBytes += file.size ?? 0;
76
+ }
77
+ }
78
+ return { files: [...kept, ...accepted], accepted, rejected };
79
+ }
55
80
  export {
56
81
  FILE_ACCEPT_PRESETS,
57
82
  FILE_REJECTION,
58
83
  matchesAccept,
59
84
  parseFileSize,
60
- resolveAccept
85
+ resolveAccept,
86
+ screenFiles
61
87
  };
62
88
  //# sourceMappingURL=fileRules.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fileRules.js","sources":["../../src/upload/fileRules.js"],"sourcesContent":["// Las reglas de qué archivo se acepta: su tipo (accept) y su peso (maxSize). Las comparten las dos zonas para soltar\n// archivos del paquete, la de MUI (upload/FileDropzone.jsx) y la de FilePond (filepond/FileDropzone.jsx), para que se\n// configuren igual.\n//\n// accept un nombre del menú ('excel'), una lista (['excel', 'pdf']) o lo de siempre del input ('.xlsx,.xls',\n// 'image/*'); se pueden mezclar: ['excel', '.dat'].\n// maxSize bytes (número) o texto con unidades: '500 KB', '10mb', '1 GB'.\n//\n// OJO: los tamaños van en base 1000 (1 MB = 1,000,000 bytes), igual que formatFileSize y que el navegador en sus\n// descargas. En base 1024 un límite de «10 MB» se pintaría como «10.5 MB».\n//\n// Funciones puras, sin React: function (regla de la casa). Se prueban con node --test (fileRules.test.js).\n\n/**\n * Por qué se rechazó un archivo (lo que recibe onReject de las dos zonas). La de MUI solo rechaza por tipo y por peso;\n * la de FilePond además por el peso de todos juntos, por cantidad y por contenido (validate).\n */\nexport const FILE_REJECTION = Object.freeze({type: 'type', size: 'size', total: 'total', count: 'count', content: 'content'});\n\n/** El menú de tipos comunes, para no memorizar extensiones. */\nexport const FILE_ACCEPT_PRESETS = Object.freeze({\n excel: '.xlsx,.xls',\n csv: '.csv',\n pdf: '.pdf',\n word: '.doc,.docx',\n text: '.txt',\n json: '.json',\n xml: '.xml',\n zip: '.zip,.rar,.7z',\n image: 'image/*',\n audio: 'audio/*',\n video: 'video/*',\n});\n\n// bytes de cada unidad que se puede escribir en maxSize\nconst BYTES_BY_UNIT = Object.freeze({b: 1, kb: 1e3, mb: 1e6, gb: 1e9});\nconst SIZE_TEXT = /^\\s*(\\d+(?:\\.\\d+)?)\\s*(b|kb|mb|gb)?\\s*$/i;\nconst ACCEPT_SEPARATOR = ',';\nconst WILDCARD_SUFFIX = '/*';\n\n/**\n * El accept del paquete como lo entiende el input del navegador.\n *\n * @param {string|string[]|undefined} accept 'excel' | ['excel', 'pdf'] | '.xlsx,.xls' | 'image/*'\n * @returns {string|undefined} '.xlsx,.xls,.pdf'; undefined si se acepta todo\n */\nexport function resolveAccept(accept) {\n if (!accept) {\n return undefined;\n }\n const parts = Array.isArray(accept) ? accept : [accept];\n return parts.map((part) => FILE_ACCEPT_PRESETS[String(part).toLowerCase()] ?? part).join(ACCEPT_SEPARATOR);\n}\n\n/**\n * ¿El archivo es de un tipo permitido? Revisa la extensión (.xlsx), el tipo exacto (application/pdf) o la familia\n * (image/*). El input del navegador ya filtra al elegir, pero al soltar un archivo no filtra nada.\n *\n * @param {{name: string, type?: string}} file\n * @param {string|undefined} resolvedAccept lo que regresa resolveAccept\n * @returns {boolean}\n */\nexport function matchesAccept(file, resolvedAccept) {\n if (!resolvedAccept) {\n return true;\n }\n const fileName = file.name.toLowerCase();\n const fileType = (file.type ?? '').toLowerCase();\n return resolvedAccept\n .split(ACCEPT_SEPARATOR)\n .map((rule) => rule.trim().toLowerCase())\n .filter(Boolean)\n .some((rule) => {\n if (rule.startsWith('.')) {\n return fileName.endsWith(rule);\n }\n if (rule.endsWith(WILDCARD_SUFFIX)) {\n return fileType.startsWith(rule.slice(0, -1));\n }\n return fileType === rule;\n });\n}\n\n/**\n * Un tamaño escrito por una persona en bytes: '10 MB' → 10000000.\n *\n * @param {number|string|undefined|null} size\n * @returns {number|null} null si no hay límite\n */\nexport function parseFileSize(size) {\n if (size === undefined || size === null || size === '') {\n return null;\n }\n if (typeof size === 'number') {\n return size;\n }\n const match = SIZE_TEXT.exec(size);\n // guard clause: un límite mal escrito es error de quien configura, no algo que se ignore callado\n if (!match) {\n throw new Error(`«${size}» no es un tamaño: se espera un número de bytes o algo como '10 MB'`);\n }\n return Math.round(Number(match[1]) * BYTES_BY_UNIT[(match[2] ?? 'b').toLowerCase()]);\n}\n"],"names":[],"mappings":"AAiBY,MAAC,iBAAiB,OAAO,OAAO,EAAC,MAAM,QAAQ,MAAM,QAAQ,OAAO,SAAS,OAAO,SAAS,SAAS,UAAS,CAAC;AAGhH,MAAC,sBAAsB,OAAO,OAAO;AAAA,EAC7C,OAAO;AAAA,EACP,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACX,CAAC;AAGD,MAAM,gBAAgB,OAAO,OAAO,EAAC,GAAG,GAAG,IAAI,KAAK,IAAI,KAAK,IAAI,IAAG,CAAC;AACrE,MAAM,YAAY;AAClB,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;AAQjB,SAAS,cAAc,QAAQ;AAClC,MAAI,CAAC,QAAQ;AACT,WAAO;AAAA,EACX;AACA,QAAM,QAAQ,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM;AACtD,SAAO,MAAM,IAAI,CAAC,SAAS,oBAAoB,OAAO,IAAI,EAAE,YAAW,CAAE,KAAK,IAAI,EAAE,KAAK,gBAAgB;AAC7G;AAUO,SAAS,cAAc,MAAM,gBAAgB;AAChD,MAAI,CAAC,gBAAgB;AACjB,WAAO;AAAA,EACX;AACA,QAAM,WAAW,KAAK,KAAK,YAAW;AACtC,QAAM,YAAY,KAAK,QAAQ,IAAI,YAAW;AAC9C,SAAO,eACF,MAAM,gBAAgB,EACtB,IAAI,CAAC,SAAS,KAAK,KAAI,EAAG,YAAW,CAAE,EACvC,OAAO,OAAO,EACd,KAAK,CAAC,SAAS;AACZ,QAAI,KAAK,WAAW,GAAG,GAAG;AACtB,aAAO,SAAS,SAAS,IAAI;AAAA,IACjC;AACA,QAAI,KAAK,SAAS,eAAe,GAAG;AAChC,aAAO,SAAS,WAAW,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,IAChD;AACA,WAAO,aAAa;AAAA,EACxB,CAAC;AACT;AAQO,SAAS,cAAc,MAAM;AAChC,MAAI,SAAS,UAAa,SAAS,QAAQ,SAAS,IAAI;AACpD,WAAO;AAAA,EACX;AACA,MAAI,OAAO,SAAS,UAAU;AAC1B,WAAO;AAAA,EACX;AACA,QAAM,QAAQ,UAAU,KAAK,IAAI;AAEjC,MAAI,CAAC,OAAO;AACR,UAAM,IAAI,MAAM,IAAI,IAAI,qEAAqE;AAAA,EACjG;AACA,SAAO,KAAK,MAAM,OAAO,MAAM,CAAC,CAAC,IAAI,eAAe,MAAM,CAAC,KAAK,KAAK,YAAW,CAAE,CAAC;AACvF;"}
1
+ {"version":3,"file":"fileRules.js","sources":["../../src/upload/fileRules.js"],"sourcesContent":["// Las reglas de qué archivo se acepta: su tipo (accept) y su peso (maxSize). Las comparten las dos zonas para soltar\n// archivos del paquete, la de MUI (upload/FileDropzone.jsx) y la de FilePond (filepond/FileDropzone.jsx), para que se\n// configuren igual.\n//\n// accept un nombre del menú ('excel'), una lista (['excel', 'pdf']) o lo de siempre del input ('.xlsx,.xls',\n// 'image/*'); se pueden mezclar: ['excel', '.dat'].\n// maxSize bytes (número) o texto con unidades: '500 KB', '10mb', '1 GB'.\n//\n// OJO: los tamaños van en base 1000 (1 MB = 1,000,000 bytes), igual que formatFileSize y que el navegador en sus\n// descargas. En base 1024 un límite de «10 MB» se pintaría como «10.5 MB».\n//\n// Funciones puras, sin React: function (regla de la casa). Se prueban con node --test (fileRules.test.js).\n\n/**\n * Por qué se rechazó un archivo (lo que recibe onReject de las dos zonas). La de MUI solo rechaza por tipo y por peso;\n * la de FilePond además por el peso de todos juntos, por cantidad y por contenido (validate).\n */\nexport const FILE_REJECTION = Object.freeze({type: 'type', size: 'size', total: 'total', count: 'count', content: 'content'});\n\n/** El menú de tipos comunes, para no memorizar extensiones. */\nexport const FILE_ACCEPT_PRESETS = Object.freeze({\n excel: '.xlsx,.xls',\n csv: '.csv',\n pdf: '.pdf',\n word: '.doc,.docx',\n text: '.txt',\n json: '.json',\n xml: '.xml',\n zip: '.zip,.rar,.7z',\n image: 'image/*',\n audio: 'audio/*',\n video: 'video/*',\n});\n\n// bytes de cada unidad que se puede escribir en maxSize\nconst BYTES_BY_UNIT = Object.freeze({b: 1, kb: 1e3, mb: 1e6, gb: 1e9});\nconst SIZE_TEXT = /^\\s*(\\d+(?:\\.\\d+)?)\\s*(b|kb|mb|gb)?\\s*$/i;\nconst ACCEPT_SEPARATOR = ',';\nconst WILDCARD_SUFFIX = '/*';\n\n/**\n * El accept del paquete como lo entiende el input del navegador.\n *\n * @param {string|string[]|undefined} accept 'excel' | ['excel', 'pdf'] | '.xlsx,.xls' | 'image/*'\n * @returns {string|undefined} '.xlsx,.xls,.pdf'; undefined si se acepta todo\n */\nexport function resolveAccept(accept) {\n if (!accept) {\n return undefined;\n }\n const parts = Array.isArray(accept) ? accept : [accept];\n return parts.map((part) => FILE_ACCEPT_PRESETS[String(part).toLowerCase()] ?? part).join(ACCEPT_SEPARATOR);\n}\n\n/**\n * ¿El archivo es de un tipo permitido? Revisa la extensión (.xlsx), el tipo exacto (application/pdf) o la familia\n * (image/*). El input del navegador ya filtra al elegir, pero al soltar un archivo no filtra nada.\n *\n * @param {{name: string, type?: string}} file\n * @param {string|undefined} resolvedAccept lo que regresa resolveAccept\n * @returns {boolean}\n */\nexport function matchesAccept(file, resolvedAccept) {\n if (!resolvedAccept) {\n return true;\n }\n const fileName = file.name.toLowerCase();\n const fileType = (file.type ?? '').toLowerCase();\n return resolvedAccept\n .split(ACCEPT_SEPARATOR)\n .map((rule) => rule.trim().toLowerCase())\n .filter(Boolean)\n .some((rule) => {\n if (rule.startsWith('.')) {\n return fileName.endsWith(rule);\n }\n if (rule.endsWith(WILDCARD_SUFFIX)) {\n return fileType.startsWith(rule.slice(0, -1));\n }\n return fileType === rule;\n });\n}\n\n/**\n * Un tamaño escrito por una persona en bytes: '10 MB' → 10000000.\n *\n * @param {number|string|undefined|null} size\n * @returns {number|null} null si no hay límite\n */\nexport function parseFileSize(size) {\n if (size === undefined || size === null || size === '') {\n return null;\n }\n if (typeof size === 'number') {\n return size;\n }\n const match = SIZE_TEXT.exec(size);\n // guard clause: un límite mal escrito es error de quien configura, no algo que se ignore callado\n if (!match) {\n throw new Error(`«${size}» no es un tamaño: se espera un número de bytes o algo como '10 MB'`);\n }\n return Math.round(Number(match[1]) * BYTES_BY_UNIT[(match[2] ?? 'b').toLowerCase()]);\n}\n\n/**\n * Lo que queda al elegir o soltar archivos: cuáles pasan y cuáles no, con su motivo. La usan los cargadores de MUI del\n * paquete (la zona, el compacto, «Adjuntar» y la imagen), así rechazan igual y con los mismos motivos.\n *\n * Un archivo con el MISMO nombre que uno que ya estaba lo reemplaza (se volvió a elegir corregido) y no cuenta doble ni\n * en la cantidad ni en el peso. Se revisa en este orden: tipo, peso del archivo, cantidad y peso de todos juntos.\n *\n * @param {Array<{name: string, type?: string, size?: number}>} pickedFiles lo que se eligió o se soltó\n * @param {object} rules\n * @param {string} [rules.resolvedAccept] lo que regresa resolveAccept\n * @param {number|null} [rules.maxBytes] el peso máximo de cada archivo\n * @param {number} [rules.maxFiles] cuántos como máximo entre los que ya estaban y los nuevos\n * @param {number|null} [rules.maxTotalBytes] cuánto pueden pesar todos juntos\n * @param {Array<{name: string, size?: number}>} [rules.keptFiles] los que ya estaban (un archivo guardado sin peso cuenta 0)\n * @returns {{files: Array<object>, accepted: Array<object>, rejected: Array<{file: object, reason: string}>}} files: los\n * que ya estaban (sin los reemplazados) y después los nuevos que pasaron\n */\nexport function screenFiles(pickedFiles, {resolvedAccept, maxBytes = null, maxFiles, maxTotalBytes = null, keptFiles = []} = {}) {\n const kept = keptFiles.filter((keptFile) => !pickedFiles.some((picked) => picked.name === keptFile.name));\n const accepted = [];\n const rejected = [];\n let totalBytes = kept.reduce((sum, keptFile) => sum + (keptFile.size ?? 0), 0);\n\n for (const file of pickedFiles) {\n let reason = null;\n if (!matchesAccept(file, resolvedAccept)) {\n reason = FILE_REJECTION.type;\n } else if (maxBytes && file.size > maxBytes) {\n reason = FILE_REJECTION.size;\n } else if (maxFiles && kept.length + accepted.length >= maxFiles) {\n reason = FILE_REJECTION.count;\n } else if (maxTotalBytes && totalBytes + (file.size ?? 0) > maxTotalBytes) {\n reason = FILE_REJECTION.total;\n }\n\n if (reason) {\n rejected.push({file, reason});\n } else {\n accepted.push(file);\n totalBytes += file.size ?? 0;\n }\n }\n\n return {files: [...kept, ...accepted], accepted, rejected};\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ const PERCENT = 100;
2
+ const MILLISECONDS_PER_SECOND = 1e3;
3
+ const MIN_SECONDS_FOR_SPEED = 0.5;
4
+ function transferProgressOf({ loaded, total, rate, estimated }, startedAt, now = Date.now()) {
5
+ const elapsedSeconds = (now - startedAt) / MILLISECONDS_PER_SECOND;
6
+ const measuredSpeed = elapsedSeconds >= MIN_SECONDS_FOR_SPEED && loaded > 0 ? loaded / elapsedSeconds : null;
7
+ const bytesPerSecond = rate ?? measuredSpeed;
8
+ let remainingSeconds = estimated ?? null;
9
+ if (remainingSeconds == null && bytesPerSecond) {
10
+ remainingSeconds = Math.max(0, Math.ceil((total - loaded) / bytesPerSecond));
11
+ }
12
+ return {
13
+ percent: total > 0 ? Math.min(PERCENT, Math.round(loaded * PERCENT / total)) : 0,
14
+ loaded,
15
+ total,
16
+ bytesPerSecond,
17
+ remainingSeconds
18
+ };
19
+ }
20
+ export {
21
+ transferProgressOf
22
+ };
23
+ //# sourceMappingURL=transferProgress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transferProgress.js","sources":["../../src/upload/transferProgress.js"],"sourcesContent":["// Cuánto va de una subida, para decirlo en palabras: el porcentaje, lo que va de lo que pesa, la velocidad y cuánto falta.\n// La velocidad y lo que falta salen de lo que ha viajado desde que empezó; si la subida ya los da (axios trae rate y\n// estimated), se usan esos.\n//\n// Puro (sin React): se prueba con node (transferProgress.test.js).\n//\n// Genérico del paquete: function (regla de la casa).\n\nconst PERCENT = 100;\nconst MILLISECONDS_PER_SECOND = 1000;\n// con menos de medio segundo de subida la velocidad todavía brinca: mejor no decirla\nconst MIN_SECONDS_FOR_SPEED = 0.5;\n\n/**\n * @param {{loaded: number, total: number, rate?: number, estimated?: number}} transfer lo que avisa la subida (bytes)\n * @param {number} startedAt cuándo empezó la subida, en milisegundos\n * @param {number} [now]\n * @returns {{percent: number, loaded: number, total: number, bytesPerSecond: number|null, remainingSeconds: number|null}}\n */\nexport function transferProgressOf({loaded, total, rate, estimated}, startedAt, now = Date.now()) {\n const elapsedSeconds = (now - startedAt) / MILLISECONDS_PER_SECOND;\n const measuredSpeed = elapsedSeconds >= MIN_SECONDS_FOR_SPEED && loaded > 0 ? loaded / elapsedSeconds : null;\n const bytesPerSecond = rate ?? measuredSpeed;\n let remainingSeconds = estimated ?? null;\n if (remainingSeconds == null && bytesPerSecond) {\n remainingSeconds = Math.max(0, Math.ceil((total - loaded) / bytesPerSecond));\n }\n return {\n percent: total > 0 ? Math.min(PERCENT, Math.round((loaded * PERCENT) / total)) : 0,\n loaded,\n total,\n bytesPerSecond,\n remainingSeconds,\n };\n}\n"],"names":[],"mappings":"AAQA,MAAM,UAAU;AAChB,MAAM,0BAA0B;AAEhC,MAAM,wBAAwB;AAQvB,SAAS,mBAAmB,EAAC,QAAQ,OAAO,MAAM,UAAS,GAAG,WAAW,MAAM,KAAK,OAAO;AAC9F,QAAM,kBAAkB,MAAM,aAAa;AAC3C,QAAM,gBAAgB,kBAAkB,yBAAyB,SAAS,IAAI,SAAS,iBAAiB;AACxG,QAAM,iBAAiB,QAAQ;AAC/B,MAAI,mBAAmB,aAAa;AACpC,MAAI,oBAAoB,QAAQ,gBAAgB;AAC5C,uBAAmB,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,UAAU,cAAc,CAAC;AAAA,EAC/E;AACA,SAAO;AAAA,IACH,SAAS,QAAQ,IAAI,KAAK,IAAI,SAAS,KAAK,MAAO,SAAS,UAAW,KAAK,CAAC,IAAI;AAAA,IACjF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACR;AACA;"}
@@ -1,5 +1,5 @@
1
1
  import { assign, setup, fromCallback } from "xstate";
2
- const resetContext = assign({ progress: null, result: null, problem: null });
2
+ const resetContext = assign({ progress: null, transfer: null, result: null, problem: null });
3
3
  const uploadMachine = setup({
4
4
  actors: {
5
5
  upload: fromCallback(() => {
@@ -13,7 +13,7 @@ const uploadMachine = setup({
13
13
  }).createMachine({
14
14
  id: "upload",
15
15
  initial: "idle",
16
- context: { progress: null, result: null, problem: null },
16
+ context: { progress: null, transfer: null, result: null, problem: null },
17
17
  states: {
18
18
  idle: {
19
19
  on: { UPLOAD: { target: "uploading", actions: resetContext } }
@@ -25,8 +25,8 @@ const uploadMachine = setup({
25
25
  sending: {
26
26
  on: {
27
27
  PROGRESS: [
28
- { guard: "isFullySent", target: "processing", actions: assign({ progress: ({ event }) => event.percent }) },
29
- { actions: assign({ progress: ({ event }) => event.percent }) }
28
+ { guard: "isFullySent", target: "processing", actions: assign({ progress: ({ event }) => event.percent, transfer: ({ event }) => event.transfer ?? null }) },
29
+ { actions: assign({ progress: ({ event }) => event.percent, transfer: ({ event }) => event.transfer ?? null }) }
30
30
  ]
31
31
  }
32
32
  },
@@ -34,10 +34,10 @@ const uploadMachine = setup({
34
34
  processing: {}
35
35
  },
36
36
  on: {
37
- DONE: { target: "done", actions: assign({ result: ({ event }) => event.output, progress: null }) },
38
- FAIL: { target: "failed", actions: assign({ problem: ({ event }) => event.problem, progress: null }) },
37
+ DONE: { target: "done", actions: assign({ result: ({ event }) => event.output, progress: null, transfer: null }) },
38
+ FAIL: { target: "failed", actions: assign({ problem: ({ event }) => event.problem, progress: null, transfer: null }) },
39
39
  // salir de uploading DETIENE el actor y su cleanup aborta la petición de verdad (no solo la UI)
40
- CANCEL: { target: "cancelled", actions: assign({ progress: null }) }
40
+ CANCEL: { target: "cancelled", actions: assign({ progress: null, transfer: null }) }
41
41
  }
42
42
  },
43
43
  done: {
@@ -56,7 +56,7 @@ function buildUploadActors(uploadFile) {
56
56
  return {
57
57
  upload: fromCallback(({ input, sendBack }) => {
58
58
  const abortController = new AbortController();
59
- uploadFile(input, (percent) => sendBack({ type: "PROGRESS", percent }), abortController.signal).then((output) => sendBack({ type: "DONE", output })).catch((problem) => {
59
+ uploadFile(input, (percent, transfer) => sendBack({ type: "PROGRESS", percent, transfer }), abortController.signal).then((output) => sendBack({ type: "DONE", output })).catch((problem) => {
60
60
  if (problem?.name === "AbortError" || problem?.name === "CanceledError") {
61
61
  return;
62
62
  }
@@ -1 +1 @@
1
- {"version":3,"file":"uploadMachine.js","sources":["../../src/upload/uploadMachine.js"],"sourcesContent":["// Máquina del flujo de SUBIDA de un archivo (compañera de una zona para soltar archivos).\n//\n// idle ──UPLOAD──▶ uploading.sending ──(PROGRESS 100%)──▶ uploading.processing\n// │ │\n// ├────────────── DONE ────────────────────┼──▶ done\n// ├────────────── FAIL ────────────────────┴──▶ failed\n// └─── CANCEL (el cleanup aborta la petición) ──▶ cancelled\n//\n// Por qué máquina y no cuatro useState: los estados imposibles dejan de existir (no hay \"resultado y error a la vez\"\n// ni \"progreso sin carga\") y el flujo sending → processing → done queda DECLARADO, no regado en callbacks.\n//\n// Contexto: progress (% de bytes enviados; null fuera de sending) · result (lo que resuelva la subida) · problem (el\n// error RFC 9457 del rechazo, normalmente un ApiError).\n//\n// Uso:\n// const [uploadSnapshot, sendToUpload] = useMachine(uploadMachine.provide({actors: buildUploadActors(uploadFile)}));\n// sendToUpload({type: 'UPLOAD', input: {file}});\n//\n// Pura: solo importa xstate.\nimport {assign, fromCallback, setup} from 'xstate';\n\nconst resetContext = assign({progress: null, result: null, problem: null});\n\nexport const uploadMachine = setup({\n actors: {\n upload: fromCallback(() => {\n throw new Error('uploadMachine: falta proveer upload con buildUploadActors().');\n }),\n },\n guards: {\n // 100% enviado no es terminado: el servidor sigue trabajando\n isFullySent: ({event}) => event.percent >= 100,\n },\n}).createMachine({\n id: 'upload',\n initial: 'idle',\n context: {progress: null, result: null, problem: null},\n states: {\n idle: {\n on: {UPLOAD: {target: 'uploading', actions: resetContext}},\n },\n uploading: {\n invoke: {src: 'upload', input: ({event}) => event.input},\n initial: 'sending',\n states: {\n sending: {\n on: {\n PROGRESS: [\n {guard: 'isFullySent', target: 'processing', actions: assign({progress: ({event}) => event.percent})},\n {actions: assign({progress: ({event}) => event.percent})},\n ],\n },\n },\n // cuerpo entregado; esperando la respuesta del servidor (progreso indeterminado)\n processing: {},\n },\n on: {\n DONE: {target: 'done', actions: assign({result: ({event}) => event.output, progress: null})},\n FAIL: {target: 'failed', actions: assign({problem: ({event}) => event.problem, progress: null})},\n // salir de uploading DETIENE el actor y su cleanup aborta la petición de verdad (no solo la UI)\n CANCEL: {target: 'cancelled', actions: assign({progress: null})},\n },\n },\n done: {\n on: {UPLOAD: {target: 'uploading', actions: resetContext}, RESET: {target: 'idle', actions: resetContext}},\n },\n failed: {\n on: {UPLOAD: {target: 'uploading', actions: resetContext}, RESET: {target: 'idle', actions: resetContext}},\n },\n // cancelado por la persona: el archivo sigue elegido y se puede reintentar o limpiar\n cancelled: {\n on: {UPLOAD: {target: 'uploading', actions: resetContext}, RESET: {target: 'idle', actions: resetContext}},\n },\n },\n});\n\n/**\n * El actor upload a partir de la función de la pantalla.\n *\n * fromCallback y no fromPromise: hacen falta EVENTOS a medio camino (el avance) y un CLEANUP que aborte la petición.\n *\n * @param {(input: object, onProgress: (percent: number) => void, signal: AbortSignal) => Promise<unknown>} uploadFile\n */\nexport function buildUploadActors(uploadFile) {\n return {\n upload: fromCallback(({input, sendBack}) => {\n const abortController = new AbortController();\n uploadFile(input, (percent) => sendBack({type: 'PROGRESS', percent}), abortController.signal)\n .then((output) => sendBack({type: 'DONE', output}))\n .catch((problem) => {\n // aborto esperado (CANCEL): la máquina ya cambió de estado sola\n if (problem?.name === 'AbortError' || problem?.name === 'CanceledError') {\n return;\n }\n sendBack({type: 'FAIL', problem});\n });\n return () => abortController.abort();\n }),\n };\n}\n"],"names":[],"mappings":";AAqBA,MAAM,eAAe,OAAO,EAAC,UAAU,MAAM,QAAQ,MAAM,SAAS,KAAI,CAAC;AAE7D,MAAC,gBAAgB,MAAM;AAAA,EAC/B,QAAQ;AAAA,IACJ,QAAQ,aAAa,MAAM;AACvB,YAAM,IAAI,MAAM,8DAA8D;AAAA,IAClF,CAAC;AAAA,EACT;AAAA,EACI,QAAQ;AAAA;AAAA,IAEJ,aAAa,CAAC,EAAC,MAAK,MAAM,MAAM,WAAW;AAAA,EACnD;AACA,CAAC,EAAE,cAAc;AAAA,EACb,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,SAAS,EAAC,UAAU,MAAM,QAAQ,MAAM,SAAS,KAAI;AAAA,EACrD,QAAQ;AAAA,IACJ,MAAM;AAAA,MACF,IAAI,EAAC,QAAQ,EAAC,QAAQ,aAAa,SAAS,aAAY,EAAC;AAAA,IACrE;AAAA,IACQ,WAAW;AAAA,MACP,QAAQ,EAAC,KAAK,UAAU,OAAO,CAAC,EAAC,MAAK,MAAM,MAAM,MAAK;AAAA,MACvD,SAAS;AAAA,MACT,QAAQ;AAAA,QACJ,SAAS;AAAA,UACL,IAAI;AAAA,YACA,UAAU;AAAA,cACN,EAAC,OAAO,eAAe,QAAQ,cAAc,SAAS,OAAO,EAAC,UAAU,CAAC,EAAC,MAAK,MAAM,MAAM,QAAO,CAAC,EAAC;AAAA,cACpG,EAAC,SAAS,OAAO,EAAC,UAAU,CAAC,EAAC,MAAK,MAAM,MAAM,QAAO,CAAC,EAAC;AAAA,YACpF;AAAA,UACA;AAAA,QACA;AAAA;AAAA,QAEgB,YAAY,CAAA;AAAA,MAC5B;AAAA,MACY,IAAI;AAAA,QACA,MAAM,EAAC,QAAQ,QAAQ,SAAS,OAAO,EAAC,QAAQ,CAAC,EAAC,MAAK,MAAM,MAAM,QAAQ,UAAU,KAAI,CAAC,EAAC;AAAA,QAC3F,MAAM,EAAC,QAAQ,UAAU,SAAS,OAAO,EAAC,SAAS,CAAC,EAAC,MAAK,MAAM,MAAM,SAAS,UAAU,KAAI,CAAC,EAAC;AAAA;AAAA,QAE/F,QAAQ,EAAC,QAAQ,aAAa,SAAS,OAAO,EAAC,UAAU,KAAI,CAAC,EAAC;AAAA,MAC/E;AAAA,IACA;AAAA,IACQ,MAAM;AAAA,MACF,IAAI,EAAC,QAAQ,EAAC,QAAQ,aAAa,SAAS,aAAY,GAAG,OAAO,EAAC,QAAQ,QAAQ,SAAS,aAAY,EAAC;AAAA,IACrH;AAAA,IACQ,QAAQ;AAAA,MACJ,IAAI,EAAC,QAAQ,EAAC,QAAQ,aAAa,SAAS,aAAY,GAAG,OAAO,EAAC,QAAQ,QAAQ,SAAS,aAAY,EAAC;AAAA,IACrH;AAAA;AAAA,IAEQ,WAAW;AAAA,MACP,IAAI,EAAC,QAAQ,EAAC,QAAQ,aAAa,SAAS,aAAY,GAAG,OAAO,EAAC,QAAQ,QAAQ,SAAS,aAAY,EAAC;AAAA,IACrH;AAAA,EACA;AACA,CAAC;AASM,SAAS,kBAAkB,YAAY;AAC1C,SAAO;AAAA,IACH,QAAQ,aAAa,CAAC,EAAC,OAAO,SAAQ,MAAM;AACxC,YAAM,kBAAkB,IAAI,gBAAe;AAC3C,iBAAW,OAAO,CAAC,YAAY,SAAS,EAAC,MAAM,YAAY,QAAO,CAAC,GAAG,gBAAgB,MAAM,EACvF,KAAK,CAAC,WAAW,SAAS,EAAC,MAAM,QAAQ,OAAM,CAAC,CAAC,EACjD,MAAM,CAAC,YAAY;AAEhB,YAAI,SAAS,SAAS,gBAAgB,SAAS,SAAS,iBAAiB;AACrE;AAAA,QACJ;AACA,iBAAS,EAAC,MAAM,QAAQ,QAAO,CAAC;AAAA,MACpC,CAAC;AACL,aAAO,MAAM,gBAAgB,MAAK;AAAA,IACtC,CAAC;AAAA,EACT;AACA;"}
1
+ {"version":3,"file":"uploadMachine.js","sources":["../../src/upload/uploadMachine.js"],"sourcesContent":["// Máquina del flujo de SUBIDA de un archivo (compañera de una zona para soltar archivos).\n//\n// idle ──UPLOAD──▶ uploading.sending ──(PROGRESS 100%)──▶ uploading.processing\n// │ │\n// ├────────────── DONE ────────────────────┼──▶ done\n// ├────────────── FAIL ────────────────────┴──▶ failed\n// └─── CANCEL (el cleanup aborta la petición) ──▶ cancelled\n//\n// Por qué máquina y no cuatro useState: los estados imposibles dejan de existir (no hay \"resultado y error a la vez\"\n// ni \"progreso sin carga\") y el flujo sending → processing → done queda DECLARADO, no regado en callbacks.\n//\n// Contexto: progress (% de bytes enviados; null fuera de sending) · transfer (cuánto va y cuánto pesa, {loaded, total}, si\n// la subida lo da) · result (lo que resuelva la subida) · problem (el error RFC 9457 del rechazo, normalmente un ApiError).\n//\n// Uso:\n// const [uploadSnapshot, sendToUpload] = useMachine(uploadMachine.provide({actors: buildUploadActors(uploadFile)}));\n// sendToUpload({type: 'UPLOAD', input: {file}});\n//\n// Pura: solo importa xstate.\nimport {assign, fromCallback, setup} from 'xstate';\n\nconst resetContext = assign({progress: null, transfer: null, result: null, problem: null});\n\nexport const uploadMachine = setup({\n actors: {\n upload: fromCallback(() => {\n throw new Error('uploadMachine: falta proveer upload con buildUploadActors().');\n }),\n },\n guards: {\n // 100% enviado no es terminado: el servidor sigue trabajando\n isFullySent: ({event}) => event.percent >= 100,\n },\n}).createMachine({\n id: 'upload',\n initial: 'idle',\n context: {progress: null, transfer: null, result: null, problem: null},\n states: {\n idle: {\n on: {UPLOAD: {target: 'uploading', actions: resetContext}},\n },\n uploading: {\n invoke: {src: 'upload', input: ({event}) => event.input},\n initial: 'sending',\n states: {\n sending: {\n on: {\n PROGRESS: [\n {guard: 'isFullySent', target: 'processing', actions: assign({progress: ({event}) => event.percent, transfer: ({event}) => event.transfer ?? null})},\n {actions: assign({progress: ({event}) => event.percent, transfer: ({event}) => event.transfer ?? null})},\n ],\n },\n },\n // cuerpo entregado; esperando la respuesta del servidor (progreso indeterminado)\n processing: {},\n },\n on: {\n DONE: {target: 'done', actions: assign({result: ({event}) => event.output, progress: null, transfer: null})},\n FAIL: {target: 'failed', actions: assign({problem: ({event}) => event.problem, progress: null, transfer: null})},\n // salir de uploading DETIENE el actor y su cleanup aborta la petición de verdad (no solo la UI)\n CANCEL: {target: 'cancelled', actions: assign({progress: null, transfer: null})},\n },\n },\n done: {\n on: {UPLOAD: {target: 'uploading', actions: resetContext}, RESET: {target: 'idle', actions: resetContext}},\n },\n failed: {\n on: {UPLOAD: {target: 'uploading', actions: resetContext}, RESET: {target: 'idle', actions: resetContext}},\n },\n // cancelado por la persona: el archivo sigue elegido y se puede reintentar o limpiar\n cancelled: {\n on: {UPLOAD: {target: 'uploading', actions: resetContext}, RESET: {target: 'idle', actions: resetContext}},\n },\n },\n});\n\n/**\n * El actor upload a partir de la función de la pantalla.\n *\n * fromCallback y no fromPromise: hacen falta EVENTOS a medio camino (el avance) y un CLEANUP que aborte la petición.\n *\n * @param {(input: object, onProgress: (percent: number, transfer?: {loaded: number, total: number}) => void, signal: AbortSignal) => Promise<unknown>} uploadFile\n * onProgress lleva, si se sabe, cuánto va y cuánto pesa (para la velocidad y lo que falta)\n */\nexport function buildUploadActors(uploadFile) {\n return {\n upload: fromCallback(({input, sendBack}) => {\n const abortController = new AbortController();\n uploadFile(input, (percent, transfer) => sendBack({type: 'PROGRESS', percent, transfer}), abortController.signal)\n .then((output) => sendBack({type: 'DONE', output}))\n .catch((problem) => {\n // aborto esperado (CANCEL): la máquina ya cambió de estado sola\n if (problem?.name === 'AbortError' || problem?.name === 'CanceledError') {\n return;\n }\n sendBack({type: 'FAIL', problem});\n });\n return () => abortController.abort();\n }),\n };\n}\n"],"names":[],"mappings":"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"}
@@ -27,7 +27,7 @@ function uploadWithProgress(url, formData, { headers = {}, onProgress, signal, w
27
27
  }
28
28
  request.upload.onprogress = (event) => {
29
29
  if (event.lengthComputable) {
30
- onProgress?.(Math.round(event.loaded / event.total * PERCENT));
30
+ onProgress?.(Math.round(event.loaded / event.total * PERCENT), { loaded: event.loaded, total: event.total });
31
31
  }
32
32
  };
33
33
  request.onload = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"uploadWithProgress.js","sources":["../../src/upload/uploadWithProgress.js"],"sourcesContent":["// Subir un formulario con archivos (multipart) con el AVANCE real de la subida.\n//\n// fetch no dice cuántos bytes del cuerpo ya viajaron; XMLHttpRequest sí (xhr.upload.onprogress). Es UNA petición normal,\n// el mismo POST de siempre, pero la pantalla puede pintar «Subiendo 47 %».\n//\n// El avance llega a 100 % cuando el CUERPO terminó de viajar; lo que sigue (el servidor procesando y la respuesta\n// bajando) ya no se puede medir aquí: la pantalla cambia a «procesando…» sin porcentaje (uploadMachine lo hace sola).\n//\n// Responde como fetch: un Response (res.ok, res.status, res.headers, res.json(), res.blob()), así quien llama trata el\n// error RFC 9457 igual que con cualquier otra petición. La cancelación también es la de fetch: AbortSignal → AbortError.\n//\n// Funciones del navegador, sin React: function (regla de la casa). Se prueba con node --test (uploadWithProgress.test.js)\n// con un XMLHttpRequest de mentira.\nimport {toolkitSettings} from '@/toolkit/toolkitSettings.js';\n\nconst PERCENT = 100;\n\n/**\n * Los headers de XMLHttpRequest ('k: v\\r\\nk2: v2') como objeto para Response.\n *\n * @param {string|null} rawHeaders\n * @returns {Record<string, string>}\n */\nfunction headersOf(rawHeaders) {\n const headers = {};\n for (const line of String(rawHeaders ?? '').trim().split(/[\\r\\n]+/)) {\n const separatorPosition = line.indexOf(': ');\n if (separatorPosition > 0) {\n headers[line.slice(0, separatorPosition)] = line.slice(separatorPosition + 2);\n }\n }\n return headers;\n}\n\n/**\n * @param {string} url\n * @param {FormData} formData los archivos y los campos que pida el backend\n * @param {object} [options]\n * @param {Record<string, string>} [options.headers] p. ej. Authorization; Accept-Language ya va con el idioma activo\n * @param {(percent: number) => void} [options.onProgress] 0 a 100 de lo que ya viajó del cuerpo\n * @param {AbortSignal} [options.signal]\n * @param {boolean} [options.withCredentials] manda las cookies a otro dominio (sesión de Sanctum en otro subdominio)\n * @returns {Promise<Response>}\n */\nexport function uploadWithProgress(url, formData, {headers = {}, onProgress, signal, withCredentials = false} = {}) {\n return new Promise((resolve, reject) => {\n // guard clause: ya venía cancelada\n if (signal?.aborted) {\n reject(new DOMException('La subida se canceló', 'AbortError'));\n return;\n }\n\n const request = new XMLHttpRequest();\n request.open('POST', url);\n request.responseType = 'blob';\n request.withCredentials = withCredentials;\n signal?.addEventListener('abort', () => request.abort(), {once: true});\n\n // OJO: Content-Type NO se pone a mano: el navegador lo arma con el separador del multipart; puesto a mano, el\n // servidor no encuentra los archivos\n const finalHeaders = {'Accept-Language': toolkitSettings().language, ...headers};\n for (const [name, value] of Object.entries(finalHeaders)) {\n request.setRequestHeader(name, value);\n }\n\n request.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n onProgress?.(Math.round((event.loaded / event.total) * PERCENT));\n }\n };\n request.onload = () => {\n resolve(new Response(request.response, {status: request.status, headers: headersOf(request.getAllResponseHeaders())}));\n };\n request.onerror = () => reject(new TypeError('No hubo respuesta del servidor'));\n request.ontimeout = () => reject(new TypeError('El servidor tardó demasiado en responder'));\n request.onabort = () => reject(new DOMException('La subida se canceló', 'AbortError'));\n request.send(formData);\n });\n}\n"],"names":[],"mappings":";AAeA,MAAM,UAAU;AAQhB,SAAS,UAAU,YAAY;AAC3B,QAAM,UAAU,CAAA;AAChB,aAAW,QAAQ,OAAO,cAAc,EAAE,EAAE,KAAI,EAAG,MAAM,SAAS,GAAG;AACjE,UAAM,oBAAoB,KAAK,QAAQ,IAAI;AAC3C,QAAI,oBAAoB,GAAG;AACvB,cAAQ,KAAK,MAAM,GAAG,iBAAiB,CAAC,IAAI,KAAK,MAAM,oBAAoB,CAAC;AAAA,IAChF;AAAA,EACJ;AACA,SAAO;AACX;AAYO,SAAS,mBAAmB,KAAK,UAAU,EAAC,UAAU,CAAA,GAAI,YAAY,QAAQ,kBAAkB,MAAK,IAAI,CAAA,GAAI;AAChH,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAEpC,QAAI,QAAQ,SAAS;AACjB,aAAO,IAAI,aAAa,wBAAwB,YAAY,CAAC;AAC7D;AAAA,IACJ;AAEA,UAAM,UAAU,IAAI,eAAc;AAClC,YAAQ,KAAK,QAAQ,GAAG;AACxB,YAAQ,eAAe;AACvB,YAAQ,kBAAkB;AAC1B,YAAQ,iBAAiB,SAAS,MAAM,QAAQ,SAAS,EAAC,MAAM,KAAI,CAAC;AAIrE,UAAM,eAAe,EAAC,mBAAmB,gBAAe,EAAG,UAAU,GAAG,QAAO;AAC/E,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACtD,cAAQ,iBAAiB,MAAM,KAAK;AAAA,IACxC;AAEA,YAAQ,OAAO,aAAa,CAAC,UAAU;AACnC,UAAI,MAAM,kBAAkB;AACxB,qBAAa,KAAK,MAAO,MAAM,SAAS,MAAM,QAAS,OAAO,CAAC;AAAA,MACnE;AAAA,IACJ;AACA,YAAQ,SAAS,MAAM;AACnB,cAAQ,IAAI,SAAS,QAAQ,UAAU,EAAC,QAAQ,QAAQ,QAAQ,SAAS,UAAU,QAAQ,sBAAqB,CAAE,EAAC,CAAC,CAAC;AAAA,IACzH;AACA,YAAQ,UAAU,MAAM,OAAO,IAAI,UAAU,gCAAgC,CAAC;AAC9E,YAAQ,YAAY,MAAM,OAAO,IAAI,UAAU,0CAA0C,CAAC;AAC1F,YAAQ,UAAU,MAAM,OAAO,IAAI,aAAa,wBAAwB,YAAY,CAAC;AACrF,YAAQ,KAAK,QAAQ;AAAA,EACzB,CAAC;AACL;"}
1
+ {"version":3,"file":"uploadWithProgress.js","sources":["../../src/upload/uploadWithProgress.js"],"sourcesContent":["// Subir un formulario con archivos (multipart) con el AVANCE real de la subida.\n//\n// fetch no dice cuántos bytes del cuerpo ya viajaron; XMLHttpRequest sí (xhr.upload.onprogress). Es UNA petición normal,\n// el mismo POST de siempre, pero la pantalla puede pintar «Subiendo 47 %».\n//\n// El avance llega a 100 % cuando el CUERPO terminó de viajar; lo que sigue (el servidor procesando y la respuesta\n// bajando) ya no se puede medir aquí: la pantalla cambia a «procesando…» sin porcentaje (uploadMachine lo hace sola).\n//\n// Responde como fetch: un Response (res.ok, res.status, res.headers, res.json(), res.blob()), así quien llama trata el\n// error RFC 9457 igual que con cualquier otra petición. La cancelación también es la de fetch: AbortSignal → AbortError.\n//\n// Funciones del navegador, sin React: function (regla de la casa). Se prueba con node --test (uploadWithProgress.test.js)\n// con un XMLHttpRequest de mentira.\nimport {toolkitSettings} from '@/toolkit/toolkitSettings.js';\n\nconst PERCENT = 100;\n\n/**\n * Los headers de XMLHttpRequest ('k: v\\r\\nk2: v2') como objeto para Response.\n *\n * @param {string|null} rawHeaders\n * @returns {Record<string, string>}\n */\nfunction headersOf(rawHeaders) {\n const headers = {};\n for (const line of String(rawHeaders ?? '').trim().split(/[\\r\\n]+/)) {\n const separatorPosition = line.indexOf(': ');\n if (separatorPosition > 0) {\n headers[line.slice(0, separatorPosition)] = line.slice(separatorPosition + 2);\n }\n }\n return headers;\n}\n\n/**\n * @param {string} url\n * @param {FormData} formData los archivos y los campos que pida el backend\n * @param {object} [options]\n * @param {Record<string, string>} [options.headers] p. ej. Authorization; Accept-Language ya va con el idioma activo\n * @param {(percent: number, transfer: {loaded: number, total: number}) => void} [options.onProgress] 0 a 100 de lo que ya\n * viajó del cuerpo, y los bytes (para la velocidad y lo que falta)\n * @param {AbortSignal} [options.signal]\n * @param {boolean} [options.withCredentials] manda las cookies a otro dominio (sesión de Sanctum en otro subdominio)\n * @returns {Promise<Response>}\n */\nexport function uploadWithProgress(url, formData, {headers = {}, onProgress, signal, withCredentials = false} = {}) {\n return new Promise((resolve, reject) => {\n // guard clause: ya venía cancelada\n if (signal?.aborted) {\n reject(new DOMException('La subida se canceló', 'AbortError'));\n return;\n }\n\n const request = new XMLHttpRequest();\n request.open('POST', url);\n request.responseType = 'blob';\n request.withCredentials = withCredentials;\n signal?.addEventListener('abort', () => request.abort(), {once: true});\n\n // OJO: Content-Type NO se pone a mano: el navegador lo arma con el separador del multipart; puesto a mano, el\n // servidor no encuentra los archivos\n const finalHeaders = {'Accept-Language': toolkitSettings().language, ...headers};\n for (const [name, value] of Object.entries(finalHeaders)) {\n request.setRequestHeader(name, value);\n }\n\n request.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n onProgress?.(Math.round((event.loaded / event.total) * PERCENT), {loaded: event.loaded, total: event.total});\n }\n };\n request.onload = () => {\n resolve(new Response(request.response, {status: request.status, headers: headersOf(request.getAllResponseHeaders())}));\n };\n request.onerror = () => reject(new TypeError('No hubo respuesta del servidor'));\n request.ontimeout = () => reject(new TypeError('El servidor tardó demasiado en responder'));\n request.onabort = () => reject(new DOMException('La subida se canceló', 'AbortError'));\n request.send(formData);\n });\n}\n"],"names":[],"mappings":";AAeA,MAAM,UAAU;AAQhB,SAAS,UAAU,YAAY;AAC3B,QAAM,UAAU,CAAA;AAChB,aAAW,QAAQ,OAAO,cAAc,EAAE,EAAE,KAAI,EAAG,MAAM,SAAS,GAAG;AACjE,UAAM,oBAAoB,KAAK,QAAQ,IAAI;AAC3C,QAAI,oBAAoB,GAAG;AACvB,cAAQ,KAAK,MAAM,GAAG,iBAAiB,CAAC,IAAI,KAAK,MAAM,oBAAoB,CAAC;AAAA,IAChF;AAAA,EACJ;AACA,SAAO;AACX;AAaO,SAAS,mBAAmB,KAAK,UAAU,EAAC,UAAU,CAAA,GAAI,YAAY,QAAQ,kBAAkB,MAAK,IAAI,CAAA,GAAI;AAChH,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAEpC,QAAI,QAAQ,SAAS;AACjB,aAAO,IAAI,aAAa,wBAAwB,YAAY,CAAC;AAC7D;AAAA,IACJ;AAEA,UAAM,UAAU,IAAI,eAAc;AAClC,YAAQ,KAAK,QAAQ,GAAG;AACxB,YAAQ,eAAe;AACvB,YAAQ,kBAAkB;AAC1B,YAAQ,iBAAiB,SAAS,MAAM,QAAQ,SAAS,EAAC,MAAM,KAAI,CAAC;AAIrE,UAAM,eAAe,EAAC,mBAAmB,gBAAe,EAAG,UAAU,GAAG,QAAO;AAC/E,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACtD,cAAQ,iBAAiB,MAAM,KAAK;AAAA,IACxC;AAEA,YAAQ,OAAO,aAAa,CAAC,UAAU;AACnC,UAAI,MAAM,kBAAkB;AACxB,qBAAa,KAAK,MAAO,MAAM,SAAS,MAAM,QAAS,OAAO,GAAG,EAAC,QAAQ,MAAM,QAAQ,OAAO,MAAM,MAAK,CAAC;AAAA,MAC/G;AAAA,IACJ;AACA,YAAQ,SAAS,MAAM;AACnB,cAAQ,IAAI,SAAS,QAAQ,UAAU,EAAC,QAAQ,QAAQ,QAAQ,SAAS,UAAU,QAAQ,sBAAqB,CAAE,EAAC,CAAC,CAAC;AAAA,IACzH;AACA,YAAQ,UAAU,MAAM,OAAO,IAAI,UAAU,gCAAgC,CAAC;AAC9E,YAAQ,YAAY,MAAM,OAAO,IAAI,UAAU,0CAA0C,CAAC;AAC1F,YAAQ,UAAU,MAAM,OAAO,IAAI,aAAa,wBAAwB,YAAY,CAAC;AACrF,YAAQ,KAAK,QAAQ;AAAA,EACzB,CAAC;AACL;"}
@@ -0,0 +1,101 @@
1
+ "use client";
2
+ import { useRef, useState } from "react";
3
+ import { toastError } from "../feedback/toast.js";
4
+ import { useFormatters } from "../toolkit/useFormatters.js";
5
+ import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
6
+ import { resolveAccept, parseFileSize, screenFiles, FILE_REJECTION } from "./fileRules.js";
7
+ function useFilePicker({
8
+ accept,
9
+ maxSize,
10
+ multiple = false,
11
+ maxFiles,
12
+ maxTotalSize,
13
+ keptFiles = [],
14
+ disabled = false,
15
+ onAccept,
16
+ onReject,
17
+ texts
18
+ }) {
19
+ const { t } = useToolkitTranslation("common", texts);
20
+ const { formatFileSize } = useFormatters();
21
+ const inputRef = useRef(null);
22
+ const [isDragging, setIsDragging] = useState(false);
23
+ const resolvedAccept = resolveAccept(accept);
24
+ const maxBytes = parseFileSize(maxSize);
25
+ const maxTotalBytes = multiple ? parseFileSize(maxTotalSize) : null;
26
+ const rejectionTextOf = (file, reason) => {
27
+ switch (reason) {
28
+ case FILE_REJECTION.size:
29
+ return t("upload.tooLarge", { name: file.name, max: formatFileSize(maxBytes) });
30
+ case FILE_REJECTION.count:
31
+ return t("upload.tooManyFiles", { count: maxFiles });
32
+ case FILE_REJECTION.total:
33
+ return t("upload.totalTooLarge", { name: file.name, max: formatFileSize(maxTotalBytes) });
34
+ default:
35
+ return t("upload.invalidType", { name: file.name, accept: resolvedAccept });
36
+ }
37
+ };
38
+ const pickFiles = (fileList) => {
39
+ const picked = [...fileList ?? []].slice(0, multiple ? void 0 : 1);
40
+ if (!picked.length || disabled) {
41
+ return;
42
+ }
43
+ const { files, accepted, rejected } = screenFiles(picked, {
44
+ resolvedAccept,
45
+ maxBytes,
46
+ maxFiles: multiple ? maxFiles : void 0,
47
+ maxTotalBytes,
48
+ keptFiles: multiple ? keptFiles : []
49
+ });
50
+ for (const { file, reason } of rejected) {
51
+ if (onReject) {
52
+ onReject(file, reason);
53
+ } else {
54
+ toastError(rejectionTextOf(file, reason));
55
+ }
56
+ }
57
+ if (accepted.length) {
58
+ onAccept(multiple ? files : accepted[0]);
59
+ }
60
+ };
61
+ const open = () => {
62
+ if (disabled || !inputRef.current) {
63
+ return;
64
+ }
65
+ inputRef.current.value = "";
66
+ inputRef.current.click();
67
+ };
68
+ return {
69
+ open,
70
+ pickFiles,
71
+ isDragging,
72
+ resolvedAccept,
73
+ maxBytes,
74
+ maxTotalBytes,
75
+ inputProps: {
76
+ ref: inputRef,
77
+ type: "file",
78
+ accept: resolvedAccept,
79
+ multiple,
80
+ hidden: true,
81
+ disabled,
82
+ onChange: (event) => pickFiles(event.target.files)
83
+ },
84
+ dropHandlers: {
85
+ onDragOver: (event) => {
86
+ event.preventDefault();
87
+ setIsDragging(!disabled);
88
+ },
89
+ onDragLeave: () => setIsDragging(false),
90
+ onDrop: (event) => {
91
+ event.preventDefault();
92
+ setIsDragging(false);
93
+ pickFiles(event.dataTransfer?.files);
94
+ }
95
+ }
96
+ };
97
+ }
98
+ export {
99
+ useFilePicker
100
+ };
101
+ //# sourceMappingURL=useFilePicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFilePicker.js","sources":["../../src/upload/useFilePicker.js"],"sourcesContent":["// Lo que necesita cualquier cargador para ELEGIR archivos: la ventana de archivos del sistema, soltar encima, revisar tipo,\n// peso, cuántos y cuánto pesan juntos (screenFiles), y avisar lo que no pasó. Lo usan los cargadores del paquete (la zona,\n// el compacto, «Adjuntar» y la imagen) y queda suelto para que un proyecto arme el suyo con su propio botón:\n//\n// const picker = useFilePicker({accept: 'pdf', maxSize: '5 MB', onAccept: setFile});\n// <input {...picker.inputProps} />\n// <Button onClick={picker.open} {...picker.dropHandlers}>Subir el contrato</Button>\n//\n// Solo elige: enviarlo es de la pantalla (uploadWithProgress). Lo rechazado se avisa con toastError y los textos del\n// paquete; con onReject la pantalla decide qué hacer.\n//\n// Hook genérico: function (regla de la casa).\nimport {useRef, useState} from 'react';\n\nimport {toastError} from '@/feedback/toast.jsx';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {FILE_REJECTION, parseFileSize, resolveAccept, screenFiles} from '@/upload/fileRules.js';\n\n/**\n * @param {object} options\n * @param {string|string[]} [options.accept] 'excel' | ['excel', 'pdf'] | '.xlsx,.xls' | 'image/*'\n * @param {number|string} [options.maxSize] el peso máximo de cada archivo: bytes o '10 MB'\n * @param {boolean} [options.multiple] varios a la vez; sin él, solo el primero que se elija o se suelte\n * @param {number} [options.maxFiles] con multiple: cuántos como máximo, contando los que ya estaban\n * @param {number|string} [options.maxTotalSize] con multiple: cuánto pueden pesar todos juntos\n * @param {Array<{name: string, size?: number}>} [options.keptFiles] con multiple: los que ya estaban (cuentan en los topes)\n * @param {boolean} [options.disabled] no se puede elegir ni soltar (también mientras se sube)\n * @param {(picked: any) => void} options.onAccept sin multiple, el archivo; con multiple, la lista completa (los que ya\n * estaban y los nuevos), lista para guardarse\n * @param {(file: File, reason: string) => void} [options.onReject] reason es uno de FILE_REJECTION; sin él, un aviso\n * @param {object} [options.texts] los textos que cambian, con la forma de `common`\n * @returns {{inputProps: object, open: () => void, pickFiles: (fileList: FileList|File[]|null|undefined) => void, isDragging: boolean, dropHandlers: object, resolvedAccept: string|undefined, maxBytes: number|null, maxTotalBytes: number|null}}\n */\nexport function useFilePicker({\n accept, maxSize, multiple = false, maxFiles, maxTotalSize, keptFiles = [], disabled = false, onAccept, onReject, texts,\n}) {\n const {t} = useToolkitTranslation('common', texts);\n const {formatFileSize} = useFormatters();\n const inputRef = useRef(null);\n const [isDragging, setIsDragging] = useState(false);\n const resolvedAccept = resolveAccept(accept);\n const maxBytes = parseFileSize(maxSize);\n const maxTotalBytes = multiple ? parseFileSize(maxTotalSize) : null;\n\n // el aviso de cada motivo, con el nombre del archivo y el límite que no cumplió\n const rejectionTextOf = (file, reason) => {\n switch (reason) {\n case FILE_REJECTION.size:\n return t('upload.tooLarge', {name: file.name, max: formatFileSize(maxBytes)});\n case FILE_REJECTION.count:\n return t('upload.tooManyFiles', {count: maxFiles});\n case FILE_REJECTION.total:\n return t('upload.totalTooLarge', {name: file.name, max: formatFileSize(maxTotalBytes)});\n default:\n return t('upload.invalidType', {name: file.name, accept: resolvedAccept});\n }\n };\n\n const pickFiles = (fileList) => {\n // se cerró la ventana sin elegir, o el candado está puesto\n const picked = [...(fileList ?? [])].slice(0, multiple ? undefined : 1);\n if (!picked.length || disabled) {\n return;\n }\n const {files, accepted, rejected} = screenFiles(picked, {\n resolvedAccept, maxBytes, maxFiles: multiple ? maxFiles : undefined, maxTotalBytes, keptFiles: multiple ? keptFiles : [],\n });\n for (const {file, reason} of rejected) {\n if (onReject) {\n onReject(file, reason);\n } else {\n toastError(rejectionTextOf(file, reason));\n }\n }\n if (accepted.length) {\n onAccept(multiple ? files : accepted[0]);\n }\n };\n\n const open = () => {\n if (disabled || !inputRef.current) {\n return;\n }\n // OJO: se limpia el valor del input para poder volver a elegir EL MISMO archivo (corregido en disco); sin esto el\n // navegador no avisa el cambio\n inputRef.current.value = '';\n inputRef.current.click();\n };\n\n return {\n open,\n pickFiles,\n isDragging,\n resolvedAccept,\n maxBytes,\n maxTotalBytes,\n inputProps: {\n ref: inputRef, type: 'file', accept: resolvedAccept, multiple, hidden: true, disabled,\n onChange: (event) => pickFiles(event.target.files),\n },\n dropHandlers: {\n onDragOver: (event) => {\n event.preventDefault();\n setIsDragging(!disabled);\n },\n onDragLeave: () => setIsDragging(false),\n onDrop: (event) => {\n event.preventDefault();\n setIsDragging(false);\n pickFiles(event.dataTransfer?.files);\n },\n },\n };\n}\n"],"names":[],"mappings":";;;;;;AAkCO,SAAS,cAAc;AAAA,EAC1B;AAAA,EAAQ;AAAA,EAAS,WAAW;AAAA,EAAO;AAAA,EAAU;AAAA,EAAc,YAAY,CAAA;AAAA,EAAI,WAAW;AAAA,EAAO;AAAA,EAAU;AAAA,EAAU;AACrH,GAAG;AACC,QAAM,EAAC,EAAC,IAAI,sBAAsB,UAAU,KAAK;AACjD,QAAM,EAAC,eAAc,IAAI,cAAa;AACtC,QAAM,WAAW,OAAO,IAAI;AAC5B,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAClD,QAAM,iBAAiB,cAAc,MAAM;AAC3C,QAAM,WAAW,cAAc,OAAO;AACtC,QAAM,gBAAgB,WAAW,cAAc,YAAY,IAAI;AAG/D,QAAM,kBAAkB,CAAC,MAAM,WAAW;AACtC,YAAQ,QAAM;AAAA,MACV,KAAK,eAAe;AAChB,eAAO,EAAE,mBAAmB,EAAC,MAAM,KAAK,MAAM,KAAK,eAAe,QAAQ,EAAC,CAAC;AAAA,MAChF,KAAK,eAAe;AAChB,eAAO,EAAE,uBAAuB,EAAC,OAAO,SAAQ,CAAC;AAAA,MACrD,KAAK,eAAe;AAChB,eAAO,EAAE,wBAAwB,EAAC,MAAM,KAAK,MAAM,KAAK,eAAe,aAAa,EAAC,CAAC;AAAA,MAC1F;AACI,eAAO,EAAE,sBAAsB,EAAC,MAAM,KAAK,MAAM,QAAQ,eAAc,CAAC;AAAA,IACxF;AAAA,EACI;AAEA,QAAM,YAAY,CAAC,aAAa;AAE5B,UAAM,SAAS,CAAC,GAAI,YAAY,EAAG,EAAE,MAAM,GAAG,WAAW,SAAY,CAAC;AACtE,QAAI,CAAC,OAAO,UAAU,UAAU;AAC5B;AAAA,IACJ;AACA,UAAM,EAAC,OAAO,UAAU,SAAQ,IAAI,YAAY,QAAQ;AAAA,MACpD;AAAA,MAAgB;AAAA,MAAU,UAAU,WAAW,WAAW;AAAA,MAAW;AAAA,MAAe,WAAW,WAAW,YAAY,CAAA;AAAA,IAClI,CAAS;AACD,eAAW,EAAC,MAAM,OAAM,KAAK,UAAU;AACnC,UAAI,UAAU;AACV,iBAAS,MAAM,MAAM;AAAA,MACzB,OAAO;AACH,mBAAW,gBAAgB,MAAM,MAAM,CAAC;AAAA,MAC5C;AAAA,IACJ;AACA,QAAI,SAAS,QAAQ;AACjB,eAAS,WAAW,QAAQ,SAAS,CAAC,CAAC;AAAA,IAC3C;AAAA,EACJ;AAEA,QAAM,OAAO,MAAM;AACf,QAAI,YAAY,CAAC,SAAS,SAAS;AAC/B;AAAA,IACJ;AAGA,aAAS,QAAQ,QAAQ;AACzB,aAAS,QAAQ,MAAK;AAAA,EAC1B;AAEA,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,MACR,KAAK;AAAA,MAAU,MAAM;AAAA,MAAQ,QAAQ;AAAA,MAAgB;AAAA,MAAU,QAAQ;AAAA,MAAM;AAAA,MAC7E,UAAU,CAAC,UAAU,UAAU,MAAM,OAAO,KAAK;AAAA,IAC7D;AAAA,IACQ,cAAc;AAAA,MACV,YAAY,CAAC,UAAU;AACnB,cAAM,eAAc;AACpB,sBAAc,CAAC,QAAQ;AAAA,MAC3B;AAAA,MACA,aAAa,MAAM,cAAc,KAAK;AAAA,MACtC,QAAQ,CAAC,UAAU;AACf,cAAM,eAAc;AACpB,sBAAc,KAAK;AACnB,kBAAU,MAAM,cAAc,KAAK;AAAA,MACvC;AAAA,IACZ;AAAA,EACA;AACA;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackcraftmx/calcita",
3
- "version": "0.32.2",
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",
@@ -91,6 +91,14 @@
91
91
  "types": "./dist/types/money.d.ts",
92
92
  "import": "./dist/money.js"
93
93
  },
94
+ "./mexico": {
95
+ "types": "./dist/types/mexico.d.ts",
96
+ "import": "./dist/mexico.js"
97
+ },
98
+ "./rich-text": {
99
+ "types": "./dist/types/rich-text.d.ts",
100
+ "import": "./dist/rich-text.js"
101
+ },
94
102
  "./filepond": {
95
103
  "types": "./dist/types/filepond.d.ts",
96
104
  "import": "./dist/filepond.js"
@@ -164,12 +172,18 @@
164
172
  "@mui/x-data-grid": "^8.0.0",
165
173
  "@mui/x-date-pickers": "^8.0.0",
166
174
  "@simplewebauthn/browser": "^14.0.0",
175
+ "@tiptap/extension-text-align": "^3.0.0",
176
+ "@tiptap/extensions": "^3.0.0",
177
+ "@tiptap/pm": "^3.0.0",
178
+ "@tiptap/react": "^3.0.0",
179
+ "@tiptap/starter-kit": "^3.0.0",
167
180
  "@xstate/react": "^6.0.0",
168
181
  "dayjs": "^1.11.0",
169
182
  "filepond": "^4.32.0",
170
183
  "filepond-plugin-file-validate-size": "^2.2.8",
171
184
  "filepond-plugin-file-validate-type": "^1.2.9",
172
185
  "formik": "^2.4.0",
186
+ "jsrsasign": "^11.0.0",
173
187
  "leaflet": "^1.9.0",
174
188
  "next": ">=15.0.0",
175
189
  "nuqs": "^2.0.0",
@@ -179,6 +193,7 @@
179
193
  "react-hook-form": "^7.50.0",
180
194
  "react-leaflet": "^5.0.0",
181
195
  "react-router": "^7.0.0",
196
+ "react-window": "^2.0.0",
182
197
  "recharts": "^3.0.0",
183
198
  "sonner": "^2.0.0",
184
199
  "xstate": "^5.0.0",
@@ -221,6 +236,21 @@
221
236
  "@simplewebauthn/browser": {
222
237
  "optional": true
223
238
  },
239
+ "@tiptap/extension-text-align": {
240
+ "optional": true
241
+ },
242
+ "@tiptap/extensions": {
243
+ "optional": true
244
+ },
245
+ "@tiptap/pm": {
246
+ "optional": true
247
+ },
248
+ "@tiptap/react": {
249
+ "optional": true
250
+ },
251
+ "@tiptap/starter-kit": {
252
+ "optional": true
253
+ },
224
254
  "dayjs": {
225
255
  "optional": true
226
256
  },
@@ -236,6 +266,9 @@
236
266
  "formik": {
237
267
  "optional": true
238
268
  },
269
+ "jsrsasign": {
270
+ "optional": true
271
+ },
239
272
  "leaflet": {
240
273
  "optional": true
241
274
  },
@@ -257,6 +290,9 @@
257
290
  "react-router": {
258
291
  "optional": true
259
292
  },
293
+ "react-window": {
294
+ "optional": true
295
+ },
260
296
  "recharts": {
261
297
  "optional": true
262
298
  },
@@ -281,6 +317,11 @@
281
317
  "@mui/x-data-grid": "8.29.3",
282
318
  "@mui/x-date-pickers": "8.29.4",
283
319
  "@simplewebauthn/browser": "14.0.0",
320
+ "@tiptap/extension-text-align": "3.32.0",
321
+ "@tiptap/extensions": "3.32.0",
322
+ "@tiptap/pm": "3.32.0",
323
+ "@tiptap/react": "3.32.0",
324
+ "@tiptap/starter-kit": "3.32.0",
284
325
  "@types/leaflet": "1.9.22",
285
326
  "@types/react": "19.3.0",
286
327
  "@types/react-dom": "19.3.0",
@@ -293,6 +334,7 @@
293
334
  "filepond-plugin-file-validate-size": "2.2.8",
294
335
  "filepond-plugin-file-validate-type": "1.2.9",
295
336
  "formik": "2.4.9",
337
+ "jsrsasign": "11.1.5",
296
338
  "leaflet": "1.9.4",
297
339
  "next": "16.4.2",
298
340
  "nuqs": "2.10.1",
@@ -302,6 +344,7 @@
302
344
  "react-hook-form": "7.90.0",
303
345
  "react-leaflet": "5.0.0",
304
346
  "react-router": "7.18.3",
347
+ "react-window": "2.3.4",
305
348
  "recharts": "3.10.1",
306
349
  "sonner": "2.0.8",
307
350
  "tsc-alias": "1.9.7",
@@ -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
- }