@stackcraftmx/calcita 0.47.0 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (488) hide show
  1. package/README.md +173 -12
  2. package/cli/calcita.js +15 -0
  3. package/cli/checkTexts.js +209 -0
  4. package/cli/packageVersions.js +6 -1
  5. package/cli/projectFiles.js +4 -2
  6. package/cli/templates/project/README.md.tpl +21 -1
  7. package/cli/templates/project/eslint.config.js.tpl +27 -0
  8. package/cli/templates/project/src/app/appTexts.js.tpl +2 -1
  9. package/cli/templates/project/src/core/publicPaths.js.tpl +10 -2
  10. package/cli/templates/project/vite.config.js.tpl +8 -1
  11. package/dist/DataTable/AuditTrailDialog.js +3 -2
  12. package/dist/DataTable/AuditTrailDialog.js.map +1 -1
  13. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +3 -2
  14. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
  15. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +3 -2
  16. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
  17. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +3 -2
  18. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
  19. package/dist/DataTable/EmptyState.js +3 -2
  20. package/dist/DataTable/EmptyState.js.map +1 -1
  21. package/dist/DataTable/FilterChips.js +3 -2
  22. package/dist/DataTable/FilterChips.js.map +1 -1
  23. package/dist/DataTable/GoToPage.js +3 -2
  24. package/dist/DataTable/GoToPage.js.map +1 -1
  25. package/dist/DataTable/ServerTable.js +95 -28
  26. package/dist/DataTable/ServerTable.js.map +1 -1
  27. package/dist/DataTable/ServerTableFilterDrawer.js +8 -3
  28. package/dist/DataTable/ServerTableFilterDrawer.js.map +1 -1
  29. package/dist/DataTable/StackedCell.js +60 -0
  30. package/dist/DataTable/StackedCell.js.map +1 -0
  31. package/dist/DataTable/TableCardsView.js +88 -0
  32. package/dist/DataTable/TableCardsView.js.map +1 -0
  33. package/dist/DataTable/columnWidths.js +30 -0
  34. package/dist/DataTable/columnWidths.js.map +1 -0
  35. package/dist/DataTable/columns.js +47 -1
  36. package/dist/DataTable/columns.js.map +1 -1
  37. package/dist/DataTable/fixedColumns.js +24 -0
  38. package/dist/DataTable/fixedColumns.js.map +1 -0
  39. package/dist/DataTable/useTableView.js +29 -0
  40. package/dist/DataTable/useTableView.js.map +1 -0
  41. package/dist/access/PermissionMatrix.js +3 -2
  42. package/dist/access/PermissionMatrix.js.map +1 -1
  43. package/dist/account/AccountProvider.js +1 -1
  44. package/dist/account/AccountSecuritySection.js +3 -2
  45. package/dist/account/AccountSecuritySection.js.map +1 -1
  46. package/dist/account/DemoTotpCodeButton.js +3 -2
  47. package/dist/account/DemoTotpCodeButton.js.map +1 -1
  48. package/dist/account/ProfileScreen.js +3 -2
  49. package/dist/account/ProfileScreen.js.map +1 -1
  50. package/dist/account/SignInScreen.js +3 -2
  51. package/dist/account/SignInScreen.js.map +1 -1
  52. package/dist/appShell/AccountMenu.js +3 -2
  53. package/dist/appShell/AccountMenu.js.map +1 -1
  54. package/dist/appShell/AppLayout.js +3 -2
  55. package/dist/appShell/AppLayout.js.map +1 -1
  56. package/dist/appShell/AppearanceSettings.js +3 -2
  57. package/dist/appShell/AppearanceSettings.js.map +1 -1
  58. package/dist/appShell/AuthLayout.js +3 -2
  59. package/dist/appShell/AuthLayout.js.map +1 -1
  60. package/dist/appShell/BarActionButton.js +11 -4
  61. package/dist/appShell/BarActionButton.js.map +1 -1
  62. package/dist/appShell/BarActions.js +3 -2
  63. package/dist/appShell/BarActions.js.map +1 -1
  64. package/dist/appShell/BarCapsule.js +3 -2
  65. package/dist/appShell/BarCapsule.js.map +1 -1
  66. package/dist/appShell/BarSearch.js +3 -2
  67. package/dist/appShell/BarSearch.js.map +1 -1
  68. package/dist/appShell/HeaderTools.js +3 -2
  69. package/dist/appShell/HeaderTools.js.map +1 -1
  70. package/dist/appShell/MobileTabBar.js +3 -2
  71. package/dist/appShell/MobileTabBar.js.map +1 -1
  72. package/dist/appShell/SettingsMenu.js +3 -2
  73. package/dist/appShell/SettingsMenu.js.map +1 -1
  74. package/dist/appShell/SideMenu.js +3 -2
  75. package/dist/appShell/SideMenu.js.map +1 -1
  76. package/dist/appShell/SideMenuEntry.js +3 -2
  77. package/dist/appShell/SideMenuEntry.js.map +1 -1
  78. package/dist/appShell/SubmenuActionsMenu.js +3 -2
  79. package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
  80. package/dist/appShell/TabBarEditor.js +3 -2
  81. package/dist/appShell/TabBarEditor.js.map +1 -1
  82. package/dist/appShell/TopMenu.js +3 -2
  83. package/dist/appShell/TopMenu.js.map +1 -1
  84. package/dist/appShell/Wordmark.js +3 -2
  85. package/dist/appShell/Wordmark.js.map +1 -1
  86. package/dist/auth/PasswordChecklist.js +3 -2
  87. package/dist/auth/PasswordChecklist.js.map +1 -1
  88. package/dist/calendar/EventCalendar.js +3 -2
  89. package/dist/calendar/EventCalendar.js.map +1 -1
  90. package/dist/calendar/EventDetails.js +3 -2
  91. package/dist/calendar/EventDetails.js.map +1 -1
  92. package/dist/datePickers/DateInput.js +28 -22
  93. package/dist/datePickers/DateInput.js.map +1 -1
  94. package/dist/datePickers/DateTimeInput.js +33 -27
  95. package/dist/datePickers/DateTimeInput.js.map +1 -1
  96. package/dist/datePickers/MonthInput.js +27 -21
  97. package/dist/datePickers/MonthInput.js.map +1 -1
  98. package/dist/datePickers/TimeInput.js +26 -20
  99. package/dist/datePickers/TimeInput.js.map +1 -1
  100. package/dist/datePickers/usePickerField.js +5 -4
  101. package/dist/datePickers/usePickerField.js.map +1 -1
  102. package/dist/downloads/DownloadManager.js +3 -2
  103. package/dist/downloads/DownloadManager.js.map +1 -1
  104. package/dist/feedback/ConfirmDialog.js +3 -2
  105. package/dist/feedback/ConfirmDialog.js.map +1 -1
  106. package/dist/feedback/ModalWaiting.js +3 -2
  107. package/dist/feedback/ModalWaiting.js.map +1 -1
  108. package/dist/feedback/NewBuildNotice.js +3 -2
  109. package/dist/feedback/NewBuildNotice.js.map +1 -1
  110. package/dist/filepond/FileDropzone.js +3 -2
  111. package/dist/filepond/FileDropzone.js.map +1 -1
  112. package/dist/forms/FormProblemAlert.js +3 -2
  113. package/dist/forms/FormProblemAlert.js.map +1 -1
  114. package/dist/forms/SubmitButton.js +7 -2
  115. package/dist/forms/SubmitButton.js.map +1 -1
  116. package/dist/forms/auth/SignInForm.js +3 -2
  117. package/dist/forms/auth/SignInForm.js.map +1 -1
  118. package/dist/forms/fieldRules.js +30 -0
  119. package/dist/forms/fieldRules.js.map +1 -0
  120. package/dist/forms/security/SecondStepForm.js +3 -2
  121. package/dist/forms/security/SecondStepForm.js.map +1 -1
  122. package/dist/forms/security/TwoStepVerificationCard.js +3 -2
  123. package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
  124. package/dist/forms/useValidationText.js +18 -0
  125. package/dist/forms/useValidationText.js.map +1 -0
  126. package/dist/forms/validation.js +35 -31
  127. package/dist/forms/validation.js.map +1 -1
  128. package/dist/forms/validationMessages.js +64 -7
  129. package/dist/forms/validationMessages.js.map +1 -1
  130. package/dist/forms.js +3 -0
  131. package/dist/forms.js.map +1 -1
  132. package/dist/hookForm/FormProblemAlert.js +3 -2
  133. package/dist/hookForm/FormProblemAlert.js.map +1 -1
  134. package/dist/hookForm/SubmitButton.js +7 -2
  135. package/dist/hookForm/SubmitButton.js.map +1 -1
  136. package/dist/inbox/InboxLayout.js +3 -2
  137. package/dist/inbox/InboxLayout.js.map +1 -1
  138. package/dist/inbox/MessageList.js +3 -2
  139. package/dist/inbox/MessageList.js.map +1 -1
  140. package/dist/inbox/MessageView.js +3 -2
  141. package/dist/inbox/MessageView.js.map +1 -1
  142. package/dist/index.js +186 -163
  143. package/dist/index.js.map +1 -1
  144. package/dist/inputs/CatalogInput.js +32 -25
  145. package/dist/inputs/CatalogInput.js.map +1 -1
  146. package/dist/inputs/CheckboxGroupInput.js +8 -5
  147. package/dist/inputs/CheckboxGroupInput.js.map +1 -1
  148. package/dist/inputs/ColorInput.js +7 -4
  149. package/dist/inputs/ColorInput.js.map +1 -1
  150. package/dist/inputs/FieldFrame.js +10 -4
  151. package/dist/inputs/FieldFrame.js.map +1 -1
  152. package/dist/inputs/FormSection.js +1 -1
  153. package/dist/inputs/MaskedInput.js +1 -0
  154. package/dist/inputs/MaskedInput.js.map +1 -1
  155. package/dist/inputs/NumberInput.js +29 -24
  156. package/dist/inputs/NumberInput.js.map +1 -1
  157. package/dist/inputs/RepeatingFields.js +8 -5
  158. package/dist/inputs/RepeatingFields.js.map +1 -1
  159. package/dist/inputs/SelectInput.js +8 -5
  160. package/dist/inputs/SelectInput.js.map +1 -1
  161. package/dist/inputs/TextInput.js +5 -3
  162. package/dist/inputs/TextInput.js.map +1 -1
  163. package/dist/inputs/TransferListInput.js +8 -5
  164. package/dist/inputs/TransferListInput.js.map +1 -1
  165. package/dist/inputs/WizardLayout.js +3 -2
  166. package/dist/inputs/WizardLayout.js.map +1 -1
  167. package/dist/kanban/KanbanBoard.js +3 -2
  168. package/dist/kanban/KanbanBoard.js.map +1 -1
  169. package/dist/legal/CookieNotice.js +3 -2
  170. package/dist/legal/CookieNotice.js.map +1 -1
  171. package/dist/legal/TermsAcceptanceDialog.js +3 -2
  172. package/dist/legal/TermsAcceptanceDialog.js.map +1 -1
  173. package/dist/locales/en.js +24 -0
  174. package/dist/locales/en.js.map +1 -1
  175. package/dist/locales/es.js +24 -0
  176. package/dist/locales/es.js.map +1 -1
  177. package/dist/maps/MapView.js +3 -2
  178. package/dist/maps/MapView.js.map +1 -1
  179. package/dist/mexico/CfdiSummary.js +3 -2
  180. package/dist/mexico/CfdiSummary.js.map +1 -1
  181. package/dist/mexico/EfirmaFields.js +3 -2
  182. package/dist/mexico/EfirmaFields.js.map +1 -1
  183. package/dist/mexico/mexicoIdentifiers.js +5 -0
  184. package/dist/mexico/mexicoIdentifiers.js.map +1 -1
  185. package/dist/mexico/mexicoRules.js +9 -4
  186. package/dist/mexico/mexicoRules.js.map +1 -1
  187. package/dist/mexico.js +4 -2
  188. package/dist/pwa/InstallAppSetting.js +3 -2
  189. package/dist/pwa/InstallAppSetting.js.map +1 -1
  190. package/dist/pwa/InstallInstructionsDialog.js +3 -2
  191. package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
  192. package/dist/pwa/InstallPromptBanner.js +3 -2
  193. package/dist/pwa/InstallPromptBanner.js.map +1 -1
  194. package/dist/react-hook-form.js +3 -0
  195. package/dist/react-hook-form.js.map +1 -1
  196. package/dist/richText/RichTextEditor.js +7 -4
  197. package/dist/richText/RichTextEditor.js.map +1 -1
  198. package/dist/richText/RichTextView.js +3 -2
  199. package/dist/richText/RichTextView.js.map +1 -1
  200. package/dist/security/ActivityLog.js +3 -2
  201. package/dist/security/ActivityLog.js.map +1 -1
  202. package/dist/security/RecoveryCodesDialog.js +3 -2
  203. package/dist/security/RecoveryCodesDialog.js.map +1 -1
  204. package/dist/security/SessionsCard.js +3 -2
  205. package/dist/security/SessionsCard.js.map +1 -1
  206. package/dist/table.js +21 -2
  207. package/dist/table.js.map +1 -1
  208. package/dist/theme/themePieces.js +70 -4
  209. package/dist/theme/themePieces.js.map +1 -1
  210. package/dist/toolkit/ToolkitProvider.js +8 -1
  211. package/dist/toolkit/ToolkitProvider.js.map +1 -1
  212. package/dist/toolkit/browserNavigation.js +19 -4
  213. package/dist/toolkit/browserNavigation.js.map +1 -1
  214. package/dist/toolkit/combineTexts.js +32 -0
  215. package/dist/toolkit/combineTexts.js.map +1 -0
  216. package/dist/toolkit/hashNavigation.js +17 -3
  217. package/dist/toolkit/hashNavigation.js.map +1 -1
  218. package/dist/toolkit/navigationPaths.js +15 -0
  219. package/dist/toolkit/navigationPaths.js.map +1 -1
  220. package/dist/toolkit/pathIndex.js +66 -0
  221. package/dist/toolkit/pathIndex.js.map +1 -0
  222. package/dist/toolkit/toolkitSettings.js +19 -1
  223. package/dist/toolkit/toolkitSettings.js.map +1 -1
  224. package/dist/types/DataTable/AuditTrailDialog.d.ts +6 -17
  225. package/dist/types/DataTable/ColumnFilters/HeaderFilterPopover.d.ts +6 -5
  226. package/dist/types/DataTable/ColumnFilters/MultiSelectColumnFilter.d.ts +6 -9
  227. package/dist/types/DataTable/ColumnFilters/SortableFilterHeader.d.ts +6 -14
  228. package/dist/types/DataTable/EmptyState.d.ts +6 -9
  229. package/dist/types/DataTable/FilterChips.d.ts +6 -11
  230. package/dist/types/DataTable/GoToPage.d.ts +6 -9
  231. package/dist/types/DataTable/ServerTable.d.ts +16 -80
  232. package/dist/types/DataTable/ServerTableFilterDrawer.d.ts +6 -13
  233. package/dist/types/DataTable/StackedCell.d.ts +12 -0
  234. package/dist/types/DataTable/TableCardsView.d.ts +27 -0
  235. package/dist/types/DataTable/columnWidths.d.ts +21 -0
  236. package/dist/types/DataTable/columns.d.ts +111 -0
  237. package/dist/types/DataTable/fixedColumns.d.ts +29 -0
  238. package/dist/types/DataTable/index.d.ts +6 -1
  239. package/dist/types/DataTable/useTableView.d.ts +22 -0
  240. package/dist/types/access/PermissionMatrix.d.ts +6 -10
  241. package/dist/types/account/AccountSecuritySection.d.ts +6 -7
  242. package/dist/types/account/DemoTotpCodeButton.d.ts +6 -5
  243. package/dist/types/account/ProfileScreen.d.ts +6 -18
  244. package/dist/types/account/SignInScreen.d.ts +6 -13
  245. package/dist/types/appShell/AccountMenu.d.ts +6 -11
  246. package/dist/types/appShell/AppLayout.d.ts +3 -40
  247. package/dist/types/appShell/AppearanceSettings.d.ts +6 -12
  248. package/dist/types/appShell/AuthLayout.d.ts +3 -11
  249. package/dist/types/appShell/BarActionButton.d.ts +6 -10
  250. package/dist/types/appShell/BarActions.d.ts +6 -15
  251. package/dist/types/appShell/BarCapsule.d.ts +6 -9
  252. package/dist/types/appShell/BarSearch.d.ts +6 -15
  253. package/dist/types/appShell/HeaderTools.d.ts +6 -16
  254. package/dist/types/appShell/MobileTabBar.d.ts +6 -13
  255. package/dist/types/appShell/SettingsMenu.d.ts +6 -10
  256. package/dist/types/appShell/SideMenu.d.ts +6 -20
  257. package/dist/types/appShell/SideMenuEntry.d.ts +6 -11
  258. package/dist/types/appShell/SubmenuActionsMenu.d.ts +6 -12
  259. package/dist/types/appShell/TabBarEditor.d.ts +6 -9
  260. package/dist/types/appShell/TopMenu.d.ts +6 -5
  261. package/dist/types/appShell/Wordmark.d.ts +6 -7
  262. package/dist/types/auth/PasswordChecklist.d.ts +6 -9
  263. package/dist/types/calendar/EventCalendar.d.ts +6 -23
  264. package/dist/types/calendar/EventDetails.d.ts +6 -10
  265. package/dist/types/datePickers/DateInput.d.ts +7 -22
  266. package/dist/types/datePickers/DateTimeInput.d.ts +7 -27
  267. package/dist/types/datePickers/MonthInput.d.ts +7 -21
  268. package/dist/types/datePickers/TimeInput.d.ts +7 -21
  269. package/dist/types/datePickers/usePickerField.d.ts +5 -1
  270. package/dist/types/downloads/DownloadManager.d.ts +6 -6
  271. package/dist/types/feedback/ConfirmDialog.d.ts +6 -18
  272. package/dist/types/feedback/ModalWaiting.d.ts +6 -9
  273. package/dist/types/feedback/NewBuildNotice.d.ts +6 -10
  274. package/dist/types/filepond/FileDropzone.d.ts +6 -29
  275. package/dist/types/forms/FormProblemAlert.d.ts +6 -5
  276. package/dist/types/forms/SubmitButton.d.ts +6 -6
  277. package/dist/types/forms/auth/SignInForm.d.ts +6 -11
  278. package/dist/types/forms/fieldRules.d.ts +44 -0
  279. package/dist/types/forms/index.d.ts +1 -0
  280. package/dist/types/forms/security/SecondStepForm.d.ts +6 -14
  281. package/dist/types/forms/security/TwoStepVerificationCard.d.ts +6 -21
  282. package/dist/types/forms/useValidationText.d.ts +12 -0
  283. package/dist/types/forms/validation.d.ts +117 -174
  284. package/dist/types/forms/validationMessages.d.ts +54 -6
  285. package/dist/types/forms.d.ts +1 -1
  286. package/dist/types/hookForm/FormProblemAlert.d.ts +6 -5
  287. package/dist/types/hookForm/SubmitButton.d.ts +6 -13
  288. package/dist/types/inbox/InboxLayout.d.ts +6 -17
  289. package/dist/types/inbox/MessageList.d.ts +6 -18
  290. package/dist/types/inbox/MessageView.d.ts +6 -14
  291. package/dist/types/index.d.ts +8 -1
  292. package/dist/types/inputs/CatalogInput.d.ts +7 -24
  293. package/dist/types/inputs/CheckboxGroupInput.d.ts +7 -18
  294. package/dist/types/inputs/ColorInput.d.ts +7 -16
  295. package/dist/types/inputs/FieldFrame.d.ts +6 -10
  296. package/dist/types/inputs/MaskedInput.d.ts +3 -0
  297. package/dist/types/inputs/NumberInput.d.ts +7 -20
  298. package/dist/types/inputs/RepeatingFields.d.ts +7 -28
  299. package/dist/types/inputs/SelectInput.d.ts +7 -20
  300. package/dist/types/inputs/TextInput.d.ts +3 -0
  301. package/dist/types/inputs/TransferListInput.d.ts +7 -20
  302. package/dist/types/inputs/WizardLayout.d.ts +6 -19
  303. package/dist/types/kanban/KanbanBoard.d.ts +6 -25
  304. package/dist/types/legal/CookieNotice.d.ts +6 -16
  305. package/dist/types/legal/TermsAcceptanceDialog.d.ts +6 -18
  306. package/dist/types/locales/en.d.ts +24 -0
  307. package/dist/types/locales/es.d.ts +24 -0
  308. package/dist/types/maps/MapView.d.ts +6 -17
  309. package/dist/types/mexico/CfdiSummary.d.ts +6 -11
  310. package/dist/types/mexico/EfirmaFields.d.ts +6 -16
  311. package/dist/types/mexico/mexicoIdentifiers.d.ts +7 -0
  312. package/dist/types/mexico/mexicoRules.d.ts +19 -3
  313. package/dist/types/mexico.d.ts +2 -2
  314. package/dist/types/pwa/InstallAppSetting.d.ts +6 -6
  315. package/dist/types/pwa/InstallInstructionsDialog.d.ts +6 -9
  316. package/dist/types/pwa/InstallPromptBanner.d.ts +6 -11
  317. package/dist/types/react-hook-form.d.ts +1 -0
  318. package/dist/types/richText/RichTextEditor.d.ts +7 -22
  319. package/dist/types/richText/RichTextView.d.ts +6 -9
  320. package/dist/types/security/ActivityLog.d.ts +6 -9
  321. package/dist/types/security/RecoveryCodesDialog.d.ts +6 -11
  322. package/dist/types/security/SessionsCard.d.ts +6 -11
  323. package/dist/types/table.d.ts +3 -1
  324. package/dist/types/theme/themePieces.d.ts +55 -3
  325. package/dist/types/toolkit/ToolkitProvider.d.ts +13 -1
  326. package/dist/types/toolkit/browserNavigation.d.ts +7 -3
  327. package/dist/types/toolkit/combineTexts.d.ts +6 -0
  328. package/dist/types/toolkit/hashNavigation.d.ts +4 -2
  329. package/dist/types/toolkit/navigationPaths.d.ts +35 -0
  330. package/dist/types/toolkit/pathIndex.d.ts +27 -0
  331. package/dist/types/toolkit/toolkitSettings.d.ts +7 -4
  332. package/dist/types/ui/actions/ActionsMenu.d.ts +9 -11
  333. package/dist/types/ui/actions/CopyButton.d.ts +6 -12
  334. package/dist/types/ui/actions/DownloadMenu.d.ts +6 -29
  335. package/dist/types/ui/actions/SecretField.d.ts +6 -11
  336. package/dist/types/ui/actions/SelectionActions.d.ts +6 -13
  337. package/dist/types/ui/cards/RecordCard.d.ts +6 -31
  338. package/dist/types/ui/cards/RecordCardSkeleton.d.ts +6 -11
  339. package/dist/types/ui/countdown/Countdown.d.ts +6 -15
  340. package/dist/types/ui/documents/PdfViewerDialog.d.ts +6 -13
  341. package/dist/types/ui/filters/DateRangeFilter.d.ts +6 -10
  342. package/dist/types/ui/filters/FilterDrawer.d.ts +6 -17
  343. package/dist/types/ui/filters/PeriodRangeSelector.d.ts +6 -13
  344. package/dist/types/ui/filters/QuickFilters.d.ts +6 -12
  345. package/dist/types/ui/help/HelpButton.d.ts +6 -10
  346. package/dist/types/ui/help/HelpCarouselDialog.d.ts +6 -14
  347. package/dist/types/ui/labels/MarkedText.d.ts +10 -0
  348. package/dist/types/ui/labels/Tag.d.ts +6 -12
  349. package/dist/types/ui/labels/markedTextPieces.d.ts +22 -0
  350. package/dist/types/ui/layout/CollapsibleSection.d.ts +6 -12
  351. package/dist/types/ui/layout/ContentDialog.d.ts +6 -10
  352. package/dist/types/ui/layout/DefinitionList.d.ts +6 -9
  353. package/dist/types/ui/layout/DetailHeader.d.ts +6 -10
  354. package/dist/types/ui/layout/ErrorPage.d.ts +6 -17
  355. package/dist/types/ui/layout/FullPageLoader.d.ts +6 -6
  356. package/dist/types/ui/layout/GlassPanel.d.ts +6 -8
  357. package/dist/types/ui/layout/PageHeader.d.ts +6 -10
  358. package/dist/types/ui/layout/PageHeading.d.ts +6 -11
  359. package/dist/types/ui/layout/ProfileHeader.d.ts +6 -11
  360. package/dist/types/ui/layout/ScrollableRow.d.ts +6 -13
  361. package/dist/types/ui/layout/SectionCard.d.ts +6 -8
  362. package/dist/types/ui/metrics/BarList.d.ts +6 -12
  363. package/dist/types/ui/metrics/CalendarHeatmap.d.ts +6 -19
  364. package/dist/types/ui/metrics/ChartTooltip.d.ts +6 -6
  365. package/dist/types/ui/metrics/ColumnChart.d.ts +6 -25
  366. package/dist/types/ui/metrics/LineChart.d.ts +6 -20
  367. package/dist/types/ui/metrics/MetricCard.d.ts +6 -17
  368. package/dist/types/ui/metrics/TableToggle.d.ts +6 -6
  369. package/dist/types/ui/metrics/chartParts.d.ts +15 -30
  370. package/dist/types/ui/navigation/BackButton.d.ts +6 -9
  371. package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +6 -9
  372. package/dist/types/ui/navigation/FontSizeToggle.d.ts +6 -8
  373. package/dist/types/ui/navigation/LanguageToggle.d.ts +6 -8
  374. package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +6 -7
  375. package/dist/types/ui/navigation/RouteTabs.d.ts +7 -12
  376. package/dist/types/ui/timeline/GroupedTimeline.d.ts +6 -23
  377. package/dist/types/upload/AttachmentsInput.d.ts +11 -1
  378. package/dist/types/upload/FileDropzone.d.ts +6 -21
  379. package/dist/types/upload/FileInput.d.ts +7 -24
  380. package/dist/types/upload/FileUploadInput.d.ts +7 -31
  381. package/dist/types/upload/ImageInput.d.ts +7 -25
  382. package/dist/types/upload/TemplateDownloadButton.d.ts +6 -18
  383. package/dist/ui/actions/ActionsMenu.js +14 -5
  384. package/dist/ui/actions/ActionsMenu.js.map +1 -1
  385. package/dist/ui/actions/CopyButton.js +8 -3
  386. package/dist/ui/actions/CopyButton.js.map +1 -1
  387. package/dist/ui/actions/DownloadMenu.js +3 -2
  388. package/dist/ui/actions/DownloadMenu.js.map +1 -1
  389. package/dist/ui/actions/SecretField.js +8 -3
  390. package/dist/ui/actions/SecretField.js.map +1 -1
  391. package/dist/ui/actions/SelectionActions.js +3 -2
  392. package/dist/ui/actions/SelectionActions.js.map +1 -1
  393. package/dist/ui/cards/RecordCard.js +4 -3
  394. package/dist/ui/cards/RecordCard.js.map +1 -1
  395. package/dist/ui/cards/RecordCardSkeleton.js +8 -3
  396. package/dist/ui/cards/RecordCardSkeleton.js.map +1 -1
  397. package/dist/ui/countdown/Countdown.js +3 -2
  398. package/dist/ui/countdown/Countdown.js.map +1 -1
  399. package/dist/ui/documents/PdfViewerDialog.js +3 -2
  400. package/dist/ui/documents/PdfViewerDialog.js.map +1 -1
  401. package/dist/ui/filters/DateRangeFilter.js +3 -2
  402. package/dist/ui/filters/DateRangeFilter.js.map +1 -1
  403. package/dist/ui/filters/FilterDrawer.js +3 -2
  404. package/dist/ui/filters/FilterDrawer.js.map +1 -1
  405. package/dist/ui/filters/PeriodRangeSelector.js +3 -2
  406. package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
  407. package/dist/ui/filters/QuickFilters.js +3 -2
  408. package/dist/ui/filters/QuickFilters.js.map +1 -1
  409. package/dist/ui/help/HelpButton.js +8 -3
  410. package/dist/ui/help/HelpButton.js.map +1 -1
  411. package/dist/ui/help/HelpCarouselDialog.js +3 -2
  412. package/dist/ui/help/HelpCarouselDialog.js.map +1 -1
  413. package/dist/ui/labels/MarkedText.js +31 -0
  414. package/dist/ui/labels/MarkedText.js.map +1 -0
  415. package/dist/ui/labels/Tag.js +3 -2
  416. package/dist/ui/labels/Tag.js.map +1 -1
  417. package/dist/ui/labels/markedTextPieces.js +64 -0
  418. package/dist/ui/labels/markedTextPieces.js.map +1 -0
  419. package/dist/ui/layout/CollapsibleSection.js +3 -2
  420. package/dist/ui/layout/CollapsibleSection.js.map +1 -1
  421. package/dist/ui/layout/ContentDialog.js +3 -2
  422. package/dist/ui/layout/ContentDialog.js.map +1 -1
  423. package/dist/ui/layout/DefinitionList.js +3 -2
  424. package/dist/ui/layout/DefinitionList.js.map +1 -1
  425. package/dist/ui/layout/DetailHeader.js +3 -2
  426. package/dist/ui/layout/DetailHeader.js.map +1 -1
  427. package/dist/ui/layout/ErrorPage.js +3 -2
  428. package/dist/ui/layout/ErrorPage.js.map +1 -1
  429. package/dist/ui/layout/FullPageLoader.js +3 -2
  430. package/dist/ui/layout/FullPageLoader.js.map +1 -1
  431. package/dist/ui/layout/GlassPanel.js +3 -2
  432. package/dist/ui/layout/GlassPanel.js.map +1 -1
  433. package/dist/ui/layout/PageHeader.js +3 -2
  434. package/dist/ui/layout/PageHeader.js.map +1 -1
  435. package/dist/ui/layout/PageHeading.js +3 -2
  436. package/dist/ui/layout/PageHeading.js.map +1 -1
  437. package/dist/ui/layout/ProfileHeader.js +3 -2
  438. package/dist/ui/layout/ProfileHeader.js.map +1 -1
  439. package/dist/ui/layout/ScrollableRow.js +3 -2
  440. package/dist/ui/layout/ScrollableRow.js.map +1 -1
  441. package/dist/ui/layout/SectionCard.js +3 -2
  442. package/dist/ui/layout/SectionCard.js.map +1 -1
  443. package/dist/ui/metrics/BarList.js +3 -2
  444. package/dist/ui/metrics/BarList.js.map +1 -1
  445. package/dist/ui/metrics/CalendarHeatmap.js +3 -2
  446. package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
  447. package/dist/ui/metrics/ChartTooltip.js +3 -2
  448. package/dist/ui/metrics/ChartTooltip.js.map +1 -1
  449. package/dist/ui/metrics/ColumnChart.js +3 -2
  450. package/dist/ui/metrics/ColumnChart.js.map +1 -1
  451. package/dist/ui/metrics/LineChart.js +3 -2
  452. package/dist/ui/metrics/LineChart.js.map +1 -1
  453. package/dist/ui/metrics/MetricCard.js +3 -2
  454. package/dist/ui/metrics/MetricCard.js.map +1 -1
  455. package/dist/ui/metrics/TableToggle.js +3 -2
  456. package/dist/ui/metrics/TableToggle.js.map +1 -1
  457. package/dist/ui/metrics/chartParts.js +7 -4
  458. package/dist/ui/metrics/chartParts.js.map +1 -1
  459. package/dist/ui/navigation/BackButton.js +7 -2
  460. package/dist/ui/navigation/BackButton.js.map +1 -1
  461. package/dist/ui/navigation/ColorSchemeToggle.js +3 -2
  462. package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
  463. package/dist/ui/navigation/FontSizeToggle.js +3 -2
  464. package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
  465. package/dist/ui/navigation/LanguageToggle.js +3 -2
  466. package/dist/ui/navigation/LanguageToggle.js.map +1 -1
  467. package/dist/ui/navigation/PageBreadcrumbs.js +3 -2
  468. package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
  469. package/dist/ui/navigation/RouteTabs.js +8 -4
  470. package/dist/ui/navigation/RouteTabs.js.map +1 -1
  471. package/dist/ui/timeline/GroupedTimeline.js +3 -2
  472. package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
  473. package/dist/upload/AttachmentsInput.js +9 -6
  474. package/dist/upload/AttachmentsInput.js.map +1 -1
  475. package/dist/upload/FileChip.js +2 -1
  476. package/dist/upload/FileChip.js.map +1 -1
  477. package/dist/upload/FileDropzone.js +5 -4
  478. package/dist/upload/FileDropzone.js.map +1 -1
  479. package/dist/upload/FileInput.js +9 -6
  480. package/dist/upload/FileInput.js.map +1 -1
  481. package/dist/upload/FileUploadInput.js +9 -6
  482. package/dist/upload/FileUploadInput.js.map +1 -1
  483. package/dist/upload/ImageInput.js +8 -5
  484. package/dist/upload/ImageInput.js.map +1 -1
  485. package/dist/upload/TemplateDownloadButton.js +3 -2
  486. package/dist/upload/TemplateDownloadButton.js.map +1 -1
  487. package/package.json +1 -1
  488. package/cli/templates/project/src/app/combineTexts.js.tpl +0 -31
@@ -1,25 +1,4 @@
1
- /**
2
- * @param {object} props
3
- * @param {Object[]} props.groups
4
- * @param {string} props.groups[].key
5
- * @param {string} [props.groups[].title] texto ya traducido; sin título el grupo no pinta encabezado
6
- * @param {string} [props.groups[].badge] insignia junto al título (p. ej. «Intento actual»)
7
- * @param {string} [props.groups[].summary] lo que se lee junto al título del grupo plegado (p. ej. «6 eventos»)
8
- * @param {boolean} [props.groups[].isCollapsible] el título se vuelve un botón que abre y cierra el grupo (necesita
9
- * title)
10
- * @param {boolean} [props.groups[].defaultExpanded] si un grupo plegable arranca abierto (por omisión, sí)
11
- * @param {'highlighted'|'normal'|'muted'} [props.groups[].emphasis]
12
- * @param {Object[]} props.groups[].items
13
- * @param {string} props.groups[].items[].key
14
- * @param {import('react').ElementType} [props.groups[].items[].icon] ícono dentro del punto
15
- * @param {string} [props.groups[].items[].tone] success, warning, error, info, primary o grey
16
- * @param {import('react').ReactNode} props.groups[].items[].title
17
- * @param {string} [props.groups[].items[].timestamp] fecha y hora ya formateadas
18
- * @param {import('react').ReactNode} [props.groups[].items[].details] lo que va abajo del título (chip de resultado, una liga...)
19
- * @param {(groupKey: string, isExpanded: boolean) => void} [props.onGroupToggle] la persona abrió o plegó un grupo (por ejemplo,
20
- * para pedir sus eventos hasta que se abre)
21
- */
22
- export default function GroupedTimeline(props: {
1
+ declare const GroupedTimeline: (props: {
23
2
  groups: {
24
3
  key: string;
25
4
  title?: string;
@@ -38,4 +17,8 @@ export default function GroupedTimeline(props: {
38
17
  }[];
39
18
  }[];
40
19
  onGroupToggle?: (groupKey: string, isExpanded: boolean) => void;
41
- }): import("react").JSX.Element;
20
+ } & {
21
+ slots?: Record<string, import('react').ElementType>;
22
+ slotProps?: Record<string, object | ((partProps: object) => object)>;
23
+ }) => import("react").JSX.Element;
24
+ export default GroupedTimeline;
@@ -25,9 +25,13 @@
25
25
  * plantilla» junto a «Adjuntar»
26
26
  * @param {import('react').ReactNode} [props.actions] botones suyos junto a «Adjuntar»
27
27
  * @param {object} [props.sx]
28
+ * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación
29
+ * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos
28
30
  * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete
31
+ * @param {Record<string, import('react').ElementType>} [props.slots] otro componente en lugar de una parte (root, actions, list…)
32
+ * @param {Record<string, object>} [props.slotProps] props de más para una parte
29
33
  */
30
- export default function AttachmentsInput<T extends File | {
34
+ declare function AttachmentsInputContent<T extends File | {
31
35
  id?: string;
32
36
  name: string;
33
37
  size?: number;
@@ -58,5 +62,11 @@ export default function AttachmentsInput<T extends File | {
58
62
  template?: Parameters<typeof import('./TemplateDownloadButton.js').default>[0];
59
63
  actions?: import('react').ReactNode;
60
64
  sx?: object;
65
+ messages?: Record<string, string | object>;
61
66
  texts?: object;
67
+ slots?: Record<string, import('react').ElementType>;
68
+ slotProps?: Record<string, object>;
62
69
  }): import("react").JSX.Element;
70
+ /** @type {typeof AttachmentsInputContent} */
71
+ declare const AttachmentsInput: typeof AttachmentsInputContent;
72
+ export default AttachmentsInput;
@@ -1,23 +1,4 @@
1
- /**
2
- * @param {object} props
3
- * @param {File|null} [props.value] el archivo elegido
4
- * @param {(file: File|null) => void} props.onChange null al quitarlo
5
- * @param {string|string[]} [props.accept] 'excel' | ['excel', 'pdf'] | '.xlsx,.xls' | 'image/*'
6
- * @param {number|string} [props.maxSize] bytes o '10 MB'
7
- * @param {string} [props.hint] ya traducido; por omisión «Arrastre aquí su archivo»
8
- * @param {string} [props.buttonLabel] ya traducido; por omisión «Elegir archivo»
9
- * @param {boolean} [props.disabled]
10
- * @param {boolean} [props.busy] candado mientras se sube: no se puede soltar, elegir ni quitar
11
- * @param {boolean|{title?: string, text?: string}} [props.busyModal] además bloquea la pantalla mientras busy
12
- * @param {(file: File, reason: string) => void} [props.onReject] reason es uno de FILE_REJECTION; sin él, un aviso
13
- * @param {Parameters<typeof import('./TemplateDownloadButton.js').default>[0]} [props.template] «Descargar la
14
- * plantilla» junto a «Elegir archivo»: {href} de un archivo fijo o {request} al API
15
- * @param {import('react').ReactNode} [props.actions]
16
- * @param {import('react').ReactNode} [props.children]
17
- * @param {object} [props.sx] ajustes del recuadro
18
- * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete
19
- */
20
- export default function FileDropzone(props: {
1
+ declare const FileDropzone: (props: {
21
2
  value?: File | null;
22
3
  onChange: (file: File | null) => void;
23
4
  accept?: string | string[];
@@ -36,4 +17,8 @@ export default function FileDropzone(props: {
36
17
  children?: import('react').ReactNode;
37
18
  sx?: object;
38
19
  texts?: object;
39
- }): import("react").JSX.Element;
20
+ } & {
21
+ slots?: Record<string, import('react').ElementType>;
22
+ slotProps?: Record<string, object | ((partProps: object) => object)>;
23
+ }) => import("react").JSX.Element;
24
+ export default FileDropzone;
@@ -1,26 +1,4 @@
1
- /**
2
- * @param {object} props
3
- * @param {string} [props.name]
4
- * @param {import('react').ReactNode} [props.label] ya traducida
5
- * @param {File|{name: string, size?: number}|null} [props.value] el archivo nuevo o el que ya está guardado
6
- * @param {(file: File|null) => void} props.onChange null al quitarlo
7
- * @param {() => void} [props.onBlur] se llama al elegir o quitar (para que el formulario lo marque como tocado)
8
- * @param {string|string[]} [props.accept] 'excel' | ['pdf', 'image'] | '.xlsx,.xls' | 'image/*'
9
- * @param {number|string} [props.maxSize] bytes o '10 MB'
10
- * @param {string|{key: string, values?: object}} [props.error]
11
- * @param {string} [props.helperText] ya traducida
12
- * @param {string} [props.buttonLabel] ya traducido; por omisión «Elegir archivo»
13
- * @param {string} [props.emptyText] ya traducido; por omisión «Ningún archivo elegido»
14
- * @param {boolean} [props.disabled]
15
- * @param {boolean} [props.busy] candado mientras se sube: no se puede elegir, soltar ni quitar
16
- * @param {(file: File, reason: string) => void} [props.onReject] reason es uno de FILE_REJECTION; sin él, un aviso
17
- * @param {Parameters<typeof import('./TemplateDownloadButton.js').default>[0]} [props.template] «Descargar la
18
- * plantilla» junto al botón
19
- * @param {import('react').ReactNode} [props.actions] botones suyos en el mismo renglón
20
- * @param {object} [props.sx] ajustes del renglón
21
- * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete
22
- */
23
- export default function FileInput(props: {
1
+ declare const FileInput: (props: {
24
2
  name?: string;
25
3
  label?: import('react').ReactNode;
26
4
  value?: File | {
@@ -44,5 +22,10 @@ export default function FileInput(props: {
44
22
  template?: Parameters<typeof import('./TemplateDownloadButton.js').default>[0];
45
23
  actions?: import('react').ReactNode;
46
24
  sx?: object;
25
+ messages?: Record<string, string | object>;
47
26
  texts?: object;
48
- }): import("react").JSX.Element;
27
+ } & {
28
+ slots?: Record<string, import('react').ElementType>;
29
+ slotProps?: Record<string, object | ((partProps: object) => object)>;
30
+ }) => import("react").JSX.Element;
31
+ export default FileInput;
@@ -6,36 +6,7 @@ export declare const FILE_UPLOAD_STATUS: Readonly<{
6
6
  uploaded: "uploaded";
7
7
  failed: "failed";
8
8
  }>;
9
- /**
10
- * @param {object} props
11
- * @param {string} [props.name]
12
- * @param {import('react').ReactNode} [props.label] ya traducida: el nombre del documento; sin ella, el renglón va solo
13
- * @param {string|null} [props.value] lo que el servidor dio para reconocer el archivo subido ('' o null = ninguno)
14
- * @param {(value: string) => void} props.onChange recibe el id al terminar de subir, '' al quitarlo o mientras sube otro
15
- * @param {() => void} [props.onBlur] se llama al elegir o quitar (para que el formulario lo marque como tocado)
16
- * @param {(file: File, options: {signal: AbortSignal, idempotencyKey: string, onUploadProgress: (transfer: {loaded: number, total: number, rate?: number, estimated?: number}) => void}) => Promise<any>} props.upload
17
- * sube el archivo (con uploadWithProgress, axios o el cliente del proyecto) y regresa lo que conteste el servidor
18
- * @param {(result: any) => string} [props.idOf] de la respuesta, lo que se guarda en el formulario; por omisión result.id
19
- * @param {{name: string, size?: number}|null} [props.uploadedFile] el que ya estaba subido, para enseñar su nombre al editar
20
- * @param {(value: string, transferOptions: object) => Promise<{blob: Blob, fileName: string}>} [props.download] baja el
21
- * que ya subió (pasa por el panel de descargas); sin él no sale el ícono
22
- * @param {string|string[]} [props.accept] 'pdf' | ['pdf', 'image'] | '.xlsx,.xls' | 'image/*'
23
- * @param {number|string} [props.maxSize] bytes o '10 MB'
24
- * @param {string} [props.limitsText] ya traducido: qué acepta, en palabras («PDF o foto, hasta 5 MB»); sale al pasar sobre
25
- * el botón. Por omisión solo el peso máximo
26
- * @param {string|{key: string, values?: object}} [props.error]
27
- * @param {string} [props.helperText] ya traducida
28
- * @param {boolean} [props.disabled]
29
- * @param {import('react').ReactNode} [props.actions] lo del negocio junto al estado (Aprobado, Falta información)
30
- * @param {(result: any) => void} [props.onUploaded] terminó de subir (p. ej. para enseñar el folio de la respuesta)
31
- * @param {(error: unknown) => void} [props.onUploadFailed] no se pudo subir (el motivo ya sale abajo)
32
- * @param {() => void} [props.onCancel] la persona canceló a media subida
33
- * @param {() => void} [props.onRemove] la persona quitó el archivo
34
- * @param {(status: string) => void} [props.onStatusChange] uno de FILE_UPLOAD_STATUS, cada vez que cambia
35
- * @param {object} [props.sx] ajustes del renglón
36
- * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete
37
- */
38
- export default function FileUploadInput(props: {
9
+ declare const FileUploadInput: (props: {
39
10
  name?: string;
40
11
  label?: import('react').ReactNode;
41
12
  value?: string | null;
@@ -76,5 +47,10 @@ export default function FileUploadInput(props: {
76
47
  onRemove?: () => void;
77
48
  onStatusChange?: (status: string) => void;
78
49
  sx?: object;
50
+ messages?: Record<string, string | object>;
79
51
  texts?: object;
80
- }): import("react").JSX.Element;
52
+ } & {
53
+ slots?: Record<string, import('react').ElementType>;
54
+ slotProps?: Record<string, object | ((partProps: object) => object)>;
55
+ }) => import("react").JSX.Element;
56
+ export default FileUploadInput;
@@ -3,30 +3,7 @@ export declare const IMAGE_SHAPE: Readonly<{
3
3
  circle: "circle";
4
4
  rounded: "rounded";
5
5
  }>;
6
- /**
7
- * @param {object} props
8
- * @param {string} [props.name]
9
- * @param {import('react').ReactNode} [props.label] ya traducida
10
- * @param {File|string|null} [props.value] la imagen nueva, la dirección de la que ya está guardada o null
11
- * @param {(file: File|null) => void} props.onChange null al quitarla
12
- * @param {() => void} [props.onBlur] se llama al elegir o quitar (para que el formulario lo marque como tocado)
13
- * @param {'circle'|'rounded'} [props.shape] IMAGE_SHAPE; por omisión, círculo
14
- * @param {number} [props.size] el lado de la vista previa en px; por omisión 96
15
- * @param {string} [props.alt] ya traducido: qué se ve en la imagen (por omisión, la etiqueta)
16
- * @param {import('react').ReactNode} [props.placeholder] lo que se ve sin imagen; por omisión, un ícono
17
- * @param {string|string[]} [props.accept] por omisión, cualquier imagen
18
- * @param {number|string} [props.maxSize] bytes o '2 MB'
19
- * @param {string|{key: string, values?: object}} [props.error]
20
- * @param {string} [props.helperText] ya traducida (p. ej. «JPG o PNG, cuadrada, hasta 2 MB»)
21
- * @param {string} [props.chooseLabel] ya traducido; por omisión «Elegir imagen» (o «Cambiar la imagen» si ya hay una)
22
- * @param {string} [props.removeLabel] ya traducido; por omisión «Quitar la imagen»
23
- * @param {boolean} [props.disabled]
24
- * @param {boolean} [props.busy] candado mientras se sube
25
- * @param {(file: File, reason: string) => void} [props.onReject] reason es uno de FILE_REJECTION; sin él, un aviso
26
- * @param {object} [props.sx]
27
- * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete
28
- */
29
- export default function ImageInput(props: {
6
+ declare const ImageInput: (props: {
30
7
  name?: string;
31
8
  label?: import('react').ReactNode;
32
9
  value?: File | string | null;
@@ -49,5 +26,10 @@ export default function ImageInput(props: {
49
26
  busy?: boolean;
50
27
  onReject?: (file: File, reason: string) => void;
51
28
  sx?: object;
29
+ messages?: Record<string, string | object>;
52
30
  texts?: object;
53
- }): import("react").JSX.Element;
31
+ } & {
32
+ slots?: Record<string, import('react').ElementType>;
33
+ slotProps?: Record<string, object | ((partProps: object) => object)>;
34
+ }) => import("react").JSX.Element;
35
+ export default ImageInput;
@@ -1,20 +1,4 @@
1
- /**
2
- * @param {object} props
3
- * @param {string} [props.href] un archivo fijo; se baja con un enlace
4
- * @param {string} [props.fileName] con href: con qué nombre se guarda (por omisión, el del archivo)
5
- * @param {(transferOptions: {signal: AbortSignal, onDownloadProgress: (progress: {loaded: number, total?: number|null}) => void}) => Promise<{blob: Blob, fileName: string}>} [props.request]
6
- * lo pide al API y va al panel de descargas (startDownload)
7
- * @param {string} [props.format] con request: el tipo de archivo, para su ícono en el panel (xlsx, csv…)
8
- * @param {string} [props.label] ya traducido; por omisión «Descargar la plantilla»
9
- * @param {() => void} [props.onDownload] al empezar la descarga (para medir cuántos la bajan, por ejemplo)
10
- * @param {'text'|'outlined'|'contained'} [props.variant]
11
- * @param {'small'|'medium'|'large'} [props.size]
12
- * @param {boolean} [props.disabled]
13
- * @param {import('react').ReactNode} [props.startIcon] por omisión, la flecha de descarga
14
- * @param {object} [props.sx]
15
- * @param {object} [props.texts] los textos que cambian, con la forma de `common`
16
- */
17
- export default function TemplateDownloadButton(props: {
1
+ declare const TemplateDownloadButton: (props: {
18
2
  href?: string;
19
3
  fileName?: string;
20
4
  request?: (transferOptions: {
@@ -36,4 +20,8 @@ export default function TemplateDownloadButton(props: {
36
20
  startIcon?: import('react').ReactNode;
37
21
  sx?: object;
38
22
  texts?: object;
39
- }): import("react").JSX.Element;
23
+ } & {
24
+ slots?: Record<string, import('react').ElementType>;
25
+ slotProps?: Record<string, object | ((partProps: object) => object)>;
26
+ }) => import("react").JSX.Element;
27
+ export default TemplateDownloadButton;
@@ -12,7 +12,8 @@ import Tooltip from "@mui/material/Tooltip";
12
12
  import ChevronLeftRoundedIcon from "@mui/icons-material/ChevronLeftRounded";
13
13
  import ChevronRightRoundedIcon from "@mui/icons-material/ChevronRightRounded";
14
14
  import MoreHorizRoundedIcon from "@mui/icons-material/MoreHorizRounded";
15
- import { piecePart, usePieceProps } from "../../theme/themePieces.js";
15
+ import { piecePart, withPieceSlots, usePieceProps } from "../../theme/themePieces.js";
16
+ import { useToolkitNavigation } from "../../toolkit/toolkitContext.js";
16
17
  import { useToolkitTranslation } from "../../toolkit/useToolkitTranslation.js";
17
18
  import { warnUnknownProps } from "../../toolkit/unknownProps.js";
18
19
  const ACTIONS_MENU_ROW = Object.freeze({ section: "section", divider: "divider" });
@@ -32,10 +33,11 @@ function levelOf(actions, path) {
32
33
  }
33
34
  return { items, parents };
34
35
  }
35
- function ActionsMenu(props) {
36
+ function ActionsMenuContent(props) {
36
37
  const { label, actions, icon, size = "small", texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
37
38
  warnUnknownProps(THEME_NAME, unknownProps);
38
39
  const { t } = useToolkitTranslation("common", texts);
40
+ const { Link } = useToolkitNavigation();
39
41
  const [anchor, setAnchor] = useState(null);
40
42
  const [path, setPath] = useState([]);
41
43
  const listRef = useRef(null);
@@ -99,11 +101,17 @@ function ActionsMenu(props) {
99
101
  return /* @__PURE__ */ jsx("li", { children: item.render({ close }) }, item.key);
100
102
  }
101
103
  const hasChildren = Boolean(item.children?.length);
104
+ let destinationProps = {};
105
+ if (item.to) {
106
+ destinationProps = { component: Link, to: item.to, ...item.replace && { replace: true } };
107
+ } else if (item.href) {
108
+ destinationProps = { component: "a", href: item.href, download: item.download };
109
+ }
102
110
  return /* @__PURE__ */ jsxs(
103
111
  ActionsItem,
104
112
  {
105
113
  disabled: item.disabled,
106
- ...item.href && { component: "a", href: item.href, download: item.download },
114
+ ...destinationProps,
107
115
  "aria-haspopup": hasChildren ? "menu" : void 0,
108
116
  onKeyDown: (event) => {
109
117
  if (hasChildren && event.key === "ArrowRight") {
@@ -111,13 +119,13 @@ function ActionsMenu(props) {
111
119
  setPath((current) => [...current, item.key]);
112
120
  }
113
121
  },
114
- onClick: () => {
122
+ onClick: (event) => {
115
123
  if (hasChildren) {
116
124
  setPath((current) => [...current, item.key]);
117
125
  return;
118
126
  }
119
127
  close();
120
- item.onClick?.();
128
+ item.onClick?.(event);
121
129
  },
122
130
  ownSx: item.color ? { color: `${item.color}.main` } : void 0,
123
131
  children: [
@@ -134,6 +142,7 @@ function ActionsMenu(props) {
134
142
  )
135
143
  ] });
136
144
  }
145
+ const ActionsMenu = withPieceSlots(ActionsMenuContent, THEME_NAME);
137
146
  export {
138
147
  ACTIONS_MENU_ROW,
139
148
  ActionsMenu as default
@@ -1 +1 @@
1
- {"version":3,"file":"ActionsMenu.js","sources":["../../../src/ui/actions/ActionsMenu.jsx"],"sourcesContent":["// Un botón «⋯» con un menú de acciones: el de cada tarjeta del tablero, el de cada columna, el de cada mensaje de la bandeja,\n// el de cada tarjeta de registro. Las acciones las da la pantalla (label ya traducido, ícono, color, apagada); sin acciones\n// no se pinta nada.\n//\n// <ActionsMenu label=\"Acciones de «Junta de cierre»\"\n// actions={[{key: 'delete', label: 'Borrar', icon: <DeleteOutlineIcon fontSize=\"small\" />, color: 'error', onClick: remove}]} />\n//\n// Tan flexible como un menú de sistema (cada renglón es uno de estos):\n// {key, label, icon?, description?, color?, disabled?, onClick} una acción\n// {key, label, href, download?} una liga (bajar un documento, abrir otra página)\n// {key, label, children: [...]} un submenú: se abre DENTRO del mismo menú, con «‹ Regresar»\n// arriba (igual en el teléfono); también con → y ←\n// {type: 'section', key, label} un título de sección\n// {type: 'divider', key} una línea\n// {key, render: ({close}) => …} un renglón propio (abre su ventana y cierra el menú)\n//\n// El clic no llega a lo de abajo: no levanta una tarjeta que se arrastra ni abre el renglón donde vive.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaActionsMenu con defaultProps y\n// styleOverrides de sus partes: item, itemIcon.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useRef, useState} from 'react';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport ListSubheader from '@mui/material/ListSubheader';\nimport Menu from '@mui/material/Menu';\nimport MenuItem from '@mui/material/MenuItem';\nimport Tooltip from '@mui/material/Tooltip';\nimport ChevronLeftRoundedIcon from '@mui/icons-material/ChevronLeftRounded';\nimport ChevronRightRoundedIcon from '@mui/icons-material/ChevronRightRounded';\nimport MoreHorizRoundedIcon from '@mui/icons-material/MoreHorizRounded';\n\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/** Los renglones que no son acciones. */\nexport const ACTIONS_MENU_ROW = Object.freeze({section: 'section', divider: 'divider'});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaActionsMenu)\nconst THEME_NAME = 'CalcitaActionsMenu';\nconst ActionsItem = piecePart(THEME_NAME, 'Item', MenuItem);\nconst ActionsItemIcon = piecePart(THEME_NAME, 'ItemIcon', ListItemIcon);\n\n/**\n * Los renglones del nivel abierto y sus títulos, siguiendo las llaves de los submenús abiertos.\n *\n * @param {object[]} actions\n * @param {string[]} path las llaves de los submenús abiertos, del primero al último\n * @returns {{items: object[], parents: object[]}}\n */\nfunction levelOf(actions, path) {\n const parents = [];\n let items = actions;\n for (const key of path) {\n const parent = items.find((item) => item.key === key);\n if (!parent?.children) {\n break;\n }\n parents.push(parent);\n items = parent.children;\n }\n return {items, parents};\n}\n\n/**\n * @param {object} props\n * @param {string} props.label el nombre del botón (lector de pantalla y su tooltip), ya traducido\n * @param {Array<{key: string, type?: string, label?: string, icon?: import('react').ReactNode, description?: string, color?: string, disabled?: boolean, onClick?: () => void, href?: string, download?: string|boolean, children?: object[], render?: (helpers: {close: () => void}) => import('react').ReactNode}>} [props.actions]\n * @param {import('react').ReactNode} [props.icon] otro ícono para el botón (por omisión «⋯»)\n * @param {'small'|'medium'} [props.size]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function ActionsMenu(props) {\n // lo que el proyecto puso en su tema (components.CalcitaActionsMenu.defaultProps) y encima lo que llega aquí\n const {label, actions, icon, size = 'small', texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const [anchor, setAnchor] = useState(null);\n // los submenús abiertos (llaves), del primero al último\n const [path, setPath] = useState([]);\n const listRef = useRef(null);\n const {items, parents} = levelOf(actions ?? [], path);\n\n // al entrar o salir de un submenú, el foco va a su primer renglón (con el teclado se sigue sin el ratón)\n useEffect(() => {\n if (anchor) {\n listRef.current?.querySelector('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')?.focus();\n }\n }, [path, anchor]);\n\n if (!actions?.length) {\n return null;\n }\n const close = () => {\n setAnchor(null);\n setPath([]);\n };\n const goBack = () => setPath((current) => current.slice(0, -1));\n\n return (\n <>\n <Tooltip title={label}>\n <IconButton size={size} aria-label={label} aria-haspopup=\"menu\"\n onClick={(event) => {\n event.stopPropagation();\n setAnchor(event.currentTarget);\n }}>\n {icon ?? <MoreHorizRoundedIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n <Menu anchorEl={anchor} open={Boolean(anchor)} onClose={close} onClick={(event) => event.stopPropagation()}\n slotProps={{list: {ref: listRef, onKeyDown: (event) => {\n if (event.key === 'ArrowLeft' && path.length > 0) {\n event.preventDefault();\n goBack();\n }\n }}}}>\n {parents.length > 0 && [\n <ActionsItem key=\"__back\" onClick={goBack} ownSx={{fontWeight: 600}}>\n <ActionsItemIcon><ChevronLeftRoundedIcon fontSize=\"small\" /></ActionsItemIcon>\n <ListItemText primary={parents.at(-1).label} secondary={t('actionsMenu.back')} />\n </ActionsItem>,\n <Divider key=\"__back-divider\" />,\n ]}\n {items.map((item) => {\n if (item.type === ACTIONS_MENU_ROW.divider) {\n return <Divider key={item.key} />;\n }\n if (item.type === ACTIONS_MENU_ROW.section) {\n return <ListSubheader key={item.key} sx={{lineHeight: 2.5, bgcolor: 'transparent'}}>{item.label}</ListSubheader>;\n }\n if (item.render) {\n return <li key={item.key}>{item.render({close})}</li>;\n }\n const hasChildren = Boolean(item.children?.length);\n return (\n <ActionsItem\n key={item.key}\n disabled={item.disabled}\n {...(item.href && {component: 'a', href: item.href, download: item.download})}\n aria-haspopup={hasChildren ? 'menu' : undefined}\n onKeyDown={(event) => {\n if (hasChildren && event.key === 'ArrowRight') {\n event.preventDefault();\n setPath((current) => [...current, item.key]);\n }\n }}\n onClick={() => {\n if (hasChildren) {\n setPath((current) => [...current, item.key]);\n return;\n }\n close();\n item.onClick?.();\n }}\n ownSx={item.color ? {color: `${item.color}.main`} : undefined}\n >\n {item.icon && <ActionsItemIcon ownSx={item.color ? {color: 'inherit'} : undefined}>{item.icon}</ActionsItemIcon>}\n <ListItemText primary={item.label} secondary={item.description} />\n {hasChildren && <ChevronRightRoundedIcon fontSize=\"small\" sx={{ml: 2, color: 'text.secondary'}} />}\n </ActionsItem>\n );\n })}\n </Menu>\n </>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ActionsMenu.js","sources":["../../../src/ui/actions/ActionsMenu.jsx"],"sourcesContent":["// Un botón «⋯» con un menú de acciones: el de cada tarjeta del tablero, el de cada columna, el de cada mensaje de la bandeja,\n// el de cada tarjeta de registro. Las acciones las da la pantalla (label ya traducido, ícono, color, apagada); sin acciones\n// no se pinta nada.\n//\n// <ActionsMenu label=\"Acciones de «Junta de cierre»\"\n// actions={[{key: 'delete', label: 'Borrar', icon: <DeleteOutlineIcon fontSize=\"small\" />, color: 'error', onClick: remove}]} />\n//\n// Tan flexible como un menú de sistema (cada renglón es uno de estos):\n// {key, label, icon?, description?, color?, disabled?, onClick} una acción; onClick recibe el evento del clic\n// {key, label, to, replace?} una pantalla de la app, con la navegación del proyecto\n// (react-router, Next o la del navegador): el clic normal\n// navega sin recargar y Cmd/Ctrl+clic o el botón de en\n// medio la abren en otra pestaña, como cualquier liga\n// {key, label, href, download?} una liga de afuera (bajar un documento, otro sistema)\n// {key, label, children: [...]} un submenú: se abre DENTRO del mismo menú, con «‹ Regresar»\n// arriba (igual en el teléfono); también con → y ←\n// {type: 'section', key, label} un título de sección\n// {type: 'divider', key} una línea\n// {key, render: ({close}) => …} un renglón propio (abre su ventana y cierra el menú)\n//\n// El clic no llega a lo de abajo: no levanta una tarjeta que se arrastra ni abre el renglón donde vive.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaActionsMenu con defaultProps y\n// styleOverrides de sus partes: item, itemIcon.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useRef, useState} from 'react';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport ListSubheader from '@mui/material/ListSubheader';\nimport Menu from '@mui/material/Menu';\nimport MenuItem from '@mui/material/MenuItem';\nimport Tooltip from '@mui/material/Tooltip';\nimport ChevronLeftRoundedIcon from '@mui/icons-material/ChevronLeftRounded';\nimport ChevronRightRoundedIcon from '@mui/icons-material/ChevronRightRounded';\nimport MoreHorizRoundedIcon from '@mui/icons-material/MoreHorizRounded';\n\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/** Los renglones que no son acciones. */\nexport const ACTIONS_MENU_ROW = Object.freeze({section: 'section', divider: 'divider'});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaActionsMenu)\nconst THEME_NAME = 'CalcitaActionsMenu';\nconst ActionsItem = piecePart(THEME_NAME, 'Item', MenuItem);\nconst ActionsItemIcon = piecePart(THEME_NAME, 'ItemIcon', ListItemIcon);\n\n/**\n * Los renglones del nivel abierto y sus títulos, siguiendo las llaves de los submenús abiertos.\n *\n * @param {object[]} actions\n * @param {string[]} path las llaves de los submenús abiertos, del primero al último\n * @returns {{items: object[], parents: object[]}}\n */\nfunction levelOf(actions, path) {\n const parents = [];\n let items = actions;\n for (const key of path) {\n const parent = items.find((item) => item.key === key);\n if (!parent?.children) {\n break;\n }\n parents.push(parent);\n items = parent.children;\n }\n return {items, parents};\n}\n\n/**\n * @param {object} props\n * @param {string} props.label el nombre del botón (lector de pantalla y su tooltip), ya traducido\n * @param {Array<{key: string, type?: string, label?: string, icon?: import('react').ReactNode, description?: string, color?: string, disabled?: boolean, onClick?: (event: import('react').MouseEvent<HTMLElement>) => void, to?: string, replace?: boolean, href?: string, download?: string|boolean, children?: object[], render?: (helpers: {close: () => void}) => import('react').ReactNode}>} [props.actions]\n * @param {import('react').ReactNode} [props.icon] otro ícono para el botón (por omisión «⋯»)\n * @param {'small'|'medium'} [props.size]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction ActionsMenuContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaActionsMenu.defaultProps) y encima lo que llega aquí\n const {label, actions, icon, size = 'small', texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // las pantallas de la app (to) van con el enlace de la navegación del proyecto: así el clic normal no recarga la app\n const {Link} = useToolkitNavigation();\n const [anchor, setAnchor] = useState(null);\n // los submenús abiertos (llaves), del primero al último\n const [path, setPath] = useState([]);\n const listRef = useRef(null);\n const {items, parents} = levelOf(actions ?? [], path);\n\n // al entrar o salir de un submenú, el foco va a su primer renglón (con el teclado se sigue sin el ratón)\n useEffect(() => {\n if (anchor) {\n listRef.current?.querySelector('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')?.focus();\n }\n }, [path, anchor]);\n\n if (!actions?.length) {\n return null;\n }\n const close = () => {\n setAnchor(null);\n setPath([]);\n };\n const goBack = () => setPath((current) => current.slice(0, -1));\n\n return (\n <>\n <Tooltip title={label}>\n <IconButton size={size} aria-label={label} aria-haspopup=\"menu\"\n onClick={(event) => {\n event.stopPropagation();\n setAnchor(event.currentTarget);\n }}>\n {icon ?? <MoreHorizRoundedIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n <Menu anchorEl={anchor} open={Boolean(anchor)} onClose={close} onClick={(event) => event.stopPropagation()}\n slotProps={{list: {ref: listRef, onKeyDown: (event) => {\n if (event.key === 'ArrowLeft' && path.length > 0) {\n event.preventDefault();\n goBack();\n }\n }}}}>\n {parents.length > 0 && [\n <ActionsItem key=\"__back\" onClick={goBack} ownSx={{fontWeight: 600}}>\n <ActionsItemIcon><ChevronLeftRoundedIcon fontSize=\"small\" /></ActionsItemIcon>\n <ListItemText primary={parents.at(-1).label} secondary={t('actionsMenu.back')} />\n </ActionsItem>,\n <Divider key=\"__back-divider\" />,\n ]}\n {items.map((item) => {\n if (item.type === ACTIONS_MENU_ROW.divider) {\n return <Divider key={item.key} />;\n }\n if (item.type === ACTIONS_MENU_ROW.section) {\n return <ListSubheader key={item.key} sx={{lineHeight: 2.5, bgcolor: 'transparent'}}>{item.label}</ListSubheader>;\n }\n if (item.render) {\n return <li key={item.key}>{item.render({close})}</li>;\n }\n const hasChildren = Boolean(item.children?.length);\n // a dónde lleva el renglón: una pantalla de la app (to), una liga de afuera (href) o nada (una acción)\n let destinationProps = {};\n if (item.to) {\n destinationProps = {component: Link, to: item.to, ...(item.replace && {replace: true})};\n } else if (item.href) {\n destinationProps = {component: 'a', href: item.href, download: item.download};\n }\n return (\n <ActionsItem\n key={item.key}\n disabled={item.disabled}\n {...destinationProps}\n aria-haspopup={hasChildren ? 'menu' : undefined}\n onKeyDown={(event) => {\n if (hasChildren && event.key === 'ArrowRight') {\n event.preventDefault();\n setPath((current) => [...current, item.key]);\n }\n }}\n onClick={(event) => {\n if (hasChildren) {\n setPath((current) => [...current, item.key]);\n return;\n }\n close();\n // con el evento la pantalla decide (saber si fue con Cmd/Ctrl, o detener una liga propia)\n item.onClick?.(event);\n }}\n ownSx={item.color ? {color: `${item.color}.main`} : undefined}\n >\n {item.icon && <ActionsItemIcon ownSx={item.color ? {color: 'inherit'} : undefined}>{item.icon}</ActionsItemIcon>}\n <ListItemText primary={item.label} secondary={item.description} />\n {hasChildren && <ChevronRightRoundedIcon fontSize=\"small\" sx={{ml: 2, color: 'text.secondary'}} />}\n </ActionsItem>\n );\n })}\n </Menu>\n </>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst ActionsMenu = withPieceSlots(ActionsMenuContent, THEME_NAME);\nexport default ActionsMenu;\n"],"names":[],"mappings":"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"}
@@ -9,13 +9,17 @@ import CopyIcon from "@mui/icons-material/ContentCopyOutlined";
9
9
  import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
10
10
  import { useToolkitTranslation } from "../../toolkit/useToolkitTranslation.js";
11
11
  import { warnUnknownProps } from "../../toolkit/unknownProps.js";
12
+ import { piecePart, withPieceSlots, usePieceProps } from "../../theme/themePieces.js";
13
+ const THEME_NAME = "CalcitaCopyButton";
14
+ const CopyButtonButton = piecePart(THEME_NAME, "Button", IconButton);
12
15
  const FEEDBACK_MILLISECONDS = 2e3;
13
16
  const COPY_STATE = Object.freeze({ idle: "idle", copied: "copied", failed: "failed" });
14
17
  const ICON_BY_STATE = Object.freeze({ [COPY_STATE.idle]: CopyIcon, [COPY_STATE.copied]: CheckIcon, [COPY_STATE.failed]: ErrorOutlineIcon });
15
18
  const COLOR_BY_STATE = Object.freeze({ [COPY_STATE.idle]: void 0, [COPY_STATE.copied]: "success.dark", [COPY_STATE.failed]: "error.dark" });
16
19
  const VISUALLY_HIDDEN_SX = { position: "absolute", width: "1px", height: "1px", overflow: "hidden", clip: "rect(0 0 0 0)", whiteSpace: "nowrap" };
17
- function CopyButton({ value, label, size = "small", onCopied, onCopyFailed, texts, ...unknownProps }) {
18
- warnUnknownProps("CopyButton", unknownProps);
20
+ function CopyButtonContent(props) {
21
+ const { value, label, size = "small", onCopied, onCopyFailed, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
22
+ warnUnknownProps(THEME_NAME, unknownProps);
19
23
  const { t } = useToolkitTranslation("common", texts);
20
24
  const [copyState, setCopyState] = useState(COPY_STATE.idle);
21
25
  const resetTimer = useRef(null);
@@ -40,10 +44,11 @@ function CopyButton({ value, label, size = "small", onCopied, onCopyFailed, text
40
44
  }[copyState];
41
45
  const StateIcon = ICON_BY_STATE[copyState];
42
46
  return /* @__PURE__ */ jsxs(Fragment, { children: [
43
- /* @__PURE__ */ jsx(Tooltip, { title: feedbackText, open: copyState === COPY_STATE.idle ? void 0 : true, placement: "top", children: /* @__PURE__ */ jsx(IconButton, { size, "aria-label": buttonLabel, onClick: copy, sx: { color: COLOR_BY_STATE[copyState] }, children: /* @__PURE__ */ jsx(StateIcon, { fontSize: "inherit" }) }) }),
47
+ /* @__PURE__ */ jsx(Tooltip, { title: feedbackText, open: copyState === COPY_STATE.idle ? void 0 : true, placement: "top", children: /* @__PURE__ */ jsx(CopyButtonButton, { size, "aria-label": buttonLabel, onClick: copy, sx: { color: COLOR_BY_STATE[copyState] }, children: /* @__PURE__ */ jsx(StateIcon, { fontSize: "inherit" }) }) }),
44
48
  /* @__PURE__ */ jsx(Box, { component: "span", role: "status", "aria-live": "polite", sx: VISUALLY_HIDDEN_SX, children: copyState === COPY_STATE.idle ? "" : feedbackText })
45
49
  ] });
46
50
  }
51
+ const CopyButton = withPieceSlots(CopyButtonContent, THEME_NAME);
47
52
  export {
48
53
  CopyButton as default
49
54
  };
@@ -1 +1 @@
1
- {"version":3,"file":"CopyButton.js","sources":["../../../src/ui/actions/CopyButton.jsx"],"sourcesContent":["// Botón para copiar al portapapeles: un ícono que pone el texto y lo confirma ahí mismo («Copiado» un par de segundos, con la\n// palomita). Va donde copiar a mano cuesta trabajo: un folio, un texto largo que en pantalla va cortado, un renglón entero\n// (con tableRowTextOf: separado por tabuladores, al pegarlo en Excel cada dato cae en su celda).\n//\n// Si el navegador no deja copiar (una página en http, dentro de un iframe, sin permiso), el botón lo dice en rojo en lugar\n// de fingir que copió, y avisa con onCopyFailed. La confirmación también se anuncia a los lectores de pantalla (el globo no\n// siempre se anuncia).\n//\n// value puede ser una función: se llama al picar (arma el renglón solo si de verdad se copia).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useRef, useState} from 'react';\nimport Box from '@mui/material/Box';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport CheckIcon from '@mui/icons-material/CheckRounded';\nimport CopyIcon from '@mui/icons-material/ContentCopyOutlined';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';\n\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// cuánto se queda la confirmación (copiado o no se pudo) antes de regresar al ícono de copiar\nconst FEEDBACK_MILLISECONDS = 2000;\n// en qué va el botón: listo, copiado o no se pudo\nconst COPY_STATE = Object.freeze({idle: 'idle', copied: 'copied', failed: 'failed'});\nconst ICON_BY_STATE = Object.freeze({[COPY_STATE.idle]: CopyIcon, [COPY_STATE.copied]: CheckIcon, [COPY_STATE.failed]: ErrorOutlineIcon});\nconst COLOR_BY_STATE = Object.freeze({[COPY_STATE.idle]: undefined, [COPY_STATE.copied]: 'success.dark', [COPY_STATE.failed]: 'error.dark'});\n// el aviso para lectores de pantalla, escondido a la vista. OJO: '1px' en texto; en MUI un width: 1 es 100% y el texto\n// escondido ensanchaba la página\nconst VISUALLY_HIDDEN_SX = {position: 'absolute', width: '1px', height: '1px', overflow: 'hidden', clip: 'rect(0 0 0 0)', whiteSpace: 'nowrap'};\n\n/**\n * @param {object} props\n * @param {string|(() => string)} props.value lo que se copia; una función se llama al picar\n * @param {string} [props.label] ya traducido: qué copia («Copiar el folio»); por omisión «Copiar». Es el globo y el nombre\n * del botón para un lector de pantalla\n * @param {'small'|'medium'} [props.size]\n * @param {() => void} [props.onCopied]\n * @param {(error: unknown) => void} [props.onCopyFailed] el navegador no dejó copiar (el botón ya lo dice en rojo)\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function CopyButton({value, label, size = 'small', onCopied, onCopyFailed, texts, ...unknownProps}) {\n warnUnknownProps('CopyButton', unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const [copyState, setCopyState] = useState(COPY_STATE.idle);\n const resetTimer = useRef(null);\n const buttonLabel = label ?? t('form.copy');\n\n // al desmontar no se queda un temporizador vivo\n useEffect(() => () => clearTimeout(resetTimer.current), []);\n\n const copy = async () => {\n clearTimeout(resetTimer.current);\n try {\n await navigator.clipboard.writeText(typeof value === 'function' ? value() : value);\n setCopyState(COPY_STATE.copied);\n onCopied?.();\n } catch (error) {\n setCopyState(COPY_STATE.failed);\n onCopyFailed?.(error);\n }\n resetTimer.current = setTimeout(() => setCopyState(COPY_STATE.idle), FEEDBACK_MILLISECONDS);\n };\n\n const feedbackText = {\n [COPY_STATE.idle]: buttonLabel,\n [COPY_STATE.copied]: t('form.copied'),\n [COPY_STATE.failed]: t('form.copyFailed'),\n }[copyState];\n const StateIcon = ICON_BY_STATE[copyState];\n\n return (\n <>\n {/* la confirmación se queda abierta mientras dura, aunque el cursor ya no esté encima; arriba y no a un lado, para no\n tapar el dato de junto */}\n <Tooltip title={feedbackText} open={copyState === COPY_STATE.idle ? undefined : true} placement=\"top\">\n <IconButton size={size} aria-label={buttonLabel} onClick={copy} sx={{color: COLOR_BY_STATE[copyState]}}>\n <StateIcon fontSize=\"inherit\" />\n </IconButton>\n </Tooltip>\n <Box component=\"span\" role=\"status\" aria-live=\"polite\" sx={VISUALLY_HIDDEN_SX}>\n {copyState === COPY_STATE.idle ? '' : feedbackText}\n </Box>\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAuBA,MAAM,wBAAwB;AAE9B,MAAM,aAAa,OAAO,OAAO,EAAC,MAAM,QAAQ,QAAQ,UAAU,QAAQ,UAAS;AACnF,MAAM,gBAAgB,OAAO,OAAO,EAAC,CAAC,WAAW,IAAI,GAAG,UAAU,CAAC,WAAW,MAAM,GAAG,WAAW,CAAC,WAAW,MAAM,GAAG,kBAAiB;AACxI,MAAM,iBAAiB,OAAO,OAAO,EAAC,CAAC,WAAW,IAAI,GAAG,QAAW,CAAC,WAAW,MAAM,GAAG,gBAAgB,CAAC,WAAW,MAAM,GAAG,cAAa;AAG3I,MAAM,qBAAqB,EAAC,UAAU,YAAY,OAAO,OAAO,QAAQ,OAAO,UAAU,UAAU,MAAM,iBAAiB,YAAY,SAAA;AAYtI,SAAwB,WAAW,EAAC,OAAO,OAAO,OAAO,SAAS,UAAU,cAAc,OAAO,GAAG,gBAAe;AAC/G,mBAAiB,cAAc,YAAY;AAC3C,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,WAAW,IAAI;AAC1D,QAAM,aAAa,OAAO,IAAI;AAC9B,QAAM,cAAc,SAAS,EAAE,WAAW;AAG1C,YAAU,MAAM,MAAM,aAAa,WAAW,OAAO,GAAG,CAAA,CAAE;AAE1D,QAAM,OAAO,YAAY;AACrB,iBAAa,WAAW,OAAO;AAC/B,QAAI;AACA,YAAM,UAAU,UAAU,UAAU,OAAO,UAAU,aAAa,MAAA,IAAU,KAAK;AACjF,mBAAa,WAAW,MAAM;AAC9B,iBAAA;AAAA,IACJ,SAAS,OAAO;AACZ,mBAAa,WAAW,MAAM;AAC9B,qBAAe,KAAK;AAAA,IACxB;AACA,eAAW,UAAU,WAAW,MAAM,aAAa,WAAW,IAAI,GAAG,qBAAqB;AAAA,EAC9F;AAEA,QAAM,eAAe;AAAA,IACjB,CAAC,WAAW,IAAI,GAAG;AAAA,IACnB,CAAC,WAAW,MAAM,GAAG,EAAE,aAAa;AAAA,IACpC,CAAC,WAAW,MAAM,GAAG,EAAE,iBAAiB;AAAA,EAAA,EAC1C,SAAS;AACX,QAAM,YAAY,cAAc,SAAS;AAEzC,SACI,qBAAA,UAAA,EAGI,UAAA;AAAA,IAAA,oBAAC,SAAA,EAAQ,OAAO,cAAc,MAAM,cAAc,WAAW,OAAO,SAAY,MAAM,WAAU,OAC5F,UAAA,oBAAC,cAAW,MAAY,cAAY,aAAa,SAAS,MAAM,IAAI,EAAC,OAAO,eAAe,SAAS,EAAA,GAChG,UAAA,oBAAC,WAAA,EAAU,UAAS,UAAA,CAAU,GAClC,GACJ;AAAA,IACA,oBAAC,KAAA,EAAI,WAAU,QAAO,MAAK,UAAS,aAAU,UAAS,IAAI,oBACtD,UAAA,cAAc,WAAW,OAAO,KAAK,aAAA,CAC1C;AAAA,EAAA,GACJ;AAER;"}
1
+ {"version":3,"file":"CopyButton.js","sources":["../../../src/ui/actions/CopyButton.jsx"],"sourcesContent":["// Botón para copiar al portapapeles: un ícono que pone el texto y lo confirma ahí mismo («Copiado» un par de segundos, con la\n// palomita). Va donde copiar a mano cuesta trabajo: un folio, un texto largo que en pantalla va cortado, un renglón entero\n// (con tableRowTextOf: separado por tabuladores, al pegarlo en Excel cada dato cae en su celda).\n//\n// Si el navegador no deja copiar (una página en http, dentro de un iframe, sin permiso), el botón lo dice en rojo en lugar\n// de fingir que copió, y avisa con onCopyFailed. La confirmación también se anuncia a los lectores de pantalla (el globo no\n// siempre se anuncia).\n//\n// value puede ser una función: se llama al picar (arma el renglón solo si de verdad se copia).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaCopyButton con defaultProps, styleOverrides de\n// sus partes (button) y slots/slotProps para cambiarlas.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useRef, useState} from 'react';\nimport Box from '@mui/material/Box';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport CheckIcon from '@mui/icons-material/CheckRounded';\nimport CopyIcon from '@mui/icons-material/ContentCopyOutlined';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';\n\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.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.CalcitaCopyButton)\nconst THEME_NAME = 'CalcitaCopyButton';\nconst CopyButtonButton = piecePart(THEME_NAME, 'Button', IconButton);\n\n// cuánto se queda la confirmación (copiado o no se pudo) antes de regresar al ícono de copiar\nconst FEEDBACK_MILLISECONDS = 2000;\n// en qué va el botón: listo, copiado o no se pudo\nconst COPY_STATE = Object.freeze({idle: 'idle', copied: 'copied', failed: 'failed'});\nconst ICON_BY_STATE = Object.freeze({[COPY_STATE.idle]: CopyIcon, [COPY_STATE.copied]: CheckIcon, [COPY_STATE.failed]: ErrorOutlineIcon});\nconst COLOR_BY_STATE = Object.freeze({[COPY_STATE.idle]: undefined, [COPY_STATE.copied]: 'success.dark', [COPY_STATE.failed]: 'error.dark'});\n// el aviso para lectores de pantalla, escondido a la vista. OJO: '1px' en texto; en MUI un width: 1 es 100% y el texto\n// escondido ensanchaba la página\nconst VISUALLY_HIDDEN_SX = {position: 'absolute', width: '1px', height: '1px', overflow: 'hidden', clip: 'rect(0 0 0 0)', whiteSpace: 'nowrap'};\n\n/**\n * @param {object} props\n * @param {string|(() => string)} props.value lo que se copia; una función se llama al picar\n * @param {string} [props.label] ya traducido: qué copia («Copiar el folio»); por omisión «Copiar». Es el globo y el nombre\n * del botón para un lector de pantalla\n * @param {'small'|'medium'} [props.size]\n * @param {() => void} [props.onCopied]\n * @param {(error: unknown) => void} [props.onCopyFailed] el navegador no dejó copiar (el botón ya lo dice en rojo)\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction CopyButtonContent(props) {\n const {value, label, size = 'small', onCopied, onCopyFailed, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const [copyState, setCopyState] = useState(COPY_STATE.idle);\n const resetTimer = useRef(null);\n const buttonLabel = label ?? t('form.copy');\n\n // al desmontar no se queda un temporizador vivo\n useEffect(() => () => clearTimeout(resetTimer.current), []);\n\n const copy = async () => {\n clearTimeout(resetTimer.current);\n try {\n await navigator.clipboard.writeText(typeof value === 'function' ? value() : value);\n setCopyState(COPY_STATE.copied);\n onCopied?.();\n } catch (error) {\n setCopyState(COPY_STATE.failed);\n onCopyFailed?.(error);\n }\n resetTimer.current = setTimeout(() => setCopyState(COPY_STATE.idle), FEEDBACK_MILLISECONDS);\n };\n\n const feedbackText = {\n [COPY_STATE.idle]: buttonLabel,\n [COPY_STATE.copied]: t('form.copied'),\n [COPY_STATE.failed]: t('form.copyFailed'),\n }[copyState];\n const StateIcon = ICON_BY_STATE[copyState];\n\n return (\n <>\n {/* la confirmación se queda abierta mientras dura, aunque el cursor ya no esté encima; arriba y no a un lado, para no\n tapar el dato de junto */}\n <Tooltip title={feedbackText} open={copyState === COPY_STATE.idle ? undefined : true} placement=\"top\">\n <CopyButtonButton size={size} aria-label={buttonLabel} onClick={copy} sx={{color: COLOR_BY_STATE[copyState]}}>\n <StateIcon fontSize=\"inherit\" />\n </CopyButtonButton>\n </Tooltip>\n <Box component=\"span\" role=\"status\" aria-live=\"polite\" sx={VISUALLY_HIDDEN_SX}>\n {copyState === COPY_STATE.idle ? '' : feedbackText}\n </Box>\n </>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst CopyButton = withPieceSlots(CopyButtonContent, THEME_NAME);\nexport default CopyButton;\n"],"names":[],"mappings":";;;;;;;;;;;;AA2BA,MAAM,aAAa;AACnB,MAAM,mBAAmB,UAAU,YAAY,UAAU,UAAU;AAGnE,MAAM,wBAAwB;AAE9B,MAAM,aAAa,OAAO,OAAO,EAAC,MAAM,QAAQ,QAAQ,UAAU,QAAQ,UAAS;AACnF,MAAM,gBAAgB,OAAO,OAAO,EAAC,CAAC,WAAW,IAAI,GAAG,UAAU,CAAC,WAAW,MAAM,GAAG,WAAW,CAAC,WAAW,MAAM,GAAG,kBAAiB;AACxI,MAAM,iBAAiB,OAAO,OAAO,EAAC,CAAC,WAAW,IAAI,GAAG,QAAW,CAAC,WAAW,MAAM,GAAG,gBAAgB,CAAC,WAAW,MAAM,GAAG,cAAa;AAG3I,MAAM,qBAAqB,EAAC,UAAU,YAAY,OAAO,OAAO,QAAQ,OAAO,UAAU,UAAU,MAAM,iBAAiB,YAAY,SAAA;AAYtI,SAAS,kBAAkB,OAAO;AAC9B,QAAM,EAAC,OAAO,OAAO,OAAO,SAAS,UAAU,cAAc,OAAO,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AACtH,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,WAAW,IAAI;AAC1D,QAAM,aAAa,OAAO,IAAI;AAC9B,QAAM,cAAc,SAAS,EAAE,WAAW;AAG1C,YAAU,MAAM,MAAM,aAAa,WAAW,OAAO,GAAG,CAAA,CAAE;AAE1D,QAAM,OAAO,YAAY;AACrB,iBAAa,WAAW,OAAO;AAC/B,QAAI;AACA,YAAM,UAAU,UAAU,UAAU,OAAO,UAAU,aAAa,MAAA,IAAU,KAAK;AACjF,mBAAa,WAAW,MAAM;AAC9B,iBAAA;AAAA,IACJ,SAAS,OAAO;AACZ,mBAAa,WAAW,MAAM;AAC9B,qBAAe,KAAK;AAAA,IACxB;AACA,eAAW,UAAU,WAAW,MAAM,aAAa,WAAW,IAAI,GAAG,qBAAqB;AAAA,EAC9F;AAEA,QAAM,eAAe;AAAA,IACjB,CAAC,WAAW,IAAI,GAAG;AAAA,IACnB,CAAC,WAAW,MAAM,GAAG,EAAE,aAAa;AAAA,IACpC,CAAC,WAAW,MAAM,GAAG,EAAE,iBAAiB;AAAA,EAAA,EAC1C,SAAS;AACX,QAAM,YAAY,cAAc,SAAS;AAEzC,SACI,qBAAA,UAAA,EAGI,UAAA;AAAA,IAAA,oBAAC,SAAA,EAAQ,OAAO,cAAc,MAAM,cAAc,WAAW,OAAO,SAAY,MAAM,WAAU,OAC5F,UAAA,oBAAC,oBAAiB,MAAY,cAAY,aAAa,SAAS,MAAM,IAAI,EAAC,OAAO,eAAe,SAAS,EAAA,GACtG,UAAA,oBAAC,WAAA,EAAU,UAAS,UAAA,CAAU,GAClC,GACJ;AAAA,IACA,oBAAC,KAAA,EAAI,WAAU,QAAO,MAAK,UAAS,aAAU,UAAS,IAAI,oBACtD,UAAA,cAAc,WAAW,OAAO,KAAK,aAAA,CAC1C;AAAA,EAAA,GACJ;AAER;AAGA,MAAM,aAAa,eAAe,mBAAmB,UAAU;"}
@@ -16,11 +16,11 @@ import { startDownload } from "../../downloads/downloadQueue.js";
16
16
  import { useFileTypes } from "../../downloads/fileTypes.js";
17
17
  import ConfirmDialog from "../../feedback/ConfirmDialog.js";
18
18
  import { useConfirmAction } from "../../feedback/useConfirmAction.js";
19
- import { piecePart, usePieceProps } from "../../theme/themePieces.js";
19
+ import { piecePart, withPieceSlots, usePieceProps } from "../../theme/themePieces.js";
20
20
  import { warnUnknownProps } from "../../toolkit/unknownProps.js";
21
21
  const THEME_NAME = "CalcitaDownloadMenu";
22
22
  const DownloadButton = piecePart(THEME_NAME, "Button", Button);
23
- function DownloadMenu(props) {
23
+ function DownloadMenuContent(props) {
24
24
  const {
25
25
  formats,
26
26
  download,
@@ -163,6 +163,7 @@ function DownloadMenu(props) {
163
163
  )
164
164
  ] });
165
165
  }
166
+ const DownloadMenu = withPieceSlots(DownloadMenuContent, THEME_NAME);
166
167
  export {
167
168
  DownloadMenu as default
168
169
  };
@@ -1 +1 @@
1
- {"version":3,"file":"DownloadMenu.js","sources":["../../../src/ui/actions/DownloadMenu.jsx"],"sourcesContent":["// \"Descargar ▾\" con los formatos de un reporte: PDF para leer o archivar, Excel o CSV para trabajar.\n//\n// Un solo botón y no tres: en la barra de una pantalla tres botones de descarga compiten con la acción principal.\n// Se acomoda a donde quedó, como BarActionButton: en una cápsula de la barra (las `actions` de PageHeading con cápsulas)\n// es solo el ícono con su nombre en el tooltip, como las demás acciones; antes salía la píldora «Descargar ▾» dentro de\n// la cápsula y se veía una cápsula dentro de otra. En el «⋯» del teléfono es un renglón que abre los formatos.\n// Quien llama pasa QUÉ descargar por formato (download(format, transferOptions) → {blob, fileName}, la forma de\n// un cliente HTTP que descarga). La descarga va al panel de descargas (startDownload, downloads): el diálogo se cierra al\n// confirmar y el avance, el aviso de \"descargado\" y el error se ven allá, mientras la persona sigue trabajando.\n//\n// Regla de tablas: una descarga pasa por un diálogo de confirmación que dice qué se va a bajar (p. ej. que la base\n// completa de clientes tarda unos minutos). Con `confirmation` el formato elegido NO se descarga de inmediato: abre\n// ConfirmDialog (máquina confirmActionMachine) y solo al confirmar se pide el archivo, una sola vez aunque haya doble clic.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDownloadMenu con defaultProps y\n// styleOverrides de sus partes: button.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Button from '@mui/material/Button';\nimport IconButton from '@mui/material/IconButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Menu from '@mui/material/Menu';\nimport MenuItem from '@mui/material/MenuItem';\nimport Tooltip from '@mui/material/Tooltip';\nimport ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';\nimport FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';\n\nimport {BAR_ACTIONS_PLACEMENT, useBarActionsPlacement, useCloseBarActionsMenu} from '@/appShell/barActionsSlot.js';\nimport {startDownload} from '@/downloads/downloadQueue.js';\nimport {useFileTypes} from '@/downloads/fileTypes.js';\nimport ConfirmDialog from '@/feedback/ConfirmDialog.jsx';\nimport {useConfirmAction} from '@/feedback/useConfirmAction.js';\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.CalcitaDownloadMenu)\nconst THEME_NAME = 'CalcitaDownloadMenu';\nconst DownloadButton = piecePart(THEME_NAME, 'Button', Button);\n\n\n/**\n * @param {object} props\n * @param {string[]} props.formats los tipos de archivo, en orden: los de la casa (xlsx, csv, pdf) y los que el proyecto declare\n * en ToolkitProvider fileTypes (zip, xml…)\n * @param {(format: string, transferOptions: {signal: AbortSignal, onDownloadProgress: (progress: {loaded: number, total?: number|null}) => void}) => Promise<{blob: Blob, fileName: string}>} props.download\n * @param {string} [props.label] ya traducido; por defecto \"Descargar\"\n * @param {string} [props.downloadLabel] ya traducido; lo que se ve en el panel de descargas antes de saber el nombre\n * del archivo\n * @param {boolean} [props.disabled]\n * @param {(format: string) => {title: string, description: import('react').ReactNode, confirmLabel?: string}} [props.confirmation]\n * @param {(format: string) => void} [props.onDownloaded] p. ej. volver a pedir la tabla (si la descarga cambia algo en\n * el servidor)\n * @param {(format: string, error: unknown) => void} [props.onFailed] cuando la descarga no se pudo (el panel ya lo dice)\n * @param {(format: string) => void} [props.onCanceled] cuando la persona la canceló desde el panel\n * @param {'button'|'icon'} [props.variant] icon = solo el icono (columna de acciones de una tabla)\n * @param {string} [props.ariaLabel] ya traducido; obligatorio en la variante icon\n * @param {(format: string) => void} [props.onChooseFormat] quien llama se encarga de confirmar y descargar\n * @param {import('react').ElementType} [props.icon] ícono del botón; por defecto el de descarga. Distingue dos descargas en la\n * misma fila\n *\n * IMPORTANTE: hay que pasar `confirmation` u `onChooseFormat`. Sin ninguno de los dos el menú no descarga nada (regla de\n * tablas: toda descarga pasa por confirmación).\n *\n * OJO onChooseFormat: dentro de una celda del DataGrid el diálogo de confirmación NO puede vivir en la celda (el grid\n * virtualiza y vuelve a pintar sus celdas; el diálogo se perdía al elegir el formato). Ahí el menú solo avisa qué formato\n * se eligió y la pantalla abre SU confirmación (useConfirmAction) fuera de la tabla.\n */\nexport default function DownloadMenu(props) {\n // lo que el proyecto puso en su tema (components.CalcitaDownloadMenu.defaultProps) y encima lo que llega aquí\n const {\n formats, download, label, downloadLabel, disabled = false, confirmation, onDownloaded, onFailed, onCanceled, variant = 'button', ariaLabel,\n onChooseFormat, icon: ButtonIcon = FileDownloadOutlinedIcon,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common');\n const fileTypes = useFileTypes();\n // de dónde sale el menú de formatos: del botón, o (desde el «⋯» del teléfono, que se cierra) de donde estaba el renglón\n const [anchorElement, setAnchorElement] = useState(null);\n const [anchorPosition, setAnchorPosition] = useState(null);\n const placement = useBarActionsPlacement();\n const closeMoreMenu = useCloseBarActionsMenu();\n const closeFormats = () => {\n setAnchorElement(null);\n setAnchorPosition(null);\n };\n\n // no se espera a que termine: la descarga sigue en el panel y el diálogo de confirmación se cierra de inmediato\n const runDownload = (format) => {\n startDownload({\n label: downloadLabel ?? label ?? ariaLabel ?? t('actions.download'),\n format,\n request: (transferOptions) => download(format, transferOptions),\n onCompleted: () => onDownloaded?.(format),\n onFailed: (error) => onFailed?.(format, error),\n onCanceled: () => onCanceled?.(format),\n });\n };\n\n const confirmedDownload = useConfirmAction({run: ({subject}) => runDownload(subject.format)});\n\n const chooseFormat = (format) => {\n closeFormats();\n if (onChooseFormat) {\n onChooseFormat(format);\n return;\n }\n if (confirmation) {\n confirmedDownload.open({format});\n return;\n }\n // Regla de tablas: nada se descarga con un solo clic. Sin confirmation ni onChooseFormat es un error de quien\n // llama, no un camino válido: lo decimos en la consola y no descargamos\n console.error('DownloadMenu: falta confirmation u onChooseFormat; toda descarga pasa por un diálogo de confirmación');\n };\n\n const buttonLabel = label ?? t('actions.download');\n const openMenu = (event) => setAnchorElement(event.currentTarget);\n // desde el «⋯»: se cierra ese menú y los formatos salen donde estaba el renglón\n const openFromMoreMenu = (event) => {\n const {bottom, right} = event.currentTarget.getBoundingClientRect();\n closeMoreMenu();\n setAnchorPosition({top: bottom, left: right});\n };\n const isFormatsOpen = Boolean(anchorElement || anchorPosition);\n const confirmationTexts = confirmedDownload.subject ? confirmation?.(confirmedDownload.subject.format) : null;\n\n return (\n <>\n {placement === BAR_ACTIONS_PLACEMENT.menu && (\n <MenuItem disabled={disabled} aria-haspopup=\"menu\" onClick={openFromMoreMenu}>\n <ListItemIcon><ButtonIcon /></ListItemIcon>\n <ListItemText>{buttonLabel}</ListItemText>\n </MenuItem>\n )}\n {placement === BAR_ACTIONS_PLACEMENT.capsule && (\n // en la cápsula, del tamaño y color de las demás acciones (BarActionButton)\n <Tooltip title={buttonLabel} describeChild>\n <span>\n <IconButton color=\"primary\" aria-label={buttonLabel} aria-haspopup=\"menu\" aria-expanded={isFormatsOpen}\n disabled={disabled} onClick={openMenu}>\n <ButtonIcon />\n </IconButton>\n </span>\n </Tooltip>\n )}\n {placement === BAR_ACTIONS_PLACEMENT.inline && (variant === 'icon' ? (\n // describeChild: el nombre accesible ya lo trae el botón; sin esto el Tooltip le pone el mismo aria-label al\n // span y un lector de pantalla (o una prueba) encuentra dos \"botones\" con el mismo nombre\n <Tooltip title={ariaLabel ?? buttonLabel} describeChild>\n {/* el span deja que el tooltip funcione con el botón inhabilitado */}\n <span>\n <IconButton size=\"small\" aria-label={ariaLabel ?? buttonLabel} aria-haspopup=\"menu\"\n disabled={disabled} onClick={openMenu}>\n <ButtonIcon fontSize=\"small\" />\n </IconButton>\n </span>\n </Tooltip>\n ) : (\n <DownloadButton variant=\"outlined\" startIcon={<ButtonIcon />} endIcon={<ArrowDropDownIcon />}\n ownSx={{flexShrink: 0}} disabled={disabled} aria-haspopup=\"menu\" onClick={openMenu}>\n {buttonLabel}\n </DownloadButton>\n ))}\n <Menu open={isFormatsOpen} onClose={closeFormats}\n anchorReference={anchorPosition ? 'anchorPosition' : 'anchorEl'} anchorEl={anchorElement} anchorPosition={anchorPosition ?? undefined}\n anchorOrigin={{vertical: 'bottom', horizontal: 'right'}} transformOrigin={{vertical: 'top', horizontal: 'right'}}>\n {formats.map((format) => {\n const fileType = fileTypes[format];\n const Icon = fileType?.Icon ?? FileDownloadOutlinedIcon;\n return (\n <MenuItem key={format} onClick={() => chooseFormat(format)}>\n <ListItemIcon><Icon fontSize=\"small\" /></ListItemIcon>\n {/* los de la casa con sus textos; los del proyecto con su label y hint (o esas llaves en sus texts) */}\n <ListItemText primary={t(`download.formats.${format}.label`, {defaultValue: fileType?.label ?? format.toUpperCase()})}\n secondary={t(`download.formats.${format}.hint`, {defaultValue: fileType?.hint ?? ''})}\n slotProps={{secondary: {variant: 'caption'}}} />\n </MenuItem>\n );\n })}\n </Menu>\n {confirmation && (\n <ConfirmDialog\n {...confirmedDownload.dialogProps}\n title={confirmationTexts?.title ?? ''}\n description={confirmationTexts?.description}\n confirmLabel={confirmationTexts?.confirmLabel ?? t('actions.download')}\n />\n )}\n </>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DownloadMenu.js","sources":["../../../src/ui/actions/DownloadMenu.jsx"],"sourcesContent":["// \"Descargar ▾\" con los formatos de un reporte: PDF para leer o archivar, Excel o CSV para trabajar.\n//\n// Un solo botón y no tres: en la barra de una pantalla tres botones de descarga compiten con la acción principal.\n// Se acomoda a donde quedó, como BarActionButton: en una cápsula de la barra (las `actions` de PageHeading con cápsulas)\n// es solo el ícono con su nombre en el tooltip, como las demás acciones; antes salía la píldora «Descargar ▾» dentro de\n// la cápsula y se veía una cápsula dentro de otra. En el «⋯» del teléfono es un renglón que abre los formatos.\n// Quien llama pasa QUÉ descargar por formato (download(format, transferOptions) → {blob, fileName}, la forma de\n// un cliente HTTP que descarga). La descarga va al panel de descargas (startDownload, downloads): el diálogo se cierra al\n// confirmar y el avance, el aviso de \"descargado\" y el error se ven allá, mientras la persona sigue trabajando.\n//\n// Regla de tablas: una descarga pasa por un diálogo de confirmación que dice qué se va a bajar (p. ej. que la base\n// completa de clientes tarda unos minutos). Con `confirmation` el formato elegido NO se descarga de inmediato: abre\n// ConfirmDialog (máquina confirmActionMachine) y solo al confirmar se pide el archivo, una sola vez aunque haya doble clic.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDownloadMenu con defaultProps y\n// styleOverrides de sus partes: button.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Button from '@mui/material/Button';\nimport IconButton from '@mui/material/IconButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Menu from '@mui/material/Menu';\nimport MenuItem from '@mui/material/MenuItem';\nimport Tooltip from '@mui/material/Tooltip';\nimport ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';\nimport FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';\n\nimport {BAR_ACTIONS_PLACEMENT, useBarActionsPlacement, useCloseBarActionsMenu} from '@/appShell/barActionsSlot.js';\nimport {startDownload} from '@/downloads/downloadQueue.js';\nimport {useFileTypes} from '@/downloads/fileTypes.js';\nimport ConfirmDialog from '@/feedback/ConfirmDialog.jsx';\nimport {useConfirmAction} from '@/feedback/useConfirmAction.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaDownloadMenu)\nconst THEME_NAME = 'CalcitaDownloadMenu';\nconst DownloadButton = piecePart(THEME_NAME, 'Button', Button);\n\n\n/**\n * @param {object} props\n * @param {string[]} props.formats los tipos de archivo, en orden: los de la casa (xlsx, csv, pdf) y los que el proyecto declare\n * en ToolkitProvider fileTypes (zip, xml…)\n * @param {(format: string, transferOptions: {signal: AbortSignal, onDownloadProgress: (progress: {loaded: number, total?: number|null}) => void}) => Promise<{blob: Blob, fileName: string}>} props.download\n * @param {string} [props.label] ya traducido; por defecto \"Descargar\"\n * @param {string} [props.downloadLabel] ya traducido; lo que se ve en el panel de descargas antes de saber el nombre\n * del archivo\n * @param {boolean} [props.disabled]\n * @param {(format: string) => {title: string, description: import('react').ReactNode, confirmLabel?: string}} [props.confirmation]\n * @param {(format: string) => void} [props.onDownloaded] p. ej. volver a pedir la tabla (si la descarga cambia algo en\n * el servidor)\n * @param {(format: string, error: unknown) => void} [props.onFailed] cuando la descarga no se pudo (el panel ya lo dice)\n * @param {(format: string) => void} [props.onCanceled] cuando la persona la canceló desde el panel\n * @param {'button'|'icon'} [props.variant] icon = solo el icono (columna de acciones de una tabla)\n * @param {string} [props.ariaLabel] ya traducido; obligatorio en la variante icon\n * @param {(format: string) => void} [props.onChooseFormat] quien llama se encarga de confirmar y descargar\n * @param {import('react').ElementType} [props.icon] ícono del botón; por defecto el de descarga. Distingue dos descargas en la\n * misma fila\n *\n * IMPORTANTE: hay que pasar `confirmation` u `onChooseFormat`. Sin ninguno de los dos el menú no descarga nada (regla de\n * tablas: toda descarga pasa por confirmación).\n *\n * OJO onChooseFormat: dentro de una celda del DataGrid el diálogo de confirmación NO puede vivir en la celda (el grid\n * virtualiza y vuelve a pintar sus celdas; el diálogo se perdía al elegir el formato). Ahí el menú solo avisa qué formato\n * se eligió y la pantalla abre SU confirmación (useConfirmAction) fuera de la tabla.\n */\nfunction DownloadMenuContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaDownloadMenu.defaultProps) y encima lo que llega aquí\n const {\n formats, download, label, downloadLabel, disabled = false, confirmation, onDownloaded, onFailed, onCanceled, variant = 'button', ariaLabel,\n onChooseFormat, icon: ButtonIcon = FileDownloadOutlinedIcon,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common');\n const fileTypes = useFileTypes();\n // de dónde sale el menú de formatos: del botón, o (desde el «⋯» del teléfono, que se cierra) de donde estaba el renglón\n const [anchorElement, setAnchorElement] = useState(null);\n const [anchorPosition, setAnchorPosition] = useState(null);\n const placement = useBarActionsPlacement();\n const closeMoreMenu = useCloseBarActionsMenu();\n const closeFormats = () => {\n setAnchorElement(null);\n setAnchorPosition(null);\n };\n\n // no se espera a que termine: la descarga sigue en el panel y el diálogo de confirmación se cierra de inmediato\n const runDownload = (format) => {\n startDownload({\n label: downloadLabel ?? label ?? ariaLabel ?? t('actions.download'),\n format,\n request: (transferOptions) => download(format, transferOptions),\n onCompleted: () => onDownloaded?.(format),\n onFailed: (error) => onFailed?.(format, error),\n onCanceled: () => onCanceled?.(format),\n });\n };\n\n const confirmedDownload = useConfirmAction({run: ({subject}) => runDownload(subject.format)});\n\n const chooseFormat = (format) => {\n closeFormats();\n if (onChooseFormat) {\n onChooseFormat(format);\n return;\n }\n if (confirmation) {\n confirmedDownload.open({format});\n return;\n }\n // Regla de tablas: nada se descarga con un solo clic. Sin confirmation ni onChooseFormat es un error de quien\n // llama, no un camino válido: lo decimos en la consola y no descargamos\n console.error('DownloadMenu: falta confirmation u onChooseFormat; toda descarga pasa por un diálogo de confirmación');\n };\n\n const buttonLabel = label ?? t('actions.download');\n const openMenu = (event) => setAnchorElement(event.currentTarget);\n // desde el «⋯»: se cierra ese menú y los formatos salen donde estaba el renglón\n const openFromMoreMenu = (event) => {\n const {bottom, right} = event.currentTarget.getBoundingClientRect();\n closeMoreMenu();\n setAnchorPosition({top: bottom, left: right});\n };\n const isFormatsOpen = Boolean(anchorElement || anchorPosition);\n const confirmationTexts = confirmedDownload.subject ? confirmation?.(confirmedDownload.subject.format) : null;\n\n return (\n <>\n {placement === BAR_ACTIONS_PLACEMENT.menu && (\n <MenuItem disabled={disabled} aria-haspopup=\"menu\" onClick={openFromMoreMenu}>\n <ListItemIcon><ButtonIcon /></ListItemIcon>\n <ListItemText>{buttonLabel}</ListItemText>\n </MenuItem>\n )}\n {placement === BAR_ACTIONS_PLACEMENT.capsule && (\n // en la cápsula, del tamaño y color de las demás acciones (BarActionButton)\n <Tooltip title={buttonLabel} describeChild>\n <span>\n <IconButton color=\"primary\" aria-label={buttonLabel} aria-haspopup=\"menu\" aria-expanded={isFormatsOpen}\n disabled={disabled} onClick={openMenu}>\n <ButtonIcon />\n </IconButton>\n </span>\n </Tooltip>\n )}\n {placement === BAR_ACTIONS_PLACEMENT.inline && (variant === 'icon' ? (\n // describeChild: el nombre accesible ya lo trae el botón; sin esto el Tooltip le pone el mismo aria-label al\n // span y un lector de pantalla (o una prueba) encuentra dos \"botones\" con el mismo nombre\n <Tooltip title={ariaLabel ?? buttonLabel} describeChild>\n {/* el span deja que el tooltip funcione con el botón inhabilitado */}\n <span>\n <IconButton size=\"small\" aria-label={ariaLabel ?? buttonLabel} aria-haspopup=\"menu\"\n disabled={disabled} onClick={openMenu}>\n <ButtonIcon fontSize=\"small\" />\n </IconButton>\n </span>\n </Tooltip>\n ) : (\n <DownloadButton variant=\"outlined\" startIcon={<ButtonIcon />} endIcon={<ArrowDropDownIcon />}\n ownSx={{flexShrink: 0}} disabled={disabled} aria-haspopup=\"menu\" onClick={openMenu}>\n {buttonLabel}\n </DownloadButton>\n ))}\n <Menu open={isFormatsOpen} onClose={closeFormats}\n anchorReference={anchorPosition ? 'anchorPosition' : 'anchorEl'} anchorEl={anchorElement} anchorPosition={anchorPosition ?? undefined}\n anchorOrigin={{vertical: 'bottom', horizontal: 'right'}} transformOrigin={{vertical: 'top', horizontal: 'right'}}>\n {formats.map((format) => {\n const fileType = fileTypes[format];\n const Icon = fileType?.Icon ?? FileDownloadOutlinedIcon;\n return (\n <MenuItem key={format} onClick={() => chooseFormat(format)}>\n <ListItemIcon><Icon fontSize=\"small\" /></ListItemIcon>\n {/* los de la casa con sus textos; los del proyecto con su label y hint (o esas llaves en sus texts) */}\n <ListItemText primary={t(`download.formats.${format}.label`, {defaultValue: fileType?.label ?? format.toUpperCase()})}\n secondary={t(`download.formats.${format}.hint`, {defaultValue: fileType?.hint ?? ''})}\n slotProps={{secondary: {variant: 'caption'}}} />\n </MenuItem>\n );\n })}\n </Menu>\n {confirmation && (\n <ConfirmDialog\n {...confirmedDownload.dialogProps}\n title={confirmationTexts?.title ?? ''}\n description={confirmationTexts?.description}\n confirmLabel={confirmationTexts?.confirmLabel ?? t('actions.download')}\n />\n )}\n </>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst DownloadMenu = withPieceSlots(DownloadMenuContent, THEME_NAME);\nexport default DownloadMenu;\n"],"names":[],"mappings":"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"}
@@ -12,10 +12,14 @@ import VisibilityOffOutlinedIcon from "@mui/icons-material/VisibilityOffOutlined
12
12
  import VisibilityOutlinedIcon from "@mui/icons-material/VisibilityOutlined";
13
13
  import FieldFrame from "../../inputs/FieldFrame.js";
14
14
  import { warnUnknownProps } from "../../toolkit/unknownProps.js";
15
+ import { piecePart, withPieceSlots, usePieceProps } from "../../theme/themePieces.js";
16
+ const THEME_NAME = "CalcitaSecretField";
17
+ const SecretFieldField = piecePart(THEME_NAME, "Field", TextField);
15
18
  const COPIED_FEEDBACK_MILLISECONDS = 2e3;
16
19
  const MONOSPACE_FONT = "ui-monospace, SFMono-Regular, Menlo, monospace";
17
- function SecretField({ value, label, helperText = " ", onCopied, onRevealChange, texts, ...unknownProps }) {
18
- warnUnknownProps("SecretField", unknownProps);
20
+ function SecretFieldContent(props) {
21
+ const { value, label, helperText = " ", onCopied, onRevealChange, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
22
+ warnUnknownProps(THEME_NAME, unknownProps);
19
23
  const { t } = useToolkitTranslation("common", texts);
20
24
  const generatedId = useId();
21
25
  const inputId = `secret-${generatedId}`;
@@ -37,7 +41,7 @@ function SecretField({ value, label, helperText = " ", onCopied, onRevealChange,
37
41
  }
38
42
  };
39
43
  return /* @__PURE__ */ jsx(FieldFrame, { inputId, label, children: /* @__PURE__ */ jsx(
40
- TextField,
44
+ SecretFieldField,
41
45
  {
42
46
  id: inputId,
43
47
  fullWidth: true,
@@ -57,6 +61,7 @@ function SecretField({ value, label, helperText = " ", onCopied, onRevealChange,
57
61
  }
58
62
  ) });
59
63
  }
64
+ const SecretField = withPieceSlots(SecretFieldContent, THEME_NAME);
60
65
  export {
61
66
  SecretField as default
62
67
  };