@stackcraftmx/calcita 0.23.0 → 0.26.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 (403) hide show
  1. package/README.md +127 -22
  2. package/cli/projectFiles.js +5 -3
  3. package/cli/templates/project/README.md.tpl +28 -0
  4. package/cli/templates/project/public/manifest.webmanifest.tpl +6 -6
  5. package/cli/templates/project/src/app/AppProviders.jsx.tpl +9 -4
  6. package/cli/templates/project/src/app/appRouter.jsx.tpl +4 -2
  7. package/cli/templates/project/src/app/appSettings.js.tpl +14 -0
  8. package/cli/templates/project/src/core/AppLogo.jsx.tpl +3 -1
  9. package/cli/templates/project/src/core/index.js.tpl +1 -0
  10. package/cli/templates/project/src/core/publicPaths.js.tpl +24 -0
  11. package/cli/templates/project/vite.config.js.tpl +27 -1
  12. package/dist/DataTable/AuditTrailTable.js +5 -3
  13. package/dist/DataTable/AuditTrailTable.js.map +1 -1
  14. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +2 -1
  15. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
  16. package/dist/DataTable/EmptyState.js +2 -2
  17. package/dist/DataTable/EmptyState.js.map +1 -1
  18. package/dist/DataTable/FilterChips.js +2 -2
  19. package/dist/DataTable/FilterChips.js.map +1 -1
  20. package/dist/DataTable/GoToPage.js +4 -3
  21. package/dist/DataTable/GoToPage.js.map +1 -1
  22. package/dist/DataTable/ServerTable.js +153 -83
  23. package/dist/DataTable/ServerTable.js.map +1 -1
  24. package/dist/DataTable/rowSelection.js +61 -0
  25. package/dist/DataTable/rowSelection.js.map +1 -0
  26. package/dist/access/PermissionMatrix.js +3 -2
  27. package/dist/access/PermissionMatrix.js.map +1 -1
  28. package/dist/account/AccountSecuritySection.js +2 -2
  29. package/dist/account/AccountSecuritySection.js.map +1 -1
  30. package/dist/account/ForgotPasswordScreen.js +5 -4
  31. package/dist/account/ForgotPasswordScreen.js.map +1 -1
  32. package/dist/account/ProfileScreen.js +39 -13
  33. package/dist/account/ProfileScreen.js.map +1 -1
  34. package/dist/account/ResetPasswordScreen.js +3 -2
  35. package/dist/account/ResetPasswordScreen.js.map +1 -1
  36. package/dist/account/SignInScreen.js +7 -6
  37. package/dist/account/SignInScreen.js.map +1 -1
  38. package/dist/account/accountConnector.js.map +1 -1
  39. package/dist/account/restAccountConnector.js +2 -1
  40. package/dist/account/restAccountConnector.js.map +1 -1
  41. package/dist/adapters/reactRouterRoutes.js +7 -6
  42. package/dist/adapters/reactRouterRoutes.js.map +1 -1
  43. package/dist/api/createApiClient.js +40 -5
  44. package/dist/api/createApiClient.js.map +1 -1
  45. package/dist/appShell/AccountMenu.js +15 -23
  46. package/dist/appShell/AccountMenu.js.map +1 -1
  47. package/dist/appShell/AppLayout.js +42 -15
  48. package/dist/appShell/AppLayout.js.map +1 -1
  49. package/dist/appShell/AppearanceSettings.js +29 -6
  50. package/dist/appShell/AppearanceSettings.js.map +1 -1
  51. package/dist/appShell/AuthLayout.js +2 -0
  52. package/dist/appShell/AuthLayout.js.map +1 -1
  53. package/dist/appShell/BarActionButton.js +3 -3
  54. package/dist/appShell/BarActionButton.js.map +1 -1
  55. package/dist/appShell/BarActions.js +19 -8
  56. package/dist/appShell/BarActions.js.map +1 -1
  57. package/dist/appShell/BarCapsule.js +19 -4
  58. package/dist/appShell/BarCapsule.js.map +1 -1
  59. package/dist/appShell/BarSearch.js +92 -0
  60. package/dist/appShell/BarSearch.js.map +1 -0
  61. package/dist/appShell/HeaderTools.js +4 -2
  62. package/dist/appShell/HeaderTools.js.map +1 -1
  63. package/dist/appShell/MenuLinks.js +36 -0
  64. package/dist/appShell/MenuLinks.js.map +1 -0
  65. package/dist/appShell/MobileTabBar.js +6 -4
  66. package/dist/appShell/MobileTabBar.js.map +1 -1
  67. package/dist/appShell/SettingsMenu.js +10 -5
  68. package/dist/appShell/SettingsMenu.js.map +1 -1
  69. package/dist/appShell/SideMenu.js +5 -3
  70. package/dist/appShell/SideMenu.js.map +1 -1
  71. package/dist/appShell/SideMenuEntry.js +3 -3
  72. package/dist/appShell/SideMenuEntry.js.map +1 -1
  73. package/dist/appShell/SubmenuActionsMenu.js +3 -4
  74. package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
  75. package/dist/appShell/TopMenu.js +5 -6
  76. package/dist/appShell/TopMenu.js.map +1 -1
  77. package/dist/appShell/Wordmark.js +11 -0
  78. package/dist/appShell/Wordmark.js.map +1 -0
  79. package/dist/appShell/menuItemText.js +4 -0
  80. package/dist/appShell/menuItemText.js.map +1 -1
  81. package/dist/appShell/shellSizes.js +2 -0
  82. package/dist/appShell/shellSizes.js.map +1 -1
  83. package/dist/auth/PasswordChecklist.js +2 -2
  84. package/dist/auth/PasswordChecklist.js.map +1 -1
  85. package/dist/calendar/EventCalendar.js +16 -5
  86. package/dist/calendar/EventCalendar.js.map +1 -1
  87. package/dist/calendar/EventDetails.js +74 -0
  88. package/dist/calendar/EventDetails.js.map +1 -0
  89. package/dist/calendar/calendarEvents.js +31 -0
  90. package/dist/calendar/calendarEvents.js.map +1 -0
  91. package/dist/calendar.js +8 -1
  92. package/dist/calendar.js.map +1 -1
  93. package/dist/charts.js +10 -1
  94. package/dist/charts.js.map +1 -1
  95. package/dist/datePickers/DateInput.js +3 -2
  96. package/dist/datePickers/DateInput.js.map +1 -1
  97. package/dist/downloads/DownloadManager.js +14 -20
  98. package/dist/downloads/DownloadManager.js.map +1 -1
  99. package/dist/downloads/downloadQueue.js +4 -2
  100. package/dist/downloads/downloadQueue.js.map +1 -1
  101. package/dist/downloads/downloadsMachine.js +4 -1
  102. package/dist/downloads/downloadsMachine.js.map +1 -1
  103. package/dist/downloads/fileTypes.js +22 -0
  104. package/dist/downloads/fileTypes.js.map +1 -0
  105. package/dist/feedback/ConfirmDialog.js +3 -2
  106. package/dist/feedback/ConfirmDialog.js.map +1 -1
  107. package/dist/feedback/ModalWaiting.js +2 -2
  108. package/dist/feedback/ModalWaiting.js.map +1 -1
  109. package/dist/feedback/NewBuildNotice.js +2 -2
  110. package/dist/feedback/NewBuildNotice.js.map +1 -1
  111. package/dist/filepond/FileDropzone.js +5 -3
  112. package/dist/filepond/FileDropzone.js.map +1 -1
  113. package/dist/formatting.js +171 -143
  114. package/dist/formatting.js.map +1 -1
  115. package/dist/forms/FormWizard.js +18 -45
  116. package/dist/forms/FormWizard.js.map +1 -1
  117. package/dist/forms/auth/ChangePasswordForm.js +5 -4
  118. package/dist/forms/auth/ChangePasswordForm.js.map +1 -1
  119. package/dist/forms/auth/ForgotPasswordForm.js +2 -2
  120. package/dist/forms/auth/ForgotPasswordForm.js.map +1 -1
  121. package/dist/forms/auth/SignInForm.js +2 -2
  122. package/dist/forms/auth/SignInForm.js.map +1 -1
  123. package/dist/forms/security/SecondStepForm.js +2 -2
  124. package/dist/forms/security/SecondStepForm.js.map +1 -1
  125. package/dist/forms/security/TwoStepVerificationCard.js +8 -6
  126. package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
  127. package/dist/hookForm/FormWizard.js +59 -0
  128. package/dist/hookForm/FormWizard.js.map +1 -0
  129. package/dist/inbox/InboxLayout.js +44 -8
  130. package/dist/inbox/InboxLayout.js.map +1 -1
  131. package/dist/inbox/MessageList.js +71 -21
  132. package/dist/inbox/MessageList.js.map +1 -1
  133. package/dist/inbox/MessageView.js +80 -29
  134. package/dist/inbox/MessageView.js.map +1 -1
  135. package/dist/inbox/inboxDates.js +4 -3
  136. package/dist/inbox/inboxDates.js.map +1 -1
  137. package/dist/index.js +163 -136
  138. package/dist/index.js.map +1 -1
  139. package/dist/inputs/CatalogInput.js +8 -4
  140. package/dist/inputs/CatalogInput.js.map +1 -1
  141. package/dist/inputs/ColorInput.js +3 -2
  142. package/dist/inputs/ColorInput.js.map +1 -1
  143. package/dist/inputs/FormSection.js +3 -3
  144. package/dist/inputs/FormSection.js.map +1 -1
  145. package/dist/inputs/NumberInput.js +3 -2
  146. package/dist/inputs/NumberInput.js.map +1 -1
  147. package/dist/inputs/SelectInput.js +29 -11
  148. package/dist/inputs/SelectInput.js.map +1 -1
  149. package/dist/inputs/TextInput.js +6 -2
  150. package/dist/inputs/TextInput.js.map +1 -1
  151. package/dist/inputs/WizardLayout.js +54 -0
  152. package/dist/inputs/WizardLayout.js.map +1 -0
  153. package/dist/kanban/KanbanBoard.js +239 -14
  154. package/dist/kanban/KanbanBoard.js.map +1 -1
  155. package/dist/kanban/kanbanCards.js +19 -0
  156. package/dist/kanban/kanbanCards.js.map +1 -0
  157. package/dist/kanban.js +7 -1
  158. package/dist/kanban.js.map +1 -1
  159. package/dist/locales/en.js +74 -1
  160. package/dist/locales/en.js.map +1 -1
  161. package/dist/locales/es.js +74 -1
  162. package/dist/locales/es.js.map +1 -1
  163. package/dist/maps/MapView.js +28 -8
  164. package/dist/maps/MapView.js.map +1 -1
  165. package/dist/navigation/appMenu.js +13 -1
  166. package/dist/navigation/appMenu.js.map +1 -1
  167. package/dist/observability/logger.js +18 -0
  168. package/dist/observability/logger.js.map +1 -1
  169. package/dist/observability/usePublishedBuildWatch.js +4 -3
  170. package/dist/observability/usePublishedBuildWatch.js.map +1 -1
  171. package/dist/pwa/InstallAppSetting.js +6 -5
  172. package/dist/pwa/InstallAppSetting.js.map +1 -1
  173. package/dist/pwa/InstallInstructionsDialog.js +2 -2
  174. package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
  175. package/dist/pwa/InstallPromptBanner.js +15 -9
  176. package/dist/pwa/InstallPromptBanner.js.map +1 -1
  177. package/dist/pwa/useInstallPrompt.js +2 -1
  178. package/dist/pwa/useInstallPrompt.js.map +1 -1
  179. package/dist/react-hook-form.js +6 -4
  180. package/dist/react-hook-form.js.map +1 -1
  181. package/dist/security/ActivityLog.js +4 -3
  182. package/dist/security/ActivityLog.js.map +1 -1
  183. package/dist/security/RecoveryCodesDialog.js +4 -3
  184. package/dist/security/RecoveryCodesDialog.js.map +1 -1
  185. package/dist/security/SessionsCard.js +8 -6
  186. package/dist/security/SessionsCard.js.map +1 -1
  187. package/dist/table.js +2 -0
  188. package/dist/table.js.map +1 -1
  189. package/dist/theme/components/MuiAppBar.js +6 -5
  190. package/dist/theme/components/MuiAppBar.js.map +1 -1
  191. package/dist/theme/components/MuiDialog.js +13 -0
  192. package/dist/theme/components/MuiDialog.js.map +1 -0
  193. package/dist/theme/components/glassComponents.js +32 -31
  194. package/dist/theme/components/glassComponents.js.map +1 -1
  195. package/dist/theme/components/minimalComponents.js +8 -4
  196. package/dist/theme/components/minimalComponents.js.map +1 -1
  197. package/dist/theme/createToolkitTheme.js.map +1 -1
  198. package/dist/theme/glassSurface.js +36 -38
  199. package/dist/theme/glassSurface.js.map +1 -1
  200. package/dist/theme/lightDarkStyles.js +48 -0
  201. package/dist/theme/lightDarkStyles.js.map +1 -0
  202. package/dist/theme/toolkitComponents.js +2 -0
  203. package/dist/theme/toolkitComponents.js.map +1 -1
  204. package/dist/toolkit/ComponentTexts.js +13 -0
  205. package/dist/toolkit/ComponentTexts.js.map +1 -0
  206. package/dist/toolkit/ToolkitProvider.js +36 -28
  207. package/dist/toolkit/ToolkitProvider.js.map +1 -1
  208. package/dist/toolkit/browserNavigation.js +19 -20
  209. package/dist/toolkit/browserNavigation.js.map +1 -1
  210. package/dist/toolkit/componentTextsContext.js +15 -0
  211. package/dist/toolkit/componentTextsContext.js.map +1 -0
  212. package/dist/toolkit/hashNavigation.js +40 -0
  213. package/dist/toolkit/hashNavigation.js.map +1 -0
  214. package/dist/toolkit/navigationPaths.js +49 -0
  215. package/dist/toolkit/navigationPaths.js.map +1 -0
  216. package/dist/toolkit/toolkitSettings.js +24 -4
  217. package/dist/toolkit/toolkitSettings.js.map +1 -1
  218. package/dist/toolkit/useFormatters.js +12 -0
  219. package/dist/toolkit/useFormatters.js.map +1 -0
  220. package/dist/toolkit/useToolkitTranslation.js +11 -7
  221. package/dist/toolkit/useToolkitTranslation.js.map +1 -1
  222. package/dist/types/DataTable/AuditTrailTable.d.ts +3 -1
  223. package/dist/types/DataTable/EmptyState.d.ts +7 -2
  224. package/dist/types/DataTable/FilterChips.d.ts +3 -1
  225. package/dist/types/DataTable/GoToPage.d.ts +7 -2
  226. package/dist/types/DataTable/SelectionBar.d.ts +32 -0
  227. package/dist/types/DataTable/ServerTable.d.ts +64 -3
  228. package/dist/types/DataTable/index.d.ts +1 -1
  229. package/dist/types/DataTable/rowSelection.d.ts +113 -0
  230. package/dist/types/access/PermissionMatrix.d.ts +3 -1
  231. package/dist/types/account/AccountSecuritySection.d.ts +3 -1
  232. package/dist/types/account/ForgotPasswordScreen.d.ts +3 -1
  233. package/dist/types/account/ProfileScreen.d.ts +31 -1
  234. package/dist/types/account/ResetPasswordScreen.d.ts +3 -1
  235. package/dist/types/account/SignInScreen.d.ts +3 -1
  236. package/dist/types/account/accountConnector.d.ts +7 -2
  237. package/dist/types/adapters/reactRouterRoutes.d.ts +14 -2
  238. package/dist/types/api/createApiClient.d.ts +46 -1
  239. package/dist/types/appShell/AppLayout.d.ts +15 -1
  240. package/dist/types/appShell/AppearanceSettings.d.ts +8 -1
  241. package/dist/types/appShell/BarActionButton.d.ts +2 -2
  242. package/dist/types/appShell/BarActions.d.ts +6 -1
  243. package/dist/types/appShell/BarCapsule.d.ts +8 -0
  244. package/dist/types/appShell/BarSearch.d.ts +24 -0
  245. package/dist/types/appShell/MenuLinks.d.ts +17 -0
  246. package/dist/types/appShell/MobileTabBar.d.ts +4 -1
  247. package/dist/types/appShell/SettingsMenu.d.ts +3 -1
  248. package/dist/types/appShell/SideMenu.d.ts +3 -1
  249. package/dist/types/appShell/Wordmark.d.ts +6 -0
  250. package/dist/types/appShell/menuItemText.d.ts +16 -0
  251. package/dist/types/appShell/shellSizes.d.ts +1 -0
  252. package/dist/types/auth/PasswordChecklist.d.ts +3 -1
  253. package/dist/types/calendar/EventCalendar.d.ts +18 -1
  254. package/dist/types/calendar/EventDetails.d.ts +36 -0
  255. package/dist/types/calendar/calendarEvents.d.ts +27 -0
  256. package/dist/types/calendar.d.ts +2 -0
  257. package/dist/types/charts.d.ts +4 -0
  258. package/dist/types/datePickers/DateInput.d.ts +3 -1
  259. package/dist/types/downloads/DownloadManager.d.ts +7 -1
  260. package/dist/types/downloads/downloadQueue.d.ts +8 -3
  261. package/dist/types/downloads/fileTypes.d.ts +39 -0
  262. package/dist/types/downloads/index.d.ts +1 -0
  263. package/dist/types/feedback/ConfirmDialog.d.ts +3 -1
  264. package/dist/types/feedback/ModalWaiting.d.ts +7 -2
  265. package/dist/types/feedback/NewBuildNotice.d.ts +3 -1
  266. package/dist/types/filepond/FileDropzone.d.ts +3 -1
  267. package/dist/types/formatting.d.ts +45 -90
  268. package/dist/types/forms/FormWizard.d.ts +3 -1
  269. package/dist/types/forms/auth/ChangePasswordForm.d.ts +3 -1
  270. package/dist/types/forms/auth/ForgotPasswordForm.d.ts +3 -1
  271. package/dist/types/forms/auth/SignInForm.d.ts +3 -1
  272. package/dist/types/forms/security/SecondStepForm.d.ts +3 -1
  273. package/dist/types/forms/security/TwoStepVerificationCard.d.ts +3 -1
  274. package/dist/types/hookForm/FormWizard.d.ts +22 -0
  275. package/dist/types/inbox/InboxLayout.d.ts +14 -2
  276. package/dist/types/inbox/MessageList.d.ts +30 -5
  277. package/dist/types/inbox/MessageView.d.ts +35 -3
  278. package/dist/types/inbox/inboxDates.d.ts +6 -1
  279. package/dist/types/index.d.ts +15 -8
  280. package/dist/types/inputs/CatalogInput.d.ts +9 -5
  281. package/dist/types/inputs/ColorInput.d.ts +3 -1
  282. package/dist/types/inputs/FormSection.d.ts +2 -2
  283. package/dist/types/inputs/NumberInput.d.ts +3 -1
  284. package/dist/types/inputs/SelectInput.d.ts +9 -5
  285. package/dist/types/inputs/TextInput.d.ts +3 -1
  286. package/dist/types/inputs/WizardLayout.d.ts +34 -0
  287. package/dist/types/kanban/KanbanBoard.d.ts +61 -6
  288. package/dist/types/kanban/kanbanCards.d.ts +22 -0
  289. package/dist/types/kanban.d.ts +1 -0
  290. package/dist/types/locales/en.d.ts +77 -0
  291. package/dist/types/locales/es.d.ts +77 -0
  292. package/dist/types/maps/MapView.d.ts +12 -3
  293. package/dist/types/navigation/appMenu.d.ts +8 -0
  294. package/dist/types/observability/logger.d.ts +13 -0
  295. package/dist/types/observability/usePublishedBuildWatch.d.ts +3 -1
  296. package/dist/types/pwa/InstallAppSetting.d.ts +7 -1
  297. package/dist/types/pwa/InstallInstructionsDialog.d.ts +3 -1
  298. package/dist/types/pwa/InstallPromptBanner.d.ts +10 -1
  299. package/dist/types/pwa/useInstallPrompt.d.ts +3 -2
  300. package/dist/types/react-hook-form.d.ts +1 -0
  301. package/dist/types/security/ActivityLog.d.ts +3 -1
  302. package/dist/types/security/RecoveryCodesDialog.d.ts +6 -1
  303. package/dist/types/security/SessionsCard.d.ts +3 -1
  304. package/dist/types/table.d.ts +3 -1
  305. package/dist/types/theme/components/MuiAppBar.d.ts +3 -1
  306. package/dist/types/theme/components/MuiDialog.d.ts +9 -0
  307. package/dist/types/theme/components/glassComponents.d.ts +5 -0
  308. package/dist/types/theme/lightDarkStyles.d.ts +8 -0
  309. package/dist/types/toolkit/ComponentTexts.d.ts +11 -0
  310. package/dist/types/toolkit/ToolkitProvider.d.ts +18 -2
  311. package/dist/types/toolkit/browserNavigation.d.ts +23 -28
  312. package/dist/types/toolkit/componentTextsContext.d.ts +20 -0
  313. package/dist/types/toolkit/hashNavigation.d.ts +12 -0
  314. package/dist/types/toolkit/navigationPaths.d.ts +43 -0
  315. package/dist/types/toolkit/toolkitSettings.d.ts +49 -4
  316. package/dist/types/toolkit/useFormatters.d.ts +6 -0
  317. package/dist/types/toolkit/useToolkitTranslation.d.ts +2 -1
  318. package/dist/types/ui/actions/ActionsMenu.d.ts +20 -0
  319. package/dist/types/ui/actions/CopyButton.d.ts +3 -1
  320. package/dist/types/ui/actions/DownloadMenu.d.ts +8 -3
  321. package/dist/types/ui/actions/SecretField.d.ts +5 -1
  322. package/dist/types/ui/actions/SelectionActions.d.ts +39 -0
  323. package/dist/types/ui/filters/DateRangeFilter.d.ts +3 -1
  324. package/dist/types/ui/filters/QuickFilters.d.ts +3 -1
  325. package/dist/types/ui/index.d.ts +1 -1
  326. package/dist/types/ui/labels/tagOf.d.ts +13 -0
  327. package/dist/types/ui/layout/CollapsibleSection.d.ts +4 -1
  328. package/dist/types/ui/layout/ContentDialog.d.ts +3 -1
  329. package/dist/types/ui/layout/ErrorPage.d.ts +14 -1
  330. package/dist/types/ui/layout/FullPageLoader.d.ts +7 -1
  331. package/dist/types/ui/layout/PageHeading.d.ts +3 -1
  332. package/dist/types/ui/metrics/BarList.d.ts +7 -1
  333. package/dist/types/ui/metrics/CalendarHeatmap.d.ts +7 -1
  334. package/dist/types/ui/metrics/ChartTooltip.d.ts +9 -3
  335. package/dist/types/ui/metrics/ColumnChart.d.ts +23 -11
  336. package/dist/types/ui/metrics/LineChart.d.ts +41 -0
  337. package/dist/types/ui/metrics/MetricCard.d.ts +9 -1
  338. package/dist/types/ui/metrics/TableToggle.d.ts +9 -2
  339. package/dist/types/ui/metrics/chartParts.d.ts +112 -0
  340. package/dist/types/ui/navigation/BackButton.d.ts +3 -1
  341. package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +8 -2
  342. package/dist/types/ui/navigation/FontSizeToggle.d.ts +7 -2
  343. package/dist/types/ui/navigation/LanguageToggle.d.ts +8 -3
  344. package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +5 -2
  345. package/dist/types/ui/timeline/GroupedTimeline.d.ts +4 -1
  346. package/dist/types/upload/FileDropzone.d.ts +3 -1
  347. package/dist/ui/actions/ActionsMenu.js +51 -0
  348. package/dist/ui/actions/ActionsMenu.js.map +1 -0
  349. package/dist/ui/actions/CopyButton.js +2 -2
  350. package/dist/ui/actions/CopyButton.js.map +1 -1
  351. package/dist/ui/actions/DownloadMenu.js +11 -12
  352. package/dist/ui/actions/DownloadMenu.js.map +1 -1
  353. package/dist/ui/actions/SecretField.js +8 -4
  354. package/dist/ui/actions/SecretField.js.map +1 -1
  355. package/dist/ui/actions/SelectionActions.js +142 -0
  356. package/dist/ui/actions/SelectionActions.js.map +1 -0
  357. package/dist/ui/filters/DateRangeFilter.js +4 -3
  358. package/dist/ui/filters/DateRangeFilter.js.map +1 -1
  359. package/dist/ui/filters/QuickFilters.js +2 -2
  360. package/dist/ui/filters/QuickFilters.js.map +1 -1
  361. package/dist/ui/labels/tagOf.js +7 -0
  362. package/dist/ui/labels/tagOf.js.map +1 -0
  363. package/dist/ui/layout/CollapsibleSection.js +6 -2
  364. package/dist/ui/layout/CollapsibleSection.js.map +1 -1
  365. package/dist/ui/layout/ContentDialog.js +2 -2
  366. package/dist/ui/layout/ContentDialog.js.map +1 -1
  367. package/dist/ui/layout/ErrorPage.js +21 -7
  368. package/dist/ui/layout/ErrorPage.js.map +1 -1
  369. package/dist/ui/layout/FullPageLoader.js +2 -2
  370. package/dist/ui/layout/FullPageLoader.js.map +1 -1
  371. package/dist/ui/layout/PageHeading.js +2 -2
  372. package/dist/ui/layout/PageHeading.js.map +1 -1
  373. package/dist/ui/metrics/BarList.js +18 -13
  374. package/dist/ui/metrics/BarList.js.map +1 -1
  375. package/dist/ui/metrics/CalendarHeatmap.js +11 -6
  376. package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
  377. package/dist/ui/metrics/ChartTooltip.js +1 -1
  378. package/dist/ui/metrics/ChartTooltip.js.map +1 -1
  379. package/dist/ui/metrics/ColumnChart.js +59 -63
  380. package/dist/ui/metrics/ColumnChart.js.map +1 -1
  381. package/dist/ui/metrics/LineChart.js +117 -0
  382. package/dist/ui/metrics/LineChart.js.map +1 -0
  383. package/dist/ui/metrics/MetricCard.js +41 -8
  384. package/dist/ui/metrics/MetricCard.js.map +1 -1
  385. package/dist/ui/metrics/TableToggle.js +4 -2
  386. package/dist/ui/metrics/TableToggle.js.map +1 -1
  387. package/dist/ui/metrics/chartParts.js +93 -0
  388. package/dist/ui/metrics/chartParts.js.map +1 -0
  389. package/dist/ui/navigation/BackButton.js +2 -2
  390. package/dist/ui/navigation/BackButton.js.map +1 -1
  391. package/dist/ui/navigation/ColorSchemeToggle.js +6 -3
  392. package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
  393. package/dist/ui/navigation/FontSizeToggle.js +3 -2
  394. package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
  395. package/dist/ui/navigation/LanguageToggle.js +40 -19
  396. package/dist/ui/navigation/LanguageToggle.js.map +1 -1
  397. package/dist/ui/navigation/PageBreadcrumbs.js +2 -2
  398. package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
  399. package/dist/ui/timeline/GroupedTimeline.js +10 -8
  400. package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
  401. package/dist/upload/FileDropzone.js +5 -3
  402. package/dist/upload/FileDropzone.js.map +1 -1
  403. package/package.json +16 -7
@@ -1,45 +1,53 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
- import { useMemo } from "react";
3
+ import { useContext, useMemo } from "react";
4
4
  import { allowOnlyUnrestricted } from "../access/accessRules.js";
5
5
  import { browserNavigation } from "./browserNavigation.js";
6
6
  import { ToolkitContext } from "./toolkitContext.js";
7
7
  import { useFontSize } from "../ui/navigation/useFontSize.js";
8
- import { DEFAULT_CURRENCY, DEFAULT_LANGUAGE, browserTimeZone, configureToolkit } from "./toolkitSettings.js";
8
+ import { DEFAULT_CURRENCY, DEFAULT_LANGUAGES, DEFAULT_LANGUAGE, browserTimeZone, configureToolkit } from "./toolkitSettings.js";
9
9
  const ToolkitProvider = ({
10
- language = DEFAULT_LANGUAGE,
10
+ language,
11
+ languages,
11
12
  onLanguageChange,
12
13
  texts,
13
14
  translate,
14
15
  timeZone,
15
- currency = DEFAULT_CURRENCY,
16
- appName = "",
17
- navigation = browserNavigation,
18
- buildId = "",
19
- canAccess = allowOnlyUnrestricted,
16
+ currency,
17
+ appName,
18
+ navigation,
19
+ buildId,
20
+ canAccess,
21
+ fileTypes,
20
22
  children
21
23
  }) => {
24
+ const parent = useContext(ToolkitContext);
22
25
  const settings = useMemo(() => ({
23
- language,
24
- onLanguageChange: onLanguageChange ?? null,
25
- texts: texts ?? {},
26
- translate: translate ?? null,
27
- timeZone: timeZone ?? browserTimeZone(),
28
- currency,
29
- appName,
30
- navigation,
31
- buildId,
32
- canAccess
33
- }), [language, onLanguageChange, texts, translate, timeZone, currency, appName, navigation, buildId, canAccess]);
34
- configureToolkit({
35
- language: settings.language,
36
- texts: settings.texts,
37
- translate: settings.translate,
38
- timeZone: settings.timeZone,
39
- currency,
40
- appName,
41
- buildId
42
- });
26
+ language: language ?? parent?.language ?? DEFAULT_LANGUAGE,
27
+ languages: languages ?? parent?.languages ?? DEFAULT_LANGUAGES,
28
+ onLanguageChange: onLanguageChange ?? parent?.onLanguageChange ?? null,
29
+ texts: texts ?? parent?.texts ?? {},
30
+ translate: translate ?? parent?.translate ?? null,
31
+ timeZone: timeZone ?? parent?.timeZone ?? browserTimeZone(),
32
+ currency: currency ?? parent?.currency ?? DEFAULT_CURRENCY,
33
+ appName: appName ?? parent?.appName ?? "",
34
+ navigation: navigation ?? parent?.navigation ?? browserNavigation,
35
+ buildId: buildId ?? parent?.buildId ?? "",
36
+ canAccess: canAccess ?? parent?.canAccess ?? allowOnlyUnrestricted,
37
+ fileTypes: fileTypes ?? parent?.fileTypes ?? null
38
+ }), [parent, language, languages, onLanguageChange, texts, translate, timeZone, currency, appName, navigation, buildId, canAccess, fileTypes]);
39
+ if (!parent) {
40
+ configureToolkit({
41
+ language: settings.language,
42
+ texts: settings.texts,
43
+ translate: settings.translate,
44
+ timeZone: settings.timeZone,
45
+ currency: settings.currency,
46
+ appName: settings.appName,
47
+ buildId: settings.buildId,
48
+ languages: settings.languages
49
+ });
50
+ }
43
51
  useFontSize();
44
52
  return /* @__PURE__ */ jsx(ToolkitContext.Provider, { value: settings, children });
45
53
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ToolkitProvider.js","sources":["../../src/toolkit/ToolkitProvider.jsx"],"sourcesContent":["// El proveedor del paquete: el único lugar donde cada aplicación conecta su idioma, sus textos, su zona horaria y su\n// router. Va por encima de la aplicación, dentro del ThemeProvider de MUI (el tema lo arma cada proyecto; sin tema,\n// los componentes usan los colores por omisión de MUI).\n//\n// <ToolkitProvider language=\"es\" navigation={reactRouterNavigation} texts={{es: {common: {actions: {back: 'Volver'}}}}}>\n//\n// Sin proveedor todo funciona en español, con la zona del navegador y la navegación del navegador.\n//\n// Lo renderiza la app: arrow (regla de la casa).\nimport {useMemo} from 'react';\nimport {allowOnlyUnrestricted} from '@/access/accessRules.js';\nimport {browserNavigation} from '@/toolkit/browserNavigation.js';\nimport {ToolkitContext} from '@/toolkit/toolkitContext.js';\nimport {useFontSize} from '@/ui/navigation/useFontSize.js';\nimport {DEFAULT_CURRENCY, DEFAULT_LANGUAGE, browserTimeZone, configureToolkit} from '@/toolkit/toolkitSettings.js';\n\n/**\n * @param {object} props\n * @param {string} [props.language] idioma activo: es o en (por omisión es)\n * @param {(language: string) => void} [props.onLanguageChange] lo llama LanguageToggle; el proyecto cambia su idioma\n * @param {object} [props.texts] textos propios por idioma, con la forma de locales/ ({es: {table: {...}}})\n * @param {(namespace: string, key: string, values?: object) => string|undefined} [props.translate] traductor del\n * proyecto (por ejemplo i18next); undefined deja el texto del paquete\n * @param {string} [props.timeZone] zona de las fechas (por omisión la del navegador)\n * @param {string} [props.currency] moneda de los montos, código ISO 4217 (por omisión MXN)\n * @param {string} [props.appName] nombre de la aplicación para el título de la pestaña\n * @param {object} [props.navigation] {useNavigate, useLocation, Link}; por omisión la del navegador\n * @param {string} [props.buildId] la compilación del front que corre en esta pestaña; con ella NewBuildNotice sabe si el\n * servidor ya publicó otra (reportPublishedBuild). Vacía (en desarrollo) nunca avisa\n * @param {(access: object|undefined|null) => boolean} [props.canAccess] quién ve qué (menú, rutas, botones): la regla del\n * proyecto, normalmente createAccessChecker({abilities, roles, policies, context}). Sin ella solo se ve lo que no\n * tiene regla\n * @param {import('react').ReactNode} props.children\n */\nexport const ToolkitProvider = ({\n language = DEFAULT_LANGUAGE, onLanguageChange, texts, translate, timeZone, currency = DEFAULT_CURRENCY, appName = '',\n navigation = browserNavigation, buildId = '', canAccess = allowOnlyUnrestricted, children,\n}) => {\n const settings = useMemo(() => ({\n language,\n onLanguageChange: onLanguageChange ?? null,\n texts: texts ?? {},\n translate: translate ?? null,\n timeZone: timeZone ?? browserTimeZone(),\n currency,\n appName,\n navigation,\n buildId,\n canAccess,\n }), [language, onLanguageChange, texts, translate, timeZone, currency, appName, navigation, buildId, canAccess]);\n\n // OJO: se configura durante el render (no en un efecto) para que los formatos y avisos que se llaman en este mismo\n // render ya vean el idioma y la zona nuevos\n configureToolkit({\n language: settings.language, texts: settings.texts, translate: settings.translate, timeZone: settings.timeZone, currency, appName,\n buildId,\n });\n\n // el tamaño de letra que la persona guardó: se aplica aquí, que siempre está montado. Antes lo aplicaba su botón en la\n // barra; al pasar los ajustes al menú de la cuenta, al recargar se perdía hasta abrir el menú (error pagado)\n useFontSize();\n\n return <ToolkitContext.Provider value={settings}>{children}</ToolkitContext.Provider>;\n};\n"],"names":[],"mappings":";;;;;;;;AAkCO,MAAM,kBAAkB,CAAC;AAAA,EAC5B,WAAW;AAAA,EAAkB;AAAA,EAAkB;AAAA,EAAO;AAAA,EAAW;AAAA,EAAU,WAAW;AAAA,EAAkB,UAAU;AAAA,EAClH,aAAa;AAAA,EAAmB,UAAU;AAAA,EAAI,YAAY;AAAA,EAAuB;AACrF,MAAM;AACF,QAAM,WAAW,QAAQ,OAAO;AAAA,IAC5B;AAAA,IACA,kBAAkB,oBAAoB;AAAA,IACtC,OAAO,SAAS,CAAA;AAAA,IAChB,WAAW,aAAa;AAAA,IACxB,UAAU,YAAY,gBAAA;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA,CAAC,UAAU,kBAAkB,OAAO,WAAW,UAAU,UAAU,SAAS,YAAY,SAAS,SAAS,CAAC;AAI/G,mBAAiB;AAAA,IACb,UAAU,SAAS;AAAA,IAAU,OAAO,SAAS;AAAA,IAAO,WAAW,SAAS;AAAA,IAAW,UAAU,SAAS;AAAA,IAAU;AAAA,IAAU;AAAA,IAC1H;AAAA,EAAA,CACH;AAID,cAAA;AAEA,6BAAQ,eAAe,UAAf,EAAwB,OAAO,UAAW,UAAS;AAC/D;"}
1
+ {"version":3,"file":"ToolkitProvider.js","sources":["../../src/toolkit/ToolkitProvider.jsx"],"sourcesContent":["// El proveedor del paquete: el único lugar donde cada aplicación conecta su idioma, sus textos, su zona horaria y su\n// router. Va por encima de la aplicación, dentro del ThemeProvider de MUI (el tema lo arma cada proyecto; sin tema,\n// los componentes usan los colores por omisión de MUI).\n//\n// <ToolkitProvider language=\"es\" navigation={reactRouterNavigation} texts={{es: {common: {actions: {back: 'Volver'}}}}}>\n//\n// Sin proveedor todo funciona en español, con la zona del navegador y la navegación del navegador.\n//\n// Un proveedor dentro de otro (una parte de la app en otro idioma, una vista previa) toma del de afuera lo que no le digan, y\n// sus componentes leen el suyo: el más cercano. Solo el de la raíz pone la configuración que leen las funciones sueltas\n// (avisos, errores, formatos sueltos): antes el de adentro se la cambiaba a toda la app. Dos islas de React en una página\n// vieja son dos raíces: cada isla pinta con la suya, y las funciones sueltas usan la última que se pintó (en ese caso los\n// componentes de la casa ya formatean con su proveedor; para un aviso, mándelo con el texto ya traducido).\n//\n// Lo renderiza la app: arrow (regla de la casa).\nimport {useContext, useMemo} from 'react';\nimport {allowOnlyUnrestricted} from '@/access/accessRules.js';\nimport {browserNavigation} from '@/toolkit/browserNavigation.js';\nimport {ToolkitContext} from '@/toolkit/toolkitContext.js';\nimport {useFontSize} from '@/ui/navigation/useFontSize.js';\nimport {DEFAULT_CURRENCY, DEFAULT_LANGUAGE, DEFAULT_LANGUAGES, browserTimeZone, configureToolkit} from '@/toolkit/toolkitSettings.js';\n\n/**\n * @param {object} props\n * @param {string} [props.language] idioma activo, uno de `languages` (por omisión es)\n * @param {Array<{code: string, label: string, locale?: string}>} [props.languages] los idiomas que ofrece la app: su código,\n * su nombre en su propio idioma («Português») y su locale de Intl ('pt-BR'). Por omisión español e inglés\n * (DEFAULT_LANGUAGES). Sus traducciones van en `texts`\n * @param {Record<string, {Icon: import('react').ElementType, color?: string, label?: string, hint?: string}>} [props.fileTypes]\n * tipos de archivo del proyecto para las descargas, además de Excel, CSV y PDF (downloads/fileTypes.js)\n * @param {(language: string) => void} [props.onLanguageChange] lo llama LanguageToggle; el proyecto cambia su idioma\n * @param {object} [props.texts] textos propios por idioma, con la forma de locales/ ({es: {table: {...}}})\n * @param {(namespace: string, key: string, values?: object) => string|undefined} [props.translate] traductor del\n * proyecto (por ejemplo i18next); undefined deja el texto del paquete\n * @param {string} [props.timeZone] zona de las fechas (por omisión la del navegador)\n * @param {string} [props.currency] moneda de los montos, código ISO 4217 (por omisión MXN)\n * @param {string} [props.appName] nombre de la aplicación para el título de la pestaña\n * @param {object} [props.navigation] {useNavigate, useLocation, Link}; por omisión la del navegador\n * @param {string} [props.buildId] la compilación del front que corre en esta pestaña; con ella NewBuildNotice sabe si el\n * servidor ya publicó otra (reportPublishedBuild). Vacía (en desarrollo) nunca avisa\n * @param {(access: object|undefined|null) => boolean} [props.canAccess] quién ve qué (menú, rutas, botones): la regla del\n * proyecto, normalmente createAccessChecker({abilities, roles, policies, context}). Sin ella solo se ve lo que no\n * tiene regla\n * @param {import('react').ReactNode} props.children\n */\nexport const ToolkitProvider = ({\n language, languages, onLanguageChange, texts, translate, timeZone, currency, appName, navigation, buildId, canAccess, fileTypes, children,\n}) => {\n // el proveedor de afuera, si este va dentro de otro: de él sale lo que este no diga\n const parent = useContext(ToolkitContext);\n const settings = useMemo(() => ({\n language: language ?? parent?.language ?? DEFAULT_LANGUAGE,\n languages: languages ?? parent?.languages ?? DEFAULT_LANGUAGES,\n onLanguageChange: onLanguageChange ?? parent?.onLanguageChange ?? null,\n texts: texts ?? parent?.texts ?? {},\n translate: translate ?? parent?.translate ?? null,\n timeZone: timeZone ?? parent?.timeZone ?? browserTimeZone(),\n currency: currency ?? parent?.currency ?? DEFAULT_CURRENCY,\n appName: appName ?? parent?.appName ?? '',\n navigation: navigation ?? parent?.navigation ?? browserNavigation,\n buildId: buildId ?? parent?.buildId ?? '',\n canAccess: canAccess ?? parent?.canAccess ?? allowOnlyUnrestricted,\n fileTypes: fileTypes ?? parent?.fileTypes ?? null,\n }), [parent, language, languages, onLanguageChange, texts, translate, timeZone, currency, appName, navigation, buildId, canAccess, fileTypes]);\n\n // solo el de la raíz: un proveedor de adentro le cambiaba el idioma y la zona a las funciones sueltas de toda la app.\n // OJO: se configura durante el render (no en un efecto) para que los formatos y avisos que se llaman en este mismo\n // render ya vean el idioma y la zona nuevos\n if (!parent) {\n configureToolkit({\n language: settings.language, texts: settings.texts, translate: settings.translate, timeZone: settings.timeZone, currency: settings.currency,\n appName: settings.appName, buildId: settings.buildId, languages: settings.languages,\n });\n }\n\n // el tamaño de letra que la persona guardó: se aplica aquí, que siempre está montado. Antes lo aplicaba su botón en la\n // barra; al pasar los ajustes al menú de la cuenta, al recargar se perdía hasta abrir el menú (error pagado)\n useFontSize();\n\n return <ToolkitContext.Provider value={settings}>{children}</ToolkitContext.Provider>;\n};\n"],"names":[],"mappings":";;;;;;;;AA6CO,MAAM,kBAAkB,CAAC;AAAA,EAC5B;AAAA,EAAU;AAAA,EAAW;AAAA,EAAkB;AAAA,EAAO;AAAA,EAAW;AAAA,EAAU;AAAA,EAAU;AAAA,EAAS;AAAA,EAAY;AAAA,EAAS;AAAA,EAAW;AAAA,EAAW;AACrI,MAAM;AAEF,QAAM,SAAS,WAAW,cAAc;AACxC,QAAM,WAAW,QAAQ,OAAO;AAAA,IAC5B,UAAU,YAAY,QAAQ,YAAY;AAAA,IAC1C,WAAW,aAAa,QAAQ,aAAa;AAAA,IAC7C,kBAAkB,oBAAoB,QAAQ,oBAAoB;AAAA,IAClE,OAAO,SAAS,QAAQ,SAAS,CAAA;AAAA,IACjC,WAAW,aAAa,QAAQ,aAAa;AAAA,IAC7C,UAAU,YAAY,QAAQ,YAAY,gBAAA;AAAA,IAC1C,UAAU,YAAY,QAAQ,YAAY;AAAA,IAC1C,SAAS,WAAW,QAAQ,WAAW;AAAA,IACvC,YAAY,cAAc,QAAQ,cAAc;AAAA,IAChD,SAAS,WAAW,QAAQ,WAAW;AAAA,IACvC,WAAW,aAAa,QAAQ,aAAa;AAAA,IAC7C,WAAW,aAAa,QAAQ,aAAa;AAAA,EAAA,IAC7C,CAAC,QAAQ,UAAU,WAAW,kBAAkB,OAAO,WAAW,UAAU,UAAU,SAAS,YAAY,SAAS,WAAW,SAAS,CAAC;AAK7I,MAAI,CAAC,QAAQ;AACT,qBAAiB;AAAA,MACb,UAAU,SAAS;AAAA,MAAU,OAAO,SAAS;AAAA,MAAO,WAAW,SAAS;AAAA,MAAW,UAAU,SAAS;AAAA,MAAU,UAAU,SAAS;AAAA,MACnI,SAAS,SAAS;AAAA,MAAS,SAAS,SAAS;AAAA,MAAS,WAAW,SAAS;AAAA,IAAA,CAC7E;AAAA,EACL;AAIA,cAAA;AAEA,6BAAQ,eAAe,UAAf,EAAwB,OAAO,UAAW,UAAS;AAC/D;"}
@@ -1,13 +1,7 @@
1
1
  "use client";
2
2
  import { createElement, useSyncExternalStore } from "react";
3
+ import { pathWithBase, pathWithoutBase } from "./navigationPaths.js";
3
4
  const HISTORY_BACK = -1;
4
- function navigateInBrowser(destination) {
5
- if (destination === HISTORY_BACK) {
6
- window.history.back();
7
- return;
8
- }
9
- window.location.assign(destination);
10
- }
11
5
  function subscribeToHistory(onChange) {
12
6
  window.addEventListener("popstate", onChange);
13
7
  return () => window.removeEventListener("popstate", onChange);
@@ -15,20 +9,25 @@ function subscribeToHistory(onChange) {
15
9
  function currentHref() {
16
10
  return window.location.href;
17
11
  }
18
- function useBrowserLocation() {
19
- const href = useSyncExternalStore(subscribeToHistory, currentHref, () => "");
20
- const url = href ? new URL(href) : null;
21
- return { pathname: url?.pathname ?? "/", search: url?.search ?? "", key: href };
22
- }
23
- function BrowserLink({ to, ...props }) {
24
- return createElement("a", { href: to, ...props });
12
+ function createBrowserNavigation({ basePath = "" } = {}) {
13
+ const navigate = (destination) => {
14
+ if (destination === HISTORY_BACK) {
15
+ window.history.back();
16
+ return;
17
+ }
18
+ window.location.assign(pathWithBase(basePath, destination));
19
+ };
20
+ const useBrowserLocation = () => {
21
+ const href = useSyncExternalStore(subscribeToHistory, currentHref, () => "");
22
+ const url = href ? new URL(href) : null;
23
+ return { pathname: url ? pathWithoutBase(basePath, url.pathname) : "/", search: url?.search ?? "", key: href };
24
+ };
25
+ const BrowserLink = ({ to, ...props }) => createElement("a", { href: pathWithBase(basePath, to), ...props });
26
+ return Object.freeze({ useNavigate: () => navigate, useLocation: useBrowserLocation, Link: BrowserLink });
25
27
  }
26
- const browserNavigation = Object.freeze({
27
- useNavigate: () => navigateInBrowser,
28
- useLocation: useBrowserLocation,
29
- Link: BrowserLink
30
- });
28
+ const browserNavigation = createBrowserNavigation();
31
29
  export {
32
- browserNavigation
30
+ browserNavigation,
31
+ createBrowserNavigation
33
32
  };
34
33
  //# sourceMappingURL=browserNavigation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"browserNavigation.js","sources":["../../src/toolkit/browserNavigation.js"],"sourcesContent":["// La navegación por omisión: la del navegador, para usar el paquete sin router.\n//\n// Los componentes que navegan (BackButton, MetricCard, el regreso a la última lista) no importan react-router ni\n// Next.js: le piden al proveedor una navegación con tres piezas, las mismas que trae react-router:\n// useNavigate() regresa navigate(destino), donde destino es una ruta o -1 para regresar;\n// useLocation() regresa {pathname, search, key} de la página actual;\n// Link el enlace, que recibe `to` con la ruta.\n// Un proyecto con router pasa su adaptador (@stackcraftmx/calcita/react-router); sin él, esta cambia de página como un\n// enlace normal.\n//\n// OJO: aquí cada navegación recarga la página. Para una aplicación de una sola página se usa el adaptador de su router.\nimport {createElement, useSyncExternalStore} from 'react';\n\nconst HISTORY_BACK = -1;\n\n/**\n * Cambia de página: -1 regresa en el historial; una ruta abre esa ruta.\n *\n * @param {string|number} destination\n * @returns {void}\n */\nfunction navigateInBrowser(destination) {\n if (destination === HISTORY_BACK) {\n window.history.back();\n return;\n }\n\n window.location.assign(destination);\n}\n\n/**\n * Avisa cuando cambia la página por el historial (atrás y adelante).\n *\n * @param {Function} onChange\n * @returns {Function} para dejar de escuchar\n */\nfunction subscribeToHistory(onChange) {\n window.addEventListener('popstate', onChange);\n\n return () => window.removeEventListener('popstate', onChange);\n}\n\n/**\n * La dirección actual como texto, para saber si cambió.\n *\n * @returns {string}\n */\nfunction currentHref() {\n return window.location.href;\n}\n\n/**\n * La página actual, como la da react-router: la ruta, la búsqueda y una llave por página.\n *\n * @returns {{pathname: string, search: string, key: string}}\n */\nfunction useBrowserLocation() {\n const href = useSyncExternalStore(subscribeToHistory, currentHref, () => '');\n const url = href ? new URL(href) : null;\n\n return {pathname: url?.pathname ?? '/', search: url?.search ?? '', key: href};\n}\n\n/**\n * El enlace sin router: un <a> con href.\n *\n * @param {{to: string}} props lo demás pasa al <a>\n * @returns {import('react').ReactElement}\n */\nfunction BrowserLink({to, ...props}) {\n return createElement('a', {href: to, ...props});\n}\n\nexport const browserNavigation = Object.freeze({\n useNavigate: () => navigateInBrowser,\n useLocation: useBrowserLocation,\n Link: BrowserLink,\n});\n"],"names":[],"mappings":";;AAaA,MAAM,eAAe;AAQrB,SAAS,kBAAkB,aAAa;AACpC,MAAI,gBAAgB,cAAc;AAC9B,WAAO,QAAQ,KAAI;AACnB;AAAA,EACJ;AAEA,SAAO,SAAS,OAAO,WAAW;AACtC;AAQA,SAAS,mBAAmB,UAAU;AAClC,SAAO,iBAAiB,YAAY,QAAQ;AAE5C,SAAO,MAAM,OAAO,oBAAoB,YAAY,QAAQ;AAChE;AAOA,SAAS,cAAc;AACnB,SAAO,OAAO,SAAS;AAC3B;AAOA,SAAS,qBAAqB;AAC1B,QAAM,OAAO,qBAAqB,oBAAoB,aAAa,MAAM,EAAE;AAC3E,QAAM,MAAM,OAAO,IAAI,IAAI,IAAI,IAAI;AAEnC,SAAO,EAAC,UAAU,KAAK,YAAY,KAAK,QAAQ,KAAK,UAAU,IAAI,KAAK,KAAI;AAChF;AAQA,SAAS,YAAY,EAAC,IAAI,GAAG,MAAK,GAAG;AACjC,SAAO,cAAc,KAAK,EAAC,MAAM,IAAI,GAAG,MAAK,CAAC;AAClD;AAEY,MAAC,oBAAoB,OAAO,OAAO;AAAA,EAC3C,aAAa,MAAM;AAAA,EACnB,aAAa;AAAA,EACb,MAAM;AACV,CAAC;"}
1
+ {"version":3,"file":"browserNavigation.js","sources":["../../src/toolkit/browserNavigation.js"],"sourcesContent":["// La navegación por omisión: la del navegador, para usar el paquete sin router.\n//\n// Los componentes que navegan (BackButton, MetricCard, el regreso a la última lista) no importan react-router ni\n// Next.js: le piden al proveedor una navegación con tres piezas, las mismas que trae react-router:\n// useNavigate() regresa navigate(destino), donde destino es una ruta o -1 para regresar;\n// useLocation() regresa {pathname, search, key} de la página actual;\n// Link el enlace, que recibe `to` con la ruta.\n// Un proyecto con router pasa su adaptador (@stackcraftmx/calcita/react-router); sin él, esta cambia de página como un\n// enlace normal.\n//\n// Para un sistema que ya existe, sin router:\n// - con prefijo (la app detrás de un proxy en /portal): createBrowserNavigation({basePath: '/portal'}). Los componentes\n// siguen hablando de '/pedidos' y la dirección real lleva el prefijo;\n// - con # en la dirección (un servidor que no sabe responder /pedidos al recargar): createHashNavigation(), en\n// hashNavigation.js.\n//\n// OJO: aquí cada navegación recarga la página. Para una aplicación de una sola página se usa el adaptador de su router (o la\n// de #, que no recarga).\nimport {createElement, useSyncExternalStore} from 'react';\n\nimport {pathWithBase, pathWithoutBase} from '@/toolkit/navigationPaths.js';\n\nconst HISTORY_BACK = -1;\n\n/**\n * Avisa cuando cambia la página por el historial (atrás y adelante).\n *\n * @param {Function} onChange\n * @returns {Function} para dejar de escuchar\n */\nfunction subscribeToHistory(onChange) {\n window.addEventListener('popstate', onChange);\n\n return () => window.removeEventListener('popstate', onChange);\n}\n\n/**\n * La dirección actual como texto, para saber si cambió.\n *\n * @returns {string}\n */\nfunction currentHref() {\n return window.location.href;\n}\n\n/**\n * La navegación del navegador, con o sin prefijo.\n *\n * @param {{basePath?: string}} [options] basePath: donde vive la app detrás de un proxy ('/portal'); sin él, la raíz\n * @returns {{useNavigate: () => (destination: string|number) => void, useLocation: () => {pathname: string, search: string, key: string}, Link: import('react').ElementType}}\n */\nexport function createBrowserNavigation({basePath = ''} = {}) {\n // cambia de página: -1 regresa en el historial; una ruta de la app abre esa ruta con el prefijo\n const navigate = (destination) => {\n if (destination === HISTORY_BACK) {\n window.history.back();\n return;\n }\n window.location.assign(pathWithBase(basePath, destination));\n };\n\n // la página actual como la da react-router (la ruta SIN el prefijo, la búsqueda y una llave por página)\n const useBrowserLocation = () => {\n const href = useSyncExternalStore(subscribeToHistory, currentHref, () => '');\n const url = href ? new URL(href) : null;\n return {pathname: url ? pathWithoutBase(basePath, url.pathname) : '/', search: url?.search ?? '', key: href};\n };\n\n // el enlace sin router: un <a> con la dirección real\n const BrowserLink = ({to, ...props}) => createElement('a', {href: pathWithBase(basePath, to), ...props});\n\n return Object.freeze({useNavigate: () => navigate, useLocation: useBrowserLocation, Link: BrowserLink});\n}\n\n/** La de omisión: sin prefijo. */\nexport const browserNavigation = createBrowserNavigation();\n"],"names":[],"mappings":";;;AAsBA,MAAM,eAAe;AAQrB,SAAS,mBAAmB,UAAU;AAClC,SAAO,iBAAiB,YAAY,QAAQ;AAE5C,SAAO,MAAM,OAAO,oBAAoB,YAAY,QAAQ;AAChE;AAOA,SAAS,cAAc;AACnB,SAAO,OAAO,SAAS;AAC3B;AAQO,SAAS,wBAAwB,EAAC,WAAW,GAAE,IAAI,CAAA,GAAI;AAE1D,QAAM,WAAW,CAAC,gBAAgB;AAC9B,QAAI,gBAAgB,cAAc;AAC9B,aAAO,QAAQ,KAAI;AACnB;AAAA,IACJ;AACA,WAAO,SAAS,OAAO,aAAa,UAAU,WAAW,CAAC;AAAA,EAC9D;AAGA,QAAM,qBAAqB,MAAM;AAC7B,UAAM,OAAO,qBAAqB,oBAAoB,aAAa,MAAM,EAAE;AAC3E,UAAM,MAAM,OAAO,IAAI,IAAI,IAAI,IAAI;AACnC,WAAO,EAAC,UAAU,MAAM,gBAAgB,UAAU,IAAI,QAAQ,IAAI,KAAK,QAAQ,KAAK,UAAU,IAAI,KAAK,KAAI;AAAA,EAC/G;AAGA,QAAM,cAAc,CAAC,EAAC,IAAI,GAAG,MAAK,MAAM,cAAc,KAAK,EAAC,MAAM,aAAa,UAAU,EAAE,GAAG,GAAG,MAAK,CAAC;AAEvG,SAAO,OAAO,OAAO,EAAC,aAAa,MAAM,UAAU,aAAa,oBAAoB,MAAM,YAAW,CAAC;AAC1G;AAGY,MAAC,oBAAoB,wBAAuB;"}
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { createContext } from "react";
3
+ const ComponentTextsContext = createContext(null);
4
+ function layersOf(layer) {
5
+ const layers = [];
6
+ for (let current = layer; current; current = current.parent) {
7
+ layers.push(current);
8
+ }
9
+ return layers;
10
+ }
11
+ export {
12
+ ComponentTextsContext,
13
+ layersOf
14
+ };
15
+ //# sourceMappingURL=componentTextsContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"componentTextsContext.js","sources":["../../src/toolkit/componentTextsContext.js"],"sourcesContent":["// Los textos propios que un componente les pasa a las piezas de adentro (la tabla a sus filtros de columna, sus chips y su\n// barra de elegidos): así un `texts` en ServerTable cambia también el «Limpiar esta columna» del filtro, sin pasarlo pieza por\n// pieza. Cada capa sabe cuál la envuelve (parent): la más cercana gana.\n//\n// Contexto de React, no renderiza: archivo .js (regla de la casa).\nimport {createContext} from 'react';\n\n/** @type {import('react').Context<{namespace: string, texts: object|undefined, parent: object|null}|null>} */\nexport const ComponentTextsContext = createContext(null);\n\n/**\n * Las capas de afuera hacia la más lejana, para componentTextOf.\n *\n * @param {{namespace: string, texts: object|undefined, parent: object|null}|null} layer\n * @returns {Array<{namespace: string, texts: object|undefined}>}\n */\nexport function layersOf(layer) {\n const layers = [];\n for (let current = layer; current; current = current.parent) {\n layers.push(current);\n }\n\n return layers;\n}\n"],"names":[],"mappings":";;AAQY,MAAC,wBAAwB,cAAc,IAAI;AAQhD,SAAS,SAAS,OAAO;AAC5B,QAAM,SAAS,CAAA;AACf,WAAS,UAAU,OAAO,SAAS,UAAU,QAAQ,QAAQ;AACzD,WAAO,KAAK,OAAO;AAAA,EACvB;AAEA,SAAO;AACX;"}
@@ -0,0 +1,40 @@
1
+ "use client";
2
+ import { createElement, useSyncExternalStore } from "react";
3
+ import { hashHrefOf, hashLocationOf } from "./navigationPaths.js";
4
+ const HISTORY_BACK = -1;
5
+ function subscribeToHash(onChange) {
6
+ window.addEventListener("hashchange", onChange);
7
+ window.addEventListener("popstate", onChange);
8
+ return () => {
9
+ window.removeEventListener("hashchange", onChange);
10
+ window.removeEventListener("popstate", onChange);
11
+ };
12
+ }
13
+ function currentHref() {
14
+ return window.location.href;
15
+ }
16
+ function createHashNavigation() {
17
+ const navigate = (destination) => {
18
+ if (destination === HISTORY_BACK) {
19
+ window.history.back();
20
+ return;
21
+ }
22
+ const href = hashHrefOf(destination);
23
+ if (href.startsWith("#")) {
24
+ window.location.hash = href;
25
+ return;
26
+ }
27
+ window.location.assign(href);
28
+ };
29
+ const useHashLocation = () => {
30
+ const href = useSyncExternalStore(subscribeToHash, currentHref, () => "");
31
+ const { pathname, search } = hashLocationOf(href ? new URL(href).hash : "");
32
+ return { pathname, search, key: href };
33
+ };
34
+ const HashLink = ({ to, ...props }) => createElement("a", { href: hashHrefOf(to), ...props });
35
+ return Object.freeze({ useNavigate: () => navigate, useLocation: useHashLocation, Link: HashLink });
36
+ }
37
+ export {
38
+ createHashNavigation
39
+ };
40
+ //# sourceMappingURL=hashNavigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashNavigation.js","sources":["../../src/toolkit/hashNavigation.js"],"sourcesContent":["// La navegación con # en la dirección (/app.php#/pedidos), sin router: para meter Calcita en un sistema que ya existe y cuyo\n// servidor no sabe responder /pedidos al recargar. Todo lo que va después del # se queda en el navegador: cambiar de\n// pantalla no recarga la página ni pide nada al servidor, y atrás y adelante funcionan.\n//\n// <ToolkitProvider navigation={createHashNavigation()}> // una vez, fuera del componente\n//\n// Con react-router se usa su createHashRouter con el adaptador de siempre (@stackcraftmx/calcita/react-router).\n//\n// Funciones genéricas: function (regla de la casa).\nimport {createElement, useSyncExternalStore} from 'react';\n\nimport {hashHrefOf, hashLocationOf} from '@/toolkit/navigationPaths.js';\n\nconst HISTORY_BACK = -1;\n\n/** Avisa cuando cambia lo que va después del # (un enlace, atrás o adelante). */\nfunction subscribeToHash(onChange) {\n window.addEventListener('hashchange', onChange);\n window.addEventListener('popstate', onChange);\n return () => {\n window.removeEventListener('hashchange', onChange);\n window.removeEventListener('popstate', onChange);\n };\n}\n\nfunction currentHref() {\n return window.location.href;\n}\n\n/**\n * @returns {{useNavigate: () => (destination: string|number) => void, useLocation: () => {pathname: string, search: string, key: string}, Link: import('react').ElementType}}\n */\nexport function createHashNavigation() {\n // -1 regresa en el historial; una ruta de la app cambia lo que va después del # (sin recargar)\n const navigate = (destination) => {\n if (destination === HISTORY_BACK) {\n window.history.back();\n return;\n }\n const href = hashHrefOf(destination);\n if (href.startsWith('#')) {\n window.location.hash = href;\n return;\n }\n // una dirección de afuera: como un enlace normal\n window.location.assign(href);\n };\n\n // la página de la app, leída de lo que va después del #\n const useHashLocation = () => {\n const href = useSyncExternalStore(subscribeToHash, currentHref, () => '');\n const {pathname, search} = hashLocationOf(href ? new URL(href).hash : '');\n return {pathname, search, key: href};\n };\n\n const HashLink = ({to, ...props}) => createElement('a', {href: hashHrefOf(to), ...props});\n\n return Object.freeze({useNavigate: () => navigate, useLocation: useHashLocation, Link: HashLink});\n}\n"],"names":[],"mappings":";;;AAaA,MAAM,eAAe;AAGrB,SAAS,gBAAgB,UAAU;AAC/B,SAAO,iBAAiB,cAAc,QAAQ;AAC9C,SAAO,iBAAiB,YAAY,QAAQ;AAC5C,SAAO,MAAM;AACT,WAAO,oBAAoB,cAAc,QAAQ;AACjD,WAAO,oBAAoB,YAAY,QAAQ;AAAA,EACnD;AACJ;AAEA,SAAS,cAAc;AACnB,SAAO,OAAO,SAAS;AAC3B;AAKO,SAAS,uBAAuB;AAEnC,QAAM,WAAW,CAAC,gBAAgB;AAC9B,QAAI,gBAAgB,cAAc;AAC9B,aAAO,QAAQ,KAAI;AACnB;AAAA,IACJ;AACA,UAAM,OAAO,WAAW,WAAW;AACnC,QAAI,KAAK,WAAW,GAAG,GAAG;AACtB,aAAO,SAAS,OAAO;AACvB;AAAA,IACJ;AAEA,WAAO,SAAS,OAAO,IAAI;AAAA,EAC/B;AAGA,QAAM,kBAAkB,MAAM;AAC1B,UAAM,OAAO,qBAAqB,iBAAiB,aAAa,MAAM,EAAE;AACxE,UAAM,EAAC,UAAU,OAAM,IAAI,eAAe,OAAO,IAAI,IAAI,IAAI,EAAE,OAAO,EAAE;AACxE,WAAO,EAAC,UAAU,QAAQ,KAAK,KAAI;AAAA,EACvC;AAEA,QAAM,WAAW,CAAC,EAAC,IAAI,GAAG,MAAK,MAAM,cAAc,KAAK,EAAC,MAAM,WAAW,EAAE,GAAG,GAAG,MAAK,CAAC;AAExF,SAAO,OAAO,OAAO,EAAC,aAAa,MAAM,UAAU,aAAa,iBAAiB,MAAM,SAAQ,CAAC;AACpG;"}
@@ -0,0 +1,49 @@
1
+ const HASH_SIGN = "#";
2
+ const ROOT_PATH = "/";
3
+ function normalizedBasePath(basePath) {
4
+ const trimmed = (basePath ?? "").trim().replace(/\/+$/, "");
5
+ if (!trimmed) {
6
+ return "";
7
+ }
8
+ return trimmed.startsWith(ROOT_PATH) ? trimmed : `${ROOT_PATH}${trimmed}`;
9
+ }
10
+ function isAppPath(destination) {
11
+ return destination.startsWith(ROOT_PATH) && !destination.startsWith("//");
12
+ }
13
+ function pathWithBase(basePath, destination) {
14
+ const base = normalizedBasePath(basePath);
15
+ return base && isAppPath(destination) ? `${base}${destination}` : destination;
16
+ }
17
+ function pathWithoutBase(basePath, pathname) {
18
+ const base = normalizedBasePath(basePath);
19
+ if (!base) {
20
+ return pathname;
21
+ }
22
+ if (pathname === base) {
23
+ return ROOT_PATH;
24
+ }
25
+ return pathname.startsWith(`${base}${ROOT_PATH}`) ? pathname.slice(base.length) : pathname;
26
+ }
27
+ function hashLocationOf(hash) {
28
+ const route = (hash ?? "").replace(/^#/, "");
29
+ if (!route) {
30
+ return { pathname: ROOT_PATH, search: "" };
31
+ }
32
+ const searchStart = route.indexOf("?");
33
+ const pathname = searchStart === -1 ? route : route.slice(0, searchStart);
34
+ return {
35
+ pathname: pathname.startsWith(ROOT_PATH) ? pathname : `${ROOT_PATH}${pathname}`,
36
+ search: searchStart === -1 ? "" : route.slice(searchStart)
37
+ };
38
+ }
39
+ function hashHrefOf(destination) {
40
+ return isAppPath(destination) ? `${HASH_SIGN}${destination}` : destination;
41
+ }
42
+ export {
43
+ hashHrefOf,
44
+ hashLocationOf,
45
+ normalizedBasePath,
46
+ pathWithBase,
47
+ pathWithoutBase
48
+ };
49
+ //# sourceMappingURL=navigationPaths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigationPaths.js","sources":["../../src/toolkit/navigationPaths.js"],"sourcesContent":["// Las rutas de la navegación sin router, para sistemas que ya existen (una página de PHP, JSP o .NET con React en un pedazo):\n// - con prefijo: la app vive en /portal/… detrás de un proxy, y los componentes hablan de /pedidos sin saberlo;\n// - con # en la dirección (/app.php#/pedidos): el servidor viejo no sabe responder /pedidos al recargar, y todo lo que va\n// después del # se queda en el navegador.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\n\nconst HASH_SIGN = '#';\nconst ROOT_PATH = '/';\n\n/**\n * El prefijo limpio: '' sin prefijo; si no, empieza con / y no termina con / ('portal/' → '/portal').\n *\n * @param {string|null|undefined} basePath\n * @returns {string}\n */\nexport function normalizedBasePath(basePath) {\n const trimmed = (basePath ?? '').trim().replace(/\\/+$/, '');\n if (!trimmed) {\n return '';\n }\n return trimmed.startsWith(ROOT_PATH) ? trimmed : `${ROOT_PATH}${trimmed}`;\n}\n\n/**\n * ¿Es una ruta de la app ('/pedidos')? Una dirección de afuera ('https://…', '//otro.sitio') o relativa ('?pagina=2') no.\n *\n * @param {string} destination\n * @returns {boolean}\n */\nfunction isAppPath(destination) {\n return destination.startsWith(ROOT_PATH) && !destination.startsWith('//');\n}\n\n/**\n * La dirección real de una ruta de la app con el prefijo puesto: '/pedidos' → '/portal/pedidos'. Lo que no es ruta de la\n * app se queda como viene.\n *\n * @param {string} basePath\n * @param {string} destination\n * @returns {string}\n */\nexport function pathWithBase(basePath, destination) {\n const base = normalizedBasePath(basePath);\n return base && isAppPath(destination) ? `${base}${destination}` : destination;\n}\n\n/**\n * La ruta de la app de una dirección real, sin el prefijo: '/portal/pedidos' → '/pedidos'; el prefijo solo → '/'. Una\n * dirección de fuera del prefijo se queda como viene.\n *\n * @param {string} basePath\n * @param {string} pathname\n * @returns {string}\n */\nexport function pathWithoutBase(basePath, pathname) {\n const base = normalizedBasePath(basePath);\n if (!base) {\n return pathname;\n }\n if (pathname === base) {\n return ROOT_PATH;\n }\n return pathname.startsWith(`${base}${ROOT_PATH}`) ? pathname.slice(base.length) : pathname;\n}\n\n/**\n * La página de la app que va después del # ('#/pedidos?estado=pendiente' → {pathname: '/pedidos', search: '?estado=pendiente'}).\n * Sin nada después del #, el inicio.\n *\n * @param {string} hash el de la dirección (location.hash), con o sin #\n * @returns {{pathname: string, search: string}}\n */\nexport function hashLocationOf(hash) {\n const route = (hash ?? '').replace(/^#/, '');\n if (!route) {\n return {pathname: ROOT_PATH, search: ''};\n }\n const searchStart = route.indexOf('?');\n const pathname = searchStart === -1 ? route : route.slice(0, searchStart);\n return {\n pathname: pathname.startsWith(ROOT_PATH) ? pathname : `${ROOT_PATH}${pathname}`,\n search: searchStart === -1 ? '' : route.slice(searchStart),\n };\n}\n\n/**\n * El enlace de una ruta de la app con # ('/pedidos' → '#/pedidos'). Lo que no es ruta de la app se queda como viene.\n *\n * @param {string} destination\n * @returns {string}\n */\nexport function hashHrefOf(destination) {\n return isAppPath(destination) ? `${HASH_SIGN}${destination}` : destination;\n}\n"],"names":[],"mappings":"AAOA,MAAM,YAAY;AAClB,MAAM,YAAY;AAQX,SAAS,mBAAmB,UAAU;AACzC,QAAM,WAAW,YAAY,IAAI,KAAI,EAAG,QAAQ,QAAQ,EAAE;AAC1D,MAAI,CAAC,SAAS;AACV,WAAO;AAAA,EACX;AACA,SAAO,QAAQ,WAAW,SAAS,IAAI,UAAU,GAAG,SAAS,GAAG,OAAO;AAC3E;AAQA,SAAS,UAAU,aAAa;AAC5B,SAAO,YAAY,WAAW,SAAS,KAAK,CAAC,YAAY,WAAW,IAAI;AAC5E;AAUO,SAAS,aAAa,UAAU,aAAa;AAChD,QAAM,OAAO,mBAAmB,QAAQ;AACxC,SAAO,QAAQ,UAAU,WAAW,IAAI,GAAG,IAAI,GAAG,WAAW,KAAK;AACtE;AAUO,SAAS,gBAAgB,UAAU,UAAU;AAChD,QAAM,OAAO,mBAAmB,QAAQ;AACxC,MAAI,CAAC,MAAM;AACP,WAAO;AAAA,EACX;AACA,MAAI,aAAa,MAAM;AACnB,WAAO;AAAA,EACX;AACA,SAAO,SAAS,WAAW,GAAG,IAAI,GAAG,SAAS,EAAE,IAAI,SAAS,MAAM,KAAK,MAAM,IAAI;AACtF;AASO,SAAS,eAAe,MAAM;AACjC,QAAM,SAAS,QAAQ,IAAI,QAAQ,MAAM,EAAE;AAC3C,MAAI,CAAC,OAAO;AACR,WAAO,EAAC,UAAU,WAAW,QAAQ,GAAE;AAAA,EAC3C;AACA,QAAM,cAAc,MAAM,QAAQ,GAAG;AACrC,QAAM,WAAW,gBAAgB,KAAK,QAAQ,MAAM,MAAM,GAAG,WAAW;AACxE,SAAO;AAAA,IACH,UAAU,SAAS,WAAW,SAAS,IAAI,WAAW,GAAG,SAAS,GAAG,QAAQ;AAAA,IAC7E,QAAQ,gBAAgB,KAAK,KAAK,MAAM,MAAM,WAAW;AAAA,EACjE;AACA;AAQO,SAAS,WAAW,aAAa;AACpC,SAAO,UAAU,WAAW,IAAI,GAAG,SAAS,GAAG,WAAW,KAAK;AACnE;"}
@@ -3,7 +3,10 @@ import en from "../locales/en.js";
3
3
  const DEFAULT_LANGUAGE = "es";
4
4
  const DEFAULT_CURRENCY = "MXN";
5
5
  const PACKAGE_TEXTS_BY_LANGUAGE = Object.freeze({ es, en });
6
- const INTL_LOCALE_BY_LANGUAGE = Object.freeze({ es: "es-MX", en: "en-US" });
6
+ const DEFAULT_LANGUAGES = Object.freeze([
7
+ Object.freeze({ code: "es", label: "Español", locale: "es-MX" }),
8
+ Object.freeze({ code: "en", label: "English", locale: "en-US" })
9
+ ]);
7
10
  const NAMESPACE_SEPARATOR = ":";
8
11
  const KEY_SEPARATOR = ".";
9
12
  const PLURAL_SEPARATOR = "_";
@@ -20,7 +23,9 @@ let currentSettings = Object.freeze({
20
23
  currency: DEFAULT_CURRENCY,
21
24
  appName: "",
22
25
  // la compilación del front que corre en esta pestaña ('' en desarrollo): con ella se sabe si hay una versión nueva
23
- buildId: ""
26
+ buildId: "",
27
+ // los idiomas que ofrece la app (DEFAULT_LANGUAGES)
28
+ languages: DEFAULT_LANGUAGES
24
29
  });
25
30
  function configureToolkit(settings) {
26
31
  currentSettings = Object.freeze({ ...currentSettings, ...settings });
@@ -28,8 +33,9 @@ function configureToolkit(settings) {
28
33
  function toolkitSettings() {
29
34
  return currentSettings;
30
35
  }
31
- function intlLocaleOf(language) {
32
- return INTL_LOCALE_BY_LANGUAGE[language] ?? INTL_LOCALE_BY_LANGUAGE[DEFAULT_LANGUAGE];
36
+ function intlLocaleOf(language, languages = currentSettings.languages) {
37
+ const known = languages?.find((entry) => entry.code === language) ?? DEFAULT_LANGUAGES.find((entry) => entry.code === language);
38
+ return known?.locale ?? language ?? DEFAULT_LANGUAGES[0].locale;
33
39
  }
34
40
  function valueAtPath(texts, path) {
35
41
  let value = texts;
@@ -56,6 +62,18 @@ function textOf(texts, namespace, key, values, language) {
56
62
  function interpolate(text, values) {
57
63
  return text.replace(INTERPOLATION, (placeholder, name) => values?.[name] === void 0 ? placeholder : String(values[name]));
58
64
  }
65
+ function componentTextOf(layers, namespace, key, values, language) {
66
+ for (const layer of layers) {
67
+ if (layer.namespace !== namespace || !layer.texts) {
68
+ continue;
69
+ }
70
+ const text = textOf({ [namespace]: layer.texts }, namespace, key, values, language);
71
+ if (text !== void 0) {
72
+ return interpolate(text, values);
73
+ }
74
+ }
75
+ return void 0;
76
+ }
59
77
  function translateWith(settings, defaultNamespace, key, values) {
60
78
  const [namespace, plainKey] = key.includes(NAMESPACE_SEPARATOR) ? key.split(NAMESPACE_SEPARATOR, 2) : [defaultNamespace, key];
61
79
  const projectText = settings.translate?.(namespace, plainKey, values);
@@ -77,7 +95,9 @@ function translateToolkit(defaultNamespace, key, values) {
77
95
  export {
78
96
  DEFAULT_CURRENCY,
79
97
  DEFAULT_LANGUAGE,
98
+ DEFAULT_LANGUAGES,
80
99
  browserTimeZone,
100
+ componentTextOf,
81
101
  configureToolkit,
82
102
  intlLocaleOf,
83
103
  toolkitSettings,
@@ -1 +1 @@
1
- {"version":3,"file":"toolkitSettings.js","sources":["../../src/toolkit/toolkitSettings.js"],"sourcesContent":["// La configuración del paquete: idioma, textos, zona horaria, moneda, nombre de la aplicación y navegación.\n//\n// La pone ToolkitProvider en cada render y la leen también las funciones que no son componentes (formatos de fecha y\n// número, avisos, errores del servidor). Sin proveedor valen los de omisión: español, la zona del navegador y la\n// navegación del navegador.\n//\n// Los textos se resuelven en este orden, para que cada proyecto cambie solo lo que necesite:\n// 1. translate del proyecto (por ejemplo el t de i18next), si regresa un texto;\n// 2. los textos que el proyecto pasó en `texts`, del idioma activo;\n// 3. los textos del paquete (locales/), del idioma activo y, si no está, en español.\n// Las llaves usan la forma de i18next: «namespace:llave.anidada», {{variable}} y plurales con _one / _other.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\nimport es from '@/locales/es.js';\nimport en from '@/locales/en.js';\n\nexport const DEFAULT_LANGUAGE = 'es';\n// la moneda de los montos (código ISO 4217) cuando el proyecto no dice otra\nexport const DEFAULT_CURRENCY = 'MXN';\n\nconst PACKAGE_TEXTS_BY_LANGUAGE = Object.freeze({es, en});\n\n// cómo se escriben números y fechas en cada idioma (Intl)\nconst INTL_LOCALE_BY_LANGUAGE = Object.freeze({es: 'es-MX', en: 'en-US'});\n\nconst NAMESPACE_SEPARATOR = ':';\nconst KEY_SEPARATOR = '.';\nconst PLURAL_SEPARATOR = '_';\nconst PLURAL_OTHER = 'other';\nconst INTERPOLATION = /\\{\\{\\s*(\\w+)\\s*\\}\\}/g;\n\n/**\n * La zona horaria del navegador; si el navegador no la sabe, la de la Ciudad de México.\n *\n * @returns {string}\n */\nexport function browserTimeZone() {\n return Intl.DateTimeFormat().resolvedOptions().timeZone ?? 'America/Mexico_City';\n}\n\nlet currentSettings = Object.freeze({\n language: DEFAULT_LANGUAGE,\n texts: {},\n translate: null,\n timeZone: browserTimeZone(),\n currency: DEFAULT_CURRENCY,\n appName: '',\n // la compilación del front que corre en esta pestaña ('' en desarrollo): con ella se sabe si hay una versión nueva\n buildId: '',\n});\n\n/**\n * Cambia la configuración que leen las funciones del paquete. La llama ToolkitProvider; un proyecto sin React (o una\n * prueba) la puede llamar directo.\n *\n * @param {{language?: string, texts?: object, translate?: Function|null, timeZone?: string, currency?: string, appName?: string, buildId?: string}} settings\n * @returns {void}\n */\nexport function configureToolkit(settings) {\n currentSettings = Object.freeze({...currentSettings, ...settings});\n}\n\n/**\n * La configuración vigente.\n *\n * @returns {{language: string, texts: object, translate: Function|null, timeZone: string, currency: string, appName: string, buildId: string}}\n */\nexport function toolkitSettings() {\n return currentSettings;\n}\n\n/**\n * El locale de Intl del idioma (es → es-MX, en → en-US).\n *\n * @param {string} language\n * @returns {string}\n */\nexport function intlLocaleOf(language) {\n return INTL_LOCALE_BY_LANGUAGE[language] ?? INTL_LOCALE_BY_LANGUAGE[DEFAULT_LANGUAGE];\n}\n\n/**\n * Lo que hay en una ruta de llaves («toast.error») dentro de un objeto de textos.\n *\n * @param {object|undefined} texts\n * @param {string} path\n * @returns {unknown}\n */\nfunction valueAtPath(texts, path) {\n let value = texts;\n for (const part of path.split(KEY_SEPARATOR)) {\n if (value === null || typeof value !== 'object') {\n return undefined;\n }\n value = value[part];\n }\n\n return value;\n}\n\n/**\n * El texto de una llave en un objeto de textos, con su plural si trae count (como i18next: llave_one, llave_other).\n *\n * @param {object|undefined} texts los textos de un idioma, por namespace\n * @param {string} namespace\n * @param {string} key\n * @param {object|undefined} values\n * @param {string} language\n * @returns {string|undefined}\n */\nfunction textOf(texts, namespace, key, values, language) {\n const namespaceTexts = texts?.[namespace];\n if (typeof values?.count === 'number') {\n const pluralCategory = new Intl.PluralRules(intlLocaleOf(language)).select(values.count);\n const pluralText = valueAtPath(namespaceTexts, `${key}${PLURAL_SEPARATOR}${pluralCategory}`)\n ?? valueAtPath(namespaceTexts, `${key}${PLURAL_SEPARATOR}${PLURAL_OTHER}`);\n if (typeof pluralText === 'string') {\n return pluralText;\n }\n }\n\n const text = valueAtPath(namespaceTexts, key);\n\n return typeof text === 'string' ? text : undefined;\n}\n\n/**\n * Pone los valores en las {{variables}} del texto; una variable sin valor se queda como está.\n *\n * @param {string} text\n * @param {object|undefined} values\n * @returns {string}\n */\nfunction interpolate(text, values) {\n return text.replace(INTERPOLATION, (placeholder, name) => (values?.[name] === undefined ? placeholder : String(values[name])));\n}\n\n/**\n * El texto de una llave con una configuración dada (la del proveedor o la vigente).\n *\n * @param {{language: string, texts: object, translate: Function|null}} settings\n * @param {string} defaultNamespace el namespace cuando la llave no trae uno («table», «common», «problems»...)\n * @param {string} key «llave» o «namespace:llave»\n * @param {object} [values] las variables del texto y, para el plural, count\n * @returns {string} la llave misma si no hay texto, para que se note qué falta\n */\nexport function translateWith(settings, defaultNamespace, key, values) {\n const [namespace, plainKey] = key.includes(NAMESPACE_SEPARATOR) ? key.split(NAMESPACE_SEPARATOR, 2) : [defaultNamespace, key];\n const projectText = settings.translate?.(namespace, plainKey, values);\n if (typeof projectText === 'string') {\n return projectText;\n }\n\n const text = textOf(settings.texts?.[settings.language], namespace, plainKey, values, settings.language)\n ?? textOf(PACKAGE_TEXTS_BY_LANGUAGE[settings.language], namespace, plainKey, values, settings.language)\n ?? textOf(PACKAGE_TEXTS_BY_LANGUAGE[DEFAULT_LANGUAGE], namespace, plainKey, values, DEFAULT_LANGUAGE);\n\n if (text !== undefined) {\n return interpolate(text, values);\n }\n // como en i18next: sin la llave en ningún lado, el texto por omisión que pidió quien llama (un globo opcional pasa ''\n // y no se pinta); sin él, la llave tal cual, para que se note qué falta\n if (typeof values?.defaultValue === 'string') {\n return interpolate(values.defaultValue, values);\n }\n return `${namespace}${NAMESPACE_SEPARATOR}${plainKey}`;\n}\n\n/**\n * El texto de una llave con la configuración vigente, para lo que no es componente (avisos, errores del servidor).\n *\n * @param {string} defaultNamespace\n * @param {string} key\n * @param {object} [values]\n * @returns {string}\n */\nexport function translateToolkit(defaultNamespace, key, values) {\n return translateWith(currentSettings, defaultNamespace, key, values);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"toolkitSettings.js","sources":["../../src/toolkit/toolkitSettings.js"],"sourcesContent":["// La configuración del paquete: idioma, textos, zona horaria, moneda, nombre de la aplicación y navegación.\n//\n// La pone ToolkitProvider en cada render y la leen también las funciones que no son componentes (formatos de fecha y\n// número, avisos, errores del servidor). Sin proveedor valen los de omisión: español, la zona del navegador y la\n// navegación del navegador.\n//\n// Los textos se resuelven en este orden, para que cada proyecto cambie solo lo que necesite:\n// 1. translate del proyecto (por ejemplo el t de i18next), si regresa un texto;\n// 2. los textos que el proyecto pasó en `texts`, del idioma activo;\n// 3. los textos del paquete (locales/), del idioma activo y, si no está, en español.\n// Las llaves usan la forma de i18next: «namespace:llave.anidada», {{variable}} y plurales con _one / _other.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\nimport es from '@/locales/es.js';\nimport en from '@/locales/en.js';\n\nexport const DEFAULT_LANGUAGE = 'es';\n// la moneda de los montos (código ISO 4217) cuando el proyecto no dice otra\nexport const DEFAULT_CURRENCY = 'MXN';\n\nconst PACKAGE_TEXTS_BY_LANGUAGE = Object.freeze({es, en});\n\n/**\n * Los idiomas que ofrece la app cuando el proyecto no dice otros: su código, su nombre en su propio idioma (así lo busca quien\n * lo habla) y cómo se escriben sus números y fechas (Intl). El proyecto agrega los suyos en ToolkitProvider `languages` y pone\n * sus traducciones en `texts` (lo que no traduzca sale en español); los textos del paquete solo vienen en español e inglés.\n */\nexport const DEFAULT_LANGUAGES = Object.freeze([\n Object.freeze({code: 'es', label: 'Español', locale: 'es-MX'}),\n Object.freeze({code: 'en', label: 'English', locale: 'en-US'}),\n]);\n\nconst NAMESPACE_SEPARATOR = ':';\nconst KEY_SEPARATOR = '.';\nconst PLURAL_SEPARATOR = '_';\nconst PLURAL_OTHER = 'other';\nconst INTERPOLATION = /\\{\\{\\s*(\\w+)\\s*\\}\\}/g;\n\n/**\n * La zona horaria del navegador; si el navegador no la sabe, la de la Ciudad de México.\n *\n * @returns {string}\n */\nexport function browserTimeZone() {\n return Intl.DateTimeFormat().resolvedOptions().timeZone ?? 'America/Mexico_City';\n}\n\nlet currentSettings = Object.freeze({\n language: DEFAULT_LANGUAGE,\n texts: {},\n translate: null,\n timeZone: browserTimeZone(),\n currency: DEFAULT_CURRENCY,\n appName: '',\n // la compilación del front que corre en esta pestaña ('' en desarrollo): con ella se sabe si hay una versión nueva\n buildId: '',\n // los idiomas que ofrece la app (DEFAULT_LANGUAGES)\n languages: DEFAULT_LANGUAGES,\n});\n\n/**\n * Cambia la configuración que leen las funciones del paquete. La llama ToolkitProvider; un proyecto sin React (o una\n * prueba) la puede llamar directo.\n *\n * @param {{language?: string, texts?: object, translate?: Function|null, timeZone?: string, currency?: string, appName?: string, buildId?: string, languages?: Array<{code: string, label: string, locale?: string}>}} settings\n * @returns {void}\n */\nexport function configureToolkit(settings) {\n currentSettings = Object.freeze({...currentSettings, ...settings});\n}\n\n/**\n * La configuración vigente.\n *\n * @returns {{language: string, texts: object, translate: Function|null, timeZone: string, currency: string, appName: string, buildId: string, languages: Array<{code: string, label: string, locale?: string}>}}\n */\nexport function toolkitSettings() {\n return currentSettings;\n}\n\n/**\n * El locale de Intl del idioma: el que dice su lista de idiomas (es → es-MX, pt → pt-BR) o, si no dice, el código mismo\n * (Intl entiende «pt»). OJO: antes un idioma que no fuera es ni en salía con los números y las fechas de México.\n *\n * @param {string} language\n * @param {Array<{code: string, locale?: string}>} [languages] por omisión los de la configuración vigente\n * @returns {string}\n */\nexport function intlLocaleOf(language, languages = currentSettings.languages) {\n const known = languages?.find((entry) => entry.code === language) ?? DEFAULT_LANGUAGES.find((entry) => entry.code === language);\n return known?.locale ?? language ?? DEFAULT_LANGUAGES[0].locale;\n}\n\n/**\n * Lo que hay en una ruta de llaves («toast.error») dentro de un objeto de textos.\n *\n * @param {object|undefined} texts\n * @param {string} path\n * @returns {unknown}\n */\nfunction valueAtPath(texts, path) {\n let value = texts;\n for (const part of path.split(KEY_SEPARATOR)) {\n if (value === null || typeof value !== 'object') {\n return undefined;\n }\n value = value[part];\n }\n\n return value;\n}\n\n/**\n * El texto de una llave en un objeto de textos, con su plural si trae count (como i18next: llave_one, llave_other).\n *\n * @param {object|undefined} texts los textos de un idioma, por namespace\n * @param {string} namespace\n * @param {string} key\n * @param {object|undefined} values\n * @param {string} language\n * @returns {string|undefined}\n */\nfunction textOf(texts, namespace, key, values, language) {\n const namespaceTexts = texts?.[namespace];\n if (typeof values?.count === 'number') {\n const pluralCategory = new Intl.PluralRules(intlLocaleOf(language)).select(values.count);\n const pluralText = valueAtPath(namespaceTexts, `${key}${PLURAL_SEPARATOR}${pluralCategory}`)\n ?? valueAtPath(namespaceTexts, `${key}${PLURAL_SEPARATOR}${PLURAL_OTHER}`);\n if (typeof pluralText === 'string') {\n return pluralText;\n }\n }\n\n const text = valueAtPath(namespaceTexts, key);\n\n return typeof text === 'string' ? text : undefined;\n}\n\n/**\n * Pone los valores en las {{variables}} del texto; una variable sin valor se queda como está.\n *\n * @param {string} text\n * @param {object|undefined} values\n * @returns {string}\n */\nfunction interpolate(text, values) {\n return text.replace(INTERPOLATION, (placeholder, name) => (values?.[name] === undefined ? placeholder : String(values[name])));\n}\n\n/**\n * El texto de una llave en los textos propios de los componentes (la prop `texts` de un componente y los de ComponentTexts\n * de afuera), si alguno la trae. Cada capa es {namespace, texts} con la misma forma que ese namespace en los textos del\n * paquete (es.js): plurales con _one/_other y {{variables}}. La primera capa que trae la llave gana.\n *\n * @param {Array<{namespace: string, texts: object|undefined}>} layers de la más cercana a la más lejana\n * @param {string} namespace el de la llave\n * @param {string} key la llave sin namespace\n * @param {object|undefined} values\n * @param {string} language para elegir el plural\n * @returns {string|undefined} el texto ya con sus variables, o undefined si ninguna capa lo trae\n */\nexport function componentTextOf(layers, namespace, key, values, language) {\n for (const layer of layers) {\n if (layer.namespace !== namespace || !layer.texts) {\n continue;\n }\n const text = textOf({[namespace]: layer.texts}, namespace, key, values, language);\n if (text !== undefined) {\n return interpolate(text, values);\n }\n }\n\n return undefined;\n}\n\n/**\n * El texto de una llave con una configuración dada (la del proveedor o la vigente).\n *\n * @param {{language: string, texts: object, translate: Function|null}} settings\n * @param {string} defaultNamespace el namespace cuando la llave no trae uno («table», «common», «problems»...)\n * @param {string} key «llave» o «namespace:llave»\n * @param {object} [values] las variables del texto y, para el plural, count\n * @returns {string} la llave misma si no hay texto, para que se note qué falta\n */\nexport function translateWith(settings, defaultNamespace, key, values) {\n const [namespace, plainKey] = key.includes(NAMESPACE_SEPARATOR) ? key.split(NAMESPACE_SEPARATOR, 2) : [defaultNamespace, key];\n const projectText = settings.translate?.(namespace, plainKey, values);\n if (typeof projectText === 'string') {\n return projectText;\n }\n\n const text = textOf(settings.texts?.[settings.language], namespace, plainKey, values, settings.language)\n ?? textOf(PACKAGE_TEXTS_BY_LANGUAGE[settings.language], namespace, plainKey, values, settings.language)\n ?? textOf(PACKAGE_TEXTS_BY_LANGUAGE[DEFAULT_LANGUAGE], namespace, plainKey, values, DEFAULT_LANGUAGE);\n\n if (text !== undefined) {\n return interpolate(text, values);\n }\n // como en i18next: sin la llave en ningún lado, el texto por omisión que pidió quien llama (un globo opcional pasa ''\n // y no se pinta); sin él, la llave tal cual, para que se note qué falta\n if (typeof values?.defaultValue === 'string') {\n return interpolate(values.defaultValue, values);\n }\n return `${namespace}${NAMESPACE_SEPARATOR}${plainKey}`;\n}\n\n/**\n * El texto de una llave con la configuración vigente, para lo que no es componente (avisos, errores del servidor).\n *\n * @param {string} defaultNamespace\n * @param {string} key\n * @param {object} [values]\n * @returns {string}\n */\nexport function translateToolkit(defaultNamespace, key, values) {\n return translateWith(currentSettings, defaultNamespace, key, values);\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { useMemo } from "react";
3
+ import { formattersOf } from "../formatting.js";
4
+ import { useToolkitSettings } from "./toolkitContext.js";
5
+ function useFormatters() {
6
+ const settings = useToolkitSettings();
7
+ return useMemo(() => formattersOf(() => settings), [settings]);
8
+ }
9
+ export {
10
+ useFormatters
11
+ };
12
+ //# sourceMappingURL=useFormatters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFormatters.js","sources":["../../src/toolkit/useFormatters.js"],"sourcesContent":["// Los formatos de fecha, hora, número, moneda y tamaño de archivo con la configuración del ToolkitProvider MÁS CERCANO.\n//\n// Es lo que usan los componentes del paquete, y lo que conviene en los del proyecto: con dos proveedores (una parte de la app\n// en otro idioma, o dos islas de React en una página que no es de React) cada parte escribe con el suyo. Los formatos sueltos\n// (formatDate…) usan el de la raíz: sirven para lo que no es componente.\n//\n// const {formatDate, formatCurrency} = useFormatters();\n// <Typography>{formatDate(order.created_at)} · {formatCurrency(order.total)}</Typography>\n//\n// Hook genérico: function (regla de la casa).\nimport {useMemo} from 'react';\n\nimport {formattersOf} from '@/formatting.js';\nimport {useToolkitSettings} from '@/toolkit/toolkitContext.js';\n\n/**\n * @returns {ReturnType<typeof formattersOf>} formatNumber, formatList, formatCurrency, formatFileSize, formatPercent,\n * formatDateTime, formatDate, formatTime, formatMonthName, formatMonthShortName y formatWeekdayShortName\n */\nexport function useFormatters() {\n const settings = useToolkitSettings();\n return useMemo(() => formattersOf(() => settings), [settings]);\n}\n"],"names":[],"mappings":";;;;AAmBO,SAAS,gBAAgB;AAC5B,QAAM,WAAW,mBAAkB;AACnC,SAAO,QAAQ,MAAM,aAAa,MAAM,QAAQ,GAAG,CAAC,QAAQ,CAAC;AACjE;"}
@@ -1,14 +1,18 @@
1
1
  "use client";
2
- import { useCallback } from "react";
2
+ import { useContext, useCallback } from "react";
3
+ import { ComponentTextsContext, layersOf } from "./componentTextsContext.js";
3
4
  import { useToolkitSettings } from "./toolkitContext.js";
4
- import { translateWith } from "./toolkitSettings.js";
5
- function useToolkitTranslation(namespace) {
5
+ import { componentTextOf, translateWith } from "./toolkitSettings.js";
6
+ const NAMESPACE_SEPARATOR = ":";
7
+ function useToolkitTranslation(namespace, ownTexts) {
6
8
  const settings = useToolkitSettings();
9
+ const outerTexts = useContext(ComponentTextsContext);
7
10
  const defaultNamespace = Array.isArray(namespace) ? namespace[0] : namespace;
8
- const t = useCallback(
9
- (key, values) => translateWith(settings, defaultNamespace, key, values),
10
- [settings, defaultNamespace]
11
- );
11
+ const t = useCallback((key, values) => {
12
+ const [keyNamespace, plainKey] = key.includes(NAMESPACE_SEPARATOR) ? key.split(NAMESPACE_SEPARATOR, 2) : [defaultNamespace, key];
13
+ const layers = [{ namespace: defaultNamespace, texts: ownTexts }, ...layersOf(outerTexts)];
14
+ return componentTextOf(layers, keyNamespace, plainKey, values, settings.language) ?? translateWith(settings, defaultNamespace, key, values);
15
+ }, [settings, defaultNamespace, ownTexts, outerTexts]);
12
16
  const changeLanguage = useCallback((language) => settings.onLanguageChange?.(language), [settings]);
13
17
  return { t, language: settings.language, changeLanguage };
14
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useToolkitTranslation.js","sources":["../../src/toolkit/useToolkitTranslation.js"],"sourcesContent":["// Los textos del paquete dentro de un componente, con la misma forma que useTranslation de react-i18next:\n//\n// const {t, language, changeLanguage} = useToolkitTranslation('table');\n// t('goToPage.of', {count: pageCount, total})\n//\n// Se vuelve a pintar cuando cambia el idioma o los textos del proveedor. El orden en que se buscan los textos está en\n// toolkitSettings.js.\n//\n// Hook genérico: function (regla de la casa).\nimport {useCallback} from 'react';\nimport {useToolkitSettings} from '@/toolkit/toolkitContext.js';\nimport {translateWith} from '@/toolkit/toolkitSettings.js';\n\n/**\n * @param {string|string[]} [namespace] el namespace de las llaves sin prefijo; con una lista, el primero. Sin él, cada\n * llave lleva el suyo ('orders:list.title')\n * @returns {{t: (key: string, values?: object) => string, language: string, changeLanguage: (language: string) => void}}\n */\nexport function useToolkitTranslation(namespace) {\n const settings = useToolkitSettings();\n const defaultNamespace = Array.isArray(namespace) ? namespace[0] : namespace;\n const t = useCallback(\n (key, values) => translateWith(settings, defaultNamespace, key, values),\n [settings, defaultNamespace],\n );\n // sin onLanguageChange del proyecto no hay a quién avisarle: el botón de idioma no hace nada\n const changeLanguage = useCallback((language) => settings.onLanguageChange?.(language), [settings]);\n\n return {t, language: settings.language, changeLanguage};\n}\n"],"names":[],"mappings":";;;;AAkBO,SAAS,sBAAsB,WAAW;AAC7C,QAAM,WAAW,mBAAkB;AACnC,QAAM,mBAAmB,MAAM,QAAQ,SAAS,IAAI,UAAU,CAAC,IAAI;AACnE,QAAM,IAAI;AAAA,IACN,CAAC,KAAK,WAAW,cAAc,UAAU,kBAAkB,KAAK,MAAM;AAAA,IACtE,CAAC,UAAU,gBAAgB;AAAA,EACnC;AAEI,QAAM,iBAAiB,YAAY,CAAC,aAAa,SAAS,mBAAmB,QAAQ,GAAG,CAAC,QAAQ,CAAC;AAElG,SAAO,EAAC,GAAG,UAAU,SAAS,UAAU,eAAc;AAC1D;"}
1
+ {"version":3,"file":"useToolkitTranslation.js","sources":["../../src/toolkit/useToolkitTranslation.js"],"sourcesContent":["// Los textos del paquete dentro de un componente, con la misma forma que useTranslation de react-i18next:\n//\n// const {t, language, changeLanguage} = useToolkitTranslation('table');\n// t('goToPage.of', {count: pageCount, total})\n//\n// Se vuelve a pintar cuando cambia el idioma o los textos del proveedor. El orden en que se buscan los textos está en\n// toolkitSettings.js; antes que todos van los textos propios del componente (su prop `texts`, el segundo parámetro) y los de\n// ComponentTexts de afuera: un texto de una pantalla se cambia ahí, sin tocar el idioma completo.\n//\n// const {t} = useToolkitTranslation('table', texts);\n//\n// Hook genérico: function (regla de la casa).\nimport {useCallback, useContext} from 'react';\nimport {ComponentTextsContext, layersOf} from '@/toolkit/componentTextsContext.js';\nimport {useToolkitSettings} from '@/toolkit/toolkitContext.js';\nimport {componentTextOf, translateWith} from '@/toolkit/toolkitSettings.js';\n\nconst NAMESPACE_SEPARATOR = ':';\n\n/**\n * @param {string|string[]} [namespace] el namespace de las llaves sin prefijo; con una lista, el primero. Sin él, cada\n * llave lleva el suyo ('orders:list.title')\n * @param {object} [ownTexts] los textos propios del componente (su prop `texts`), con la forma de ese namespace\n * @returns {{t: (key: string, values?: object) => string, language: string, changeLanguage: (language: string) => void}}\n */\nexport function useToolkitTranslation(namespace, ownTexts) {\n const settings = useToolkitSettings();\n const outerTexts = useContext(ComponentTextsContext);\n const defaultNamespace = Array.isArray(namespace) ? namespace[0] : namespace;\n const t = useCallback((key, values) => {\n const [keyNamespace, plainKey] = key.includes(NAMESPACE_SEPARATOR) ? key.split(NAMESPACE_SEPARATOR, 2) : [defaultNamespace, key];\n const layers = [{namespace: defaultNamespace, texts: ownTexts}, ...layersOf(outerTexts)];\n return componentTextOf(layers, keyNamespace, plainKey, values, settings.language)\n ?? translateWith(settings, defaultNamespace, key, values);\n }, [settings, defaultNamespace, ownTexts, outerTexts]);\n // sin onLanguageChange del proyecto no hay a quién avisarle: el botón de idioma no hace nada\n const changeLanguage = useCallback((language) => settings.onLanguageChange?.(language), [settings]);\n\n return {t, language: settings.language, changeLanguage};\n}\n"],"names":[],"mappings":";;;;;AAiBA,MAAM,sBAAsB;AAQrB,SAAS,sBAAsB,WAAW,UAAU;AACvD,QAAM,WAAW,mBAAkB;AACnC,QAAM,aAAa,WAAW,qBAAqB;AACnD,QAAM,mBAAmB,MAAM,QAAQ,SAAS,IAAI,UAAU,CAAC,IAAI;AACnE,QAAM,IAAI,YAAY,CAAC,KAAK,WAAW;AACnC,UAAM,CAAC,cAAc,QAAQ,IAAI,IAAI,SAAS,mBAAmB,IAAI,IAAI,MAAM,qBAAqB,CAAC,IAAI,CAAC,kBAAkB,GAAG;AAC/H,UAAM,SAAS,CAAC,EAAC,WAAW,kBAAkB,OAAO,SAAQ,GAAG,GAAG,SAAS,UAAU,CAAC;AACvF,WAAO,gBAAgB,QAAQ,cAAc,UAAU,QAAQ,SAAS,QAAQ,KACzE,cAAc,UAAU,kBAAkB,KAAK,MAAM;AAAA,EAChE,GAAG,CAAC,UAAU,kBAAkB,UAAU,UAAU,CAAC;AAErD,QAAM,iBAAiB,YAAY,CAAC,aAAa,SAAS,mBAAmB,QAAQ,GAAG,CAAC,QAAQ,CAAC;AAElG,SAAO,EAAC,GAAG,UAAU,SAAS,UAAU,eAAc;AAC1D;"}
@@ -10,8 +10,9 @@
10
10
  * @param {string} props.ariaLabel
11
11
  * @param {number} [props.maxGridHeight]
12
12
  * @param {unknown} [props.refreshToken] cambia para volver a consultar (después de una acción sobre el mismo renglón)
13
+ * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete
13
14
  */
14
- export default function AuditTrailTable({ subjectKey, fetchPage, eventDictionary, resultDictionary, extraColumns, ariaLabel, maxGridHeight, refreshToken, eventSuffixOf, }: {
15
+ export default function AuditTrailTable({ subjectKey, fetchPage, eventDictionary, resultDictionary, extraColumns, ariaLabel, maxGridHeight, refreshToken, eventSuffixOf, texts, }: {
15
16
  subjectKey: string;
16
17
  fetchPage: (tableRequest: object, signal: AbortSignal) => Promise<{
17
18
  rows: any[];
@@ -25,4 +26,5 @@ export default function AuditTrailTable({ subjectKey, fetchPage, eventDictionary
25
26
  ariaLabel: string;
26
27
  maxGridHeight?: number;
27
28
  refreshToken?: unknown;
29
+ texts?: object;
28
30
  }): import("react").JSX.Element;
@@ -1,8 +1,13 @@
1
1
  /**
2
- * @param {{filtered?: boolean, label?: string, onClearFilters?: () => void}} props label ya traducido
2
+ * @param {object} [props]
3
+ * @param {boolean} [props.filtered]
4
+ * @param {string} [props.label] ya traducido
5
+ * @param {() => void} [props.onClearFilters]
6
+ * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete
3
7
  */
4
- export default function EmptyState({ filtered, label, onClearFilters }: {
8
+ export default function EmptyState({ filtered, label, onClearFilters, texts }?: {
5
9
  filtered?: boolean;
6
10
  label?: string;
7
11
  onClearFilters?: () => void;
12
+ texts?: object;
8
13
  }): import("react").JSX.Element;
@@ -5,11 +5,13 @@
5
5
  * @param {(field: string, value: unknown) => void} props.onSetFilter
6
6
  * @param {() => void} props.onClearAll
7
7
  * @param {number} [props.quickActiveCount] accesos rápidos puestos que no tienen chip aquí
8
+ * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete
8
9
  */
9
- export default function FilterChips({ chipConfig, filters, onSetFilter, onClearAll, quickActiveCount }: {
10
+ export default function FilterChips({ chipConfig, filters, onSetFilter, onClearAll, quickActiveCount, texts }: {
10
11
  chipConfig: Array<object>;
11
12
  filters: object;
12
13
  onSetFilter: (field: string, value: unknown) => void;
13
14
  onClearAll: () => void;
14
15
  quickActiveCount?: number;
16
+ texts?: object;
15
17
  }): import("react").JSX.Element | null;
@@ -1,8 +1,13 @@
1
1
  /**
2
- * @param {{page: number, pageCount: number, onChange: (page: number) => void}} props page cuenta desde 0
2
+ * @param {object} props
3
+ * @param {number} props.page cuenta desde 0
4
+ * @param {number} props.pageCount
5
+ * @param {(page: number) => void} props.onChange
6
+ * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete
3
7
  */
4
- export default function GoToPage({ page, pageCount, onChange }: {
8
+ export default function GoToPage({ page, pageCount, onChange, texts }: {
5
9
  page: number;
6
10
  pageCount: number;
7
11
  onChange: (page: number) => void;
12
+ texts?: object;
8
13
  }): import("react").JSX.Element | null;
@@ -0,0 +1,32 @@
1
+ /** Dónde va la barra de los elegidos: todo en el renglón, o dividida en el teléfono (arriba el conteo, abajo las acciones). */
2
+ export declare const SELECTION_BAR_VARIANT: Readonly<{
3
+ row: "row";
4
+ header: "header";
5
+ actions: "actions";
6
+ }>;
7
+ /**
8
+ * @param {object} props
9
+ * @param {string} props.countText «5 elegidos», ya traducido
10
+ * @param {Array<{key: string, label: string, icon?: import('react').ReactNode, color?: string, isDisabled?: boolean}>} props.actions
11
+ * las acciones de la pantalla, con isDisabled ya resuelto para la selección de ahora
12
+ * @param {string|null} props.runningActionKey la acción que está corriendo: mientras, las demás se apagan
13
+ * @param {(actionKey: string) => void} props.onRunAction
14
+ * @param {() => void} props.onClear quitar la selección
15
+ * @param {'row'|'header'|'actions'} [props.variant] SELECTION_BAR_VARIANT; por omisión el renglón
16
+ * @param {object} [props.sx]
17
+ */
18
+ export default function SelectionBar({ countText, actions, runningActionKey, onRunAction, onClear, variant, sx }: {
19
+ countText: string;
20
+ actions: Array<{
21
+ key: string;
22
+ label: string;
23
+ icon?: import('react').ReactNode;
24
+ color?: string;
25
+ isDisabled?: boolean;
26
+ }>;
27
+ runningActionKey: string | null;
28
+ onRunAction: (actionKey: string) => void;
29
+ onClear: () => void;
30
+ variant?: 'row' | 'header' | 'actions';
31
+ sx?: object;
32
+ }): import("react").JSX.Element;