@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimeInput.js","sources":["../../src/datePickers/TimeInput.jsx"],"sourcesContent":["// Campo de HORA suelto con el TimePicker de MUI X (@stackcraftmx/calcita/date-pickers), para una hora del día sin fecha:\n// la hora de una cita en un día ya elegido, el horario de una sucursal, «recordar a las 08:00».\n//\n// Viaja 'HH:mm' de 24 horas aunque en pantalla se vea con a.m. y p.m. (el hourCycle del proveedor decide cómo se ve, no\n// cómo viaja). Una hora del día no tiene zona: no se pasa por Date ni por UTC. '' = vacía.\n//\n// Para un instante (fecha y hora de algo que pasa una vez) va DateTimeInput, que sí viaja en UTC.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTimeInput con defaultProps, styleOverrides de\n// sus partes (picker) y slots/slotProps para cambiarlas.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {TimePicker} from '@mui/x-date-pickers/TimePicker';\n\nimport PickerFrame, {textFieldSlotPropsOf} from '@/datePickers/PickerFrame.jsx';\nimport {DEFAULT_MINUTES_STEP, pickerTimeOf, timeTextOf} from '@/datePickers/pickerValues.js';\nimport {usePickerField} from '@/datePickers/usePickerField.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaTimeInput)\nconst THEME_NAME = 'CalcitaTimeInput';\nconst TimeInputPicker = piecePart(THEME_NAME, 'Picker', TimePicker);\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|null|undefined} props.value 'HH:mm' o ''\n * @param {(value: string) => void} props.onChange recibe 'HH:mm' ('' al borrar o a medias)\n * @param {() => void} [props.onBlur]\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText]\n * @param {string} [props.minTime] 'HH:mm'\n * @param {string} [props.maxTime] 'HH:mm'\n * @param {number} [props.minutesStep] de cuánto en cuánto van los minutos; por omisión de uno en uno (30 para citas de\n * media hora)\n * @param {boolean} [props.disabled]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef]\n * @param {object} [props.pickerProps] lo demás del TimePicker de MUI X que aquí no tiene nombre (views, shouldDisableTime,\n * slots, slotProps…); value y onChange son del campo\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Elija la fecha', min: 'Desde mañana'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction TimeInputContent(props) {\n const {\n name, label, value, onChange, onBlur, error, helperText = ' ', minTime, maxTime, minutesStep = DEFAULT_MINUTES_STEP, disabled = false, inputRef,\n pickerProps, messages, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const field = usePickerField({name, kind: 'time', error, label, messages, texts});\n\n return (\n <PickerFrame inputId={field.inputId} label={label} language={field.language}>\n <TimeInputPicker\n {...pickerProps}\n format={field.formats.time}\n ampm={field.formats.ampm}\n value={pickerTimeOf(value)}\n minTime={pickerTimeOf(minTime) ?? undefined}\n maxTime={pickerTimeOf(maxTime) ?? undefined}\n disabled={disabled}\n minutesStep={minutesStep}\n timeSteps={{minutes: minutesStep, ...pickerProps?.timeSteps}}\n inputRef={inputRef}\n onChange={(pickedValue) => onChange(timeTextOf(pickedValue))}\n onClose={() => {\n pickerProps?.onClose?.();\n onBlur?.();\n }}\n slotProps={textFieldSlotPropsOf(\n {id: field.inputId, name, onBlur, error: Boolean(field.errorText), helperText: field.errorText ?? helperText},\n pickerProps,\n )}\n />\n </PickerFrame>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst TimeInput = withPieceSlots(TimeInputContent, THEME_NAME);\nexport default TimeInput;\n"],"names":[],"mappings":";;;;;;;;AAqBA,MAAM,aAAa;AACnB,MAAM,kBAAkB,UAAU,YAAY,UAAU,UAAU;AAuBlE,SAAS,iBAAiB,OAAO;AAC7B,QAAM;AAAA,IACF;AAAA,IAAM;AAAA,IAAO;AAAA,IAAO;AAAA,IAAU;AAAA,IAAQ;AAAA,IAAO,aAAa;AAAA,IAAK;AAAA,IAAS;AAAA,IAAS,cAAc;AAAA,IAAsB,WAAW;AAAA,IAAO;AAAA,IACvI;AAAA,IAAa;AAAA,IAAU;AAAA,IACvB,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AACnC,mBAAiB,YAAY,YAAY;AACzC,QAAM,QAAQ,eAAe,EAAC,MAAM,MAAM,QAAQ,OAAO,OAAO,UAAU,OAAM;AAEhF,SACI,oBAAC,eAAY,SAAS,MAAM,SAAS,OAAc,UAAU,MAAM,UAC/D,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACI,GAAG;AAAA,MACJ,QAAQ,MAAM,QAAQ;AAAA,MACtB,MAAM,MAAM,QAAQ;AAAA,MACpB,OAAO,aAAa,KAAK;AAAA,MACzB,SAAS,aAAa,OAAO,KAAK;AAAA,MAClC,SAAS,aAAa,OAAO,KAAK;AAAA,MAClC;AAAA,MACA;AAAA,MACA,WAAW,EAAC,SAAS,aAAa,GAAG,aAAa,UAAA;AAAA,MAClD;AAAA,MACA,UAAU,CAAC,gBAAgB,SAAS,WAAW,WAAW,CAAC;AAAA,MAC3D,SAAS,MAAM;AACX,qBAAa,UAAA;AACb,iBAAA;AAAA,MACJ;AAAA,MACA,WAAW;AAAA,QACP,EAAC,IAAI,MAAM,SAAS,MAAM,QAAQ,OAAO,QAAQ,MAAM,SAAS,GAAG,YAAY,MAAM,aAAa,WAAA;AAAA,QAClG;AAAA,MAAA;AAAA,IACJ;AAAA,EAAA,GAER;AAER;AAGA,MAAM,YAAY,eAAe,kBAAkB,UAAU;"}
@@ -0,0 +1,24 @@
1
+ import { instantPlusMinutes, earliestInstantFromNow } from "./pickerValues.js";
2
+ function minutesFromNowRule(minutes) {
3
+ return {
4
+ name: "minutesFromNow",
5
+ message: { key: "validation:minutesFromNow", values: { count: minutes } },
6
+ // la hora se toma al revisar, no al armar el esquema: el mínimo se recorre con el reloj
7
+ test: (value) => !value || Date.parse(String(value)) >= Date.parse(earliestInstantFromNow(minutes))
8
+ };
9
+ }
10
+ function minutesAfterRule(startField, minutes) {
11
+ return {
12
+ name: "minutesAfter",
13
+ message: { key: "validation:minutesAfter", values: { count: minutes } },
14
+ test: (value, context) => {
15
+ const earliest = instantPlusMinutes(context.parent?.[startField], minutes);
16
+ return !value || !earliest || Date.parse(String(value)) >= Date.parse(earliest);
17
+ }
18
+ };
19
+ }
20
+ export {
21
+ minutesAfterRule,
22
+ minutesFromNowRule
23
+ };
24
+ //# sourceMappingURL=dateTimeRules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dateTimeRules.js","sources":["../../src/datePickers/dateTimeRules.js"],"sourcesContent":["// Las reglas de yup para una fecha con hora que depende del reloj o de otro campo, con sus mensajes en el idioma activo:\n//\n// minutesFromNowRule(5) al menos 5 minutos después de ahora (publicar algo con anticipación)\n// minutesAfterRule('startsAt', 30) al menos 30 minutos después del campo startsAt (algo que dura al menos media hora)\n//\n// Yup.object({\n// startsAt: Yup.string().required().test(minutesFromNowRule(5)),\n// endsAt: Yup.string().required().test(minutesAfterRule('startsAt', 30)),\n// })\n//\n// Un campo vacío pasa: que sea obligatorio lo dice required(). El servidor vuelve a revisar: entre que se llena el\n// formulario y se guarda pasa el tiempo.\n//\n// Son objetos de .test() y no un Yup propio: el proyecto usa su copia de yup y aquí no se importa.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {earliestInstantFromNow, instantPlusMinutes} from '@/datePickers/pickerValues.js';\n\n/**\n * @param {number} minutes\n * @returns {{name: string, message: {key: string, values: {count: number}}, test: (value: unknown) => boolean}}\n */\nexport function minutesFromNowRule(minutes) {\n return {\n name: 'minutesFromNow',\n message: {key: 'validation:minutesFromNow', values: {count: minutes}},\n // la hora se toma al revisar, no al armar el esquema: el mínimo se recorre con el reloj\n test: (value) => !value || Date.parse(String(value)) >= Date.parse(earliestInstantFromNow(minutes)),\n };\n}\n\n/**\n * @param {string} startField el nombre del campo de inicio, en el mismo objeto del esquema\n * @param {number} minutes\n * @returns {{name: string, message: {key: string, values: {count: number}}, test: (value: unknown, context: {parent: object}) => boolean}}\n */\nexport function minutesAfterRule(startField, minutes) {\n return {\n name: 'minutesAfter',\n message: {key: 'validation:minutesAfter', values: {count: minutes}},\n test: (value, context) => {\n const earliest = instantPlusMinutes(context.parent?.[startField], minutes);\n // sin inicio todavía no hay contra qué comparar: eso lo dice la regla del inicio\n return !value || !earliest || Date.parse(String(value)) >= Date.parse(earliest);\n },\n };\n}\n"],"names":[],"mappings":";AAsBO,SAAS,mBAAmB,SAAS;AACxC,SAAO;AAAA,IACH,MAAM;AAAA,IACN,SAAS,EAAC,KAAK,6BAA6B,QAAQ,EAAC,OAAO,QAAO,EAAC;AAAA;AAAA,IAEpE,MAAM,CAAC,UAAU,CAAC,SAAS,KAAK,MAAM,OAAO,KAAK,CAAC,KAAK,KAAK,MAAM,uBAAuB,OAAO,CAAC;AAAA,EAC1G;AACA;AAOO,SAAS,iBAAiB,YAAY,SAAS;AAClD,SAAO;AAAA,IACH,MAAM;AAAA,IACN,SAAS,EAAC,KAAK,2BAA2B,QAAQ,EAAC,OAAO,QAAO,EAAC;AAAA,IAClE,MAAM,CAAC,OAAO,YAAY;AACtB,YAAM,WAAW,mBAAmB,QAAQ,SAAS,UAAU,GAAG,OAAO;AAEzE,aAAO,CAAC,SAAS,CAAC,YAAY,KAAK,MAAM,OAAO,KAAK,CAAC,KAAK,KAAK,MAAM,QAAQ;AAAA,IAClF;AAAA,EACR;AACA;"}
@@ -0,0 +1,106 @@
1
+ import dayjs from "dayjs";
2
+ import timezone from "dayjs/plugin/timezone.js";
3
+ import utc from "dayjs/plugin/utc.js";
4
+ const CALENDAR_DATE_FORMAT = "YYYY-MM-DD";
5
+ const CALENDAR_MONTH_FORMAT = "YYYY-MM";
6
+ const TIME_OF_DAY_FORMAT = "HH:mm";
7
+ const INSTANT_FORMAT = "YYYY-MM-DDTHH:mm:ss[Z]";
8
+ const DEFAULT_MINUTES_STEP = 1;
9
+ const MILLISECONDS_PER_MINUTE = 6e4;
10
+ const TIME_OF_DAY_REFERENCE_DATE = "2000-01-03";
11
+ const CALENDAR_MONTH_PATTERN = /^\d{4}-\d{2}$/;
12
+ const TIME_OF_DAY_PATTERN = /^\d{2}:\d{2}$/;
13
+ const DISPLAY_FORMATS_BY_LANGUAGE = Object.freeze({
14
+ es: { date: "DD/MM/YYYY", month: "MMMM YYYY" },
15
+ en: { date: "MM/DD/YYYY", month: "MMMM YYYY" }
16
+ });
17
+ const TIME_DISPLAY_FORMATS = Object.freeze({ h23: "HH:mm", h12: "hh:mm a" });
18
+ function zonedDayjs() {
19
+ dayjs.extend(utc);
20
+ dayjs.extend(timezone);
21
+ return dayjs;
22
+ }
23
+ function displayFormatsOf(language, hourCycle = "h23") {
24
+ const formats = DISPLAY_FORMATS_BY_LANGUAGE[language] ?? DISPLAY_FORMATS_BY_LANGUAGE.es;
25
+ const time = TIME_DISPLAY_FORMATS[hourCycle] ?? TIME_DISPLAY_FORMATS.h23;
26
+ return { ...formats, time, dateTime: `${formats.date} ${time}`, ampm: hourCycle === "h12" };
27
+ }
28
+ function timeZoneNameOf(timeZone, intlLocale, at = /* @__PURE__ */ new Date()) {
29
+ try {
30
+ const name = new Intl.DateTimeFormat(intlLocale, { timeZone, timeZoneName: "longGeneric" }).formatToParts(at).find((part) => part.type === "timeZoneName")?.value;
31
+ return name ? name.charAt(0).toLocaleUpperCase(intlLocale) + name.slice(1) : timeZone;
32
+ } catch {
33
+ return timeZone;
34
+ }
35
+ }
36
+ function pickerInstantOf(instantText, timeZone) {
37
+ const zoned = zonedDayjs();
38
+ if (!instantText) {
39
+ return null;
40
+ }
41
+ const instant = zoned.utc(instantText);
42
+ return instant.isValid() ? instant.tz(timeZone) : null;
43
+ }
44
+ function instantTextOf(pickedValue) {
45
+ return pickedValue?.isValid() ? pickedValue.utc().format(INSTANT_FORMAT) : "";
46
+ }
47
+ function earliestInstantFromNow(minutes, now = Date.now()) {
48
+ const nowMilliseconds = now instanceof Date ? now.getTime() : now;
49
+ const startOfMinute = Math.floor(nowMilliseconds / MILLISECONDS_PER_MINUTE) * MILLISECONDS_PER_MINUTE;
50
+ return instantTextOf(zonedDayjs()(startOfMinute + minutes * MILLISECONDS_PER_MINUTE));
51
+ }
52
+ function instantPlusMinutes(instantText, minutes) {
53
+ if (!instantText) {
54
+ return "";
55
+ }
56
+ const instant = zonedDayjs()(instantText);
57
+ return instant.isValid() ? instantTextOf(instant.add(minutes, "minute")) : "";
58
+ }
59
+ function latestInstantOf(...instantTexts) {
60
+ const present = instantTexts.filter(Boolean);
61
+ if (present.length === 0) {
62
+ return "";
63
+ }
64
+ return present.reduce((latest, candidate) => Date.parse(candidate) > Date.parse(latest) ? candidate : latest);
65
+ }
66
+ function pickerTimeOf(timeText) {
67
+ if (!timeText || !TIME_OF_DAY_PATTERN.test(timeText)) {
68
+ return null;
69
+ }
70
+ const time = dayjs(`${TIME_OF_DAY_REFERENCE_DATE}T${timeText}`);
71
+ return time.isValid() ? time : null;
72
+ }
73
+ function timeTextOf(pickedValue) {
74
+ return pickedValue?.isValid() ? pickedValue.format(TIME_OF_DAY_FORMAT) : "";
75
+ }
76
+ function pickerMonthOf(monthText) {
77
+ if (!monthText || !CALENDAR_MONTH_PATTERN.test(monthText)) {
78
+ return null;
79
+ }
80
+ const month = dayjs(`${monthText}-01`);
81
+ return month.isValid() ? month : null;
82
+ }
83
+ function monthTextOf(pickedValue) {
84
+ return pickedValue?.isValid() ? pickedValue.format(CALENDAR_MONTH_FORMAT) : "";
85
+ }
86
+ export {
87
+ CALENDAR_DATE_FORMAT,
88
+ CALENDAR_MONTH_FORMAT,
89
+ DEFAULT_MINUTES_STEP,
90
+ INSTANT_FORMAT,
91
+ MILLISECONDS_PER_MINUTE,
92
+ TIME_OF_DAY_FORMAT,
93
+ displayFormatsOf,
94
+ earliestInstantFromNow,
95
+ instantPlusMinutes,
96
+ instantTextOf,
97
+ latestInstantOf,
98
+ monthTextOf,
99
+ pickerInstantOf,
100
+ pickerMonthOf,
101
+ pickerTimeOf,
102
+ timeTextOf,
103
+ timeZoneNameOf,
104
+ zonedDayjs
105
+ };
106
+ //# sourceMappingURL=pickerValues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pickerValues.js","sources":["../../src/datePickers/pickerValues.js"],"sourcesContent":["// Lo que comparten los campos de fecha, fecha con hora, hora y mes (@stackcraftmx/calcita/date-pickers): cómo viaja cada\n// valor, cómo se ve en cada idioma y cómo se nombra la zona horaria en pantalla.\n//\n// Cada campo viaja en texto, nunca como Date (que movería una fecha de día según la zona del navegador):\n// fecha 'AAAA-MM-DD' una fecha de calendario: no tiene hora ni zona\n// mes 'AAAA-MM' lo mismo, sin el día\n// hora 'HH:mm', de 24 horas una hora del día («abre a las 09:00»): tampoco tiene zona\n// fecha con hora '2026-11-01T18:30:00Z' un INSTANTE: viaja en UTC y se pinta en la zona del proveedor, rotulada\n// '' = vacío en los cuatro. Lo que llega del servidor con otra forma (un instante con -06:00) también se lee.\n//\n// Puro (sin React): se prueba con node (pickerValues.test.js).\n//\n// Genérico del paquete: function (regla de la casa).\nimport dayjs from 'dayjs';\nimport timezone from 'dayjs/plugin/timezone.js';\nimport utc from 'dayjs/plugin/utc.js';\n\n/** Cómo viaja una fecha de calendario. */\nexport const CALENDAR_DATE_FORMAT = 'YYYY-MM-DD';\n/** Cómo viaja un mes. */\nexport const CALENDAR_MONTH_FORMAT = 'YYYY-MM';\n/** Cómo viaja una hora del día (de 24 horas, aunque en pantalla se vea con a.m. y p.m.). */\nexport const TIME_OF_DAY_FORMAT = 'HH:mm';\n/** Cómo viaja un instante: en UTC, con la Z al final. */\nexport const INSTANT_FORMAT = 'YYYY-MM-DDTHH:mm:ss[Z]';\n/** De cuánto en cuánto van los minutos en la fecha con hora y en la hora: de uno en uno (MUI X trae de 5 en 5). */\nexport const DEFAULT_MINUTES_STEP = 1;\n/** Un minuto. */\nexport const MILLISECONDS_PER_MINUTE = 60_000;\n\n// una hora del día no tiene fecha, pero el selector de MUI X trabaja con fechas: se le pega a un día cualquiera sin cambio\n// de horario de verano en ningún país\nconst TIME_OF_DAY_REFERENCE_DATE = '2000-01-03';\nconst CALENDAR_MONTH_PATTERN = /^\\d{4}-\\d{2}$/;\nconst TIME_OF_DAY_PATTERN = /^\\d{2}:\\d{2}$/;\n\n// cómo se ve cada campo en pantalla según el idioma; el que no está aquí sale como el español (como DateInput desde antes)\nconst DISPLAY_FORMATS_BY_LANGUAGE = Object.freeze({\n es: {date: 'DD/MM/YYYY', month: 'MMMM YYYY'},\n en: {date: 'MM/DD/YYYY', month: 'MMMM YYYY'},\n});\n// la hora en pantalla según el hourCycle del proveedor: 15:10 o 03:10 p. m.\nconst TIME_DISPLAY_FORMATS = Object.freeze({h23: 'HH:mm', h12: 'hh:mm a'});\n\n/**\n * dayjs con las zonas horarias puestas: el selector de MUI X las necesita para pintar un instante en otra zona.\n * OJO: se llama al usarla y no al importar el archivo: el paquete se declara sin efectos al importar (sideEffects: false)\n * y un import solo por su efecto se lo puede saltar el empaquetador del proyecto.\n *\n * @returns {typeof dayjs}\n */\nexport function zonedDayjs() {\n // extend no repite: cada complemento se instala una sola vez\n dayjs.extend(utc);\n dayjs.extend(timezone);\n return dayjs;\n}\n\n/**\n * Cómo se ven en pantalla los cuatro campos.\n *\n * @param {string} language el del proveedor más cercano\n * @param {'h23'|'h12'} [hourCycle] el del proveedor; por omisión de 24 horas\n * @returns {{date: string, month: string, time: string, dateTime: string, ampm: boolean}}\n */\nexport function displayFormatsOf(language, hourCycle = 'h23') {\n const formats = DISPLAY_FORMATS_BY_LANGUAGE[language] ?? DISPLAY_FORMATS_BY_LANGUAGE.es;\n const time = TIME_DISPLAY_FORMATS[hourCycle] ?? TIME_DISPLAY_FORMATS.h23;\n return {...formats, time, dateTime: `${formats.date} ${time}`, ampm: hourCycle === 'h12'};\n}\n\n/**\n * El nombre de la zona horaria como lo dice una persona («Hora estándar central», «Pacific Time»), para rotular la fecha\n * con hora. Si el navegador no sabe nombrarla, la zona tal cual (America/Mexico_City).\n *\n * @param {string} timeZone la zona IANA del proveedor\n * @param {string} intlLocale es-MX, en-US…\n * @param {Date} [at] el momento que se nombra (en las zonas con horario de verano el nombre puede cambiar)\n * @returns {string}\n */\nexport function timeZoneNameOf(timeZone, intlLocale, at = new Date()) {\n try {\n const name = new Intl.DateTimeFormat(intlLocale, {timeZone, timeZoneName: 'longGeneric'})\n .formatToParts(at)\n .find((part) => part.type === 'timeZoneName')?.value;\n return name ? name.charAt(0).toLocaleUpperCase(intlLocale) + name.slice(1) : timeZone;\n } catch {\n return timeZone;\n }\n}\n\n/**\n * Un instante como lo quiere el selector, en la zona en que se pinta; null si está vacío o no se entiende.\n *\n * @param {string|null|undefined} instantText '2026-11-01T18:30:00Z' o con su desfase ('…-06:00')\n * @param {string} timeZone la zona en que se pinta\n * @returns {import('dayjs').Dayjs|null}\n */\nexport function pickerInstantOf(instantText, timeZone) {\n // OJO: las zonas se ponen ANTES de ver si está vacío. El selector con timezone las pide al pintarse aunque no tenga\n // valor («Missing UTC plugin»): un «Posponer hasta…» vacío tumbaba la pantalla\n const zoned = zonedDayjs();\n if (!instantText) {\n return null;\n }\n const instant = zoned.utc(instantText);\n return instant.isValid() ? instant.tz(timeZone) : null;\n}\n\n/**\n * Lo que eligió la persona como instante en UTC; '' si está vacío o a medias.\n *\n * @param {import('dayjs').Dayjs|null} pickedValue\n * @returns {string}\n */\nexport function instantTextOf(pickedValue) {\n return pickedValue?.isValid() ? pickedValue.utc().format(INSTANT_FORMAT) : '';\n}\n\n/**\n * El primer instante que se puede elegir cuando la regla es «al menos N minutos después de ahora» (publicar algo con\n * anticipación): este minuto, sin segundos, más N minutos. Sin segundos para que la regla no cambie entre que la persona\n * mira la hora y la elige.\n *\n * @param {number} minutes\n * @param {Date|number} [now]\n * @returns {string} el instante en UTC ('2026-11-02T18:35:00Z')\n */\nexport function earliestInstantFromNow(minutes, now = Date.now()) {\n const nowMilliseconds = now instanceof Date ? now.getTime() : now;\n const startOfMinute = Math.floor(nowMilliseconds / MILLISECONDS_PER_MINUTE) * MILLISECONDS_PER_MINUTE;\n return instantTextOf(zonedDayjs()(startOfMinute + minutes * MILLISECONDS_PER_MINUTE));\n}\n\n/**\n * Un instante más N minutos (el fin de algo que dura al menos N minutos desde su inicio). '' si el instante viene vacío\n * o no se entiende.\n *\n * @param {string|null|undefined} instantText\n * @param {number} minutes\n * @returns {string}\n */\nexport function instantPlusMinutes(instantText, minutes) {\n if (!instantText) {\n return '';\n }\n const instant = zonedDayjs()(instantText);\n return instant.isValid() ? instantTextOf(instant.add(minutes, 'minute')) : '';\n}\n\n/**\n * El más tarde de varios instantes (los vacíos no cuentan): el mínimo que de verdad aplica cuando hay más de una regla.\n *\n * @param {...(string|null|undefined)} instantTexts\n * @returns {string} '' si todos vienen vacíos\n */\nexport function latestInstantOf(...instantTexts) {\n const present = instantTexts.filter(Boolean);\n if (present.length === 0) {\n return '';\n }\n return present.reduce((latest, candidate) => (Date.parse(candidate) > Date.parse(latest) ? candidate : latest));\n}\n\n/**\n * Una hora del día 'HH:mm' como la quiere el selector; null si está vacía o no tiene esa forma.\n *\n * @param {string|null|undefined} timeText\n * @returns {import('dayjs').Dayjs|null}\n */\nexport function pickerTimeOf(timeText) {\n if (!timeText || !TIME_OF_DAY_PATTERN.test(timeText)) {\n return null;\n }\n const time = dayjs(`${TIME_OF_DAY_REFERENCE_DATE}T${timeText}`);\n return time.isValid() ? time : null;\n}\n\n/**\n * Lo que eligió la persona como 'HH:mm'; '' si está vacío o a medias.\n *\n * @param {import('dayjs').Dayjs|null} pickedValue\n * @returns {string}\n */\nexport function timeTextOf(pickedValue) {\n return pickedValue?.isValid() ? pickedValue.format(TIME_OF_DAY_FORMAT) : '';\n}\n\n/**\n * Un mes 'AAAA-MM' como lo quiere el selector (su día 1); null si está vacío o no tiene esa forma.\n *\n * @param {string|null|undefined} monthText\n * @returns {import('dayjs').Dayjs|null}\n */\nexport function pickerMonthOf(monthText) {\n if (!monthText || !CALENDAR_MONTH_PATTERN.test(monthText)) {\n return null;\n }\n // dayjs lee 'AAAA-MM-DD' como día local (new Date lo tomaría en UTC y lo movería de día)\n const month = dayjs(`${monthText}-01`);\n return month.isValid() ? month : null;\n}\n\n/**\n * Lo que eligió la persona como 'AAAA-MM'; '' si está vacío o a medias.\n *\n * @param {import('dayjs').Dayjs|null} pickedValue\n * @returns {string}\n */\nexport function monthTextOf(pickedValue) {\n return pickedValue?.isValid() ? pickedValue.format(CALENDAR_MONTH_FORMAT) : '';\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { useState, useEffect } from "react";
3
+ import { MILLISECONDS_PER_MINUTE } from "./pickerValues.js";
4
+ const startOfMinuteOf = (milliseconds) => Math.floor(milliseconds / MILLISECONDS_PER_MINUTE) * MILLISECONDS_PER_MINUTE;
5
+ function useCurrentMinute(enabled) {
6
+ const [currentMinute, setCurrentMinute] = useState(() => startOfMinuteOf(Date.now()));
7
+ useEffect(() => {
8
+ if (!enabled) {
9
+ return void 0;
10
+ }
11
+ let timer;
12
+ const waitForNextMinute = () => {
13
+ const untilNextMinute = MILLISECONDS_PER_MINUTE - Date.now() % MILLISECONDS_PER_MINUTE;
14
+ timer = setTimeout(() => {
15
+ setCurrentMinute(startOfMinuteOf(Date.now()));
16
+ waitForNextMinute();
17
+ }, untilNextMinute);
18
+ };
19
+ setCurrentMinute(startOfMinuteOf(Date.now()));
20
+ waitForNextMinute();
21
+ return () => clearTimeout(timer);
22
+ }, [enabled]);
23
+ return currentMinute;
24
+ }
25
+ export {
26
+ useCurrentMinute
27
+ };
28
+ //# sourceMappingURL=useCurrentMinute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCurrentMinute.js","sources":["../../src/datePickers/useCurrentMinute.js"],"sourcesContent":["// El minuto de ahora, que se actualiza solo al empezar cada minuto: para una regla como «al menos 5 minutos después de\n// ahora», que se va recorriendo mientras la pantalla está abierta (si la persona deja el formulario abierto diez minutos,\n// el mínimo ya no es el de cuando lo abrió).\n//\n// Un solo temporizador, hasta el siguiente minuto en punto; se apaga al salir de la pantalla o si enabled es false.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useState} from 'react';\n\nimport {MILLISECONDS_PER_MINUTE} from '@/datePickers/pickerValues.js';\n\nconst startOfMinuteOf = (milliseconds) => Math.floor(milliseconds / MILLISECONDS_PER_MINUTE) * MILLISECONDS_PER_MINUTE;\n\n/**\n * @param {boolean} enabled sin regla que dependa de la hora no hace falta el temporizador\n * @returns {number} el inicio del minuto de ahora, en milisegundos\n */\nexport function useCurrentMinute(enabled) {\n const [currentMinute, setCurrentMinute] = useState(() => startOfMinuteOf(Date.now()));\n\n useEffect(() => {\n if (!enabled) {\n return undefined;\n }\n let timer;\n const waitForNextMinute = () => {\n const untilNextMinute = MILLISECONDS_PER_MINUTE - (Date.now() % MILLISECONDS_PER_MINUTE);\n timer = setTimeout(() => {\n setCurrentMinute(startOfMinuteOf(Date.now()));\n waitForNextMinute();\n }, untilNextMinute);\n };\n // al volver a encender, el minuto puede haber cambiado mientras estaba apagado\n setCurrentMinute(startOfMinuteOf(Date.now()));\n waitForNextMinute();\n return () => clearTimeout(timer);\n }, [enabled]);\n\n return currentMinute;\n}\n"],"names":[],"mappings":";;;AAWA,MAAM,kBAAkB,CAAC,iBAAiB,KAAK,MAAM,eAAe,uBAAuB,IAAI;AAMxF,SAAS,iBAAiB,SAAS;AACtC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,MAAM,gBAAgB,KAAK,IAAG,CAAE,CAAC;AAEpF,YAAU,MAAM;AACZ,QAAI,CAAC,SAAS;AACV,aAAO;AAAA,IACX;AACA,QAAI;AACJ,UAAM,oBAAoB,MAAM;AAC5B,YAAM,kBAAkB,0BAA2B,KAAK,IAAG,IAAK;AAChE,cAAQ,WAAW,MAAM;AACrB,yBAAiB,gBAAgB,KAAK,IAAG,CAAE,CAAC;AAC5C,0BAAiB;AAAA,MACrB,GAAG,eAAe;AAAA,IACtB;AAEA,qBAAiB,gBAAgB,KAAK,IAAG,CAAE,CAAC;AAC5C,sBAAiB;AACjB,WAAO,MAAM,aAAa,KAAK;AAAA,EACnC,GAAG,CAAC,OAAO,CAAC;AAEZ,SAAO;AACX;"}
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { useId } from "react";
3
+ import { displayFormatsOf } from "./pickerValues.js";
4
+ import { useValidationText } from "../forms/useValidationText.js";
5
+ import { useToolkitSettings } from "../toolkit/toolkitContext.js";
6
+ import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
7
+ function usePickerField({ name, kind, error, label, messages, texts }) {
8
+ const { language } = useToolkitTranslation("common", texts);
9
+ const validationTextOf = useValidationText({ name, label, messages });
10
+ const { timeZone, hourCycle } = useToolkitSettings();
11
+ const generatedId = useId();
12
+ return {
13
+ language,
14
+ timeZone,
15
+ inputId: `${name ?? kind}-${generatedId}`,
16
+ errorText: validationTextOf(error),
17
+ formats: displayFormatsOf(language, hourCycle)
18
+ };
19
+ }
20
+ export {
21
+ usePickerField
22
+ };
23
+ //# sourceMappingURL=usePickerField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePickerField.js","sources":["../../src/datePickers/usePickerField.js"],"sourcesContent":["// Lo que necesita cada campo de fecha antes de pintarse: los textos (con los de la pantalla encima), el id que une la\n// etiqueta con el campo, el error ya traducido y cómo se ve en el idioma y el hourCycle del proveedor más cercano.\n//\n// Hook genérico: function (regla de la casa).\nimport {useId} from 'react';\n\nimport {displayFormatsOf} from '@/datePickers/pickerValues.js';\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport {useToolkitSettings} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\n\n/**\n * @param {object} field\n * @param {string} [field.name]\n * @param {string} field.kind de qué campo es (date, dateTime, time, month): da el principio del id si no hay name\n * @param {string|{key: string, values?: object}} [field.error]\n * @param {string} [field.label] el nombre del campo, para los textos de error que lo dicen\n * @param {Record<string, string|object>} [field.messages] el texto del error por regla de validación (gana al de Calcita)\n * @param {object} [field.texts] los textos que cambian, con la forma de `common`\n * @returns {{language: string, timeZone: string, inputId: string, errorText: string|undefined, formats: ReturnType<typeof displayFormatsOf>}}\n */\nexport function usePickerField({name, kind, error, label, messages, texts}) {\n const {language} = useToolkitTranslation('common', texts);\n const validationTextOf = useValidationText({name, label, messages});\n const {timeZone, hourCycle} = useToolkitSettings();\n const generatedId = useId();\n\n return {\n language,\n timeZone,\n inputId: `${name ?? kind}-${generatedId}`,\n errorText: validationTextOf(error),\n formats: displayFormatsOf(language, hourCycle),\n };\n}\n"],"names":[],"mappings":";;;;;;AAqBO,SAAS,eAAe,EAAC,MAAM,MAAM,OAAO,OAAO,UAAU,MAAK,GAAG;AACxE,QAAM,EAAC,SAAQ,IAAI,sBAAsB,UAAU,KAAK;AACxD,QAAM,mBAAmB,kBAAkB,EAAC,MAAM,OAAO,SAAQ,CAAC;AAClE,QAAM,EAAC,UAAU,UAAS,IAAI,mBAAkB;AAChD,QAAM,cAAc,MAAK;AAEzB,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA,SAAS,GAAG,QAAQ,IAAI,IAAI,WAAW;AAAA,IACvC,WAAW,iBAAiB,KAAK;AAAA,IACjC,SAAS,iBAAiB,UAAU,SAAS;AAAA,EACrD;AACA;"}
@@ -8,12 +8,14 @@ const UNKNOWN_ENTRY = Object.freeze({
8
8
  color: "default",
9
9
  isKnown: false
10
10
  });
11
- function dictionaryEntryOf(value, keyPrefix, color, { hasShortLabel = false } = {}) {
11
+ function dictionaryEntryOf(value, keyPrefix, color, { hasShortLabel = false, icon } = {}) {
12
12
  return Object.freeze({
13
13
  value,
14
14
  labelKey: `${NAMESPACE}:${keyPrefix}.label`,
15
15
  tooltipKey: `${NAMESPACE}:${keyPrefix}.tooltip`,
16
16
  ...hasShortLabel ? { shortLabelKey: `${NAMESPACE}:${keyPrefix}.shortLabel` } : {},
17
+ // el ícono es solo una referencia: el diccionario sigue sin React
18
+ ...icon ? { icon } : {},
17
19
  color,
18
20
  isKnown: true
19
21
  });
@@ -1 +1 @@
1
- {"version":3,"file":"dictionaries.js","sources":["../../src/dictionaries/dictionaries.js"],"sourcesContent":["// Diccionarios de valores cerrados que llegan del API → etiqueta, tooltip y color del chip (StatusChip, DictionaryText).\n//\n// El paquete trae el mecanismo; los diccionarios los arma cada proyecto con dictionaryEntryOf:\n//\n// export const ORDER_STATUS = Object.freeze({\n// pending: dictionaryEntryOf('pending', 'orderStatus.pending', 'warning'),\n// paid: dictionaryEntryOf('paid', 'orderStatus.paid', 'success'),\n// });\n//\n// Forma de cada entrada: {value, labelKey, tooltipKey, color, isKnown} y, solo en algunas, shortLabelKey\n// - value: el código del API tal cual.\n// - labelKey / tooltipKey: llaves de texto del namespace \"dictionaries\" (los textos los pone el proyecto con `texts` o\n// `translate` de ToolkitProvider). El texto NUNCA va aquí: así cambia de idioma sin tocar el diccionario.\n// - shortLabelKey: palabra corta para una columna angosta («Rechazada» por «Rechazada por estructura»). Solo la traen\n// las entradas cuyo nombre completo no cabe; quien la pinta deja el nombre completo en el tooltip (StatusChip, short).\n// - color: color de paleta de MUI (success, warning, error, info, default).\n// - isKnown: false solo en la entrada \"unknown\"; sirve para pintar el código crudo cuando no hay texto (p. ej. un\n// estatus nuevo que el backend empezó a mandar).\n//\n// Se congelan con Object.freeze para que nadie los mute por accidente desde una pantalla.\n// Un valor que el API mande y no esté en el diccionario no truena la pantalla: lookup regresa la entrada \"unknown\" y lo\n// anota en el log para agregarlo.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\nimport {createLogger} from '@/observability/logger.js';\n\nconst log = createLogger('dictionaries');\n\nconst NAMESPACE = 'dictionaries';\n\nconst UNKNOWN_ENTRY = Object.freeze({\n value: null,\n labelKey: `${NAMESPACE}:unknown.label`,\n tooltipKey: `${NAMESPACE}:unknown.tooltip`,\n color: 'default',\n isKnown: false,\n});\n\n/**\n * Una entrada de diccionario, congelada.\n *\n * @param {string} value el código del API\n * @param {string} keyPrefix dónde viven sus textos dentro del namespace dictionaries ('orderStatus.paid' → orderStatus.paid.label)\n * @param {string} color color de paleta de MUI\n * @param {{hasShortLabel?: boolean}} [options] hasShortLabel: trae palabra corta (keyPrefix.shortLabel)\n * @returns {{value: string, labelKey: string, tooltipKey: string, shortLabelKey?: string, color: string, isKnown: boolean}}\n */\nexport function dictionaryEntryOf(value, keyPrefix, color, {hasShortLabel = false} = {}) {\n return Object.freeze({\n value,\n labelKey: `${NAMESPACE}:${keyPrefix}.label`,\n tooltipKey: `${NAMESPACE}:${keyPrefix}.tooltip`,\n ...(hasShortLabel ? {shortLabelKey: `${NAMESPACE}:${keyPrefix}.shortLabel`} : {}),\n color,\n isKnown: true,\n });\n}\n\n/**\n * La entrada del diccionario para un valor del API.\n *\n * @param {Record<string, object>} dictionary p. ej. ORDER_STATUS\n * @param {string|null|undefined} value código del API\n * @returns {{value: string|null, labelKey: string, tooltipKey: string, color: string, isKnown: boolean}}\n */\nexport function lookup(dictionary, value) {\n if (value !== null && value !== undefined && Object.hasOwn(dictionary, value)) {\n return dictionary[value];\n }\n if (value !== null && value !== undefined) {\n log.warn('valor sin entrada en el diccionario', {value});\n }\n return {...UNKNOWN_ENTRY, value: value ?? null};\n}\n\n/**\n * Texto que se pinta para una entrada: su etiqueta traducida o, si el valor no está en el diccionario, el código\n * crudo. Un estatus nuevo se lee con su código y no como \"Sin estatus\".\n *\n * @param {{value: string|null, labelKey: string, isKnown: boolean}} dictionaryEntry lo que regresa lookup\n * @param {(key: string) => string} translate el t de useToolkitTranslation\n * @returns {string}\n */\nexport function labelOf(dictionaryEntry, translate) {\n if (dictionaryEntry.isKnown || dictionaryEntry.value === null) {\n return translate(dictionaryEntry.labelKey);\n }\n return dictionaryEntry.value;\n}\n\n/**\n * La palabra corta de una entrada, para una columna angosta. Una entrada sin palabra corta regresa su etiqueta de siempre.\n *\n * @param {object} dictionaryEntry entrada del diccionario (lookup)\n * @param {Function} translate traductor\n * @returns {string}\n */\nexport function shortLabelOf(dictionaryEntry, translate) {\n if (dictionaryEntry.isKnown && dictionaryEntry.shortLabelKey) {\n return translate(dictionaryEntry.shortLabelKey);\n }\n return labelOf(dictionaryEntry, translate);\n}\n"],"names":[],"mappings":";AA0BA,MAAM,MAAM,aAAa,cAAc;AAEvC,MAAM,YAAY;AAElB,MAAM,gBAAgB,OAAO,OAAO;AAAA,EAChC,OAAO;AAAA,EACP,UAAU,GAAG,SAAS;AAAA,EACtB,YAAY,GAAG,SAAS;AAAA,EACxB,OAAO;AAAA,EACP,SAAS;AACb,CAAC;AAWM,SAAS,kBAAkB,OAAO,WAAW,OAAO,EAAC,gBAAgB,MAAK,IAAI,IAAI;AACrF,SAAO,OAAO,OAAO;AAAA,IACjB;AAAA,IACA,UAAU,GAAG,SAAS,IAAI,SAAS;AAAA,IACnC,YAAY,GAAG,SAAS,IAAI,SAAS;AAAA,IACrC,GAAI,gBAAgB,EAAC,eAAe,GAAG,SAAS,IAAI,SAAS,cAAa,IAAI;IAC9E;AAAA,IACA,SAAS;AAAA,EACjB,CAAK;AACL;AASO,SAAS,OAAO,YAAY,OAAO;AACtC,MAAI,UAAU,QAAQ,UAAU,UAAa,OAAO,OAAO,YAAY,KAAK,GAAG;AAC3E,WAAO,WAAW,KAAK;AAAA,EAC3B;AACA,MAAI,UAAU,QAAQ,UAAU,QAAW;AACvC,QAAI,KAAK,uCAAuC,EAAC,MAAK,CAAC;AAAA,EAC3D;AACA,SAAO,EAAC,GAAG,eAAe,OAAO,SAAS,KAAI;AAClD;AAUO,SAAS,QAAQ,iBAAiB,WAAW;AAChD,MAAI,gBAAgB,WAAW,gBAAgB,UAAU,MAAM;AAC3D,WAAO,UAAU,gBAAgB,QAAQ;AAAA,EAC7C;AACA,SAAO,gBAAgB;AAC3B;AASO,SAAS,aAAa,iBAAiB,WAAW;AACrD,MAAI,gBAAgB,WAAW,gBAAgB,eAAe;AAC1D,WAAO,UAAU,gBAAgB,aAAa;AAAA,EAClD;AACA,SAAO,QAAQ,iBAAiB,SAAS;AAC7C;"}
1
+ {"version":3,"file":"dictionaries.js","sources":["../../src/dictionaries/dictionaries.js"],"sourcesContent":["// Diccionarios de valores cerrados que llegan del API → etiqueta, tooltip y color del chip (StatusChip, DictionaryText).\n//\n// El paquete trae el mecanismo; los diccionarios los arma cada proyecto con dictionaryEntryOf:\n//\n// export const ORDER_STATUS = Object.freeze({\n// pending: dictionaryEntryOf('pending', 'orderStatus.pending', 'warning'),\n// paid: dictionaryEntryOf('paid', 'orderStatus.paid', 'success'),\n// });\n//\n// Forma de cada entrada: {value, labelKey, tooltipKey, color, isKnown} y, solo en algunas, shortLabelKey\n// - value: el código del API tal cual.\n// - labelKey / tooltipKey: llaves de texto del namespace \"dictionaries\" (los textos los pone el proyecto con `texts` o\n// `translate` de ToolkitProvider). El texto NUNCA va aquí: así cambia de idioma sin tocar el diccionario.\n// - shortLabelKey: palabra corta para una columna angosta («Rechazada» por «Rechazada por estructura»). Solo la traen\n// las entradas cuyo nombre completo no cabe; quien la pinta deja el nombre completo en el tooltip (StatusChip, short).\n// - color: color de paleta de MUI (success, warning, error, info, default).\n// - icon (opcional): el ícono con que la pinta una insignia (IconBadge); el diccionario solo guarda la referencia.\n// - isKnown: false solo en la entrada \"unknown\"; sirve para pintar el código crudo cuando no hay texto (p. ej. un\n// estatus nuevo que el backend empezó a mandar).\n//\n// Se congelan con Object.freeze para que nadie los mute por accidente desde una pantalla.\n// Un valor que el API mande y no esté en el diccionario no truena la pantalla: lookup regresa la entrada \"unknown\" y lo\n// anota en el log para agregarlo.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\nimport {createLogger} from '@/observability/logger.js';\n\nconst log = createLogger('dictionaries');\n\nconst NAMESPACE = 'dictionaries';\n\nconst UNKNOWN_ENTRY = Object.freeze({\n value: null,\n labelKey: `${NAMESPACE}:unknown.label`,\n tooltipKey: `${NAMESPACE}:unknown.tooltip`,\n color: 'default',\n isKnown: false,\n});\n\n/**\n * Una entrada de diccionario, congelada.\n *\n * @param {string} value el código del API\n * @param {string} keyPrefix dónde viven sus textos dentro del namespace dictionaries ('orderStatus.paid' → orderStatus.paid.label)\n * @param {string} color color de paleta de MUI\n * @param {{hasShortLabel?: boolean, icon?: import('react').ElementType}} [options] hasShortLabel: trae palabra corta\n * (keyPrefix.shortLabel); icon: el ícono con que se pinta en una insignia (IconBadge), p. ej. CreditCardOutlinedIcon\n * @returns {{value: string, labelKey: string, tooltipKey: string, shortLabelKey?: string, icon?: import('react').ElementType, color: string, isKnown: boolean}}\n */\nexport function dictionaryEntryOf(value, keyPrefix, color, {hasShortLabel = false, icon} = {}) {\n return Object.freeze({\n value,\n labelKey: `${NAMESPACE}:${keyPrefix}.label`,\n tooltipKey: `${NAMESPACE}:${keyPrefix}.tooltip`,\n ...(hasShortLabel ? {shortLabelKey: `${NAMESPACE}:${keyPrefix}.shortLabel`} : {}),\n // el ícono es solo una referencia: el diccionario sigue sin React\n ...(icon ? {icon} : {}),\n color,\n isKnown: true,\n });\n}\n\n/**\n * La entrada del diccionario para un valor del API.\n *\n * @param {Record<string, object>} dictionary p. ej. ORDER_STATUS\n * @param {string|null|undefined} value código del API\n * @returns {{value: string|null, labelKey: string, tooltipKey: string, color: string, isKnown: boolean}}\n */\nexport function lookup(dictionary, value) {\n if (value !== null && value !== undefined && Object.hasOwn(dictionary, value)) {\n return dictionary[value];\n }\n if (value !== null && value !== undefined) {\n log.warn('valor sin entrada en el diccionario', {value});\n }\n return {...UNKNOWN_ENTRY, value: value ?? null};\n}\n\n/**\n * Texto que se pinta para una entrada: su etiqueta traducida o, si el valor no está en el diccionario, el código\n * crudo. Un estatus nuevo se lee con su código y no como \"Sin estatus\".\n *\n * @param {{value: string|null, labelKey: string, isKnown: boolean}} dictionaryEntry lo que regresa lookup\n * @param {(key: string) => string} translate el t de useToolkitTranslation\n * @returns {string}\n */\nexport function labelOf(dictionaryEntry, translate) {\n if (dictionaryEntry.isKnown || dictionaryEntry.value === null) {\n return translate(dictionaryEntry.labelKey);\n }\n return dictionaryEntry.value;\n}\n\n/**\n * La palabra corta de una entrada, para una columna angosta. Una entrada sin palabra corta regresa su etiqueta de siempre.\n *\n * @param {object} dictionaryEntry entrada del diccionario (lookup)\n * @param {Function} translate traductor\n * @returns {string}\n */\nexport function shortLabelOf(dictionaryEntry, translate) {\n if (dictionaryEntry.isKnown && dictionaryEntry.shortLabelKey) {\n return translate(dictionaryEntry.shortLabelKey);\n }\n return labelOf(dictionaryEntry, translate);\n}\n"],"names":[],"mappings":";AA2BA,MAAM,MAAM,aAAa,cAAc;AAEvC,MAAM,YAAY;AAElB,MAAM,gBAAgB,OAAO,OAAO;AAAA,EAChC,OAAO;AAAA,EACP,UAAU,GAAG,SAAS;AAAA,EACtB,YAAY,GAAG,SAAS;AAAA,EACxB,OAAO;AAAA,EACP,SAAS;AACb,CAAC;AAYM,SAAS,kBAAkB,OAAO,WAAW,OAAO,EAAC,gBAAgB,OAAO,KAAI,IAAI,IAAI;AAC3F,SAAO,OAAO,OAAO;AAAA,IACjB;AAAA,IACA,UAAU,GAAG,SAAS,IAAI,SAAS;AAAA,IACnC,YAAY,GAAG,SAAS,IAAI,SAAS;AAAA,IACrC,GAAI,gBAAgB,EAAC,eAAe,GAAG,SAAS,IAAI,SAAS,cAAa,IAAI;;IAE9E,GAAI,OAAO,EAAC,KAAI,IAAI;IACpB;AAAA,IACA,SAAS;AAAA,EACjB,CAAK;AACL;AASO,SAAS,OAAO,YAAY,OAAO;AACtC,MAAI,UAAU,QAAQ,UAAU,UAAa,OAAO,OAAO,YAAY,KAAK,GAAG;AAC3E,WAAO,WAAW,KAAK;AAAA,EAC3B;AACA,MAAI,UAAU,QAAQ,UAAU,QAAW;AACvC,QAAI,KAAK,uCAAuC,EAAC,MAAK,CAAC;AAAA,EAC3D;AACA,SAAO,EAAC,GAAG,eAAe,OAAO,SAAS,KAAI;AAClD;AAUO,SAAS,QAAQ,iBAAiB,WAAW;AAChD,MAAI,gBAAgB,WAAW,gBAAgB,UAAU,MAAM;AAC3D,WAAO,UAAU,gBAAgB,QAAQ;AAAA,EAC7C;AACA,SAAO,gBAAgB;AAC3B;AASO,SAAS,aAAa,iBAAiB,WAAW;AACrD,MAAI,gBAAgB,WAAW,gBAAgB,eAAe;AAC1D,WAAO,UAAU,gBAAgB,aAAa;AAAA,EAClD;AACA,SAAO,QAAQ,iBAAiB,SAAS;AAC7C;"}
@@ -27,7 +27,7 @@ import { DOWNLOAD_STATUS } from "./downloadsMachine.js";
27
27
  import { useFormatters } from "../toolkit/useFormatters.js";
28
28
  import { isGlassTheme, glassStylesOf } from "../theme/glassSurface.js";
29
29
  import ComponentTexts from "../toolkit/ComponentTexts.js";
30
- import { piecePart } from "../theme/themePieces.js";
30
+ import { piecePart, withPieceSlots } from "../theme/themePieces.js";
31
31
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
32
32
  const THEME_NAME = "CalcitaDownloadManager";
33
33
  const DownloadsDoneIcon = piecePart(THEME_NAME, "DoneIcon", CheckCircleIcon);
@@ -143,7 +143,7 @@ function DownloadRow({ download }) {
143
143
  ] })
144
144
  );
145
145
  }
146
- function DownloadManager({ texts, ...unknownProps } = {}) {
146
+ function DownloadManagerContent({ texts, ...unknownProps } = {}) {
147
147
  warnUnknownProps("DownloadManager", unknownProps);
148
148
  const { t } = useToolkitTranslation("common", texts);
149
149
  const downloads = useSelector(downloadsActor, (snapshot) => snapshot.context.downloads);
@@ -207,6 +207,7 @@ function DownloadManager({ texts, ...unknownProps } = {}) {
207
207
  }
208
208
  ) }) });
209
209
  }
210
+ const DownloadManager = withPieceSlots(DownloadManagerContent, THEME_NAME);
210
211
  export {
211
212
  DownloadManager as default
212
213
  };
@@ -1 +1 @@
1
- {"version":3,"file":"DownloadManager.js","sources":["../../src/downloads/DownloadManager.jsx"],"sourcesContent":["// Panel de descargas al estilo de Google Drive: se pega abajo a la derecha SOLO mientras hay descargas, con una barra que\n// resume («Descargando 2 archivos…», «3 descargas listas») y la lista con el ícono del tipo de archivo y un anillo de\n// avance que termina en ✓. Con MUI y XState, sin Redux.\n//\n// Qué hace para no hacer ruido:\n// - no hay botón fijo: sin descargas no se pinta nada;\n// - se pliega a la barra con la flecha y se vuelve a abrir cuando entra otra descarga;\n// - cuando todo terminó bien se va solo a los AUTO_DISMISS_MILLISECONDS; si algo falló o se canceló se queda hasta que\n// la persona lo cierra, para que vea el motivo;\n// - la X solo aparece cuando ya nada descarga (cerrar a media descarga dejaría el archivo sin aviso de que terminó).\n//\n// Se monta UNA sola vez en la raíz de la aplicación. Lee la lista de downloadsActor; las descargas las arranca startDownload desde cada\n// pantalla. Los avisos (sonner) salen abajo a la izquierda, así que el panel va a la derecha.\n// Con el vidrio del tema (createToolkitTheme({glass: true})) el panel es de vidrio: flota sobre la pantalla.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDownloadManager con defaultProps y\n// styleOverrides de sus partes: doneIcon, failedIcon, canceledIcon, cancelButton, progress, cancelIcon, item, itemText,\n// itemStatus, itemActions, panel, header, title, list.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {Fragment, useEffect, useRef, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {useSelector} from '@xstate/react';\nimport Box from '@mui/material/Box';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Collapse from '@mui/material/Collapse';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport List from '@mui/material/List';\nimport ListItem from '@mui/material/ListItem';\nimport Paper from '@mui/material/Paper';\nimport Slide from '@mui/material/Slide';\nimport Stack from '@mui/material/Stack';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport BlockOutlinedIcon from '@mui/icons-material/BlockOutlined';\nimport CheckCircleIcon from '@mui/icons-material/CheckCircle';\nimport CloseIcon from '@mui/icons-material/Close';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';\nimport ExpandLessIcon from '@mui/icons-material/ExpandLess';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\n\nimport {cancelDownload, clearFinishedDownloads, countActiveDownloads, downloadsActor} from '@/downloads/downloadQueue.js';\nimport {UNKNOWN_FILE_TYPE, useFileTypes} from '@/downloads/fileTypes.js';\nimport {DOWNLOAD_STATUS} from '@/downloads/downloadsMachine.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {glassStylesOf, isGlassTheme} from '@/theme/glassSurface.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {piecePart} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaDownloadManager)\nconst THEME_NAME = 'CalcitaDownloadManager';\nconst DownloadsDoneIcon = piecePart(THEME_NAME, 'DoneIcon', CheckCircleIcon);\nconst DownloadsFailedIcon = piecePart(THEME_NAME, 'FailedIcon', ErrorOutlineIcon);\nconst DownloadsCanceledIcon = piecePart(THEME_NAME, 'CanceledIcon', BlockOutlinedIcon);\nconst DownloadsCancelButton = piecePart(THEME_NAME, 'CancelButton', IconButton);\nconst DownloadsProgress = piecePart(THEME_NAME, 'Progress', CircularProgress);\nconst DownloadsCancelIcon = piecePart(THEME_NAME, 'CancelIcon', CloseIcon);\nconst DownloadsItem = piecePart(THEME_NAME, 'Item', ListItem);\nconst DownloadsItemText = piecePart(THEME_NAME, 'ItemText', Box);\nconst DownloadsItemStatus = piecePart(THEME_NAME, 'ItemStatus', Typography);\nconst DownloadsItemActions = piecePart(THEME_NAME, 'ItemActions', Box);\nconst DownloadsPanel = piecePart(THEME_NAME, 'Panel', Paper);\nconst DownloadsHeader = piecePart(THEME_NAME, 'Header', Stack);\nconst DownloadsTitle = piecePart(THEME_NAME, 'Title', Typography);\nconst DownloadsList = piecePart(THEME_NAME, 'List', List);\n\n// cuánto se queda el panel después de que TODAS las descargas terminaron bien\nconst AUTO_DISMISS_MILLISECONDS = 5000;\n\n// separación del borde derecho y ancho del panel (en el teléfono ocupa el ancho menos los márgenes)\nconst SCREEN_EDGE_SPACING = 3;\nconst PANEL_WIDTH_PIXELS = 360;\nconst LIST_MAX_HEIGHT = '40vh';\nconst PROGRESS_RING_PIXELS = 22;\n\n/**\n * Tipo de archivo de una descarga: el que dijo quien la arrancó o, al terminar, la extensión del nombre. Los tipos son los de\n * la casa y los del proyecto (ToolkitProvider fileTypes).\n *\n * @param {object} download renglón de la lista (downloadsMachine)\n * @param {Record<string, {Icon: import('react').ElementType, color?: string}>} fileTypes\n * @returns {{Icon: import('react').ElementType, color: string}}\n */\nfunction fileTypeAppearanceOf(download, fileTypes) {\n const extension = download.fileName?.split('.').pop()?.toLowerCase();\n const fileType = fileTypes[download.format ?? extension];\n return fileType ? {Icon: fileType.Icon ?? UNKNOWN_FILE_TYPE.Icon, color: fileType.color ?? UNKNOWN_FILE_TYPE.color} : UNKNOWN_FILE_TYPE;\n}\n\n/**\n * Segunda línea del renglón: cuánto lleva, cuánto pesó o por qué no se pudo.\n *\n * @param {object} download\n * @param {Function} t traductor de common\n * @param {(bytes: number) => string} formatFileSize el de useFormatters (el idioma del proveedor más cercano)\n * @returns {string}\n */\nfunction detailTextOf(download, t, formatFileSize) {\n if (download.status === DOWNLOAD_STATUS.completed) {\n return formatFileSize(download.loadedBytes);\n }\n if (download.status === DOWNLOAD_STATUS.failed) {\n return download.errorMessage ?? t('downloads.failed');\n }\n if (download.status === DOWNLOAD_STATUS.canceled) {\n return t('downloads.canceled');\n }\n if (download.loadedBytes === 0) {\n return t('downloads.preparing');\n }\n // un archivo que se arma al vuelo (el log) no dice su tamaño: se enseña lo que ya bajó\n return download.totalBytes\n ? t('downloads.progressOf', {loaded: formatFileSize(download.loadedBytes), total: formatFileSize(download.totalBytes)})\n : t('downloads.progressLoaded', {loaded: formatFileSize(download.loadedBytes)});\n}\n\n/**\n * Resumen de la barra, como en Drive: lo que está pasando ahora o cómo terminó.\n *\n * @param {Array<object>} downloads\n * @param {Function} t traductor de common\n * @returns {string}\n */\nfunction summaryTextOf(downloads, t) {\n const activeCount = countActiveDownloads(downloads);\n if (activeCount > 0) {\n return t('downloads.summaryDownloading', {count: activeCount});\n }\n const failedCount = downloads.filter((download) => download.status === DOWNLOAD_STATUS.failed).length;\n if (failedCount > 0) {\n return t('downloads.summaryFailed', {count: failedCount});\n }\n const completedCount = downloads.filter((download) => download.status === DOWNLOAD_STATUS.completed).length;\n return t('downloads.summaryCompleted', {count: completedCount});\n}\n\n/**\n * Lo que va a la derecha del renglón: el anillo de avance con su botón para cancelar, o cómo terminó.\n *\n * @param {{download: object, displayName: string}} props\n */\nfunction DownloadStatusIndicator({download, displayName}) {\n const {t} = useToolkitTranslation('common');\n\n if (download.status === DOWNLOAD_STATUS.completed) {\n return <DownloadsDoneIcon ownSx={{color: 'success.main'}} aria-label={t('downloads.completedOf', {name: displayName})} />;\n }\n if (download.status === DOWNLOAD_STATUS.failed) {\n return <DownloadsFailedIcon ownSx={{color: 'error.main'}} aria-label={t('downloads.failedOf', {name: displayName})} />;\n }\n if (download.status === DOWNLOAD_STATUS.canceled) {\n return <DownloadsCanceledIcon ownSx={{color: 'text.disabled'}} aria-label={t('downloads.canceledOf', {name: displayName})} />;\n }\n\n const hasKnownSize = Boolean(download.totalBytes);\n // el anillo y, encima, la X para cancelar: como en Drive, un solo lugar para ver y detener\n return (\n <Tooltip title={t('downloads.cancel')}>\n <DownloadsCancelButton size=\"small\" aria-label={t('downloads.cancelOf', {name: displayName})} onClick={() => cancelDownload(download.id)}\n ownSx={{position: 'relative', width: PROGRESS_RING_PIXELS + 10, height: PROGRESS_RING_PIXELS + 10}}>\n <DownloadsProgress\n size={PROGRESS_RING_PIXELS}\n thickness={4}\n variant={hasKnownSize ? 'determinate' : 'indeterminate'}\n value={hasKnownSize ? Math.min(100, (download.loadedBytes * 100) / download.totalBytes) : undefined}\n ownSx={{position: 'absolute'}}\n />\n <DownloadsCancelIcon ownSx={{fontSize: 12}} />\n </DownloadsCancelButton>\n </Tooltip>\n );\n}\n\n/**\n * Un renglón: ícono del tipo de archivo, nombre, detalle y estatus.\n *\n * @param {{download: object}} props\n */\nfunction DownloadRow({download}) {\n const {t} = useToolkitTranslation('common');\n const {formatFileSize} = useFormatters();\n const {Icon, color} = fileTypeAppearanceOf(download, useFileTypes());\n const displayName = download.fileName ?? download.label;\n const isFailed = download.status === DOWNLOAD_STATUS.failed;\n\n return (\n // minWidth 0: sin él un nombre largo empuja el renglón y la lista enseña una barra horizontal\n <DownloadsItem disableGutters ownSx={{gap: 1.5, px: 2, py: 1, minWidth: 0}}>\n <Icon fontSize=\"small\" sx={{color, flexShrink: 0}} />\n <DownloadsItemText ownSx={{minWidth: 0, flex: 1}}>\n <Tooltip title={displayName}>\n <Typography variant=\"body2\" noWrap>{displayName}</Typography>\n </Tooltip>\n <DownloadsItemStatus variant=\"caption\" component=\"p\" noWrap={!isFailed}\n ownSx={{color: isFailed ? 'error.main' : 'text.secondary'}}>\n {detailTextOf(download, t, formatFileSize)}\n </DownloadsItemStatus>\n </DownloadsItemText>\n <DownloadsItemActions ownSx={{flexShrink: 0, display: 'flex', alignItems: 'center'}}>\n <DownloadStatusIndicator download={download} displayName={displayName} />\n </DownloadsItemActions>\n </DownloadsItem>\n );\n}\n\n/**\n * @param {object} [props]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function DownloadManager({texts, ...unknownProps} = {}) {\n warnUnknownProps('DownloadManager', unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const downloads = useSelector(downloadsActor, (snapshot) => snapshot.context.downloads);\n const [isExpanded, setIsExpanded] = useState(true);\n const previousCountRef = useRef(downloads.length);\n\n const activeCount = countActiveDownloads(downloads);\n const allSucceeded = downloads.length > 0 && downloads.every((download) => download.status === DOWNLOAD_STATUS.completed);\n\n // una descarga nueva vuelve a desplegar el panel aunque se haya plegado\n useEffect(() => {\n if (downloads.length > previousCountRef.current) {\n setIsExpanded(true);\n }\n previousCountRef.current = downloads.length;\n }, [downloads.length]);\n\n // todo terminó bien: el panel se va solo (con un error o una cancelada se queda para que se lea)\n useEffect(() => {\n if (!allSucceeded) {\n return undefined;\n }\n const dismissTimer = setTimeout(clearFinishedDownloads, AUTO_DISMISS_MILLISECONDS);\n return () => clearTimeout(dismissTimer);\n }, [allSucceeded, downloads.length]);\n\n return (\n <ComponentTexts namespace=\"common\" texts={texts}>\n <Slide direction=\"up\" in={downloads.length > 0} mountOnEnter unmountOnExit>\n <DownloadsPanel\n elevation={8}\n role=\"region\"\n aria-label={t('downloads.title')}\n ownSx={[{\n position: 'fixed',\n right: (theme) => theme.spacing(SCREEN_EDGE_SPACING),\n bottom: 0,\n width: (theme) => `min(${PANEL_WIDTH_PIXELS}px, calc(100vw - ${theme.spacing(SCREEN_EDGE_SPACING * 2)}))`,\n // pegado al borde de abajo como en Drive: solo se redondean las esquinas de arriba\n borderBottomLeftRadius: 0,\n borderBottomRightRadius: 0,\n overflow: 'hidden',\n zIndex: (theme) => theme.zIndex.snackbar,\n }, (theme) => (isGlassTheme(theme) ? glassStylesOf(theme) : {})]}\n >\n <DownloadsHeader direction=\"row\" ownSx={{alignItems: 'center', gap: 0.5, pl: 2, pr: 1, py: 1, bgcolor: 'action.hover'}}>\n <DownloadsTitle variant=\"subtitle2\" component=\"h2\" noWrap ownSx={{flex: 1}} aria-live=\"polite\">\n {summaryTextOf(downloads, t)}\n </DownloadsTitle>\n <Tooltip title={isExpanded ? t('downloads.collapse') : t('downloads.expand')}>\n <IconButton size=\"small\" aria-expanded={isExpanded}\n aria-label={isExpanded ? t('downloads.collapse') : t('downloads.expand')}\n onClick={() => setIsExpanded((wasExpanded) => !wasExpanded)}>\n {isExpanded ? <ExpandMoreIcon fontSize=\"small\" /> : <ExpandLessIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n {/* cerrar a media descarga dejaría el archivo sin aviso de que terminó: la X sale cuando ya nada baja */}\n {activeCount === 0 && (\n <Tooltip title={t('downloads.close')}>\n <IconButton size=\"small\" aria-label={t('downloads.close')} onClick={clearFinishedDownloads}>\n <CloseIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </DownloadsHeader>\n <Collapse in={isExpanded}>\n <Divider />\n {/* OJO: overflowY auto también prende el scroll horizontal ante 1 px de más; se apaga explícito */}\n <DownloadsList dense disablePadding ownSx={{maxHeight: LIST_MAX_HEIGHT, overflowY: 'auto', overflowX: 'hidden'}}>\n {downloads.map((download, index) => (\n <Fragment key={download.id}>\n {index > 0 && <Divider component=\"li\" />}\n <DownloadRow download={download} />\n </Fragment>\n ))}\n </DownloadsList>\n </Collapse>\n </DownloadsPanel>\n </Slide>\n </ComponentTexts>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DownloadManager.js","sources":["../../src/downloads/DownloadManager.jsx"],"sourcesContent":["// Panel de descargas al estilo de Google Drive: se pega abajo a la derecha SOLO mientras hay descargas, con una barra que\n// resume («Descargando 2 archivos…», «3 descargas listas») y la lista con el ícono del tipo de archivo y un anillo de\n// avance que termina en ✓. Con MUI y XState, sin Redux.\n//\n// Qué hace para no hacer ruido:\n// - no hay botón fijo: sin descargas no se pinta nada;\n// - se pliega a la barra con la flecha y se vuelve a abrir cuando entra otra descarga;\n// - cuando todo terminó bien se va solo a los AUTO_DISMISS_MILLISECONDS; si algo falló o se canceló se queda hasta que\n// la persona lo cierra, para que vea el motivo;\n// - la X solo aparece cuando ya nada descarga (cerrar a media descarga dejaría el archivo sin aviso de que terminó).\n//\n// Se monta UNA sola vez en la raíz de la aplicación. Lee la lista de downloadsActor; las descargas las arranca startDownload desde cada\n// pantalla. Los avisos (sonner) salen abajo a la izquierda, así que el panel va a la derecha.\n// Con el vidrio del tema (createToolkitTheme({glass: true})) el panel es de vidrio: flota sobre la pantalla.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDownloadManager con defaultProps y\n// styleOverrides de sus partes: doneIcon, failedIcon, canceledIcon, cancelButton, progress, cancelIcon, item, itemText,\n// itemStatus, itemActions, panel, header, title, list.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {Fragment, useEffect, useRef, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {useSelector} from '@xstate/react';\nimport Box from '@mui/material/Box';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Collapse from '@mui/material/Collapse';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport List from '@mui/material/List';\nimport ListItem from '@mui/material/ListItem';\nimport Paper from '@mui/material/Paper';\nimport Slide from '@mui/material/Slide';\nimport Stack from '@mui/material/Stack';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport BlockOutlinedIcon from '@mui/icons-material/BlockOutlined';\nimport CheckCircleIcon from '@mui/icons-material/CheckCircle';\nimport CloseIcon from '@mui/icons-material/Close';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';\nimport ExpandLessIcon from '@mui/icons-material/ExpandLess';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\n\nimport {cancelDownload, clearFinishedDownloads, countActiveDownloads, downloadsActor} from '@/downloads/downloadQueue.js';\nimport {UNKNOWN_FILE_TYPE, useFileTypes} from '@/downloads/fileTypes.js';\nimport {DOWNLOAD_STATUS} from '@/downloads/downloadsMachine.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {glassStylesOf, isGlassTheme} from '@/theme/glassSurface.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {piecePart, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaDownloadManager)\nconst THEME_NAME = 'CalcitaDownloadManager';\nconst DownloadsDoneIcon = piecePart(THEME_NAME, 'DoneIcon', CheckCircleIcon);\nconst DownloadsFailedIcon = piecePart(THEME_NAME, 'FailedIcon', ErrorOutlineIcon);\nconst DownloadsCanceledIcon = piecePart(THEME_NAME, 'CanceledIcon', BlockOutlinedIcon);\nconst DownloadsCancelButton = piecePart(THEME_NAME, 'CancelButton', IconButton);\nconst DownloadsProgress = piecePart(THEME_NAME, 'Progress', CircularProgress);\nconst DownloadsCancelIcon = piecePart(THEME_NAME, 'CancelIcon', CloseIcon);\nconst DownloadsItem = piecePart(THEME_NAME, 'Item', ListItem);\nconst DownloadsItemText = piecePart(THEME_NAME, 'ItemText', Box);\nconst DownloadsItemStatus = piecePart(THEME_NAME, 'ItemStatus', Typography);\nconst DownloadsItemActions = piecePart(THEME_NAME, 'ItemActions', Box);\nconst DownloadsPanel = piecePart(THEME_NAME, 'Panel', Paper);\nconst DownloadsHeader = piecePart(THEME_NAME, 'Header', Stack);\nconst DownloadsTitle = piecePart(THEME_NAME, 'Title', Typography);\nconst DownloadsList = piecePart(THEME_NAME, 'List', List);\n\n// cuánto se queda el panel después de que TODAS las descargas terminaron bien\nconst AUTO_DISMISS_MILLISECONDS = 5000;\n\n// separación del borde derecho y ancho del panel (en el teléfono ocupa el ancho menos los márgenes)\nconst SCREEN_EDGE_SPACING = 3;\nconst PANEL_WIDTH_PIXELS = 360;\nconst LIST_MAX_HEIGHT = '40vh';\nconst PROGRESS_RING_PIXELS = 22;\n\n/**\n * Tipo de archivo de una descarga: el que dijo quien la arrancó o, al terminar, la extensión del nombre. Los tipos son los de\n * la casa y los del proyecto (ToolkitProvider fileTypes).\n *\n * @param {object} download renglón de la lista (downloadsMachine)\n * @param {Record<string, {Icon: import('react').ElementType, color?: string}>} fileTypes\n * @returns {{Icon: import('react').ElementType, color: string}}\n */\nfunction fileTypeAppearanceOf(download, fileTypes) {\n const extension = download.fileName?.split('.').pop()?.toLowerCase();\n const fileType = fileTypes[download.format ?? extension];\n return fileType ? {Icon: fileType.Icon ?? UNKNOWN_FILE_TYPE.Icon, color: fileType.color ?? UNKNOWN_FILE_TYPE.color} : UNKNOWN_FILE_TYPE;\n}\n\n/**\n * Segunda línea del renglón: cuánto lleva, cuánto pesó o por qué no se pudo.\n *\n * @param {object} download\n * @param {Function} t traductor de common\n * @param {(bytes: number) => string} formatFileSize el de useFormatters (el idioma del proveedor más cercano)\n * @returns {string}\n */\nfunction detailTextOf(download, t, formatFileSize) {\n if (download.status === DOWNLOAD_STATUS.completed) {\n return formatFileSize(download.loadedBytes);\n }\n if (download.status === DOWNLOAD_STATUS.failed) {\n return download.errorMessage ?? t('downloads.failed');\n }\n if (download.status === DOWNLOAD_STATUS.canceled) {\n return t('downloads.canceled');\n }\n if (download.loadedBytes === 0) {\n return t('downloads.preparing');\n }\n // un archivo que se arma al vuelo (el log) no dice su tamaño: se enseña lo que ya bajó\n return download.totalBytes\n ? t('downloads.progressOf', {loaded: formatFileSize(download.loadedBytes), total: formatFileSize(download.totalBytes)})\n : t('downloads.progressLoaded', {loaded: formatFileSize(download.loadedBytes)});\n}\n\n/**\n * Resumen de la barra, como en Drive: lo que está pasando ahora o cómo terminó.\n *\n * @param {Array<object>} downloads\n * @param {Function} t traductor de common\n * @returns {string}\n */\nfunction summaryTextOf(downloads, t) {\n const activeCount = countActiveDownloads(downloads);\n if (activeCount > 0) {\n return t('downloads.summaryDownloading', {count: activeCount});\n }\n const failedCount = downloads.filter((download) => download.status === DOWNLOAD_STATUS.failed).length;\n if (failedCount > 0) {\n return t('downloads.summaryFailed', {count: failedCount});\n }\n const completedCount = downloads.filter((download) => download.status === DOWNLOAD_STATUS.completed).length;\n return t('downloads.summaryCompleted', {count: completedCount});\n}\n\n/**\n * Lo que va a la derecha del renglón: el anillo de avance con su botón para cancelar, o cómo terminó.\n *\n * @param {{download: object, displayName: string}} props\n */\nfunction DownloadStatusIndicator({download, displayName}) {\n const {t} = useToolkitTranslation('common');\n\n if (download.status === DOWNLOAD_STATUS.completed) {\n return <DownloadsDoneIcon ownSx={{color: 'success.main'}} aria-label={t('downloads.completedOf', {name: displayName})} />;\n }\n if (download.status === DOWNLOAD_STATUS.failed) {\n return <DownloadsFailedIcon ownSx={{color: 'error.main'}} aria-label={t('downloads.failedOf', {name: displayName})} />;\n }\n if (download.status === DOWNLOAD_STATUS.canceled) {\n return <DownloadsCanceledIcon ownSx={{color: 'text.disabled'}} aria-label={t('downloads.canceledOf', {name: displayName})} />;\n }\n\n const hasKnownSize = Boolean(download.totalBytes);\n // el anillo y, encima, la X para cancelar: como en Drive, un solo lugar para ver y detener\n return (\n <Tooltip title={t('downloads.cancel')}>\n <DownloadsCancelButton size=\"small\" aria-label={t('downloads.cancelOf', {name: displayName})} onClick={() => cancelDownload(download.id)}\n ownSx={{position: 'relative', width: PROGRESS_RING_PIXELS + 10, height: PROGRESS_RING_PIXELS + 10}}>\n <DownloadsProgress\n size={PROGRESS_RING_PIXELS}\n thickness={4}\n variant={hasKnownSize ? 'determinate' : 'indeterminate'}\n value={hasKnownSize ? Math.min(100, (download.loadedBytes * 100) / download.totalBytes) : undefined}\n ownSx={{position: 'absolute'}}\n />\n <DownloadsCancelIcon ownSx={{fontSize: 12}} />\n </DownloadsCancelButton>\n </Tooltip>\n );\n}\n\n/**\n * Un renglón: ícono del tipo de archivo, nombre, detalle y estatus.\n *\n * @param {{download: object}} props\n */\nfunction DownloadRow({download}) {\n const {t} = useToolkitTranslation('common');\n const {formatFileSize} = useFormatters();\n const {Icon, color} = fileTypeAppearanceOf(download, useFileTypes());\n const displayName = download.fileName ?? download.label;\n const isFailed = download.status === DOWNLOAD_STATUS.failed;\n\n return (\n // minWidth 0: sin él un nombre largo empuja el renglón y la lista enseña una barra horizontal\n <DownloadsItem disableGutters ownSx={{gap: 1.5, px: 2, py: 1, minWidth: 0}}>\n <Icon fontSize=\"small\" sx={{color, flexShrink: 0}} />\n <DownloadsItemText ownSx={{minWidth: 0, flex: 1}}>\n <Tooltip title={displayName}>\n <Typography variant=\"body2\" noWrap>{displayName}</Typography>\n </Tooltip>\n <DownloadsItemStatus variant=\"caption\" component=\"p\" noWrap={!isFailed}\n ownSx={{color: isFailed ? 'error.main' : 'text.secondary'}}>\n {detailTextOf(download, t, formatFileSize)}\n </DownloadsItemStatus>\n </DownloadsItemText>\n <DownloadsItemActions ownSx={{flexShrink: 0, display: 'flex', alignItems: 'center'}}>\n <DownloadStatusIndicator download={download} displayName={displayName} />\n </DownloadsItemActions>\n </DownloadsItem>\n );\n}\n\n/**\n * @param {object} [props]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction DownloadManagerContent({texts, ...unknownProps} = {}) {\n warnUnknownProps('DownloadManager', unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const downloads = useSelector(downloadsActor, (snapshot) => snapshot.context.downloads);\n const [isExpanded, setIsExpanded] = useState(true);\n const previousCountRef = useRef(downloads.length);\n\n const activeCount = countActiveDownloads(downloads);\n const allSucceeded = downloads.length > 0 && downloads.every((download) => download.status === DOWNLOAD_STATUS.completed);\n\n // una descarga nueva vuelve a desplegar el panel aunque se haya plegado\n useEffect(() => {\n if (downloads.length > previousCountRef.current) {\n setIsExpanded(true);\n }\n previousCountRef.current = downloads.length;\n }, [downloads.length]);\n\n // todo terminó bien: el panel se va solo (con un error o una cancelada se queda para que se lea)\n useEffect(() => {\n if (!allSucceeded) {\n return undefined;\n }\n const dismissTimer = setTimeout(clearFinishedDownloads, AUTO_DISMISS_MILLISECONDS);\n return () => clearTimeout(dismissTimer);\n }, [allSucceeded, downloads.length]);\n\n return (\n <ComponentTexts namespace=\"common\" texts={texts}>\n <Slide direction=\"up\" in={downloads.length > 0} mountOnEnter unmountOnExit>\n <DownloadsPanel\n elevation={8}\n role=\"region\"\n aria-label={t('downloads.title')}\n ownSx={[{\n position: 'fixed',\n right: (theme) => theme.spacing(SCREEN_EDGE_SPACING),\n bottom: 0,\n width: (theme) => `min(${PANEL_WIDTH_PIXELS}px, calc(100vw - ${theme.spacing(SCREEN_EDGE_SPACING * 2)}))`,\n // pegado al borde de abajo como en Drive: solo se redondean las esquinas de arriba\n borderBottomLeftRadius: 0,\n borderBottomRightRadius: 0,\n overflow: 'hidden',\n zIndex: (theme) => theme.zIndex.snackbar,\n }, (theme) => (isGlassTheme(theme) ? glassStylesOf(theme) : {})]}\n >\n <DownloadsHeader direction=\"row\" ownSx={{alignItems: 'center', gap: 0.5, pl: 2, pr: 1, py: 1, bgcolor: 'action.hover'}}>\n <DownloadsTitle variant=\"subtitle2\" component=\"h2\" noWrap ownSx={{flex: 1}} aria-live=\"polite\">\n {summaryTextOf(downloads, t)}\n </DownloadsTitle>\n <Tooltip title={isExpanded ? t('downloads.collapse') : t('downloads.expand')}>\n <IconButton size=\"small\" aria-expanded={isExpanded}\n aria-label={isExpanded ? t('downloads.collapse') : t('downloads.expand')}\n onClick={() => setIsExpanded((wasExpanded) => !wasExpanded)}>\n {isExpanded ? <ExpandMoreIcon fontSize=\"small\" /> : <ExpandLessIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n {/* cerrar a media descarga dejaría el archivo sin aviso de que terminó: la X sale cuando ya nada baja */}\n {activeCount === 0 && (\n <Tooltip title={t('downloads.close')}>\n <IconButton size=\"small\" aria-label={t('downloads.close')} onClick={clearFinishedDownloads}>\n <CloseIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </DownloadsHeader>\n <Collapse in={isExpanded}>\n <Divider />\n {/* OJO: overflowY auto también prende el scroll horizontal ante 1 px de más; se apaga explícito */}\n <DownloadsList dense disablePadding ownSx={{maxHeight: LIST_MAX_HEIGHT, overflowY: 'auto', overflowX: 'hidden'}}>\n {downloads.map((download, index) => (\n <Fragment key={download.id}>\n {index > 0 && <Divider component=\"li\" />}\n <DownloadRow download={download} />\n </Fragment>\n ))}\n </DownloadsList>\n </Collapse>\n </DownloadsPanel>\n </Slide>\n </ComponentTexts>\n );\n}\n\nconst DownloadManager = withPieceSlots(DownloadManagerContent, THEME_NAME);\nexport default DownloadManager;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAM,aAAa;AACnB,MAAM,oBAAoB,UAAU,YAAY,YAAY,eAAe;AAC3E,MAAM,sBAAsB,UAAU,YAAY,cAAc,gBAAgB;AAChF,MAAM,wBAAwB,UAAU,YAAY,gBAAgB,iBAAiB;AACrF,MAAM,wBAAwB,UAAU,YAAY,gBAAgB,UAAU;AAC9E,MAAM,oBAAoB,UAAU,YAAY,YAAY,gBAAgB;AAC5E,MAAM,sBAAsB,UAAU,YAAY,cAAc,SAAS;AACzE,MAAM,gBAAgB,UAAU,YAAY,QAAQ,QAAQ;AAC5D,MAAM,oBAAoB,UAAU,YAAY,YAAY,GAAG;AAC/D,MAAM,sBAAsB,UAAU,YAAY,cAAc,UAAU;AAC1E,MAAM,uBAAuB,UAAU,YAAY,eAAe,GAAG;AACrE,MAAM,iBAAiB,UAAU,YAAY,SAAS,KAAK;AAC3D,MAAM,kBAAkB,UAAU,YAAY,UAAU,KAAK;AAC7D,MAAM,iBAAiB,UAAU,YAAY,SAAS,UAAU;AAChE,MAAM,gBAAgB,UAAU,YAAY,QAAQ,IAAI;AAGxD,MAAM,4BAA4B;AAGlC,MAAM,sBAAsB;AAC5B,MAAM,qBAAqB;AAC3B,MAAM,kBAAkB;AACxB,MAAM,uBAAuB;AAU7B,SAAS,qBAAqB,UAAU,WAAW;AAC/C,QAAM,YAAY,SAAS,UAAU,MAAM,GAAG,EAAE,IAAA,GAAO,YAAA;AACvD,QAAM,WAAW,UAAU,SAAS,UAAU,SAAS;AACvD,SAAO,WAAW,EAAC,MAAM,SAAS,QAAQ,kBAAkB,MAAM,OAAO,SAAS,SAAS,kBAAkB,MAAA,IAAS;AAC1H;AAUA,SAAS,aAAa,UAAU,GAAG,gBAAgB;AAC/C,MAAI,SAAS,WAAW,gBAAgB,WAAW;AAC/C,WAAO,eAAe,SAAS,WAAW;AAAA,EAC9C;AACA,MAAI,SAAS,WAAW,gBAAgB,QAAQ;AAC5C,WAAO,SAAS,gBAAgB,EAAE,kBAAkB;AAAA,EACxD;AACA,MAAI,SAAS,WAAW,gBAAgB,UAAU;AAC9C,WAAO,EAAE,oBAAoB;AAAA,EACjC;AACA,MAAI,SAAS,gBAAgB,GAAG;AAC5B,WAAO,EAAE,qBAAqB;AAAA,EAClC;AAEA,SAAO,SAAS,aACV,EAAE,wBAAwB,EAAC,QAAQ,eAAe,SAAS,WAAW,GAAG,OAAO,eAAe,SAAS,UAAU,EAAA,CAAE,IACpH,EAAE,4BAA4B,EAAC,QAAQ,eAAe,SAAS,WAAW,GAAE;AACtF;AASA,SAAS,cAAc,WAAW,GAAG;AACjC,QAAM,cAAc,qBAAqB,SAAS;AAClD,MAAI,cAAc,GAAG;AACjB,WAAO,EAAE,gCAAgC,EAAC,OAAO,aAAY;AAAA,EACjE;AACA,QAAM,cAAc,UAAU,OAAO,CAAC,aAAa,SAAS,WAAW,gBAAgB,MAAM,EAAE;AAC/F,MAAI,cAAc,GAAG;AACjB,WAAO,EAAE,2BAA2B,EAAC,OAAO,aAAY;AAAA,EAC5D;AACA,QAAM,iBAAiB,UAAU,OAAO,CAAC,aAAa,SAAS,WAAW,gBAAgB,SAAS,EAAE;AACrG,SAAO,EAAE,8BAA8B,EAAC,OAAO,gBAAe;AAClE;AAOA,SAAS,wBAAwB,EAAC,UAAU,eAAc;AACtD,QAAM,EAAC,EAAA,IAAK,sBAAsB,QAAQ;AAE1C,MAAI,SAAS,WAAW,gBAAgB,WAAW;AAC/C,WAAO,oBAAC,mBAAA,EAAkB,OAAO,EAAC,OAAO,eAAA,GAAiB,cAAY,EAAE,yBAAyB,EAAC,MAAM,YAAA,CAAY,EAAA,CAAG;AAAA,EAC3H;AACA,MAAI,SAAS,WAAW,gBAAgB,QAAQ;AAC5C,WAAO,oBAAC,qBAAA,EAAoB,OAAO,EAAC,OAAO,aAAA,GAAe,cAAY,EAAE,sBAAsB,EAAC,MAAM,YAAA,CAAY,EAAA,CAAG;AAAA,EACxH;AACA,MAAI,SAAS,WAAW,gBAAgB,UAAU;AAC9C,WAAO,oBAAC,uBAAA,EAAsB,OAAO,EAAC,OAAO,gBAAA,GAAkB,cAAY,EAAE,wBAAwB,EAAC,MAAM,YAAA,CAAY,EAAA,CAAG;AAAA,EAC/H;AAEA,QAAM,eAAe,QAAQ,SAAS,UAAU;AAEhD,SACI,oBAAC,SAAA,EAAQ,OAAO,EAAE,kBAAkB,GAChC,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MAAsB,MAAK;AAAA,MAAQ,cAAY,EAAE,sBAAsB,EAAC,MAAM,aAAY;AAAA,MAAG,SAAS,MAAM,eAAe,SAAS,EAAE;AAAA,MAC3H,OAAO,EAAC,UAAU,YAAY,OAAO,uBAAuB,IAAI,QAAQ,uBAAuB,GAAA;AAAA,MACvG,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACG,MAAM;AAAA,YACN,WAAW;AAAA,YACX,SAAS,eAAe,gBAAgB;AAAA,YACxC,OAAO,eAAe,KAAK,IAAI,KAAM,SAAS,cAAc,MAAO,SAAS,UAAU,IAAI;AAAA,YAC1F,OAAO,EAAC,UAAU,WAAA;AAAA,UAAU;AAAA,QAAA;AAAA,4BAE/B,qBAAA,EAAoB,OAAO,EAAC,UAAU,KAAE,CAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,GAEpD;AAER;AAOA,SAAS,YAAY,EAAC,YAAW;AAC7B,QAAM,EAAC,EAAA,IAAK,sBAAsB,QAAQ;AAC1C,QAAM,EAAC,eAAA,IAAkB,cAAA;AACzB,QAAM,EAAC,MAAM,MAAA,IAAS,qBAAqB,UAAU,cAAc;AACnE,QAAM,cAAc,SAAS,YAAY,SAAS;AAClD,QAAM,WAAW,SAAS,WAAW,gBAAgB;AAErD;AAAA;AAAA,IAEI,qBAAC,eAAA,EAAc,gBAAc,MAAC,OAAO,EAAC,KAAK,KAAK,IAAI,GAAG,IAAI,GAAG,UAAU,KACpE,UAAA;AAAA,MAAA,oBAAC,MAAA,EAAK,UAAS,SAAQ,IAAI,EAAC,OAAO,YAAY,KAAI;AAAA,MACnD,qBAAC,qBAAkB,OAAO,EAAC,UAAU,GAAG,MAAM,KAC1C,UAAA;AAAA,QAAA,oBAAC,SAAA,EAAQ,OAAO,aACZ,UAAA,oBAAC,YAAA,EAAW,SAAQ,SAAQ,QAAM,MAAE,UAAA,YAAA,CAAY,GACpD;AAAA,QACA;AAAA,UAAC;AAAA,UAAA;AAAA,YAAoB,SAAQ;AAAA,YAAU,WAAU;AAAA,YAAI,QAAQ,CAAC;AAAA,YAClD,OAAO,EAAC,OAAO,WAAW,eAAe,iBAAA;AAAA,YAChD,UAAA,aAAa,UAAU,GAAG,cAAc;AAAA,UAAA;AAAA,QAAA;AAAA,MAC7C,GACJ;AAAA,MACA,oBAAC,sBAAA,EAAqB,OAAO,EAAC,YAAY,GAAG,SAAS,QAAQ,YAAY,YACtE,UAAA,oBAAC,yBAAA,EAAwB,UAAoB,aAA0B,EAAA,CAC3E;AAAA,IAAA,EAAA,CACJ;AAAA;AAER;AAMA,SAAS,uBAAuB,EAAC,OAAO,GAAG,aAAA,IAAgB,CAAA,GAAI;AAC3D,mBAAiB,mBAAmB,YAAY;AAChD,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,YAAY,YAAY,gBAAgB,CAAC,aAAa,SAAS,QAAQ,SAAS;AACtF,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,IAAI;AACjD,QAAM,mBAAmB,OAAO,UAAU,MAAM;AAEhD,QAAM,cAAc,qBAAqB,SAAS;AAClD,QAAM,eAAe,UAAU,SAAS,KAAK,UAAU,MAAM,CAAC,aAAa,SAAS,WAAW,gBAAgB,SAAS;AAGxH,YAAU,MAAM;AACZ,QAAI,UAAU,SAAS,iBAAiB,SAAS;AAC7C,oBAAc,IAAI;AAAA,IACtB;AACA,qBAAiB,UAAU,UAAU;AAAA,EACzC,GAAG,CAAC,UAAU,MAAM,CAAC;AAGrB,YAAU,MAAM;AACZ,QAAI,CAAC,cAAc;AACf,aAAO;AAAA,IACX;AACA,UAAM,eAAe,WAAW,wBAAwB,yBAAyB;AACjF,WAAO,MAAM,aAAa,YAAY;AAAA,EAC1C,GAAG,CAAC,cAAc,UAAU,MAAM,CAAC;AAEnC,6BACK,gBAAA,EAAe,WAAU,UAAS,OAC/B,8BAAC,OAAA,EAAM,WAAU,MAAK,IAAI,UAAU,SAAS,GAAG,cAAY,MAAC,eAAa,MACtE,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,WAAW;AAAA,MACX,MAAK;AAAA,MACL,cAAY,EAAE,iBAAiB;AAAA,MAC/B,OAAO,CAAC;AAAA,QACJ,UAAU;AAAA,QACV,OAAO,CAAC,UAAU,MAAM,QAAQ,mBAAmB;AAAA,QACnD,QAAQ;AAAA,QACR,OAAO,CAAC,UAAU,OAAO,kBAAkB,oBAAoB,MAAM,QAAQ,sBAAsB,CAAC,CAAC;AAAA;AAAA,QAErG,wBAAwB;AAAA,QACxB,yBAAyB;AAAA,QACzB,UAAU;AAAA,QACV,QAAQ,CAAC,UAAU,MAAM,OAAO;AAAA,MAAA,GACjC,CAAC,UAAW,aAAa,KAAK,IAAI,cAAc,KAAK,IAAI,EAAG;AAAA,MAE/D,UAAA;AAAA,QAAA,qBAAC,mBAAgB,WAAU,OAAM,OAAO,EAAC,YAAY,UAAU,KAAK,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,kBACnG,UAAA;AAAA,UAAA,oBAAC,kBAAe,SAAQ,aAAY,WAAU,MAAK,QAAM,MAAC,OAAO,EAAC,MAAM,KAAI,aAAU,UACjF,UAAA,cAAc,WAAW,CAAC,GAC/B;AAAA,UACA,oBAAC,WAAQ,OAAO,aAAa,EAAE,oBAAoB,IAAI,EAAE,kBAAkB,GACvE,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cAAW,MAAK;AAAA,cAAQ,iBAAe;AAAA,cAC5B,cAAY,aAAa,EAAE,oBAAoB,IAAI,EAAE,kBAAkB;AAAA,cACvE,SAAS,MAAM,cAAc,CAAC,gBAAgB,CAAC,WAAW;AAAA,cACjE,UAAA,iCAAc,gBAAA,EAAe,UAAS,SAAQ,IAAK,oBAAC,gBAAA,EAAe,UAAS,QAAA,CAAQ;AAAA,YAAA;AAAA,UAAA,GAE7F;AAAA,UAEC,gBAAgB,KACb,oBAAC,SAAA,EAAQ,OAAO,EAAE,iBAAiB,GAC/B,UAAA,oBAAC,YAAA,EAAW,MAAK,SAAQ,cAAY,EAAE,iBAAiB,GAAG,SAAS,wBAChE,8BAAC,WAAA,EAAU,UAAS,QAAA,CAAQ,EAAA,CAChC,EAAA,CACJ;AAAA,QAAA,GAER;AAAA,QACA,qBAAC,UAAA,EAAS,IAAI,YACV,UAAA;AAAA,UAAA,oBAAC,SAAA,EAAQ;AAAA,UAET,oBAAC,iBAAc,OAAK,MAAC,gBAAc,MAAC,OAAO,EAAC,WAAW,iBAAiB,WAAW,QAAQ,WAAW,YACjG,UAAA,UAAU,IAAI,CAAC,UAAU,UACtB,qBAAC,UAAA,EACI,UAAA;AAAA,YAAA,QAAQ,KAAK,oBAAC,SAAA,EAAQ,WAAU,MAAK;AAAA,YACtC,oBAAC,eAAY,SAAA,CAAoB;AAAA,UAAA,KAFtB,SAAS,EAGxB,CACH,EAAA,CACL;AAAA,QAAA,EAAA,CACJ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,GAER,EAAA,CACJ;AAER;AAEA,MAAM,kBAAkB,eAAe,wBAAwB,UAAU;"}
@@ -10,12 +10,12 @@ import DialogActions from "@mui/material/DialogActions";
10
10
  import DialogContent from "@mui/material/DialogContent";
11
11
  import DialogContentText from "@mui/material/DialogContentText";
12
12
  import DialogTitle from "@mui/material/DialogTitle";
13
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
13
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
14
14
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
15
15
  const THEME_NAME = "CalcitaConfirmDialog";
16
16
  const ConfirmProblem = piecePart(THEME_NAME, "Problem", Alert);
17
17
  const ConfirmActions = piecePart(THEME_NAME, "Actions", DialogActions);
18
- function ConfirmDialog(props) {
18
+ function ConfirmDialogContent(props) {
19
19
  const {
20
20
  open,
21
21
  title,
@@ -75,6 +75,7 @@ function ConfirmDialog(props) {
75
75
  }
76
76
  );
77
77
  }
78
+ const ConfirmDialog = withPieceSlots(ConfirmDialogContent, THEME_NAME);
78
79
  export {
79
80
  ConfirmDialog as default
80
81
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmDialog.js","sources":["../../src/feedback/ConfirmDialog.jsx"],"sourcesContent":["// Diálogo de confirmación: toda acción que cambia algo, manda un correo o descarga un archivo pasa por aquí antes de\n// ejecutarse (regla de tablas). Dice en lenguaje ciudadano QUÉ va a pasar y a QUÉ renglón («¿Dar de baja a Ana López?\n// Ya no podrá entrar; se puede reactivar después»).\n//\n// Recibe el estado de la petición por props (pending, error) en vez de hacerla él: core no conoce el API. Lo normal es\n// alimentarlo con useConfirmAction (máquina confirmActionMachine), que ya garantiza que cancelar no ejecuta y que un\n// doble clic no manda dos peticiones. Mientras la petición está en curso no se puede cerrar ni volver a confirmar.\n//\n// children: lo que el diálogo necesita pedir antes de confirmar (p. ej. el motivo de una baja), debajo del texto.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaConfirmDialog con defaultProps y\n// styleOverrides de sus partes: problem, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Alert from '@mui/material/Alert';\nimport Button from '@mui/material/Button';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Dialog from '@mui/material/Dialog';\nimport DialogActions from '@mui/material/DialogActions';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogContentText from '@mui/material/DialogContentText';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaConfirmDialog)\nconst THEME_NAME = 'CalcitaConfirmDialog';\nconst ConfirmProblem = piecePart(THEME_NAME, 'Problem', Alert);\nconst ConfirmActions = piecePart(THEME_NAME, 'Actions', DialogActions);\n\n/**\n * @param {object} props\n * @param {boolean} props.open\n * @param {string} props.title texto ya traducido, con el renglón («¿Dar de baja a Ana López?»)\n * @param {import('react').ReactNode} [props.description] qué va a pasar, en palabras normales\n * @param {string} [props.confirmLabel]\n * @param {string} [props.cancelLabel]\n * @param {'primary'|'error'|'warning'} [props.tone]\n * @param {boolean} [props.isPending]\n * @param {boolean} [props.isConfirmDisabled] la acción ya no aplica (p. ej. conflicto: el registro cambió)\n * @param {string|null} [props.errorMessage] mensaje ya traducido (ApiError.message)\n * @param {() => void} props.onConfirm\n * @param {() => void} props.onClose\n * @param {import('react').ReactNode} [props.children]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function ConfirmDialog(props) {\n // lo que el proyecto puso en su tema (components.CalcitaConfirmDialog.defaultProps) y encima lo que llega aquí\n const {\n open, title, description, confirmLabel, cancelLabel, tone = 'primary',\n isPending = false, isConfirmDisabled = false, errorMessage = null, onConfirm, onClose, children, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // ids propios: una pantalla puede tener varios diálogos montados y los aria-* no deben apuntar al de otro\n const dialogId = useId();\n\n const handleClose = () => {\n // guard clause: no se cierra a media petición\n if (isPending) {\n return;\n }\n onClose();\n };\n\n return (\n <Dialog open={open} onClose={handleClose} maxWidth=\"xs\" fullWidth\n aria-labelledby={`${dialogId}-title`} aria-describedby={`${dialogId}-description`}>\n <DialogTitle id={`${dialogId}-title`}>{title}</DialogTitle>\n <DialogContent>\n {errorMessage && <ConfirmProblem severity=\"error\" role=\"alert\" ownSx={{mb: 2}}>{errorMessage}</ConfirmProblem>}\n {description && (\n <DialogContentText id={`${dialogId}-description`}>{description}</DialogContentText>\n )}\n {children}\n </DialogContent>\n <ConfirmActions ownSx={{px: 3, pb: 2.5}}>\n <Button variant=\"outlined\" color=\"inherit\" onClick={handleClose} disabled={isPending}>\n {cancelLabel ?? t('actions.cancel')}\n </Button>\n <Button variant=\"contained\" color={tone} onClick={onConfirm} disabled={isPending || isConfirmDisabled}\n aria-busy={isPending}>\n {isPending ? <CircularProgress size={20} color=\"inherit\" /> : (confirmLabel ?? t('actions.confirm'))}\n </Button>\n </ConfirmActions>\n </Dialog>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AA4BA,MAAM,aAAa;AACnB,MAAM,iBAAiB,UAAU,YAAY,WAAW,KAAK;AAC7D,MAAM,iBAAiB,UAAU,YAAY,WAAW,aAAa;AAkBrE,SAAwB,cAAc,OAAO;AAEzC,QAAM;AAAA,IACN;AAAA,IAAM;AAAA,IAAO;AAAA,IAAa;AAAA,IAAc;AAAA,IAAa,OAAO;AAAA,IAC5D,YAAY;AAAA,IAAO,oBAAoB;AAAA,IAAO,eAAe;AAAA,IAAM;AAAA,IAAW;AAAA,IAAS;AAAA,IAAU;AAAA,IACjG,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AAEjD,QAAM,WAAW,MAAA;AAEjB,QAAM,cAAc,MAAM;AAEtB,QAAI,WAAW;AACX;AAAA,IACJ;AACA,YAAA;AAAA,EACJ;AAEA,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAO;AAAA,MAAY,SAAS;AAAA,MAAa,UAAS;AAAA,MAAK,WAAS;AAAA,MACzD,mBAAiB,GAAG,QAAQ;AAAA,MAAU,oBAAkB,GAAG,QAAQ;AAAA,MACvE,UAAA;AAAA,QAAA,oBAAC,aAAA,EAAY,IAAI,GAAG,QAAQ,UAAW,UAAA,OAAM;AAAA,6BAC5C,eAAA,EACI,UAAA;AAAA,UAAA,gBAAgB,oBAAC,gBAAA,EAAe,UAAS,SAAQ,MAAK,SAAQ,OAAO,EAAC,IAAI,EAAA,GAAK,UAAA,aAAA,CAAa;AAAA,UAC5F,eACG,oBAAC,mBAAA,EAAkB,IAAI,GAAG,QAAQ,gBAAiB,UAAA,aAAY;AAAA,UAElE;AAAA,QAAA,GACL;AAAA,QACA,qBAAC,kBAAe,OAAO,EAAC,IAAI,GAAG,IAAI,OAC/B,UAAA;AAAA,UAAA,oBAAC,QAAA,EAAO,SAAQ,YAAW,OAAM,WAAU,SAAS,aAAa,UAAU,WACtE,UAAA,eAAe,EAAE,gBAAgB,GACtC;AAAA,UACA;AAAA,YAAC;AAAA,YAAA;AAAA,cAAO,SAAQ;AAAA,cAAY,OAAO;AAAA,cAAM,SAAS;AAAA,cAAW,UAAU,aAAa;AAAA,cAC5E,aAAW;AAAA,cACd,UAAA,YAAY,oBAAC,kBAAA,EAAiB,MAAM,IAAI,OAAM,UAAA,CAAU,IAAM,gBAAgB,EAAE,iBAAiB;AAAA,YAAA;AAAA,UAAA;AAAA,QACtG,EAAA,CACJ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGZ;"}
1
+ {"version":3,"file":"ConfirmDialog.js","sources":["../../src/feedback/ConfirmDialog.jsx"],"sourcesContent":["// Diálogo de confirmación: toda acción que cambia algo, manda un correo o descarga un archivo pasa por aquí antes de\n// ejecutarse (regla de tablas). Dice en lenguaje ciudadano QUÉ va a pasar y a QUÉ renglón («¿Dar de baja a Ana López?\n// Ya no podrá entrar; se puede reactivar después»).\n//\n// Recibe el estado de la petición por props (pending, error) en vez de hacerla él: core no conoce el API. Lo normal es\n// alimentarlo con useConfirmAction (máquina confirmActionMachine), que ya garantiza que cancelar no ejecuta y que un\n// doble clic no manda dos peticiones. Mientras la petición está en curso no se puede cerrar ni volver a confirmar.\n//\n// children: lo que el diálogo necesita pedir antes de confirmar (p. ej. el motivo de una baja), debajo del texto.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaConfirmDialog con defaultProps y\n// styleOverrides de sus partes: problem, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Alert from '@mui/material/Alert';\nimport Button from '@mui/material/Button';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Dialog from '@mui/material/Dialog';\nimport DialogActions from '@mui/material/DialogActions';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogContentText from '@mui/material/DialogContentText';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaConfirmDialog)\nconst THEME_NAME = 'CalcitaConfirmDialog';\nconst ConfirmProblem = piecePart(THEME_NAME, 'Problem', Alert);\nconst ConfirmActions = piecePart(THEME_NAME, 'Actions', DialogActions);\n\n/**\n * @param {object} props\n * @param {boolean} props.open\n * @param {string} props.title texto ya traducido, con el renglón («¿Dar de baja a Ana López?»)\n * @param {import('react').ReactNode} [props.description] qué va a pasar, en palabras normales\n * @param {string} [props.confirmLabel]\n * @param {string} [props.cancelLabel]\n * @param {'primary'|'error'|'warning'} [props.tone]\n * @param {boolean} [props.isPending]\n * @param {boolean} [props.isConfirmDisabled] la acción ya no aplica (p. ej. conflicto: el registro cambió)\n * @param {string|null} [props.errorMessage] mensaje ya traducido (ApiError.message)\n * @param {() => void} props.onConfirm\n * @param {() => void} props.onClose\n * @param {import('react').ReactNode} [props.children]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction ConfirmDialogContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaConfirmDialog.defaultProps) y encima lo que llega aquí\n const {\n open, title, description, confirmLabel, cancelLabel, tone = 'primary',\n isPending = false, isConfirmDisabled = false, errorMessage = null, onConfirm, onClose, children, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // ids propios: una pantalla puede tener varios diálogos montados y los aria-* no deben apuntar al de otro\n const dialogId = useId();\n\n const handleClose = () => {\n // guard clause: no se cierra a media petición\n if (isPending) {\n return;\n }\n onClose();\n };\n\n return (\n <Dialog open={open} onClose={handleClose} maxWidth=\"xs\" fullWidth\n aria-labelledby={`${dialogId}-title`} aria-describedby={`${dialogId}-description`}>\n <DialogTitle id={`${dialogId}-title`}>{title}</DialogTitle>\n <DialogContent>\n {errorMessage && <ConfirmProblem severity=\"error\" role=\"alert\" ownSx={{mb: 2}}>{errorMessage}</ConfirmProblem>}\n {description && (\n <DialogContentText id={`${dialogId}-description`}>{description}</DialogContentText>\n )}\n {children}\n </DialogContent>\n <ConfirmActions ownSx={{px: 3, pb: 2.5}}>\n <Button variant=\"outlined\" color=\"inherit\" onClick={handleClose} disabled={isPending}>\n {cancelLabel ?? t('actions.cancel')}\n </Button>\n <Button variant=\"contained\" color={tone} onClick={onConfirm} disabled={isPending || isConfirmDisabled}\n aria-busy={isPending}>\n {isPending ? <CircularProgress size={20} color=\"inherit\" /> : (confirmLabel ?? t('actions.confirm'))}\n </Button>\n </ConfirmActions>\n </Dialog>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst ConfirmDialog = withPieceSlots(ConfirmDialogContent, THEME_NAME);\nexport default ConfirmDialog;\n"],"names":[],"mappings":";;;;;;;;;;;;;;AA4BA,MAAM,aAAa;AACnB,MAAM,iBAAiB,UAAU,YAAY,WAAW,KAAK;AAC7D,MAAM,iBAAiB,UAAU,YAAY,WAAW,aAAa;AAkBrE,SAAS,qBAAqB,OAAO;AAEjC,QAAM;AAAA,IACN;AAAA,IAAM;AAAA,IAAO;AAAA,IAAa;AAAA,IAAc;AAAA,IAAa,OAAO;AAAA,IAC5D,YAAY;AAAA,IAAO,oBAAoB;AAAA,IAAO,eAAe;AAAA,IAAM;AAAA,IAAW;AAAA,IAAS;AAAA,IAAU;AAAA,IACjG,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AAEjD,QAAM,WAAW,MAAA;AAEjB,QAAM,cAAc,MAAM;AAEtB,QAAI,WAAW;AACX;AAAA,IACJ;AACA,YAAA;AAAA,EACJ;AAEA,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAO;AAAA,MAAY,SAAS;AAAA,MAAa,UAAS;AAAA,MAAK,WAAS;AAAA,MACzD,mBAAiB,GAAG,QAAQ;AAAA,MAAU,oBAAkB,GAAG,QAAQ;AAAA,MACvE,UAAA;AAAA,QAAA,oBAAC,aAAA,EAAY,IAAI,GAAG,QAAQ,UAAW,UAAA,OAAM;AAAA,6BAC5C,eAAA,EACI,UAAA;AAAA,UAAA,gBAAgB,oBAAC,gBAAA,EAAe,UAAS,SAAQ,MAAK,SAAQ,OAAO,EAAC,IAAI,EAAA,GAAK,UAAA,aAAA,CAAa;AAAA,UAC5F,eACG,oBAAC,mBAAA,EAAkB,IAAI,GAAG,QAAQ,gBAAiB,UAAA,aAAY;AAAA,UAElE;AAAA,QAAA,GACL;AAAA,QACA,qBAAC,kBAAe,OAAO,EAAC,IAAI,GAAG,IAAI,OAC/B,UAAA;AAAA,UAAA,oBAAC,QAAA,EAAO,SAAQ,YAAW,OAAM,WAAU,SAAS,aAAa,UAAU,WACtE,UAAA,eAAe,EAAE,gBAAgB,GACtC;AAAA,UACA;AAAA,YAAC;AAAA,YAAA;AAAA,cAAO,SAAQ;AAAA,cAAY,OAAO;AAAA,cAAM,SAAS;AAAA,cAAW,UAAU,aAAa;AAAA,cAC5E,aAAW;AAAA,cACd,UAAA,YAAY,oBAAC,kBAAA,EAAiB,MAAM,IAAI,OAAM,UAAA,CAAU,IAAM,gBAAgB,EAAE,iBAAiB;AAAA,YAAA;AAAA,UAAA;AAAA,QACtG,EAAA,CACJ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGZ;AAGA,MAAM,gBAAgB,eAAe,sBAAsB,UAAU;"}
@@ -7,14 +7,14 @@ import DialogContent from "@mui/material/DialogContent";
7
7
  import DialogContentText from "@mui/material/DialogContentText";
8
8
  import DialogTitle from "@mui/material/DialogTitle";
9
9
  import Stack from "@mui/material/Stack";
10
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
10
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
11
11
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
12
12
  const THEME_NAME = "CalcitaModalWaiting";
13
13
  const WaitingRoot = piecePart(THEME_NAME, "Root", Dialog);
14
14
  const WaitingTitle = piecePart(THEME_NAME, "Title", DialogTitle);
15
15
  const WaitingBody = piecePart(THEME_NAME, "Body", Stack);
16
16
  const WaitingText = piecePart(THEME_NAME, "Text", DialogContentText);
17
- function ModalWaiting(props) {
17
+ function ModalWaitingContent(props) {
18
18
  const { open, title, text, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
19
19
  warnUnknownProps(THEME_NAME, unknownProps);
20
20
  const { t } = useToolkitTranslation("common", texts);
@@ -26,6 +26,7 @@ function ModalWaiting(props) {
26
26
  ] }) })
27
27
  ] });
28
28
  }
29
+ const ModalWaiting = withPieceSlots(ModalWaitingContent, THEME_NAME);
29
30
  export {
30
31
  ModalWaiting as default
31
32
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ModalWaiting.js","sources":["../../src/feedback/ModalWaiting.jsx"],"sourcesContent":["// Bloqueo general \"espere un momento\" como diálogo modal, para una acción que no se puede interrumpir (p. ej. generar\n// un archivo grande).\n//\n// OJO zIndex: HASTA ARRIBA de todo, encima de modal (1300), snackbar (1400) y tooltip (1500), para que ningún elemento\n// de la interfaz se le monte mientras bloquea. No se cierra con Escape a propósito.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaModalWaiting con defaultProps y\n// styleOverrides de sus partes: root, title, body, text.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Dialog from '@mui/material/Dialog';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogContentText from '@mui/material/DialogContentText';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport Stack from '@mui/material/Stack';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaModalWaiting)\nconst THEME_NAME = 'CalcitaModalWaiting';\nconst WaitingRoot = piecePart(THEME_NAME, 'Root', Dialog);\nconst WaitingTitle = piecePart(THEME_NAME, 'Title', DialogTitle);\nconst WaitingBody = piecePart(THEME_NAME, 'Body', Stack);\nconst WaitingText = piecePart(THEME_NAME, 'Text', DialogContentText);\n\n/**\n * @param {object} props\n * @param {boolean} props.open\n * @param {string} [props.title] ya traducido; por omisión common:waiting.title\n * @param {string} [props.text] ya traducido; por omisión common:waiting.text\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function ModalWaiting(props) {\n // lo que el proyecto puso en su tema (components.CalcitaModalWaiting.defaultProps) y encima lo que llega aquí\n const {open, title, text, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n\n return (\n <WaitingRoot open={open} disableEscapeKeyDown aria-busy=\"true\" ownSx={{zIndex: (theme) => theme.zIndex.tooltip + 10}}>\n <WaitingTitle ownSx={{textAlign: 'center'}}>{title ?? t('waiting.title')}</WaitingTitle>\n <DialogContent>\n <WaitingBody spacing={2} ownSx={{alignItems: 'center'}}>\n <CircularProgress size={28} />\n <WaitingText ownSx={{textAlign: 'center'}}>{text ?? t('waiting.text')}</WaitingText>\n </WaitingBody>\n </DialogContent>\n </WaitingRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAqBA,MAAM,aAAa;AACnB,MAAM,cAAc,UAAU,YAAY,QAAQ,MAAM;AACxD,MAAM,eAAe,UAAU,YAAY,SAAS,WAAW;AAC/D,MAAM,cAAc,UAAU,YAAY,QAAQ,KAAK;AACvD,MAAM,cAAc,UAAU,YAAY,QAAQ,iBAAiB;AASnE,SAAwB,aAAa,OAAO;AAExC,QAAM,EAAC,MAAM,OAAO,MAAM,OAAO,GAAG,iBAAgB,cAAc,OAAO,UAAU;AACnF,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AAEjD,8BACK,aAAA,EAAY,MAAY,sBAAoB,MAAC,aAAU,QAAO,OAAO,EAAC,QAAQ,CAAC,UAAU,MAAM,OAAO,UAAU,MAC7G,UAAA;AAAA,IAAA,oBAAC,cAAA,EAAa,OAAO,EAAC,WAAW,YAAY,UAAA,SAAS,EAAE,eAAe,EAAA,CAAE;AAAA,IACzE,oBAAC,eAAA,EACG,UAAA,qBAAC,aAAA,EAAY,SAAS,GAAG,OAAO,EAAC,YAAY,SAAA,GACzC,UAAA;AAAA,MAAA,oBAAC,kBAAA,EAAiB,MAAM,GAAA,CAAI;AAAA,MAC5B,oBAAC,aAAA,EAAY,OAAO,EAAC,WAAW,YAAY,UAAA,QAAQ,EAAE,cAAc,EAAA,CAAE;AAAA,IAAA,EAAA,CAC1E,EAAA,CACJ;AAAA,EAAA,GACJ;AAER;"}
1
+ {"version":3,"file":"ModalWaiting.js","sources":["../../src/feedback/ModalWaiting.jsx"],"sourcesContent":["// Bloqueo general \"espere un momento\" como diálogo modal, para una acción que no se puede interrumpir (p. ej. generar\n// un archivo grande).\n//\n// OJO zIndex: HASTA ARRIBA de todo, encima de modal (1300), snackbar (1400) y tooltip (1500), para que ningún elemento\n// de la interfaz se le monte mientras bloquea. No se cierra con Escape a propósito.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaModalWaiting con defaultProps y\n// styleOverrides de sus partes: root, title, body, text.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Dialog from '@mui/material/Dialog';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogContentText from '@mui/material/DialogContentText';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport Stack from '@mui/material/Stack';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaModalWaiting)\nconst THEME_NAME = 'CalcitaModalWaiting';\nconst WaitingRoot = piecePart(THEME_NAME, 'Root', Dialog);\nconst WaitingTitle = piecePart(THEME_NAME, 'Title', DialogTitle);\nconst WaitingBody = piecePart(THEME_NAME, 'Body', Stack);\nconst WaitingText = piecePart(THEME_NAME, 'Text', DialogContentText);\n\n/**\n * @param {object} props\n * @param {boolean} props.open\n * @param {string} [props.title] ya traducido; por omisión common:waiting.title\n * @param {string} [props.text] ya traducido; por omisión common:waiting.text\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction ModalWaitingContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaModalWaiting.defaultProps) y encima lo que llega aquí\n const {open, title, text, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n\n return (\n <WaitingRoot open={open} disableEscapeKeyDown aria-busy=\"true\" ownSx={{zIndex: (theme) => theme.zIndex.tooltip + 10}}>\n <WaitingTitle ownSx={{textAlign: 'center'}}>{title ?? t('waiting.title')}</WaitingTitle>\n <DialogContent>\n <WaitingBody spacing={2} ownSx={{alignItems: 'center'}}>\n <CircularProgress size={28} />\n <WaitingText ownSx={{textAlign: 'center'}}>{text ?? t('waiting.text')}</WaitingText>\n </WaitingBody>\n </DialogContent>\n </WaitingRoot>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst ModalWaiting = withPieceSlots(ModalWaitingContent, THEME_NAME);\nexport default ModalWaiting;\n"],"names":[],"mappings":";;;;;;;;;;;AAqBA,MAAM,aAAa;AACnB,MAAM,cAAc,UAAU,YAAY,QAAQ,MAAM;AACxD,MAAM,eAAe,UAAU,YAAY,SAAS,WAAW;AAC/D,MAAM,cAAc,UAAU,YAAY,QAAQ,KAAK;AACvD,MAAM,cAAc,UAAU,YAAY,QAAQ,iBAAiB;AASnE,SAAS,oBAAoB,OAAO;AAEhC,QAAM,EAAC,MAAM,OAAO,MAAM,OAAO,GAAG,iBAAgB,cAAc,OAAO,UAAU;AACnF,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AAEjD,8BACK,aAAA,EAAY,MAAY,sBAAoB,MAAC,aAAU,QAAO,OAAO,EAAC,QAAQ,CAAC,UAAU,MAAM,OAAO,UAAU,MAC7G,UAAA;AAAA,IAAA,oBAAC,cAAA,EAAa,OAAO,EAAC,WAAW,YAAY,UAAA,SAAS,EAAE,eAAe,EAAA,CAAE;AAAA,IACzE,oBAAC,eAAA,EACG,UAAA,qBAAC,aAAA,EAAY,SAAS,GAAG,OAAO,EAAC,YAAY,SAAA,GACzC,UAAA;AAAA,MAAA,oBAAC,kBAAA,EAAiB,MAAM,GAAA,CAAI;AAAA,MAC5B,oBAAC,aAAA,EAAY,OAAO,EAAC,WAAW,YAAY,UAAA,QAAQ,EAAE,cAAc,EAAA,CAAE;AAAA,IAAA,EAAA,CAC1E,EAAA,CACJ;AAAA,EAAA,GACJ;AAER;AAGA,MAAM,eAAe,eAAe,qBAAqB,UAAU;"}
@@ -11,7 +11,7 @@ import { aboveMobileTabBarOf, GLASS_PANEL_GAP_PIXELS } from "../appShell/shellSi
11
11
  import { minimalFloatingStylesOf } from "../theme/components/minimalComponents.js";
12
12
  import { isGlassTheme, glassStylesOf } from "../theme/glassSurface.js";
13
13
  import { APP_BAR_HEIGHT } from "../ui/layout/appBarHeight.js";
14
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
14
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
15
15
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
16
16
  const THEME_NAME = "CalcitaNewBuildNotice";
17
17
  const NoticeFloating = piecePart(THEME_NAME, "Floating", Box);
@@ -53,7 +53,7 @@ function floatingSxOf(theme) {
53
53
  "@media (prefers-reduced-motion: reduce)": { animation: "none" }
54
54
  };
55
55
  }
56
- function NewBuildNotice(props) {
56
+ function NewBuildNoticeContent(props) {
57
57
  const { message, reloadLabel, onReload = reloadPage, variant = NEW_BUILD_NOTICE_VARIANT.ribbon, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
58
58
  warnUnknownProps(THEME_NAME, unknownProps);
59
59
  const { t } = useToolkitTranslation("common", texts);
@@ -82,6 +82,7 @@ function NewBuildNotice(props) {
82
82
  }
83
83
  );
84
84
  }
85
+ const NewBuildNotice = withPieceSlots(NewBuildNoticeContent, THEME_NAME);
85
86
  export {
86
87
  NEW_BUILD_NOTICE_VARIANT,
87
88
  NewBuildNotice as default