@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
@@ -15,9 +15,9 @@ import AddRoundedIcon from "@mui/icons-material/AddRounded";
15
15
  import DeleteOutlineRoundedIcon from "@mui/icons-material/DeleteOutlineRounded";
16
16
  import RestartAltRoundedIcon from "@mui/icons-material/RestartAltRounded";
17
17
  import ConfirmDialog from "../feedback/ConfirmDialog.js";
18
- import { translateValidationMessage } from "../forms/validationMessages.js";
18
+ import { useValidationText } from "../forms/useValidationText.js";
19
19
  import { FormSectionContext } from "./formLayoutContext.js";
20
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
20
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
21
21
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
22
22
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
23
23
  const DEFAULT_COLUMNS = Object.freeze({ xs: 1, sm: 2, md: 3 });
@@ -35,7 +35,7 @@ function gridColumnsOf(columns) {
35
35
  }
36
36
  return Object.fromEntries(Object.entries(columns).map(([breakpoint, count]) => [breakpoint, templateOf(count)]));
37
37
  }
38
- function RepeatingFields(props) {
38
+ function RepeatingFieldsContent(props) {
39
39
  const {
40
40
  label,
41
41
  rowKeys,
@@ -57,17 +57,19 @@ function RepeatingFields(props) {
57
57
  addLabel,
58
58
  disabled = false,
59
59
  sx,
60
+ messages,
60
61
  texts,
61
62
  ...unknownProps
62
63
  } = usePieceProps(props, THEME_NAME);
63
64
  warnUnknownProps(THEME_NAME, unknownProps);
64
65
  const { t } = useToolkitTranslation("common", texts);
66
+ const validationTextOf = useValidationText({ label, messages });
65
67
  const [pendingRemoval, setPendingRemoval] = useState(null);
66
68
  const blockedTitleId = `${useId()}-blocked-title`;
67
69
  const rowCount = rowKeys.length;
68
70
  const isAtMinimum = rowCount <= minRows;
69
71
  const isAtMaximum = maxRows != null && rowCount >= maxRows;
70
- const errorText = translateValidationMessage(t, error);
72
+ const errorText = validationTextOf(error);
71
73
  const titleOf = (index) => rowLabelOf?.(index) ?? t("repeating.row", { number: index + 1 });
72
74
  const requestRemove = (index) => {
73
75
  const blockedReason = removeBlockedReasonOf?.(index) ?? null;
@@ -88,7 +90,7 @@ function RepeatingFields(props) {
88
90
  onRemove(index);
89
91
  }
90
92
  };
91
- return /* @__PURE__ */ jsxs(RepeatingRoot, { spacing: 1.5, ownSx: { minWidth: 0, ...sx }, children: [
93
+ return /* @__PURE__ */ jsxs(RepeatingRoot, { spacing: 1.5, ownSx: { minWidth: 0 }, sx, children: [
92
94
  label && /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", component: "h3", children: label }),
93
95
  rowKeys.map((rowKey, index) => {
94
96
  const removeText = isAtMinimum ? t("repeating.clear", { row: titleOf(index) }) : t("repeating.remove", { row: titleOf(index) });
@@ -171,6 +173,7 @@ function RepeatingFields(props) {
171
173
  )
172
174
  ] });
173
175
  }
176
+ const RepeatingFields = withPieceSlots(RepeatingFieldsContent, THEME_NAME);
174
177
  export {
175
178
  RepeatingFields as default
176
179
  };
@@ -1 +1 @@
1
- {"version":3,"file":"RepeatingFields.js","sources":["../../src/inputs/RepeatingFields.jsx"],"sourcesContent":["// Renglones de campos que se repiten (los contactos de un cliente, los precios por volumen, el reparto de un presupuesto):\n// cada renglón con su número y «Quitar», y «Agregar» al final. Es solo la VISTA: los renglones los guarda el formulario\n// (FormRepeatingFields de formik o de react-hook-form los conecta por name).\n//\n// Reglas de la vista:\n// - minRows (por omisión 1): con el mínimo, «Quitar» se vuelve «Limpiar» y deja el renglón vacío (nunca queda la\n// lista sin renglones para escribir);\n// - maxRows: con el máximo, «Agregar» se apaga y dice hasta cuántos;\n// - quitar un renglón lo decide la pantalla: removeBlockedReasonOf(index) da el motivo si NO se puede (sale en una\n// ventana con «Entendido»), y confirmRemoveOf(index) pide confirmar antes (un renglón ya guardado);\n// - el renglón con un error se marca en rojo, para encontrarlo en una lista larga.\n//\n// En escritorio los campos de un renglón van lado a lado (columns); en el teléfono, uno debajo de otro, como tarjetas.\n// Dentro de un renglón los campos van con su etiqueta arriba aunque la lista esté dentro de una FormSection.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaRepeatingFields con defaultProps y\n// styleOverrides de sus partes: root, row, rowHeader, rowContent, addButton, helper.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Dialog from '@mui/material/Dialog';\nimport DialogActions from '@mui/material/DialogActions';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded';\nimport RestartAltRoundedIcon from '@mui/icons-material/RestartAltRounded';\n\nimport ConfirmDialog from '@/feedback/ConfirmDialog.jsx';\nimport {translateValidationMessage} from '@/forms/validationMessages.js';\nimport {FormSectionContext} from '@/inputs/formLayoutContext.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// por omisión: uno en el teléfono, dos en tableta, tres en escritorio\nconst DEFAULT_COLUMNS = Object.freeze({xs: 1, sm: 2, md: 3});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaRepeatingFields)\nconst THEME_NAME = 'CalcitaRepeatingFields';\nconst RepeatingRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst RepeatingRow = piecePart(THEME_NAME, 'Row', Paper);\nconst RepeatingRowHeader = piecePart(THEME_NAME, 'RowHeader', Stack);\nconst RepeatingRowContent = piecePart(THEME_NAME, 'RowContent', Box);\nconst RepeatingAddButton = piecePart(THEME_NAME, 'AddButton', Button);\nconst RepeatingHelper = piecePart(THEME_NAME, 'Helper', FormHelperText);\n\n/**\n * El número de columnas de la rejilla como CSS: {xs: 1, md: 3} → {xs: 'repeat(1, minmax(0, 1fr))', …}.\n *\n * @param {number|Record<string, number>} columns\n * @returns {string|Record<string, string>}\n */\nfunction gridColumnsOf(columns) {\n const templateOf = (count) => `repeat(${count}, minmax(0, 1fr))`;\n if (typeof columns === 'number') {\n return templateOf(columns);\n }\n return Object.fromEntries(Object.entries(columns).map(([breakpoint, count]) => [breakpoint, templateOf(count)]));\n}\n\n/**\n * @param {object} props\n * @param {import('react').ReactNode} [props.label] ya traducido: el título de la lista («Contactos»)\n * @param {string[]} props.rowKeys una llave estable por renglón (no el índice: al quitar uno, los de abajo no deben\n * confundirse con el que se fue)\n * @param {(index: number) => import('react').ReactNode} props.renderRow los campos del renglón\n * @param {(index: number) => string} [props.rowLabelOf] el título de cada renglón; por omisión «Renglón 1», «Renglón 2»…\n * @param {(index: number) => import('react').ReactNode} [props.rowActionsOf] botones suyos en el título del renglón\n * @param {number|Record<string, number>} [props.columns] cuántos campos lado a lado: 2 o {xs: 1, sm: 2, md: 3}\n * @param {number} [props.minRows] cuántos renglones quedan siempre (por omisión 1); con 0 se puede quedar vacía\n * @param {number|null} [props.maxRows] hasta cuántos; sin él, los que quiera\n * @param {() => void} props.onAdd agrega un renglón vacío al final\n * @param {(index: number) => void} props.onRemove quita ese renglón\n * @param {(index: number) => void} props.onClear deja ese renglón vacío (cuando ya no se puede quitar por el mínimo)\n * @param {(index: number) => string|null} [props.removeBlockedReasonOf] si ese renglón NO se puede quitar, el motivo ya\n * traducido (sale en una ventana)\n * @param {(index: number) => boolean} [props.confirmRemoveOf] true si hay que confirmar antes de quitarlo\n * @param {(index: number) => boolean} [props.rowHasErrorOf] true si el renglón tiene un error (se marca en rojo)\n * @param {string|{key: string, values?: object}} [props.error] el error de toda la lista (la suma no alcanza, faltan renglones)\n * @param {import('react').ReactNode} [props.helperText] ya traducida\n * @param {import('react').ReactNode} [props.footer] lo que va junto a «Agregar» (p. ej. «Suman $40,000 de $50,000»)\n * @param {string} [props.addLabel] ya traducido; por omisión «Agregar»\n * @param {boolean} [props.disabled]\n * @param {object} [props.sx]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function RepeatingFields(props) {\n const {\n label, rowKeys, renderRow, rowLabelOf, rowActionsOf, columns = DEFAULT_COLUMNS, minRows = 1, maxRows = null, onAdd, onRemove,\n onClear, removeBlockedReasonOf, confirmRemoveOf, rowHasErrorOf, error, helperText, footer, addLabel, disabled = false, sx, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // el renglón que se va a quitar y por qué se pregunta: {index, kind: 'confirm' | 'blocked', reason}\n const [pendingRemoval, setPendingRemoval] = useState(null);\n const blockedTitleId = `${useId()}-blocked-title`;\n const rowCount = rowKeys.length;\n const isAtMinimum = rowCount <= minRows;\n const isAtMaximum = maxRows != null && rowCount >= maxRows;\n const errorText = translateValidationMessage(t, error);\n const titleOf = (index) => rowLabelOf?.(index) ?? t('repeating.row', {number: index + 1});\n\n // quitar (o limpiar, si ya está en el mínimo): primero lo que diga la pantalla\n const requestRemove = (index) => {\n const blockedReason = removeBlockedReasonOf?.(index) ?? null;\n if (blockedReason) {\n setPendingRemoval({index, kind: 'blocked', reason: blockedReason});\n return;\n }\n if (confirmRemoveOf?.(index)) {\n setPendingRemoval({index, kind: 'confirm'});\n return;\n }\n removeOrClear(index);\n };\n const removeOrClear = (index) => {\n if (isAtMinimum) {\n onClear(index);\n } else {\n onRemove(index);\n }\n };\n\n return (\n <RepeatingRoot spacing={1.5} ownSx={{minWidth: 0, ...sx}}>\n {label && <Typography variant=\"subtitle2\" component=\"h3\">{label}</Typography>}\n {rowKeys.map((rowKey, index) => {\n const removeText = isAtMinimum ? t('repeating.clear', {row: titleOf(index)}) : t('repeating.remove', {row: titleOf(index)});\n return (\n <RepeatingRow\n key={rowKey}\n variant=\"outlined\"\n role=\"group\"\n aria-label={titleOf(index)}\n ownSx={{p: {xs: 1.5, sm: 2}, ...(rowHasErrorOf?.(index) && {borderColor: 'error.main'})}}\n >\n <RepeatingRowHeader direction=\"row\" ownSx={{alignItems: 'center', gap: 1, mb: 1.5}}>\n <Typography variant=\"subtitle2\" sx={{flexGrow: 1, minWidth: 0}} color={rowHasErrorOf?.(index) ? 'error' : 'text.primary'}>\n {titleOf(index)}\n </Typography>\n {rowActionsOf?.(index)}\n <Button size=\"small\" color=\"inherit\" disabled={disabled} onClick={() => requestRemove(index)} aria-label={removeText}\n startIcon={isAtMinimum ? <RestartAltRoundedIcon /> : <DeleteOutlineRoundedIcon />}>\n {isAtMinimum ? t('repeating.clearShort') : t('repeating.removeShort')}\n </Button>\n </RepeatingRowHeader>\n {/* los campos del renglón llevan su etiqueta arriba aunque la lista esté dentro de una FormSection */}\n <FormSectionContext.Provider value={false}>\n <RepeatingRowContent ownSx={{display: 'grid', gap: 2, gridTemplateColumns: gridColumnsOf(columns), alignItems: 'start'}}>\n {renderRow(index)}\n </RepeatingRowContent>\n </FormSectionContext.Provider>\n </RepeatingRow>\n );\n })}\n <Stack direction=\"row\" sx={{alignItems: 'center', gap: 2, flexWrap: 'wrap'}}>\n <RepeatingAddButton variant=\"outlined\" startIcon={<AddRoundedIcon />} onClick={onAdd} disabled={disabled || isAtMaximum}\n ownSx={{alignSelf: 'flex-start'}}>\n {addLabel ?? t('repeating.add')}\n </RepeatingAddButton>\n {maxRows != null && (\n <Typography variant=\"caption\" color=\"text.secondary\">{t('repeating.maxRows', {count: maxRows})}</Typography>\n )}\n {footer}\n </Stack>\n {(errorText || helperText) && (\n <RepeatingHelper error={Boolean(errorText)} role={errorText ? 'alert' : undefined} ownSx={{mx: 0}}>\n {errorText ?? helperText}\n </RepeatingHelper>\n )}\n\n <ConfirmDialog\n open={pendingRemoval?.kind === 'confirm'}\n title={t('repeating.confirmTitle', {row: pendingRemoval ? titleOf(pendingRemoval.index) : ''})}\n description={t('repeating.confirmText')}\n confirmLabel={t('repeating.removeShort')}\n tone=\"error\"\n onConfirm={() => {\n removeOrClear(pendingRemoval.index);\n setPendingRemoval(null);\n }}\n onClose={() => setPendingRemoval(null)}\n texts={texts}\n />\n <Dialog open={pendingRemoval?.kind === 'blocked'} onClose={() => setPendingRemoval(null)} maxWidth=\"xs\" fullWidth\n aria-labelledby={blockedTitleId}>\n <DialogTitle id={blockedTitleId}>{t('repeating.blockedTitle')}</DialogTitle>\n <DialogContent><Typography>{pendingRemoval?.reason}</Typography></DialogContent>\n <DialogActions>\n <Button variant=\"contained\" onClick={() => setPendingRemoval(null)} autoFocus>{t('repeating.understood')}</Button>\n </DialogActions>\n </Dialog>\n </RepeatingRoot>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RepeatingFields.js","sources":["../../src/inputs/RepeatingFields.jsx"],"sourcesContent":["// Renglones de campos que se repiten (los contactos de un cliente, los precios por volumen, el reparto de un presupuesto):\n// cada renglón con su número y «Quitar», y «Agregar» al final. Es solo la VISTA: los renglones los guarda el formulario\n// (FormRepeatingFields de formik o de react-hook-form los conecta por name).\n//\n// Reglas de la vista:\n// - minRows (por omisión 1): con el mínimo, «Quitar» se vuelve «Limpiar» y deja el renglón vacío (nunca queda la\n// lista sin renglones para escribir);\n// - maxRows: con el máximo, «Agregar» se apaga y dice hasta cuántos;\n// - quitar un renglón lo decide la pantalla: removeBlockedReasonOf(index) da el motivo si NO se puede (sale en una\n// ventana con «Entendido»), y confirmRemoveOf(index) pide confirmar antes (un renglón ya guardado);\n// - el renglón con un error se marca en rojo, para encontrarlo en una lista larga.\n//\n// En escritorio los campos de un renglón van lado a lado (columns); en el teléfono, uno debajo de otro, como tarjetas.\n// Dentro de un renglón los campos van con su etiqueta arriba aunque la lista esté dentro de una FormSection.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaRepeatingFields con defaultProps y\n// styleOverrides de sus partes: root, row, rowHeader, rowContent, addButton, helper.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Dialog from '@mui/material/Dialog';\nimport DialogActions from '@mui/material/DialogActions';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded';\nimport RestartAltRoundedIcon from '@mui/icons-material/RestartAltRounded';\n\nimport ConfirmDialog from '@/feedback/ConfirmDialog.jsx';\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport {FormSectionContext} from '@/inputs/formLayoutContext.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// por omisión: uno en el teléfono, dos en tableta, tres en escritorio\nconst DEFAULT_COLUMNS = Object.freeze({xs: 1, sm: 2, md: 3});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaRepeatingFields)\nconst THEME_NAME = 'CalcitaRepeatingFields';\nconst RepeatingRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst RepeatingRow = piecePart(THEME_NAME, 'Row', Paper);\nconst RepeatingRowHeader = piecePart(THEME_NAME, 'RowHeader', Stack);\nconst RepeatingRowContent = piecePart(THEME_NAME, 'RowContent', Box);\nconst RepeatingAddButton = piecePart(THEME_NAME, 'AddButton', Button);\nconst RepeatingHelper = piecePart(THEME_NAME, 'Helper', FormHelperText);\n\n/**\n * El número de columnas de la rejilla como CSS: {xs: 1, md: 3} → {xs: 'repeat(1, minmax(0, 1fr))', …}.\n *\n * @param {number|Record<string, number>} columns\n * @returns {string|Record<string, string>}\n */\nfunction gridColumnsOf(columns) {\n const templateOf = (count) => `repeat(${count}, minmax(0, 1fr))`;\n if (typeof columns === 'number') {\n return templateOf(columns);\n }\n return Object.fromEntries(Object.entries(columns).map(([breakpoint, count]) => [breakpoint, templateOf(count)]));\n}\n\n/**\n * @param {object} props\n * @param {import('react').ReactNode} [props.label] ya traducido: el título de la lista («Contactos»)\n * @param {string[]} props.rowKeys una llave estable por renglón (no el índice: al quitar uno, los de abajo no deben\n * confundirse con el que se fue)\n * @param {(index: number) => import('react').ReactNode} props.renderRow los campos del renglón\n * @param {(index: number) => string} [props.rowLabelOf] el título de cada renglón; por omisión «Renglón 1», «Renglón 2»…\n * @param {(index: number) => import('react').ReactNode} [props.rowActionsOf] botones suyos en el título del renglón\n * @param {number|Record<string, number>} [props.columns] cuántos campos lado a lado: 2 o {xs: 1, sm: 2, md: 3}\n * @param {number} [props.minRows] cuántos renglones quedan siempre (por omisión 1); con 0 se puede quedar vacía\n * @param {number|null} [props.maxRows] hasta cuántos; sin él, los que quiera\n * @param {() => void} props.onAdd agrega un renglón vacío al final\n * @param {(index: number) => void} props.onRemove quita ese renglón\n * @param {(index: number) => void} props.onClear deja ese renglón vacío (cuando ya no se puede quitar por el mínimo)\n * @param {(index: number) => string|null} [props.removeBlockedReasonOf] si ese renglón NO se puede quitar, el motivo ya\n * traducido (sale en una ventana)\n * @param {(index: number) => boolean} [props.confirmRemoveOf] true si hay que confirmar antes de quitarlo\n * @param {(index: number) => boolean} [props.rowHasErrorOf] true si el renglón tiene un error (se marca en rojo)\n * @param {string|{key: string, values?: object}} [props.error] el error de toda la lista (la suma no alcanza, faltan renglones)\n * @param {import('react').ReactNode} [props.helperText] ya traducida\n * @param {import('react').ReactNode} [props.footer] lo que va junto a «Agregar» (p. ej. «Suman $40,000 de $50,000»)\n * @param {string} [props.addLabel] ya traducido; por omisión «Agregar»\n * @param {boolean} [props.disabled]\n * @param {object} [props.sx]\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction RepeatingFieldsContent(props) {\n const {\n label, rowKeys, renderRow, rowLabelOf, rowActionsOf, columns = DEFAULT_COLUMNS, minRows = 1, maxRows = null, onAdd, onRemove,\n onClear, removeBlockedReasonOf, confirmRemoveOf, rowHasErrorOf, error, helperText, footer, addLabel, disabled = false, sx, messages, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // el texto del error: el de la pantalla (messages), el del proyecto para este campo o el de Calcita\n const validationTextOf = useValidationText({label, messages});\n // el renglón que se va a quitar y por qué se pregunta: {index, kind: 'confirm' | 'blocked', reason}\n const [pendingRemoval, setPendingRemoval] = useState(null);\n const blockedTitleId = `${useId()}-blocked-title`;\n const rowCount = rowKeys.length;\n const isAtMinimum = rowCount <= minRows;\n const isAtMaximum = maxRows != null && rowCount >= maxRows;\n const errorText = validationTextOf(error);\n const titleOf = (index) => rowLabelOf?.(index) ?? t('repeating.row', {number: index + 1});\n\n // quitar (o limpiar, si ya está en el mínimo): primero lo que diga la pantalla\n const requestRemove = (index) => {\n const blockedReason = removeBlockedReasonOf?.(index) ?? null;\n if (blockedReason) {\n setPendingRemoval({index, kind: 'blocked', reason: blockedReason});\n return;\n }\n if (confirmRemoveOf?.(index)) {\n setPendingRemoval({index, kind: 'confirm'});\n return;\n }\n removeOrClear(index);\n };\n const removeOrClear = (index) => {\n if (isAtMinimum) {\n onClear(index);\n } else {\n onRemove(index);\n }\n };\n\n return (\n <RepeatingRoot spacing={1.5} ownSx={{minWidth: 0}} sx={sx}>\n {label && <Typography variant=\"subtitle2\" component=\"h3\">{label}</Typography>}\n {rowKeys.map((rowKey, index) => {\n const removeText = isAtMinimum ? t('repeating.clear', {row: titleOf(index)}) : t('repeating.remove', {row: titleOf(index)});\n return (\n <RepeatingRow\n key={rowKey}\n variant=\"outlined\"\n role=\"group\"\n aria-label={titleOf(index)}\n ownSx={{p: {xs: 1.5, sm: 2}, ...(rowHasErrorOf?.(index) && {borderColor: 'error.main'})}}\n >\n <RepeatingRowHeader direction=\"row\" ownSx={{alignItems: 'center', gap: 1, mb: 1.5}}>\n <Typography variant=\"subtitle2\" sx={{flexGrow: 1, minWidth: 0}} color={rowHasErrorOf?.(index) ? 'error' : 'text.primary'}>\n {titleOf(index)}\n </Typography>\n {rowActionsOf?.(index)}\n <Button size=\"small\" color=\"inherit\" disabled={disabled} onClick={() => requestRemove(index)} aria-label={removeText}\n startIcon={isAtMinimum ? <RestartAltRoundedIcon /> : <DeleteOutlineRoundedIcon />}>\n {isAtMinimum ? t('repeating.clearShort') : t('repeating.removeShort')}\n </Button>\n </RepeatingRowHeader>\n {/* los campos del renglón llevan su etiqueta arriba aunque la lista esté dentro de una FormSection */}\n <FormSectionContext.Provider value={false}>\n <RepeatingRowContent ownSx={{display: 'grid', gap: 2, gridTemplateColumns: gridColumnsOf(columns), alignItems: 'start'}}>\n {renderRow(index)}\n </RepeatingRowContent>\n </FormSectionContext.Provider>\n </RepeatingRow>\n );\n })}\n <Stack direction=\"row\" sx={{alignItems: 'center', gap: 2, flexWrap: 'wrap'}}>\n <RepeatingAddButton variant=\"outlined\" startIcon={<AddRoundedIcon />} onClick={onAdd} disabled={disabled || isAtMaximum}\n ownSx={{alignSelf: 'flex-start'}}>\n {addLabel ?? t('repeating.add')}\n </RepeatingAddButton>\n {maxRows != null && (\n <Typography variant=\"caption\" color=\"text.secondary\">{t('repeating.maxRows', {count: maxRows})}</Typography>\n )}\n {footer}\n </Stack>\n {(errorText || helperText) && (\n <RepeatingHelper error={Boolean(errorText)} role={errorText ? 'alert' : undefined} ownSx={{mx: 0}}>\n {errorText ?? helperText}\n </RepeatingHelper>\n )}\n\n <ConfirmDialog\n open={pendingRemoval?.kind === 'confirm'}\n title={t('repeating.confirmTitle', {row: pendingRemoval ? titleOf(pendingRemoval.index) : ''})}\n description={t('repeating.confirmText')}\n confirmLabel={t('repeating.removeShort')}\n tone=\"error\"\n onConfirm={() => {\n removeOrClear(pendingRemoval.index);\n setPendingRemoval(null);\n }}\n onClose={() => setPendingRemoval(null)}\n texts={texts}\n />\n <Dialog open={pendingRemoval?.kind === 'blocked'} onClose={() => setPendingRemoval(null)} maxWidth=\"xs\" fullWidth\n aria-labelledby={blockedTitleId}>\n <DialogTitle id={blockedTitleId}>{t('repeating.blockedTitle')}</DialogTitle>\n <DialogContent><Typography>{pendingRemoval?.reason}</Typography></DialogContent>\n <DialogActions>\n <Button variant=\"contained\" onClick={() => setPendingRemoval(null)} autoFocus>{t('repeating.understood')}</Button>\n </DialogActions>\n </Dialog>\n </RepeatingRoot>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst RepeatingFields = withPieceSlots(RepeatingFieldsContent, THEME_NAME);\nexport default RepeatingFields;\n"],"names":[],"mappings":"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"}
@@ -7,17 +7,17 @@ import Checkbox from "@mui/material/Checkbox";
7
7
  import MenuItem from "@mui/material/MenuItem";
8
8
  import TextField from "@mui/material/TextField";
9
9
  import Typography from "@mui/material/Typography";
10
- import { translateValidationMessage } from "../forms/validationMessages.js";
10
+ import { useValidationText } from "../forms/useValidationText.js";
11
11
  import FieldFrame from "./FieldFrame.js";
12
12
  import { selectAllStateOf } from "./selectAllState.js";
13
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
13
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
14
14
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
15
15
  const THEME_NAME = "CalcitaSelectInput";
16
16
  const SelectOption = piecePart(THEME_NAME, "Option", MenuItem);
17
17
  const SelectOptionText = piecePart(THEME_NAME, "OptionText", Box);
18
18
  const SELECT_ALL_VALUE = "__calcita_select_all__";
19
19
  const WITHOUT_CHECKMARK = Object.freeze({ "&.Mui-selected::after": { content: "none" } });
20
- function SelectInput(props) {
20
+ function SelectInputContent(props) {
21
21
  const {
22
22
  name,
23
23
  label,
@@ -33,15 +33,17 @@ function SelectInput(props) {
33
33
  multiple = false,
34
34
  selectAll = false,
35
35
  checkboxes = false,
36
+ messages,
36
37
  texts,
37
38
  ...unknownProps
38
39
  } = usePieceProps(props, THEME_NAME);
39
40
  warnUnknownProps(THEME_NAME, unknownProps);
40
41
  const { t } = useToolkitTranslation("common", texts);
42
+ const validationTextOf = useValidationText({ name, label, messages });
41
43
  const generatedId = useId();
42
44
  const inputId = `${name ?? "select"}-${generatedId}`;
43
45
  const labelId = `${inputId}-label`;
44
- const errorText = translateValidationMessage(t, error);
46
+ const errorText = validationTextOf(error);
45
47
  const placeholderText = /* @__PURE__ */ jsx(
46
48
  Typography,
47
49
  {
@@ -58,7 +60,7 @@ function SelectInput(props) {
58
60
  return options.find((option) => option.value === selectedValue)?.label ?? placeholderText;
59
61
  };
60
62
  const currentValue = multiple ? Array.isArray(value) ? value : [] : value ?? "";
61
- const selectAllState = selectAllStateOf(currentValue, options.filter((option) => !option.disabled).map((option) => option.value));
63
+ const selectAllState = multiple ? selectAllStateOf(currentValue, options.filter((option) => !option.disabled).map((option) => option.value)) : null;
62
64
  const handleChange = (event) => {
63
65
  const nextValue = event.target.value;
64
66
  const values = multiple && typeof nextValue === "string" ? nextValue.split(",") : nextValue;
@@ -124,6 +126,7 @@ function SelectInput(props) {
124
126
  }
125
127
  ) });
126
128
  }
129
+ const SelectInput = withPieceSlots(SelectInputContent, THEME_NAME);
127
130
  export {
128
131
  SelectInput as default
129
132
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SelectInput.js","sources":["../../src/inputs/SelectInput.jsx"],"sourcesContent":["// Lista desplegable suelta, con la etiqueta arriba (mismo look que TextInput): la que pintan FormSelectField (formik) y la\n// de react-hook-form, y la que se usa sin formulario.\n//\n// Cada opción puede traer una explicación (description) que se lee en la lista para escoger; en la caja queda solo el\n// nombre de lo elegido. OJO: sin renderValue, MUI copiaba la opción completa a la caja y se leía «MenudeoCompra por pieza…».\n//\n// Con `multiple` se eligen varias: la lista se queda abierta, cada elegida lleva su palomita y en la caja quedan sus nombres\n// separados por coma, en el orden de las opciones. Al formulario llega la lista de valores (Yup.array().min(1) la valida).\n// Para catálogos largos, CatalogInput con `multiple` (busca y deja chips). Con varias, además: selectAll («Elegir todos»\n// arriba, con su casilla a medias si hay algunos) y checkboxes (una casilla en cada opción en lugar de la palomita).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSelectInput con defaultProps y\n// styleOverrides de sus partes: option, optionText.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Checkbox from '@mui/material/Checkbox';\nimport MenuItem from '@mui/material/MenuItem';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\n\nimport {translateValidationMessage} from '@/forms/validationMessages.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {selectAllStateOf} from '@/inputs/selectAllState.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.CalcitaSelectInput)\nconst THEME_NAME = 'CalcitaSelectInput';\nconst SelectOption = piecePart(THEME_NAME, 'Option', MenuItem);\nconst SelectOptionText = piecePart(THEME_NAME, 'OptionText', Box);\n// la opción de «Elegir todos»: no es de la lista y nunca llega al formulario\nconst SELECT_ALL_VALUE = '__calcita_select_all__';\n// con casillas, la palomita que el tema le pone al elegido sobra\nconst WITHOUT_CHECKMARK = Object.freeze({'&.Mui-selected::after': {content: 'none'}});\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|number|Array<string|number>|null|undefined} props.value '' = sin elegir; con multiple, la lista ([] = ninguna)\n * @param {(value: any) => void} props.onChange recibe el valor elegido (con multiple, la lista), no el evento\n * @param {() => void} [props.onBlur]\n * @param {Array<{value: string|number, label: string, description?: string, disabled?: boolean}>} props.options\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ayuda fija; el error la reemplaza\n * @param {string} [props.placeholder] texto de la opción vacía\n * @param {boolean} [props.disabled]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef]\n * @param {boolean} [props.multiple] elegir varias opciones\n * @param {boolean} [props.selectAll] con multiple: «Elegir todos» arriba de la lista\n * @param {boolean} [props.checkboxes] con multiple: una casilla en cada opción\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function SelectInput(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSelectInput.defaultProps) y encima lo que llega aquí\n const {\n name, label, value, onChange, onBlur, options, error, helperText = ' ', placeholder, disabled = false, inputRef, multiple = false,\n selectAll = false, checkboxes = false, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const generatedId = useId();\n const inputId = `${name ?? 'select'}-${generatedId}`;\n // OJO: la lista desplegable de MUI es un div y no un <input>: el `for` de la etiqueta no la une. Se nombra con su etiqueta\n // por aria-labelledby (labelId); sin esto el lector de pantalla no decía «Ciudad», solo lo elegido\n const labelId = `${inputId}-label`;\n const errorText = translateValidationMessage(t, error);\n const placeholderText = (\n <Typography component=\"span\"\n // OJO: el placeholder de un select activo se lee (text.secondary); text.disabled solo con el campo inactivo\n color={disabled ? 'text.disabled' : 'text.secondary'}>{placeholder ?? t('form.selectPlaceholder')}</Typography>\n );\n const renderSelectedValue = (selectedValue) => {\n if (multiple) {\n const selectedLabels = options.filter((option) => selectedValue.includes(option.value)).map((option) => option.label);\n return selectedLabels.length > 0 ? selectedLabels.join(', ') : placeholderText;\n }\n return options.find((option) => option.value === selectedValue)?.label ?? placeholderText;\n };\n const currentValue = multiple ? (Array.isArray(value) ? value : []) : (value ?? '');\n const selectAllState = selectAllStateOf(currentValue, options.filter((option) => !option.disabled).map((option) => option.value));\n // OJO: con multiple, el autollenado del navegador puede mandar el valor como texto separado por comas (lo dice MUI)\n const handleChange = (event) => {\n const nextValue = event.target.value;\n const values = multiple && typeof nextValue === 'string' ? nextValue.split(',') : nextValue;\n // «Elegir todos» llega como una opción más: se cambia por todos (o por ninguno, si ya estaban todos)\n if (multiple && values.includes(SELECT_ALL_VALUE)) {\n onChange(selectAllState.toggled());\n return;\n }\n onChange(values);\n };\n\n return (\n <FieldFrame inputId={inputId} labelId={labelId} label={label}>\n <TextField\n name={name}\n id={inputId}\n inputRef={inputRef}\n select\n size=\"small\"\n fullWidth\n disabled={disabled}\n value={currentValue}\n onChange={handleChange}\n onBlur={onBlur}\n error={Boolean(errorText)}\n helperText={errorText ?? helperText}\n slotProps={{select: {multiple, displayEmpty: true, renderValue: renderSelectedValue, labelId}}}>\n {/* la opción vacía solo con una: con varias, se quitan picándolas otra vez */}\n {!multiple && <MenuItem value=\"\" disabled>{placeholderText}</MenuItem>}\n {multiple && selectAll && (\n <SelectOption value={SELECT_ALL_VALUE} ownSx={{fontWeight: 600, ...WITHOUT_CHECKMARK}}>\n <Checkbox size=\"small\" tabIndex={-1} disableRipple sx={{p: 0, mr: 1}}\n checked={selectAllState.allChosen} indeterminate={selectAllState.someChosen} />\n {selectAllState.allChosen ? t('form.unselectAll') : t('form.selectAll', {count: options.length})}\n </SelectOption>\n )}\n {options.map((option) => (\n // la opción en renglón y su nombre con su explicación en un bloque: con la opción en columna, la palomita del\n // elegido (el tema la pinta al final) se bajaba a otro renglón (lo cachó una captura de Tareas)\n <SelectOption key={option.value} value={option.value} disabled={option.disabled}\n ownSx={{whiteSpace: 'normal', ...(multiple && checkboxes && WITHOUT_CHECKMARK)}}>\n {multiple && checkboxes && (\n <Checkbox size=\"small\" tabIndex={-1} disableRipple sx={{p: 0, mr: 1}} checked={currentValue.includes(option.value)} />\n )}\n <SelectOptionText component=\"span\" ownSx={{display: 'flex', flexDirection: 'column', minWidth: 0, flexGrow: 1}}>\n <Typography component=\"span\" variant=\"body2\">{option.label}</Typography>\n {option.description && (\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\">{option.description}</Typography>\n )}\n </SelectOptionText>\n </SelectOption>\n ))}\n </TextField>\n </FieldFrame>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AA8BA,MAAM,aAAa;AACnB,MAAM,eAAe,UAAU,YAAY,UAAU,QAAQ;AAC7D,MAAM,mBAAmB,UAAU,YAAY,cAAc,GAAG;AAEhE,MAAM,mBAAmB;AAEzB,MAAM,oBAAoB,OAAO,OAAO,EAAC,yBAAyB,EAAC,SAAS,OAAA,GAAQ;AAoBpF,SAAwB,YAAY,OAAO;AAEvC,QAAM;AAAA,IACN;AAAA,IAAM;AAAA,IAAO;AAAA,IAAO;AAAA,IAAU;AAAA,IAAQ;AAAA,IAAS;AAAA,IAAO,aAAa;AAAA,IAAK;AAAA,IAAa,WAAW;AAAA,IAAO;AAAA,IAAU,WAAW;AAAA,IAC5H,YAAY;AAAA,IAAO,aAAa;AAAA,IAAO;AAAA,IACvC,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,cAAc,MAAA;AACpB,QAAM,UAAU,GAAG,QAAQ,QAAQ,IAAI,WAAW;AAGlD,QAAM,UAAU,GAAG,OAAO;AAC1B,QAAM,YAAY,2BAA2B,GAAG,KAAK;AACrD,QAAM,kBACF;AAAA,IAAC;AAAA,IAAA;AAAA,MAAW,WAAU;AAAA,MAEV,OAAO,WAAW,kBAAkB;AAAA,MAAmB,UAAA,eAAe,EAAE,wBAAwB;AAAA,IAAA;AAAA,EAAA;AAEhH,QAAM,sBAAsB,CAAC,kBAAkB;AAC3C,QAAI,UAAU;AACV,YAAM,iBAAiB,QAAQ,OAAO,CAAC,WAAW,cAAc,SAAS,OAAO,KAAK,CAAC,EAAE,IAAI,CAAC,WAAW,OAAO,KAAK;AACpH,aAAO,eAAe,SAAS,IAAI,eAAe,KAAK,IAAI,IAAI;AAAA,IACnE;AACA,WAAO,QAAQ,KAAK,CAAC,WAAW,OAAO,UAAU,aAAa,GAAG,SAAS;AAAA,EAC9E;AACA,QAAM,eAAe,WAAY,MAAM,QAAQ,KAAK,IAAI,QAAQ,KAAO,SAAS;AAChF,QAAM,iBAAiB,iBAAiB,cAAc,QAAQ,OAAO,CAAC,WAAW,CAAC,OAAO,QAAQ,EAAE,IAAI,CAAC,WAAW,OAAO,KAAK,CAAC;AAEhI,QAAM,eAAe,CAAC,UAAU;AAC5B,UAAM,YAAY,MAAM,OAAO;AAC/B,UAAM,SAAS,YAAY,OAAO,cAAc,WAAW,UAAU,MAAM,GAAG,IAAI;AAElF,QAAI,YAAY,OAAO,SAAS,gBAAgB,GAAG;AAC/C,eAAS,eAAe,SAAS;AACjC;AAAA,IACJ;AACA,aAAS,MAAM;AAAA,EACnB;AAEA,SACI,oBAAC,YAAA,EAAW,SAAkB,SAAkB,OAC5C,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACG;AAAA,MACA,IAAI;AAAA,MACJ;AAAA,MACA,QAAM;AAAA,MACN,MAAK;AAAA,MACL,WAAS;AAAA,MACT;AAAA,MACA,OAAO;AAAA,MACP,UAAU;AAAA,MACV;AAAA,MACA,OAAO,QAAQ,SAAS;AAAA,MACxB,YAAY,aAAa;AAAA,MACzB,WAAW,EAAC,QAAQ,EAAC,UAAU,cAAc,MAAM,aAAa,qBAAqB,UAAO;AAAA,MAE3F,UAAA;AAAA,QAAA,CAAC,YAAY,oBAAC,UAAA,EAAS,OAAM,IAAG,UAAQ,MAAE,UAAA,iBAAgB;AAAA,QAC1D,YAAY,aACT,qBAAC,cAAA,EAAa,OAAO,kBAAkB,OAAO,EAAC,YAAY,KAAK,GAAG,kBAAA,GAC/D,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cAAS,MAAK;AAAA,cAAQ,UAAU;AAAA,cAAI,eAAa;AAAA,cAAC,IAAI,EAAC,GAAG,GAAG,IAAI,EAAA;AAAA,cACxD,SAAS,eAAe;AAAA,cAAW,eAAe,eAAe;AAAA,YAAA;AAAA,UAAA;AAAA,UAC1E,eAAe,YAAY,EAAE,kBAAkB,IAAI,EAAE,kBAAkB,EAAC,OAAO,QAAQ,OAAA,CAAO;AAAA,QAAA,GACnG;AAAA,QAEH,QAAQ,IAAI,CAAC;AAAA;AAAA;AAAA,UAGV;AAAA,YAAC;AAAA,YAAA;AAAA,cAAgC,OAAO,OAAO;AAAA,cAAO,UAAU,OAAO;AAAA,cACzD,OAAO,EAAC,YAAY,UAAU,GAAI,YAAY,cAAc,kBAAA;AAAA,cACrE,UAAA;AAAA,gBAAA,YAAY,kCACR,UAAA,EAAS,MAAK,SAAQ,UAAU,IAAI,eAAa,MAAC,IAAI,EAAC,GAAG,GAAG,IAAI,KAAI,SAAS,aAAa,SAAS,OAAO,KAAK,GAAG;AAAA,gBAExH,qBAAC,kBAAA,EAAiB,WAAU,QAAO,OAAO,EAAC,SAAS,QAAQ,eAAe,UAAU,UAAU,GAAG,UAAU,KACxG,UAAA;AAAA,kBAAA,oBAAC,cAAW,WAAU,QAAO,SAAQ,SAAS,iBAAO,OAAM;AAAA,kBAC1D,OAAO,eACJ,oBAAC,YAAA,EAAW,WAAU,QAAO,SAAQ,WAAU,OAAM,kBAAkB,UAAA,OAAO,YAAA,CAAY;AAAA,gBAAA,EAAA,CAElG;AAAA,cAAA;AAAA,YAAA;AAAA,YAVe,OAAO;AAAA,UAAA;AAAA,SAY7B;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,GAET;AAER;"}
1
+ {"version":3,"file":"SelectInput.js","sources":["../../src/inputs/SelectInput.jsx"],"sourcesContent":["// Lista desplegable suelta, con la etiqueta arriba (mismo look que TextInput): la que pintan FormSelectField (formik) y la\n// de react-hook-form, y la que se usa sin formulario.\n//\n// Cada opción puede traer una explicación (description) que se lee en la lista para escoger; en la caja queda solo el\n// nombre de lo elegido. OJO: sin renderValue, MUI copiaba la opción completa a la caja y se leía «MenudeoCompra por pieza…».\n//\n// Con `multiple` se eligen varias: la lista se queda abierta, cada elegida lleva su palomita y en la caja quedan sus nombres\n// separados por coma, en el orden de las opciones. Al formulario llega la lista de valores (Yup.array().min(1) la valida).\n// Para catálogos largos, CatalogInput con `multiple` (busca y deja chips). Con varias, además: selectAll («Elegir todos»\n// arriba, con su casilla a medias si hay algunos) y checkboxes (una casilla en cada opción en lugar de la palomita).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSelectInput con defaultProps y\n// styleOverrides de sus partes: option, optionText.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Checkbox from '@mui/material/Checkbox';\nimport MenuItem from '@mui/material/MenuItem';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\n\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {selectAllStateOf} from '@/inputs/selectAllState.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaSelectInput)\nconst THEME_NAME = 'CalcitaSelectInput';\nconst SelectOption = piecePart(THEME_NAME, 'Option', MenuItem);\nconst SelectOptionText = piecePart(THEME_NAME, 'OptionText', Box);\n// la opción de «Elegir todos»: no es de la lista y nunca llega al formulario\nconst SELECT_ALL_VALUE = '__calcita_select_all__';\n// con casillas, la palomita que el tema le pone al elegido sobra\nconst WITHOUT_CHECKMARK = Object.freeze({'&.Mui-selected::after': {content: 'none'}});\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|number|Array<string|number>|null|undefined} props.value '' = sin elegir; con multiple, la lista ([] = ninguna)\n * @param {(value: any) => void} props.onChange recibe el valor elegido (con multiple, la lista), no el evento\n * @param {() => void} [props.onBlur]\n * @param {Array<{value: string|number, label: string, description?: string, disabled?: boolean}>} props.options\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ayuda fija; el error la reemplaza\n * @param {string} [props.placeholder] texto de la opción vacía\n * @param {boolean} [props.disabled]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef]\n * @param {boolean} [props.multiple] elegir varias opciones\n * @param {boolean} [props.selectAll] con multiple: «Elegir todos» arriba de la lista\n * @param {boolean} [props.checkboxes] con multiple: una casilla en cada opción\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction SelectInputContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSelectInput.defaultProps) y encima lo que llega aquí\n const {\n name, label, value, onChange, onBlur, options, error, helperText = ' ', placeholder, disabled = false, inputRef, multiple = false,\n selectAll = false, checkboxes = false, messages, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // el texto del error: el de la pantalla (messages), el del proyecto para este campo o el de Calcita\n const validationTextOf = useValidationText({name, label, messages});\n const generatedId = useId();\n const inputId = `${name ?? 'select'}-${generatedId}`;\n // OJO: la lista desplegable de MUI es un div y no un <input>: el `for` de la etiqueta no la une. Se nombra con su etiqueta\n // por aria-labelledby (labelId); sin esto el lector de pantalla no decía «Ciudad», solo lo elegido\n const labelId = `${inputId}-label`;\n const errorText = validationTextOf(error);\n const placeholderText = (\n <Typography component=\"span\"\n // OJO: el placeholder de un select activo se lee (text.secondary); text.disabled solo con el campo inactivo\n color={disabled ? 'text.disabled' : 'text.secondary'}>{placeholder ?? t('form.selectPlaceholder')}</Typography>\n );\n const renderSelectedValue = (selectedValue) => {\n if (multiple) {\n const selectedLabels = options.filter((option) => selectedValue.includes(option.value)).map((option) => option.label);\n return selectedLabels.length > 0 ? selectedLabels.join(', ') : placeholderText;\n }\n return options.find((option) => option.value === selectedValue)?.label ?? placeholderText;\n };\n const currentValue = multiple ? (Array.isArray(value) ? value : []) : (value ?? '');\n // «Elegir todos» solo existe con varias. OJO, trampa pagada: se calculaba también con una sola, y un valor que es número\n // (un recordatorio de 60 minutos) tumbaba la pantalla: new Set(60) no es una lista\n const selectAllState = multiple\n ? selectAllStateOf(currentValue, options.filter((option) => !option.disabled).map((option) => option.value))\n : null;\n // OJO: con multiple, el autollenado del navegador puede mandar el valor como texto separado por comas (lo dice MUI)\n const handleChange = (event) => {\n const nextValue = event.target.value;\n const values = multiple && typeof nextValue === 'string' ? nextValue.split(',') : nextValue;\n // «Elegir todos» llega como una opción más: se cambia por todos (o por ninguno, si ya estaban todos)\n if (multiple && values.includes(SELECT_ALL_VALUE)) {\n onChange(selectAllState.toggled());\n return;\n }\n onChange(values);\n };\n\n return (\n <FieldFrame inputId={inputId} labelId={labelId} label={label}>\n <TextField\n name={name}\n id={inputId}\n inputRef={inputRef}\n select\n size=\"small\"\n fullWidth\n disabled={disabled}\n value={currentValue}\n onChange={handleChange}\n onBlur={onBlur}\n error={Boolean(errorText)}\n helperText={errorText ?? helperText}\n slotProps={{select: {multiple, displayEmpty: true, renderValue: renderSelectedValue, labelId}}}>\n {/* la opción vacía solo con una: con varias, se quitan picándolas otra vez */}\n {!multiple && <MenuItem value=\"\" disabled>{placeholderText}</MenuItem>}\n {multiple && selectAll && (\n <SelectOption value={SELECT_ALL_VALUE} ownSx={{fontWeight: 600, ...WITHOUT_CHECKMARK}}>\n <Checkbox size=\"small\" tabIndex={-1} disableRipple sx={{p: 0, mr: 1}}\n checked={selectAllState.allChosen} indeterminate={selectAllState.someChosen} />\n {selectAllState.allChosen ? t('form.unselectAll') : t('form.selectAll', {count: options.length})}\n </SelectOption>\n )}\n {options.map((option) => (\n // la opción en renglón y su nombre con su explicación en un bloque: con la opción en columna, la palomita del\n // elegido (el tema la pinta al final) se bajaba a otro renglón (lo cachó una captura de Tareas)\n <SelectOption key={option.value} value={option.value} disabled={option.disabled}\n ownSx={{whiteSpace: 'normal', ...(multiple && checkboxes && WITHOUT_CHECKMARK)}}>\n {multiple && checkboxes && (\n <Checkbox size=\"small\" tabIndex={-1} disableRipple sx={{p: 0, mr: 1}} checked={currentValue.includes(option.value)} />\n )}\n <SelectOptionText component=\"span\" ownSx={{display: 'flex', flexDirection: 'column', minWidth: 0, flexGrow: 1}}>\n <Typography component=\"span\" variant=\"body2\">{option.label}</Typography>\n {option.description && (\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\">{option.description}</Typography>\n )}\n </SelectOptionText>\n </SelectOption>\n ))}\n </TextField>\n </FieldFrame>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst SelectInput = withPieceSlots(SelectInputContent, THEME_NAME);\nexport default SelectInput;\n"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@ import Tooltip from "@mui/material/Tooltip";
9
9
  import CancelIcon from "@mui/icons-material/Cancel";
10
10
  import VisibilityOffOutlinedIcon from "@mui/icons-material/VisibilityOffOutlined";
11
11
  import VisibilityOutlinedIcon from "@mui/icons-material/VisibilityOutlined";
12
- import { translateValidationMessage } from "../forms/validationMessages.js";
12
+ import { useValidationText } from "../forms/useValidationText.js";
13
13
  import FieldFrame from "./FieldFrame.js";
14
14
  import { piecePart, usePieceProps } from "../theme/themePieces.js";
15
15
  const THEME_NAME = "CalcitaTextInput";
@@ -38,14 +38,16 @@ function TextInput(props) {
38
38
  normalizeOnBlur,
39
39
  inputRef,
40
40
  clearable = true,
41
+ messages,
41
42
  texts,
42
43
  ...textFieldProps
43
- } = usePieceProps(props, THEME_NAME);
44
+ } = usePieceProps(props, THEME_NAME, { ownSlotProps: true });
44
45
  const { t } = useToolkitTranslation("common", texts);
46
+ const validationTextOf = useValidationText({ name, label, messages });
45
47
  const [isRevealed, setIsRevealed] = useState(false);
46
48
  const generatedId = useId();
47
49
  const inputId = textFieldProps.id ?? `${name ?? "text"}-${generatedId}`;
48
- const errorText = translateValidationMessage(t, error);
50
+ const errorText = validationTextOf(error);
49
51
  const isPassword = type === "password";
50
52
  const revealLabel = isRevealed ? t("form.hidePassword") : t("form.showPassword");
51
53
  const passwordAdornment = isPassword ? /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(Tooltip, { title: revealLabel, children: /* @__PURE__ */ jsx(IconButton, { size: "small", edge: "end", "aria-label": revealLabel, onClick: () => setIsRevealed((currentValue) => !currentValue), children: isRevealed ? /* @__PURE__ */ jsx(VisibilityOffOutlinedIcon, { fontSize: "small" }) : /* @__PURE__ */ jsx(VisibilityOutlinedIcon, { fontSize: "small" }) }) }) }) : void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"TextInput.js","sources":["../../src/inputs/TextInput.jsx"],"sourcesContent":["// Campo de texto suelto, con la etiqueta arriba: el que pintan FormTextField (formik) y el de react-hook-form, y el que se\n// usa sin formulario (controlado: value / onChange).\n//\n// Lo que resuelve, y por lo que existe en vez de un <TextField> suelto:\n// - el renglón de ayuda está reservado desde el principio, así la tarjeta no brinca cuando aparece un error;\n// - las contraseñas traen el ojo para revelarlas (con aria-label traducido);\n// - con texto, la ⓧ para borrarlo de un toque, como los campos de Apple («Display a Clear button in the trailing end of\n// a text field», HIG «Text fields»). Sale con el cursor encima o al escribir, para que un formulario lleno no se vea\n// lleno de ⓧ; no entra al recorrido del teclado (con el teclado se borra seleccionando el texto);\n// - normalizeOnBlur deja el valor como lo va a mandar el formulario (el correo en minúsculas y sin espacios) al salir del\n// campo: la persona ve lo que se envía;\n// - uppercase normaliza a mayúsculas mientras se escribe (claves, RFC);\n// - el error llega como LLAVE de yup ({key, values}) o como texto ya traducido (el del servidor) y se pinta en el idioma\n// activo. Cuándo enseñarlo (ya se tocó, ya se envió) lo decide quien lo conecta al formulario.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTextInput con defaultProps y\n// styleOverrides.field (el TextField). El sx de la pantalla sigue ganando a todo.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport IconButton from '@mui/material/IconButton';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport CancelIcon from '@mui/icons-material/Cancel';\nimport VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';\nimport VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';\n\nimport {translateValidationMessage} from '@/forms/validationMessages.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaTextInput): el campo de MUI con lo de Calcita abajo,\n// el tema del proyecto encima y el sx de la pantalla al final\nconst THEME_NAME = 'CalcitaTextInput';\nconst InputField = piecePart(THEME_NAME, 'Field', TextField);\n\n// la ⓧ de borrar: escondida hasta que el campo tiene el cursor encima o se está escribiendo en él\nconst CLEAR_BUTTON_CLASS = 'calcita-clear-button';\nconst CLEAR_BUTTON_SX = Object.freeze({\n [`& .${CLEAR_BUTTON_CLASS}`]: {visibility: 'hidden', color: 'text.secondary'},\n [`& .MuiInputBase-root:hover .${CLEAR_BUTTON_CLASS}, & .MuiInputBase-root.Mui-focused .${CLEAR_BUTTON_CLASS}`]: {visibility: 'visible'},\n // un campo de búsqueda (type=\"search\") trae la × del navegador: con la ⓧ de la casa salían dos para lo mismo (lo cachó\n // una captura de Tareas). Se esconde la del navegador; la de la casa es la que se ve igual en todos\n '& input[type=\"search\"]::-webkit-search-cancel-button': {WebkitAppearance: 'none', display: 'none'},\n});\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|null|undefined} props.value\n * @param {(value: string) => void} props.onChange recibe el texto, no el evento\n * @param {() => void} [props.onBlur]\n * @param {string|{key: string, values?: object}} [props.error] el error a enseñar (undefined = sin error)\n * @param {string} [props.type] 'password' agrega el ojo\n * @param {string} [props.helperText] ayuda fija; el error la reemplaza. Por omisión el campo deja su renglón vacío para que\n * no brinque al salir un error; con helperText=\"\" no lo deja (un campo con botones al lado en el mismo renglón)\n * @param {string} [props.placeholder] ya traducido; el ejemplo de qué escribir (se va al escribir)\n * @param {import('react').ReactNode} [props.startAdornment]\n * @param {import('react').ReactNode} [props.endAdornment] adorno al final (en contraseñas manda el ojo)\n * @param {boolean} [props.uppercase] normaliza a mayúsculas mientras se escribe\n * @param {(value: string) => string} [props.normalizeOnBlur]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef] para enfocar el campo (react-hook-form lo usa)\n * @param {boolean} [props.clearable] la ⓧ para borrar el texto; por omisión sí (no en contraseñas ni con adorno propio)\n * @param {boolean} [props.multiline] (y lo demás de TextField de MUI: minRows, autoComplete, autoFocus, slotProps, sx…)\n * @param {number} [props.minRows]\n * @param {number} [props.maxRows]\n * @param {string} [props.autoComplete]\n * @param {boolean} [props.autoFocus]\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.required]\n * @param {boolean} [props.fullWidth]\n * @param {string} [props.id]\n * @param {object} [props.slotProps]\n * @param {object} [props.sx]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function TextInput(props) {\n // lo que el proyecto puso en su tema (components.CalcitaTextInput.defaultProps) y encima lo que llega aquí\n const {\n name, label, value, onChange, onBlur, error, type = 'text', helperText = ' ', startAdornment, endAdornment: customEndAdornment,\n uppercase = false, normalizeOnBlur, inputRef, clearable = true, texts, ...textFieldProps\n } = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('common', texts);\n const [isRevealed, setIsRevealed] = useState(false);\n const generatedId = useId();\n const inputId = textFieldProps.id ?? `${name ?? 'text'}-${generatedId}`;\n const errorText = translateValidationMessage(t, error);\n const isPassword = type === 'password';\n const revealLabel = isRevealed ? t('form.hidePassword') : t('form.showPassword');\n\n const passwordAdornment = isPassword ? (\n <InputAdornment position=\"end\">\n <Tooltip title={revealLabel}>\n <IconButton size=\"small\" edge=\"end\" aria-label={revealLabel} onClick={() => setIsRevealed((currentValue) => !currentValue)}>\n {isRevealed ? <VisibilityOffOutlinedIcon fontSize=\"small\" /> : <VisibilityOutlinedIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </InputAdornment>\n ) : undefined;\n const isEditable = !textFieldProps.disabled && !textFieldProps.slotProps?.htmlInput?.readOnly;\n const canClear = clearable && !isPassword && !customEndAdornment && isEditable && Boolean(value);\n // onMouseDown sin acción: el foco se queda en el campo al borrar (si no, el campo pierde el foco y se valida de más)\n const clearAdornment = canClear ? (\n <InputAdornment position=\"end\">\n <IconButton size=\"small\" edge=\"end\" tabIndex={-1} aria-label={t('form.clear')} className={CLEAR_BUTTON_CLASS}\n onMouseDown={(event) => event.preventDefault()} onClick={() => onChange('')}>\n <CancelIcon fontSize=\"small\" />\n </IconButton>\n </InputAdornment>\n ) : undefined;\n const endAdornment = customEndAdornment ? <InputAdornment position=\"end\">{customEndAdornment}</InputAdornment> : (passwordAdornment ?? clearAdornment);\n\n const handleBlur = () => {\n if (normalizeOnBlur) {\n const normalizedValue = normalizeOnBlur(value ?? '');\n // solo si cambió: un cambio de más dispara una validación de más\n if (normalizedValue !== value) {\n onChange(normalizedValue);\n }\n }\n onBlur?.();\n };\n\n return (\n <FieldFrame inputId={inputId} label={label}>\n <InputField\n {...textFieldProps}\n name={name}\n id={inputId}\n inputRef={inputRef}\n value={value ?? ''}\n onChange={(event) => onChange(uppercase ? event.target.value.toUpperCase() : event.target.value)}\n onBlur={handleBlur}\n type={isPassword && isRevealed ? 'text' : type}\n ownSx={CLEAR_BUTTON_SX}\n sx={textFieldProps.sx}\n error={Boolean(errorText)}\n helperText={errorText ?? helperText}\n fullWidth\n size=\"small\"\n // OJO: lo que el proyecto pasó en slotProps (htmlInput: {maxLength}) se suma a los adornos de la casa. Antes se\n // pisaba entero y el tope de caracteres de una pantalla se perdía sin avisar\n slotProps={{\n ...textFieldProps.slotProps,\n input: {\n ...textFieldProps.slotProps?.input,\n startAdornment: startAdornment ? <InputAdornment position=\"start\">{startAdornment}</InputAdornment> : undefined,\n endAdornment,\n },\n }}\n />\n </FieldFrame>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TextInput.js","sources":["../../src/inputs/TextInput.jsx"],"sourcesContent":["// Campo de texto suelto, con la etiqueta arriba: el que pintan FormTextField (formik) y el de react-hook-form, y el que se\n// usa sin formulario (controlado: value / onChange).\n//\n// Lo que resuelve, y por lo que existe en vez de un <TextField> suelto:\n// - el renglón de ayuda está reservado desde el principio, así la tarjeta no brinca cuando aparece un error;\n// - las contraseñas traen el ojo para revelarlas (con aria-label traducido);\n// - con texto, la ⓧ para borrarlo de un toque, como los campos de Apple («Display a Clear button in the trailing end of\n// a text field», HIG «Text fields»). Sale con el cursor encima o al escribir, para que un formulario lleno no se vea\n// lleno de ⓧ; no entra al recorrido del teclado (con el teclado se borra seleccionando el texto);\n// - normalizeOnBlur deja el valor como lo va a mandar el formulario (el correo en minúsculas y sin espacios) al salir del\n// campo: la persona ve lo que se envía;\n// - uppercase normaliza a mayúsculas mientras se escribe (claves, RFC);\n// - el error llega como LLAVE de yup ({key, values}) o como texto ya traducido (el del servidor) y se pinta en el idioma\n// activo. Cuándo enseñarlo (ya se tocó, ya se envió) lo decide quien lo conecta al formulario.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTextInput con defaultProps y\n// styleOverrides.field (el TextField). El sx de la pantalla sigue ganando a todo.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport IconButton from '@mui/material/IconButton';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport CancelIcon from '@mui/icons-material/Cancel';\nimport VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';\nimport VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';\n\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaTextInput): el campo de MUI con lo de Calcita abajo,\n// el tema del proyecto encima y el sx de la pantalla al final\nconst THEME_NAME = 'CalcitaTextInput';\nconst InputField = piecePart(THEME_NAME, 'Field', TextField);\n\n// la ⓧ de borrar: escondida hasta que el campo tiene el cursor encima o se está escribiendo en él\nconst CLEAR_BUTTON_CLASS = 'calcita-clear-button';\nconst CLEAR_BUTTON_SX = Object.freeze({\n [`& .${CLEAR_BUTTON_CLASS}`]: {visibility: 'hidden', color: 'text.secondary'},\n [`& .MuiInputBase-root:hover .${CLEAR_BUTTON_CLASS}, & .MuiInputBase-root.Mui-focused .${CLEAR_BUTTON_CLASS}`]: {visibility: 'visible'},\n // un campo de búsqueda (type=\"search\") trae la × del navegador: con la ⓧ de la casa salían dos para lo mismo (lo cachó\n // una captura de Tareas). Se esconde la del navegador; la de la casa es la que se ve igual en todos\n '& input[type=\"search\"]::-webkit-search-cancel-button': {WebkitAppearance: 'none', display: 'none'},\n});\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {string} props.label ya traducido\n * @param {string|null|undefined} props.value\n * @param {(value: string) => void} props.onChange recibe el texto, no el evento\n * @param {() => void} [props.onBlur]\n * @param {string|{key: string, values?: object}} [props.error] el error a enseñar (undefined = sin error)\n * @param {string} [props.type] 'password' agrega el ojo\n * @param {string} [props.helperText] ayuda fija; el error la reemplaza. Por omisión el campo deja su renglón vacío para que\n * no brinque al salir un error; con helperText=\"\" no lo deja (un campo con botones al lado en el mismo renglón)\n * @param {string} [props.placeholder] ya traducido; el ejemplo de qué escribir (se va al escribir)\n * @param {import('react').ReactNode} [props.startAdornment]\n * @param {import('react').ReactNode} [props.endAdornment] adorno al final (en contraseñas manda el ojo)\n * @param {boolean} [props.uppercase] normaliza a mayúsculas mientras se escribe\n * @param {(value: string) => string} [props.normalizeOnBlur]\n * @param {import('react').Ref<HTMLInputElement>} [props.inputRef] para enfocar el campo (react-hook-form lo usa)\n * @param {boolean} [props.clearable] la ⓧ para borrar el texto; por omisión sí (no en contraseñas ni con adorno propio)\n * @param {boolean} [props.multiline] (y lo demás de TextField de MUI: minRows, autoComplete, autoFocus, slotProps, sx…)\n * @param {number} [props.minRows]\n * @param {number} [props.maxRows]\n * @param {string} [props.autoComplete]\n * @param {boolean} [props.autoFocus]\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.required]\n * @param {boolean} [props.fullWidth]\n * @param {string} [props.id]\n * @param {object} [props.slotProps]\n * @param {object} [props.sx]\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function TextInput(props) {\n // lo que el proyecto puso en su tema (components.CalcitaTextInput.defaultProps) y encima lo que llega aquí\n const {\n name, label, value, onChange, onBlur, error, type = 'text', helperText = ' ', startAdornment, endAdornment: customEndAdornment,\n uppercase = false, normalizeOnBlur, inputRef, clearable = true, messages, texts, ...textFieldProps\n } = usePieceProps(props, THEME_NAME, {ownSlotProps: true}); // su slotProps es el del TextField de MUI (input, htmlInput…)\n const {t} = useToolkitTranslation('common', texts);\n // el texto del error: el de la pantalla (messages), el del proyecto para este campo o el de Calcita\n const validationTextOf = useValidationText({name, label, messages});\n const [isRevealed, setIsRevealed] = useState(false);\n const generatedId = useId();\n const inputId = textFieldProps.id ?? `${name ?? 'text'}-${generatedId}`;\n const errorText = validationTextOf(error);\n const isPassword = type === 'password';\n const revealLabel = isRevealed ? t('form.hidePassword') : t('form.showPassword');\n\n const passwordAdornment = isPassword ? (\n <InputAdornment position=\"end\">\n <Tooltip title={revealLabel}>\n <IconButton size=\"small\" edge=\"end\" aria-label={revealLabel} onClick={() => setIsRevealed((currentValue) => !currentValue)}>\n {isRevealed ? <VisibilityOffOutlinedIcon fontSize=\"small\" /> : <VisibilityOutlinedIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </InputAdornment>\n ) : undefined;\n const isEditable = !textFieldProps.disabled && !textFieldProps.slotProps?.htmlInput?.readOnly;\n const canClear = clearable && !isPassword && !customEndAdornment && isEditable && Boolean(value);\n // onMouseDown sin acción: el foco se queda en el campo al borrar (si no, el campo pierde el foco y se valida de más)\n const clearAdornment = canClear ? (\n <InputAdornment position=\"end\">\n <IconButton size=\"small\" edge=\"end\" tabIndex={-1} aria-label={t('form.clear')} className={CLEAR_BUTTON_CLASS}\n onMouseDown={(event) => event.preventDefault()} onClick={() => onChange('')}>\n <CancelIcon fontSize=\"small\" />\n </IconButton>\n </InputAdornment>\n ) : undefined;\n const endAdornment = customEndAdornment ? <InputAdornment position=\"end\">{customEndAdornment}</InputAdornment> : (passwordAdornment ?? clearAdornment);\n\n const handleBlur = () => {\n if (normalizeOnBlur) {\n const normalizedValue = normalizeOnBlur(value ?? '');\n // solo si cambió: un cambio de más dispara una validación de más\n if (normalizedValue !== value) {\n onChange(normalizedValue);\n }\n }\n onBlur?.();\n };\n\n return (\n <FieldFrame inputId={inputId} label={label}>\n <InputField\n {...textFieldProps}\n name={name}\n id={inputId}\n inputRef={inputRef}\n value={value ?? ''}\n onChange={(event) => onChange(uppercase ? event.target.value.toUpperCase() : event.target.value)}\n onBlur={handleBlur}\n type={isPassword && isRevealed ? 'text' : type}\n ownSx={CLEAR_BUTTON_SX}\n sx={textFieldProps.sx}\n error={Boolean(errorText)}\n helperText={errorText ?? helperText}\n fullWidth\n size=\"small\"\n // OJO: lo que el proyecto pasó en slotProps (htmlInput: {maxLength}) se suma a los adornos de la casa. Antes se\n // pisaba entero y el tope de caracteres de una pantalla se perdía sin avisar\n slotProps={{\n ...textFieldProps.slotProps,\n input: {\n ...textFieldProps.slotProps?.input,\n startAdornment: startAdornment ? <InputAdornment position=\"start\">{startAdornment}</InputAdornment> : undefined,\n endAdornment,\n },\n }}\n />\n </FieldFrame>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -17,10 +17,10 @@ import ChevronLeftRoundedIcon from "@mui/icons-material/ChevronLeftRounded";
17
17
  import ChevronRightRoundedIcon from "@mui/icons-material/ChevronRightRounded";
18
18
  import KeyboardDoubleArrowLeftRoundedIcon from "@mui/icons-material/KeyboardDoubleArrowLeftRounded";
19
19
  import KeyboardDoubleArrowRightRoundedIcon from "@mui/icons-material/KeyboardDoubleArrowRightRounded";
20
- import { translateValidationMessage } from "../forms/validationMessages.js";
20
+ import { useValidationText } from "../forms/useValidationText.js";
21
21
  import FieldFrame from "./FieldFrame.js";
22
22
  import { selectAllStateOf } from "./selectAllState.js";
23
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
23
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
24
24
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
25
25
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
26
26
  const DEFAULT_LIST_HEIGHT = 280;
@@ -104,7 +104,7 @@ function TransferColumn({ title, items, markedValues, onMark, onMarkMany, onMove
104
104
  )
105
105
  ] });
106
106
  }
107
- function TransferListInput(props) {
107
+ function TransferListInputContent(props) {
108
108
  const {
109
109
  name,
110
110
  label,
@@ -120,14 +120,16 @@ function TransferListInput(props) {
120
120
  helperText = " ",
121
121
  disabled = false,
122
122
  sx,
123
+ messages,
123
124
  texts,
124
125
  ...unknownProps
125
126
  } = usePieceProps(props, THEME_NAME);
126
127
  warnUnknownProps(THEME_NAME, unknownProps);
127
128
  const { t } = useToolkitTranslation("common", texts);
129
+ const validationTextOf = useValidationText({ name, label, messages });
128
130
  const generatedId = useId();
129
131
  const inputId = `${name ?? "transfer"}-${generatedId}`;
130
- const errorText = translateValidationMessage(t, error);
132
+ const errorText = validationTextOf(error);
131
133
  const chosenValues = Array.isArray(value) ? value : [];
132
134
  const [markedAvailable, setMarkedAvailable] = useState([]);
133
135
  const [markedChosen, setMarkedChosen] = useState([]);
@@ -161,7 +163,7 @@ function TransferListInput(props) {
161
163
  children: /* @__PURE__ */ jsx(Icon, { fontSize: "small", sx: PHONE_ROTATION })
162
164
  }
163
165
  ) }) });
164
- const lists = /* @__PURE__ */ jsxs(TransferRoot, { direction: { xs: "column", md: "row" }, ownSx: { gap: 1.5, alignItems: "stretch", ...sx }, id: inputId, children: [
166
+ const lists = /* @__PURE__ */ jsxs(TransferRoot, { direction: { xs: "column", md: "row" }, ownSx: { gap: 1.5, alignItems: "stretch" }, sx, id: inputId, children: [
165
167
  /* @__PURE__ */ jsx(
166
168
  TransferColumn,
167
169
  {
@@ -209,6 +211,7 @@ function TransferListInput(props) {
209
211
  ] });
210
212
  return label ? /* @__PURE__ */ jsx(FieldFrame, { inputId, label, children: field }) : field;
211
213
  }
214
+ const TransferListInput = withPieceSlots(TransferListInputContent, THEME_NAME);
212
215
  export {
213
216
  TransferListInput as default
214
217
  };
@@ -1 +1 @@
1
- {"version":3,"file":"TransferListInput.js","sources":["../../src/inputs/TransferListInput.jsx"],"sourcesContent":["// La lista de transferencia: dos columnas, «Disponibles» y «Elegidos», y botones para pasar de una a otra. Para elegir\n// muchos de una lista larga viendo siempre qué quedó de cada lado (los usuarios que pueden ver un reporte, las sucursales donde\n// puede comprar un cliente). Al formulario llega la lista de los elegidos, en el orden en que se pasaron.\n//\n// Cada columna trae su título con cuántos tiene, su buscador (searchable) y su casilla de «todos los que se ven» (con algo\n// buscado, solo esos). Se marcan los que se quieren pasar (clic o espacio) y se pasan con ›; » pasa todos los de la\n// columna. Doble clic pasa uno directo. En el teléfono las columnas van una debajo de otra y los botones apuntan hacia\n// abajo y arriba. Va fuera de una FormSection: necesita el ancho completo.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTransferListInput con defaultProps y\n// styleOverrides de sus partes: root, list, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport Button from '@mui/material/Button';\nimport Checkbox from '@mui/material/Checkbox';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport List from '@mui/material/List';\nimport ListItemButton from '@mui/material/ListItemButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport ChevronLeftRoundedIcon from '@mui/icons-material/ChevronLeftRounded';\nimport ChevronRightRoundedIcon from '@mui/icons-material/ChevronRightRounded';\nimport KeyboardDoubleArrowLeftRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowLeftRounded';\nimport KeyboardDoubleArrowRightRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowRightRounded';\n\nimport {translateValidationMessage} from '@/forms/validationMessages.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {selectAllStateOf} from '@/inputs/selectAllState.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// lo alto de cada columna antes de deslizar\nconst DEFAULT_LIST_HEIGHT = 280;\n// en el teléfono los botones apuntan hacia abajo (pasar) y hacia arriba (regresar)\nconst PHONE_ROTATION = Object.freeze({transform: {xs: 'rotate(90deg)', md: 'none'}});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaTransferListInput)\nconst THEME_NAME = 'CalcitaTransferListInput';\nconst TransferRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst TransferList = piecePart(THEME_NAME, 'List', Paper);\nconst TransferActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/**\n * Un texto sin acentos ni mayúsculas, para que «queretaro» encuentre «Querétaro».\n *\n * @param {unknown} text\n * @returns {string}\n */\nfunction plainTextOf(text) {\n return String(text ?? '').normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase().trim();\n}\n\n/**\n * Una columna: su título con cuántos tiene, su buscador, su casilla de «todos los que se ven» y sus renglones.\n *\n * @param {object} props\n */\nfunction TransferColumn({title, items, markedValues, onMark, onMarkMany, onMoveOne, searchable, searchLabel, emptyText, listHeight, disabled, t}) {\n const titleId = useId();\n const [searchText, setSearchText] = useState('');\n const wantedText = plainTextOf(searchText);\n const visibleItems = wantedText\n ? items.filter((item) => plainTextOf(`${item.label} ${item.description ?? ''}`).includes(wantedText))\n : items;\n const visibleValues = visibleItems.filter((item) => !item.disabled).map((item) => item.value);\n const markState = selectAllStateOf(markedValues, visibleValues);\n\n return (\n <TransferList variant=\"outlined\" ownSx={{flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column'}}>\n <Stack direction=\"row\" sx={{alignItems: 'center', gap: 1, px: 1.5, py: 1, borderBottom: 1, borderColor: 'divider'}}>\n <Checkbox size=\"small\" sx={{p: 0.5}} disabled={disabled || visibleValues.length === 0}\n checked={markState.allChosen} indeterminate={markState.someChosen}\n onChange={() => onMarkMany(markState.toggled())}\n slotProps={{input: {'aria-label': t('transfer.markVisible', {list: title})}}} />\n <Typography id={titleId} variant=\"subtitle2\" sx={{flexGrow: 1}}>{title}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {markedValues.length > 0 ? t('transfer.markedOf', {marked: markedValues.length, count: items.length}) : items.length}\n </Typography>\n </Stack>\n {searchable && (\n <TextField size=\"small\" type=\"search\" value={searchText} onChange={(event) => setSearchText(event.target.value)}\n placeholder={searchLabel} disabled={disabled} sx={{m: 1}}\n slotProps={{htmlInput: {'aria-label': `${searchLabel} · ${title}`}}} />\n )}\n <List dense role=\"listbox\" aria-labelledby={titleId} aria-multiselectable=\"true\"\n sx={{height: listHeight, overflowY: 'auto', py: 0}}>\n {visibleItems.length === 0 && (\n // vacía de verdad o vacía por lo buscado: no es lo mismo y se dice distinto\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{px: 2, py: 1.5}}>\n {items.length > 0 ? t('transfer.noMatches', {text: searchText.trim()}) : emptyText}\n </Typography>\n )}\n {visibleItems.map((item) => {\n const isMarked = markedValues.includes(item.value);\n return (\n <ListItemButton key={item.value} role=\"option\" aria-selected={isMarked} disabled={disabled || item.disabled}\n onClick={() => onMark(item.value)} onDoubleClick={() => onMoveOne(item.value)} sx={{py: 0.25}}>\n <ListItemIcon sx={{minWidth: 32}}>\n <Checkbox size=\"small\" edge=\"start\" tabIndex={-1} disableRipple checked={isMarked} sx={{p: 0.5}} />\n </ListItemIcon>\n <ListItemText primary={item.label} secondary={item.description} />\n </ListItemButton>\n );\n })}\n </List>\n </TransferList>\n );\n}\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {import('react').ReactNode} [props.label] ya traducida\n * @param {Array<string|number>|null|undefined} props.value los elegidos\n * @param {(values: Array<string|number>) => void} props.onChange\n * @param {() => void} [props.onBlur]\n * @param {Array<{value: string|number, label: string, description?: string, disabled?: boolean}>} props.options todos\n * @param {string} [props.availableTitle] ya traducido; por omisión «Disponibles»\n * @param {string} [props.chosenTitle] ya traducido; por omisión «Elegidos»\n * @param {boolean} [props.searchable] un buscador en cada columna (por omisión, con más de 8 opciones)\n * @param {number} [props.listHeight] lo alto de cada columna, en px\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ya traducida\n * @param {boolean} [props.disabled]\n * @param {object} [props.sx]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function TransferListInput(props) {\n const {\n name, label, value, onChange, onBlur, options, availableTitle, chosenTitle, searchable, listHeight = DEFAULT_LIST_HEIGHT, error,\n helperText = ' ', disabled = false, sx, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const generatedId = useId();\n const inputId = `${name ?? 'transfer'}-${generatedId}`;\n const errorText = translateValidationMessage(t, error);\n const chosenValues = Array.isArray(value) ? value : [];\n // lo marcado para pasar, de cada lado\n const [markedAvailable, setMarkedAvailable] = useState([]);\n const [markedChosen, setMarkedChosen] = useState([]);\n const available = options.filter((option) => !chosenValues.includes(option.value));\n // los elegidos en el orden en que se pasaron\n const chosen = chosenValues.map((chosenValue) => options.find((option) => option.value === chosenValue)).filter(Boolean);\n const isSearchable = searchable ?? options.length > 8;\n const titles = {available: availableTitle ?? t('transfer.available'), chosen: chosenTitle ?? t('transfer.chosen')};\n\n const change = (values) => {\n onChange(values);\n onBlur?.();\n };\n const toggleIn = (setMarked) => (itemValue) => setMarked((current) => (\n current.includes(itemValue) ? current.filter((markedValue) => markedValue !== itemValue) : [...current, itemValue]\n ));\n const moveToChosen = (values) => {\n change([...chosenValues, ...values.filter((itemValue) => !chosenValues.includes(itemValue))]);\n setMarkedAvailable((current) => current.filter((markedValue) => !values.includes(markedValue)));\n };\n const moveToAvailable = (values) => {\n change(chosenValues.filter((chosenValue) => !values.includes(chosenValue)));\n setMarkedChosen((current) => current.filter((markedValue) => !values.includes(markedValue)));\n };\n const movableOf = (items) => items.filter((item) => !item.disabled).map((item) => item.value);\n const actionButton = (titleKey, Icon, onClick, isDisabled) => (\n <Tooltip title={t(titleKey)}>\n <span>\n <Button variant=\"outlined\" size=\"small\" aria-label={t(titleKey)} disabled={disabled || isDisabled} onClick={onClick}\n sx={{minWidth: 40, px: 1}}>\n <Icon fontSize=\"small\" sx={PHONE_ROTATION} />\n </Button>\n </span>\n </Tooltip>\n );\n\n const lists = (\n <TransferRoot direction={{xs: 'column', md: 'row'}} ownSx={{gap: 1.5, alignItems: 'stretch', ...sx}} id={inputId}>\n <TransferColumn title={titles.available} items={available} markedValues={markedAvailable}\n onMark={toggleIn(setMarkedAvailable)} onMarkMany={setMarkedAvailable} onMoveOne={(itemValue) => moveToChosen([itemValue])}\n searchable={isSearchable} searchLabel={t('transfer.search')} emptyText={t('transfer.emptyAvailable')}\n listHeight={listHeight} disabled={disabled} t={t} />\n <TransferActions direction={{xs: 'row', md: 'column'}} ownSx={{gap: 1, justifyContent: 'center', alignItems: 'center'}}>\n {actionButton('transfer.moveMarked', ChevronRightRoundedIcon, () => moveToChosen(markedAvailable), markedAvailable.length === 0)}\n {actionButton('transfer.moveAll', KeyboardDoubleArrowRightRoundedIcon, () => moveToChosen(movableOf(available)), movableOf(available).length === 0)}\n {actionButton('transfer.returnMarked', ChevronLeftRoundedIcon, () => moveToAvailable(markedChosen), markedChosen.length === 0)}\n {actionButton('transfer.returnAll', KeyboardDoubleArrowLeftRoundedIcon, () => moveToAvailable(movableOf(chosen)), movableOf(chosen).length === 0)}\n </TransferActions>\n <TransferColumn title={titles.chosen} items={chosen} markedValues={markedChosen}\n onMark={toggleIn(setMarkedChosen)} onMarkMany={setMarkedChosen} onMoveOne={(itemValue) => moveToAvailable([itemValue])}\n searchable={isSearchable} searchLabel={t('transfer.search')} emptyText={t('transfer.emptyChosen')}\n listHeight={listHeight} disabled={disabled} t={t} />\n </TransferRoot>\n );\n\n const field = (\n <div>\n {lists}\n <FormHelperText error={Boolean(errorText)} role={errorText ? 'alert' : undefined}>{errorText ?? helperText}</FormHelperText>\n </div>\n );\n // sin etiqueta va solo (la pantalla pone el título a su manera)\n return label ? <FieldFrame inputId={inputId} label={label}>{field}</FieldFrame> : field;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TransferListInput.js","sources":["../../src/inputs/TransferListInput.jsx"],"sourcesContent":["// La lista de transferencia: dos columnas, «Disponibles» y «Elegidos», y botones para pasar de una a otra. Para elegir\n// muchos de una lista larga viendo siempre qué quedó de cada lado (los usuarios que pueden ver un reporte, las sucursales donde\n// puede comprar un cliente). Al formulario llega la lista de los elegidos, en el orden en que se pasaron.\n//\n// Cada columna trae su título con cuántos tiene, su buscador (searchable) y su casilla de «todos los que se ven» (con algo\n// buscado, solo esos). Se marcan los que se quieren pasar (clic o espacio) y se pasan con ›; » pasa todos los de la\n// columna. Doble clic pasa uno directo. En el teléfono las columnas van una debajo de otra y los botones apuntan hacia\n// abajo y arriba. Va fuera de una FormSection: necesita el ancho completo.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTransferListInput con defaultProps y\n// styleOverrides de sus partes: root, list, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport Button from '@mui/material/Button';\nimport Checkbox from '@mui/material/Checkbox';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport List from '@mui/material/List';\nimport ListItemButton from '@mui/material/ListItemButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport ChevronLeftRoundedIcon from '@mui/icons-material/ChevronLeftRounded';\nimport ChevronRightRoundedIcon from '@mui/icons-material/ChevronRightRounded';\nimport KeyboardDoubleArrowLeftRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowLeftRounded';\nimport KeyboardDoubleArrowRightRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowRightRounded';\n\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {selectAllStateOf} from '@/inputs/selectAllState.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// lo alto de cada columna antes de deslizar\nconst DEFAULT_LIST_HEIGHT = 280;\n// en el teléfono los botones apuntan hacia abajo (pasar) y hacia arriba (regresar)\nconst PHONE_ROTATION = Object.freeze({transform: {xs: 'rotate(90deg)', md: 'none'}});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaTransferListInput)\nconst THEME_NAME = 'CalcitaTransferListInput';\nconst TransferRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst TransferList = piecePart(THEME_NAME, 'List', Paper);\nconst TransferActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/**\n * Un texto sin acentos ni mayúsculas, para que «queretaro» encuentre «Querétaro».\n *\n * @param {unknown} text\n * @returns {string}\n */\nfunction plainTextOf(text) {\n return String(text ?? '').normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase().trim();\n}\n\n/**\n * Una columna: su título con cuántos tiene, su buscador, su casilla de «todos los que se ven» y sus renglones.\n *\n * @param {object} props\n */\nfunction TransferColumn({title, items, markedValues, onMark, onMarkMany, onMoveOne, searchable, searchLabel, emptyText, listHeight, disabled, t}) {\n const titleId = useId();\n const [searchText, setSearchText] = useState('');\n const wantedText = plainTextOf(searchText);\n const visibleItems = wantedText\n ? items.filter((item) => plainTextOf(`${item.label} ${item.description ?? ''}`).includes(wantedText))\n : items;\n const visibleValues = visibleItems.filter((item) => !item.disabled).map((item) => item.value);\n const markState = selectAllStateOf(markedValues, visibleValues);\n\n return (\n <TransferList variant=\"outlined\" ownSx={{flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column'}}>\n <Stack direction=\"row\" sx={{alignItems: 'center', gap: 1, px: 1.5, py: 1, borderBottom: 1, borderColor: 'divider'}}>\n <Checkbox size=\"small\" sx={{p: 0.5}} disabled={disabled || visibleValues.length === 0}\n checked={markState.allChosen} indeterminate={markState.someChosen}\n onChange={() => onMarkMany(markState.toggled())}\n slotProps={{input: {'aria-label': t('transfer.markVisible', {list: title})}}} />\n <Typography id={titleId} variant=\"subtitle2\" sx={{flexGrow: 1}}>{title}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {markedValues.length > 0 ? t('transfer.markedOf', {marked: markedValues.length, count: items.length}) : items.length}\n </Typography>\n </Stack>\n {searchable && (\n <TextField size=\"small\" type=\"search\" value={searchText} onChange={(event) => setSearchText(event.target.value)}\n placeholder={searchLabel} disabled={disabled} sx={{m: 1}}\n slotProps={{htmlInput: {'aria-label': `${searchLabel} · ${title}`}}} />\n )}\n <List dense role=\"listbox\" aria-labelledby={titleId} aria-multiselectable=\"true\"\n sx={{height: listHeight, overflowY: 'auto', py: 0}}>\n {visibleItems.length === 0 && (\n // vacía de verdad o vacía por lo buscado: no es lo mismo y se dice distinto\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{px: 2, py: 1.5}}>\n {items.length > 0 ? t('transfer.noMatches', {text: searchText.trim()}) : emptyText}\n </Typography>\n )}\n {visibleItems.map((item) => {\n const isMarked = markedValues.includes(item.value);\n return (\n <ListItemButton key={item.value} role=\"option\" aria-selected={isMarked} disabled={disabled || item.disabled}\n onClick={() => onMark(item.value)} onDoubleClick={() => onMoveOne(item.value)} sx={{py: 0.25}}>\n <ListItemIcon sx={{minWidth: 32}}>\n <Checkbox size=\"small\" edge=\"start\" tabIndex={-1} disableRipple checked={isMarked} sx={{p: 0.5}} />\n </ListItemIcon>\n <ListItemText primary={item.label} secondary={item.description} />\n </ListItemButton>\n );\n })}\n </List>\n </TransferList>\n );\n}\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {import('react').ReactNode} [props.label] ya traducida\n * @param {Array<string|number>|null|undefined} props.value los elegidos\n * @param {(values: Array<string|number>) => void} props.onChange\n * @param {() => void} [props.onBlur]\n * @param {Array<{value: string|number, label: string, description?: string, disabled?: boolean}>} props.options todos\n * @param {string} [props.availableTitle] ya traducido; por omisión «Disponibles»\n * @param {string} [props.chosenTitle] ya traducido; por omisión «Elegidos»\n * @param {boolean} [props.searchable] un buscador en cada columna (por omisión, con más de 8 opciones)\n * @param {number} [props.listHeight] lo alto de cada columna, en px\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ya traducida\n * @param {boolean} [props.disabled]\n * @param {object} [props.sx]\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction TransferListInputContent(props) {\n const {\n name, label, value, onChange, onBlur, options, availableTitle, chosenTitle, searchable, listHeight = DEFAULT_LIST_HEIGHT, error,\n helperText = ' ', disabled = false, sx, messages, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // el texto del error: el de la pantalla (messages), el del proyecto para este campo o el de Calcita\n const validationTextOf = useValidationText({name, label, messages});\n const generatedId = useId();\n const inputId = `${name ?? 'transfer'}-${generatedId}`;\n const errorText = validationTextOf(error);\n const chosenValues = Array.isArray(value) ? value : [];\n // lo marcado para pasar, de cada lado\n const [markedAvailable, setMarkedAvailable] = useState([]);\n const [markedChosen, setMarkedChosen] = useState([]);\n const available = options.filter((option) => !chosenValues.includes(option.value));\n // los elegidos en el orden en que se pasaron\n const chosen = chosenValues.map((chosenValue) => options.find((option) => option.value === chosenValue)).filter(Boolean);\n const isSearchable = searchable ?? options.length > 8;\n const titles = {available: availableTitle ?? t('transfer.available'), chosen: chosenTitle ?? t('transfer.chosen')};\n\n const change = (values) => {\n onChange(values);\n onBlur?.();\n };\n const toggleIn = (setMarked) => (itemValue) => setMarked((current) => (\n current.includes(itemValue) ? current.filter((markedValue) => markedValue !== itemValue) : [...current, itemValue]\n ));\n const moveToChosen = (values) => {\n change([...chosenValues, ...values.filter((itemValue) => !chosenValues.includes(itemValue))]);\n setMarkedAvailable((current) => current.filter((markedValue) => !values.includes(markedValue)));\n };\n const moveToAvailable = (values) => {\n change(chosenValues.filter((chosenValue) => !values.includes(chosenValue)));\n setMarkedChosen((current) => current.filter((markedValue) => !values.includes(markedValue)));\n };\n const movableOf = (items) => items.filter((item) => !item.disabled).map((item) => item.value);\n const actionButton = (titleKey, Icon, onClick, isDisabled) => (\n <Tooltip title={t(titleKey)}>\n <span>\n <Button variant=\"outlined\" size=\"small\" aria-label={t(titleKey)} disabled={disabled || isDisabled} onClick={onClick}\n sx={{minWidth: 40, px: 1}}>\n <Icon fontSize=\"small\" sx={PHONE_ROTATION} />\n </Button>\n </span>\n </Tooltip>\n );\n\n const lists = (\n <TransferRoot direction={{xs: 'column', md: 'row'}} ownSx={{gap: 1.5, alignItems: 'stretch'}} sx={sx} id={inputId}>\n <TransferColumn title={titles.available} items={available} markedValues={markedAvailable}\n onMark={toggleIn(setMarkedAvailable)} onMarkMany={setMarkedAvailable} onMoveOne={(itemValue) => moveToChosen([itemValue])}\n searchable={isSearchable} searchLabel={t('transfer.search')} emptyText={t('transfer.emptyAvailable')}\n listHeight={listHeight} disabled={disabled} t={t} />\n <TransferActions direction={{xs: 'row', md: 'column'}} ownSx={{gap: 1, justifyContent: 'center', alignItems: 'center'}}>\n {actionButton('transfer.moveMarked', ChevronRightRoundedIcon, () => moveToChosen(markedAvailable), markedAvailable.length === 0)}\n {actionButton('transfer.moveAll', KeyboardDoubleArrowRightRoundedIcon, () => moveToChosen(movableOf(available)), movableOf(available).length === 0)}\n {actionButton('transfer.returnMarked', ChevronLeftRoundedIcon, () => moveToAvailable(markedChosen), markedChosen.length === 0)}\n {actionButton('transfer.returnAll', KeyboardDoubleArrowLeftRoundedIcon, () => moveToAvailable(movableOf(chosen)), movableOf(chosen).length === 0)}\n </TransferActions>\n <TransferColumn title={titles.chosen} items={chosen} markedValues={markedChosen}\n onMark={toggleIn(setMarkedChosen)} onMarkMany={setMarkedChosen} onMoveOne={(itemValue) => moveToAvailable([itemValue])}\n searchable={isSearchable} searchLabel={t('transfer.search')} emptyText={t('transfer.emptyChosen')}\n listHeight={listHeight} disabled={disabled} t={t} />\n </TransferRoot>\n );\n\n const field = (\n <div>\n {lists}\n <FormHelperText error={Boolean(errorText)} role={errorText ? 'alert' : undefined}>{errorText ?? helperText}</FormHelperText>\n </div>\n );\n // sin etiqueta va solo (la pantalla pone el título a su manera)\n return label ? <FieldFrame inputId={inputId} label={label}>{field}</FieldFrame> : field;\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst TransferListInput = withPieceSlots(TransferListInputContent, THEME_NAME);\nexport default TransferListInput;\n"],"names":[],"mappings":"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"}
@@ -8,13 +8,13 @@ import Step from "@mui/material/Step";
8
8
  import StepLabel from "@mui/material/StepLabel";
9
9
  import Stepper from "@mui/material/Stepper";
10
10
  import Typography from "@mui/material/Typography";
11
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
11
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
12
12
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
13
13
  const THEME_NAME = "CalcitaWizardLayout";
14
14
  const WizardStepper = piecePart(THEME_NAME, "Stepper", Stepper);
15
15
  const WizardPhoneSteps = piecePart(THEME_NAME, "PhoneSteps", Box);
16
16
  const WizardActions = piecePart(THEME_NAME, "Actions", Stack);
17
- function WizardLayout(props) {
17
+ function WizardLayoutContent(props) {
18
18
  const {
19
19
  steps,
20
20
  activeIndex,
@@ -57,6 +57,7 @@ function WizardLayout(props) {
57
57
  ] })
58
58
  ] });
59
59
  }
60
+ const WizardLayout = withPieceSlots(WizardLayoutContent, THEME_NAME);
60
61
  export {
61
62
  WizardLayout as default
62
63
  };
@@ -1 +1 @@
1
- {"version":3,"file":"WizardLayout.js","sources":["../../src/inputs/WizardLayout.jsx"],"sourcesContent":["// Lo que se ve de un formulario por pasos: los pasos arriba (en el teléfono, «Paso 2 de 4» y su nombre), los campos del paso\n// y los botones (Anterior · Omitir este paso · Siguiente o Enviar). No sabe de formik ni de react-hook-form: el FormWizard de\n// cada uno (/forms y /react-hook-form) pone la lógica (qué revisa «Siguiente», qué hace «Omitir») y le pasa su botón de\n// enviar y su aviso de errores. Suelto sirve para armar un asistente propio con otra librería.\n//\n// Los textos se cambian con `texts`, con la forma de `common` en los textos del paquete: {wizard: {next: 'Continuar'}}.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaWizardLayout con defaultProps y\n// styleOverrides de sus partes: stepper, phoneSteps, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Step from '@mui/material/Step';\nimport StepLabel from '@mui/material/StepLabel';\nimport Stepper from '@mui/material/Stepper';\nimport Typography from '@mui/material/Typography';\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.CalcitaWizardLayout)\nconst THEME_NAME = 'CalcitaWizardLayout';\nconst WizardStepper = piecePart(THEME_NAME, 'Stepper', Stepper);\nconst WizardPhoneSteps = piecePart(THEME_NAME, 'PhoneSteps', Box);\nconst WizardActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/**\n * @param {object} props\n * @param {Object[]} props.steps en orden\n * @param {string} props.steps[].key\n * @param {string} props.steps[].label ya traducido\n * @param {boolean} [props.steps[].optional] se puede omitir\n * @param {import('react').ReactNode} props.steps[].content los campos del paso\n * @param {number} props.activeIndex el paso que se ve\n * @param {Set<string>} props.skippedKeys los pasos omitidos\n * @param {boolean} [props.isSubmitting] mientras se envía, «Anterior» se apaga\n * @param {() => void} props.onBack\n * @param {() => void} props.onNext\n * @param {() => void} props.onSkip\n * @param {import('react').ReactNode} props.submitButton el botón de enviar del último paso\n * @param {import('react').ReactNode} [props.problemAlert] el aviso de errores del servidor, arriba de los botones del último paso\n * @param {object} [props.texts] los textos que cambian, con la forma de `common`: {wizard: {next, back, skip, optional, skipped, stepOf}}\n */\nexport default function WizardLayout(props) {\n // lo que el proyecto puso en su tema (components.CalcitaWizardLayout.defaultProps) y encima lo que llega aquí\n const {\n steps, activeIndex, skippedKeys, isSubmitting = false, onBack, onNext, onSkip, submitButton, problemAlert, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const activeStep = steps[activeIndex];\n const isLastStep = activeIndex === steps.length - 1;\n\n return (\n <Stack spacing={3}>\n {/* en el teléfono los nombres de los pasos no caben: se dice en qué paso va */}\n <WizardStepper activeStep={activeIndex} alternativeLabel ownSx={{display: {xs: 'none', sm: 'flex'}}}>\n {steps.map((step) => {\n let caption;\n if (skippedKeys.has(step.key)) {\n caption = t('wizard.skipped');\n } else if (step.optional) {\n caption = t('wizard.optional');\n }\n return (\n <Step key={step.key} completed={skippedKeys.has(step.key) ? false : undefined}>\n <StepLabel optional={caption && <Typography variant=\"caption\" color=\"text.secondary\">{caption}</Typography>}>\n {step.label}\n </StepLabel>\n </Step>\n );\n })}\n </WizardStepper>\n <WizardPhoneSteps ownSx={{display: {xs: 'block', sm: 'none'}}}>\n <Typography variant=\"overline\" color=\"text.secondary\">{t('wizard.stepOf', {current: activeIndex + 1, total: steps.length})}</Typography>\n <Typography variant=\"h6\">{activeStep.label}</Typography>\n </WizardPhoneSteps>\n\n <Box>{activeStep.content}</Box>\n\n {isLastStep && problemAlert}\n\n <WizardActions direction={{xs: 'column-reverse', sm: 'row'}} spacing={1.5} ownSx={{justifyContent: 'space-between'}}>\n <Button variant=\"text\" color=\"inherit\" disabled={activeIndex === 0 || isSubmitting} onClick={onBack}>\n {t('wizard.back')}\n </Button>\n <Stack direction={{xs: 'column-reverse', sm: 'row'}} spacing={1.5}>\n {activeStep.optional && !isLastStep && (\n <Button variant=\"text\" onClick={onSkip}>{t('wizard.skip')}</Button>\n )}\n {isLastStep\n ? submitButton\n : <Button variant=\"contained\" size=\"large\" onClick={onNext}>{t('wizard.next')}</Button>}\n </Stack>\n </WizardActions>\n </Stack>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAuBA,MAAM,aAAa;AACnB,MAAM,gBAAgB,UAAU,YAAY,WAAW,OAAO;AAC9D,MAAM,mBAAmB,UAAU,YAAY,cAAc,GAAG;AAChE,MAAM,gBAAgB,UAAU,YAAY,WAAW,KAAK;AAmB5D,SAAwB,aAAa,OAAO;AAExC,QAAM;AAAA,IACN;AAAA,IAAO;AAAA,IAAa;AAAA,IAAa,eAAe;AAAA,IAAO;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAc;AAAA,IAAc;AAAA,IAC3G,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,aAAa,MAAM,WAAW;AACpC,QAAM,aAAa,gBAAgB,MAAM,SAAS;AAElD,SACI,qBAAC,OAAA,EAAM,SAAS,GAEZ,UAAA;AAAA,IAAA,oBAAC,iBAAc,YAAY,aAAa,kBAAgB,MAAC,OAAO,EAAC,SAAS,EAAC,IAAI,QAAQ,IAAI,OAAA,EAAM,GAC5F,UAAA,MAAM,IAAI,CAAC,SAAS;AACjB,UAAI;AACJ,UAAI,YAAY,IAAI,KAAK,GAAG,GAAG;AAC3B,kBAAU,EAAE,gBAAgB;AAAA,MAChC,WAAW,KAAK,UAAU;AACtB,kBAAU,EAAE,iBAAiB;AAAA,MACjC;AACA,aACI,oBAAC,MAAA,EAAoB,WAAW,YAAY,IAAI,KAAK,GAAG,IAAI,QAAQ,QAChE,UAAA,oBAAC,WAAA,EAAU,UAAU,WAAW,oBAAC,YAAA,EAAW,SAAQ,WAAU,OAAM,kBAAkB,UAAA,QAAA,CAAQ,GACzF,UAAA,KAAK,MAAA,CACV,EAAA,GAHO,KAAK,GAIhB;AAAA,IAER,CAAC,EAAA,CACL;AAAA,IACA,qBAAC,kBAAA,EAAiB,OAAO,EAAC,SAAS,EAAC,IAAI,SAAS,IAAI,OAAA,EAAM,GACvD,UAAA;AAAA,MAAA,oBAAC,YAAA,EAAW,SAAQ,YAAW,OAAM,kBAAkB,UAAA,EAAE,iBAAiB,EAAC,SAAS,cAAc,GAAG,OAAO,MAAM,OAAA,CAAO,GAAE;AAAA,MAC3H,oBAAC,YAAA,EAAW,SAAQ,MAAM,qBAAW,MAAA,CAAM;AAAA,IAAA,GAC/C;AAAA,IAEA,oBAAC,KAAA,EAAK,UAAA,WAAW,QAAA,CAAQ;AAAA,IAExB,cAAc;AAAA,IAEf,qBAAC,eAAA,EAAc,WAAW,EAAC,IAAI,kBAAkB,IAAI,MAAA,GAAQ,SAAS,KAAK,OAAO,EAAC,gBAAgB,mBAC/F,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAO,SAAQ,QAAO,OAAM,WAAU,UAAU,gBAAgB,KAAK,cAAc,SAAS,QACxF,UAAA,EAAE,aAAa,GACpB;AAAA,MACA,qBAAC,OAAA,EAAM,WAAW,EAAC,IAAI,kBAAkB,IAAI,MAAA,GAAQ,SAAS,KACzD,UAAA;AAAA,QAAA,WAAW,YAAY,CAAC,cACrB,oBAAC,QAAA,EAAO,SAAQ,QAAO,SAAS,QAAS,UAAA,EAAE,aAAa,EAAA,CAAE;AAAA,QAE7D,aACK,eACA,oBAAC,QAAA,EAAO,SAAQ,aAAY,MAAK,SAAQ,SAAS,QAAS,UAAA,EAAE,aAAa,EAAA,CAAE;AAAA,MAAA,EAAA,CACtF;AAAA,IAAA,EAAA,CACJ;AAAA,EAAA,GACJ;AAER;"}
1
+ {"version":3,"file":"WizardLayout.js","sources":["../../src/inputs/WizardLayout.jsx"],"sourcesContent":["// Lo que se ve de un formulario por pasos: los pasos arriba (en el teléfono, «Paso 2 de 4» y su nombre), los campos del paso\n// y los botones (Anterior · Omitir este paso · Siguiente o Enviar). No sabe de formik ni de react-hook-form: el FormWizard de\n// cada uno (/forms y /react-hook-form) pone la lógica (qué revisa «Siguiente», qué hace «Omitir») y le pasa su botón de\n// enviar y su aviso de errores. Suelto sirve para armar un asistente propio con otra librería.\n//\n// Los textos se cambian con `texts`, con la forma de `common` en los textos del paquete: {wizard: {next: 'Continuar'}}.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaWizardLayout con defaultProps y\n// styleOverrides de sus partes: stepper, phoneSteps, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Step from '@mui/material/Step';\nimport StepLabel from '@mui/material/StepLabel';\nimport Stepper from '@mui/material/Stepper';\nimport Typography from '@mui/material/Typography';\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.CalcitaWizardLayout)\nconst THEME_NAME = 'CalcitaWizardLayout';\nconst WizardStepper = piecePart(THEME_NAME, 'Stepper', Stepper);\nconst WizardPhoneSteps = piecePart(THEME_NAME, 'PhoneSteps', Box);\nconst WizardActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/**\n * @param {object} props\n * @param {Object[]} props.steps en orden\n * @param {string} props.steps[].key\n * @param {string} props.steps[].label ya traducido\n * @param {boolean} [props.steps[].optional] se puede omitir\n * @param {import('react').ReactNode} props.steps[].content los campos del paso\n * @param {number} props.activeIndex el paso que se ve\n * @param {Set<string>} props.skippedKeys los pasos omitidos\n * @param {boolean} [props.isSubmitting] mientras se envía, «Anterior» se apaga\n * @param {() => void} props.onBack\n * @param {() => void} props.onNext\n * @param {() => void} props.onSkip\n * @param {import('react').ReactNode} props.submitButton el botón de enviar del último paso\n * @param {import('react').ReactNode} [props.problemAlert] el aviso de errores del servidor, arriba de los botones del último paso\n * @param {object} [props.texts] los textos que cambian, con la forma de `common`: {wizard: {next, back, skip, optional, skipped, stepOf}}\n */\nfunction WizardLayoutContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaWizardLayout.defaultProps) y encima lo que llega aquí\n const {\n steps, activeIndex, skippedKeys, isSubmitting = false, onBack, onNext, onSkip, submitButton, problemAlert, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const activeStep = steps[activeIndex];\n const isLastStep = activeIndex === steps.length - 1;\n\n return (\n <Stack spacing={3}>\n {/* en el teléfono los nombres de los pasos no caben: se dice en qué paso va */}\n <WizardStepper activeStep={activeIndex} alternativeLabel ownSx={{display: {xs: 'none', sm: 'flex'}}}>\n {steps.map((step) => {\n let caption;\n if (skippedKeys.has(step.key)) {\n caption = t('wizard.skipped');\n } else if (step.optional) {\n caption = t('wizard.optional');\n }\n return (\n <Step key={step.key} completed={skippedKeys.has(step.key) ? false : undefined}>\n <StepLabel optional={caption && <Typography variant=\"caption\" color=\"text.secondary\">{caption}</Typography>}>\n {step.label}\n </StepLabel>\n </Step>\n );\n })}\n </WizardStepper>\n <WizardPhoneSteps ownSx={{display: {xs: 'block', sm: 'none'}}}>\n <Typography variant=\"overline\" color=\"text.secondary\">{t('wizard.stepOf', {current: activeIndex + 1, total: steps.length})}</Typography>\n <Typography variant=\"h6\">{activeStep.label}</Typography>\n </WizardPhoneSteps>\n\n <Box>{activeStep.content}</Box>\n\n {isLastStep && problemAlert}\n\n <WizardActions direction={{xs: 'column-reverse', sm: 'row'}} spacing={1.5} ownSx={{justifyContent: 'space-between'}}>\n <Button variant=\"text\" color=\"inherit\" disabled={activeIndex === 0 || isSubmitting} onClick={onBack}>\n {t('wizard.back')}\n </Button>\n <Stack direction={{xs: 'column-reverse', sm: 'row'}} spacing={1.5}>\n {activeStep.optional && !isLastStep && (\n <Button variant=\"text\" onClick={onSkip}>{t('wizard.skip')}</Button>\n )}\n {isLastStep\n ? submitButton\n : <Button variant=\"contained\" size=\"large\" onClick={onNext}>{t('wizard.next')}</Button>}\n </Stack>\n </WizardActions>\n </Stack>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst WizardLayout = withPieceSlots(WizardLayoutContent, THEME_NAME);\nexport default WizardLayout;\n"],"names":[],"mappings":";;;;;;;;;;;;AAuBA,MAAM,aAAa;AACnB,MAAM,gBAAgB,UAAU,YAAY,WAAW,OAAO;AAC9D,MAAM,mBAAmB,UAAU,YAAY,cAAc,GAAG;AAChE,MAAM,gBAAgB,UAAU,YAAY,WAAW,KAAK;AAmB5D,SAAS,oBAAoB,OAAO;AAEhC,QAAM;AAAA,IACN;AAAA,IAAO;AAAA,IAAa;AAAA,IAAa,eAAe;AAAA,IAAO;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAc;AAAA,IAAc;AAAA,IAC3G,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,aAAa,MAAM,WAAW;AACpC,QAAM,aAAa,gBAAgB,MAAM,SAAS;AAElD,SACI,qBAAC,OAAA,EAAM,SAAS,GAEZ,UAAA;AAAA,IAAA,oBAAC,iBAAc,YAAY,aAAa,kBAAgB,MAAC,OAAO,EAAC,SAAS,EAAC,IAAI,QAAQ,IAAI,OAAA,EAAM,GAC5F,UAAA,MAAM,IAAI,CAAC,SAAS;AACjB,UAAI;AACJ,UAAI,YAAY,IAAI,KAAK,GAAG,GAAG;AAC3B,kBAAU,EAAE,gBAAgB;AAAA,MAChC,WAAW,KAAK,UAAU;AACtB,kBAAU,EAAE,iBAAiB;AAAA,MACjC;AACA,aACI,oBAAC,MAAA,EAAoB,WAAW,YAAY,IAAI,KAAK,GAAG,IAAI,QAAQ,QAChE,UAAA,oBAAC,WAAA,EAAU,UAAU,WAAW,oBAAC,YAAA,EAAW,SAAQ,WAAU,OAAM,kBAAkB,UAAA,QAAA,CAAQ,GACzF,UAAA,KAAK,MAAA,CACV,EAAA,GAHO,KAAK,GAIhB;AAAA,IAER,CAAC,EAAA,CACL;AAAA,IACA,qBAAC,kBAAA,EAAiB,OAAO,EAAC,SAAS,EAAC,IAAI,SAAS,IAAI,OAAA,EAAM,GACvD,UAAA;AAAA,MAAA,oBAAC,YAAA,EAAW,SAAQ,YAAW,OAAM,kBAAkB,UAAA,EAAE,iBAAiB,EAAC,SAAS,cAAc,GAAG,OAAO,MAAM,OAAA,CAAO,GAAE;AAAA,MAC3H,oBAAC,YAAA,EAAW,SAAQ,MAAM,qBAAW,MAAA,CAAM;AAAA,IAAA,GAC/C;AAAA,IAEA,oBAAC,KAAA,EAAK,UAAA,WAAW,QAAA,CAAQ;AAAA,IAExB,cAAc;AAAA,IAEf,qBAAC,eAAA,EAAc,WAAW,EAAC,IAAI,kBAAkB,IAAI,MAAA,GAAQ,SAAS,KAAK,OAAO,EAAC,gBAAgB,mBAC/F,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAO,SAAQ,QAAO,OAAM,WAAU,UAAU,gBAAgB,KAAK,cAAc,SAAS,QACxF,UAAA,EAAE,aAAa,GACpB;AAAA,MACA,qBAAC,OAAA,EAAM,WAAW,EAAC,IAAI,kBAAkB,IAAI,MAAA,GAAQ,SAAS,KACzD,UAAA;AAAA,QAAA,WAAW,YAAY,CAAC,cACrB,oBAAC,QAAA,EAAO,SAAQ,QAAO,SAAS,QAAS,UAAA,EAAE,aAAa,EAAA,CAAE;AAAA,QAE7D,aACK,eACA,oBAAC,QAAA,EAAO,SAAQ,aAAY,MAAK,SAAQ,SAAS,QAAS,UAAA,EAAE,aAAa,EAAA,CAAE;AAAA,MAAA,EAAA,CACtF;AAAA,IAAA,EAAA,CACJ;AAAA,EAAA,GACJ;AAER;AAGA,MAAM,eAAe,eAAe,qBAAqB,UAAU;"}
@@ -27,7 +27,7 @@ import { DUE_STATUS, todayIsoDateOf, dueStatusOf } from "./kanbanCards.js";
27
27
  import { cardsOfColumn, isOverLimit } from "./kanbanMoves.js";
28
28
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
29
29
  import ActionsMenu from "../ui/actions/ActionsMenu.js";
30
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
30
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
31
31
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
32
32
  import { tagOf } from "../ui/labels/tagOf.js";
33
33
  const THEME_NAME = "CalcitaKanbanBoard";
@@ -180,7 +180,7 @@ function QuickAdd({ columnTitle, onAdd, onClose, t }) {
180
180
  }
181
181
  );
182
182
  }
183
- function KanbanBoard(props) {
183
+ function KanbanBoardContent(props) {
184
184
  const {
185
185
  columns,
186
186
  cards,
@@ -367,6 +367,7 @@ function KanbanBoard(props) {
367
367
  );
368
368
  }) }) });
369
369
  }
370
+ const KanbanBoard = withPieceSlots(KanbanBoardContent, THEME_NAME);
370
371
  export {
371
372
  KanbanBoard as default
372
373
  };