@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,24 +1,184 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
3
4
  import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";
5
+ import Avatar from "@mui/material/Avatar";
6
+ import AvatarGroup from "@mui/material/AvatarGroup";
4
7
  import Box from "@mui/material/Box";
5
8
  import Chip from "@mui/material/Chip";
9
+ import IconButton from "@mui/material/IconButton";
6
10
  import Paper from "@mui/material/Paper";
7
11
  import Stack from "@mui/material/Stack";
12
+ import TextField from "@mui/material/TextField";
13
+ import Tooltip from "@mui/material/Tooltip";
8
14
  import Typography from "@mui/material/Typography";
15
+ import AddRoundedIcon from "@mui/icons-material/AddRounded";
16
+ import AttachFileRoundedIcon from "@mui/icons-material/AttachFileRounded";
17
+ import ChatBubbleOutlineRoundedIcon from "@mui/icons-material/ChatBubbleOutlineRounded";
18
+ import CheckBoxOutlinedIcon from "@mui/icons-material/CheckBoxOutlined";
19
+ import CheckCircleRoundedIcon from "@mui/icons-material/CheckCircleRounded";
20
+ import EventOutlinedIcon from "@mui/icons-material/EventOutlined";
21
+ import KeyboardDoubleArrowLeftRoundedIcon from "@mui/icons-material/KeyboardDoubleArrowLeftRounded";
22
+ import KeyboardDoubleArrowRightRoundedIcon from "@mui/icons-material/KeyboardDoubleArrowRightRounded";
23
+ import RadioButtonUncheckedRoundedIcon from "@mui/icons-material/RadioButtonUncheckedRounded";
24
+ import { initialsOf } from "../appShell/menuItemText.js";
25
+ import { useFormatters } from "../toolkit/useFormatters.js";
26
+ import { DUE_STATUS, todayIsoDateOf, dueStatusOf } from "./kanbanCards.js";
9
27
  import { cardsOfColumn, isOverLimit } from "./kanbanMoves.js";
10
28
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
29
+ import ActionsMenu from "../ui/actions/ActionsMenu.js";
30
+ import { tagOf } from "../ui/labels/tagOf.js";
11
31
  const COLUMN_MIN_WIDTH_PIXELS = 220;
12
32
  const EMPTY_COLUMN_MIN_HEIGHT = 96;
13
- function DefaultCard({ card }) {
33
+ const MAX_VISIBLE_ASSIGNEES = 3;
34
+ const ASSIGNEE_AVATAR_PIXELS = 24;
35
+ const COLLAPSED_COLUMN_WIDTH_PIXELS = 52;
36
+ const DUE_COLOR = Object.freeze({ [DUE_STATUS.overdue]: "error.main", [DUE_STATUS.today]: "warning.dark", [DUE_STATUS.upcoming]: "text.secondary" });
37
+ function CompleteButton({ card, t, onComplete }) {
38
+ const label = card.completed ? t("reopen", { title: card.title }) : t("complete", { title: card.title });
39
+ return /* @__PURE__ */ jsx(Tooltip, { title: label, children: /* @__PURE__ */ jsx(
40
+ IconButton,
41
+ {
42
+ size: "small",
43
+ "aria-label": label,
44
+ "aria-pressed": Boolean(card.completed),
45
+ sx: { m: -0.5, color: card.completed ? "success.main" : "text.secondary" },
46
+ onClick: (event) => {
47
+ event.stopPropagation();
48
+ onComplete(card, !card.completed);
49
+ },
50
+ children: card.completed ? /* @__PURE__ */ jsx(CheckCircleRoundedIcon, { fontSize: "small" }) : /* @__PURE__ */ jsx(RadioButtonUncheckedRoundedIcon, { fontSize: "small" })
51
+ }
52
+ ) });
53
+ }
54
+ function DefaultCard({ card, t, today, onComplete }) {
55
+ const { formatDate } = useFormatters();
56
+ const dueStatus = card.completed && card.dueDate ? DUE_STATUS.upcoming : dueStatusOf(card.dueDate, today);
57
+ let dueText = "";
58
+ if (card.completed && card.dueDate) {
59
+ dueText = t("dueCompleted", { date: formatDate(card.dueDate) });
60
+ } else if (dueStatus === DUE_STATUS.overdue) {
61
+ dueText = t("dueOverdue", { date: formatDate(card.dueDate) });
62
+ } else if (dueStatus === DUE_STATUS.today) {
63
+ dueText = t("dueToday");
64
+ } else if (dueStatus) {
65
+ dueText = t("dueOn", { date: formatDate(card.dueDate) });
66
+ }
67
+ const hasFooter = dueStatus || card.checklist?.total > 0 || card.comments > 0 || card.attachments > 0 || card.assignees?.length > 0;
14
68
  return /* @__PURE__ */ jsxs(Stack, { spacing: 0.75, children: [
15
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", component: "p", children: card.title }),
69
+ card.tags?.length > 0 && /* @__PURE__ */ jsx(Stack, { direction: "row", spacing: 0.5, useFlexGap: true, sx: { flexWrap: "wrap" }, children: card.tags.map((rawTag) => {
70
+ const tag = tagOf(rawTag);
71
+ return /* @__PURE__ */ jsx(Chip, { label: tag.label, size: "small", color: tag.color, variant: tag.color === "default" ? "filled" : "outlined" }, tag.label);
72
+ }) }),
73
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { alignItems: "flex-start" }, children: [
74
+ onComplete && /* @__PURE__ */ jsx(CompleteButton, { card, t, onComplete }),
75
+ !onComplete && card.completed && /* @__PURE__ */ jsx(CheckCircleRoundedIcon, { fontSize: "small", sx: { color: "success.main" }, titleAccess: t("completed") }),
76
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", component: "p", sx: { color: card.completed ? "text.secondary" : void 0 }, children: card.title })
77
+ ] }),
16
78
  card.description && /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: card.description }),
17
- card.tags?.length > 0 && /* @__PURE__ */ jsx(Stack, { direction: "row", spacing: 0.5, useFlexGap: true, sx: { flexWrap: "wrap" }, children: card.tags.map((tag) => /* @__PURE__ */ jsx(Chip, { label: tag, size: "small" }, tag)) })
79
+ hasFooter && /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1.25, useFlexGap: true, sx: { alignItems: "center", flexWrap: "wrap", color: "text.secondary" }, children: [
80
+ dueStatus && /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, sx: { alignItems: "center", color: DUE_COLOR[dueStatus] }, children: [
81
+ /* @__PURE__ */ jsx(EventOutlinedIcon, { sx: { fontSize: 16 } }),
82
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", sx: { fontWeight: dueStatus === DUE_STATUS.upcoming ? 400 : 600 }, children: dueText })
83
+ ] }),
84
+ card.checklist?.total > 0 && /* @__PURE__ */ jsxs(
85
+ Stack,
86
+ {
87
+ direction: "row",
88
+ spacing: 0.5,
89
+ sx: { alignItems: "center" },
90
+ "aria-label": t("checklist", { done: card.checklist.done, total: card.checklist.total }),
91
+ children: [
92
+ /* @__PURE__ */ jsx(CheckBoxOutlinedIcon, { sx: { fontSize: 16 } }),
93
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", "aria-hidden": "true", children: [
94
+ card.checklist.done,
95
+ "/",
96
+ card.checklist.total
97
+ ] })
98
+ ]
99
+ }
100
+ ),
101
+ card.comments > 0 && /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, sx: { alignItems: "center" }, "aria-label": t("comments", { count: card.comments }), children: [
102
+ /* @__PURE__ */ jsx(ChatBubbleOutlineRoundedIcon, { sx: { fontSize: 16 } }),
103
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", "aria-hidden": "true", children: card.comments })
104
+ ] }),
105
+ card.attachments > 0 && /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, sx: { alignItems: "center" }, "aria-label": t("attachments", { count: card.attachments }), children: [
106
+ /* @__PURE__ */ jsx(AttachFileRoundedIcon, { sx: { fontSize: 16 } }),
107
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", "aria-hidden": "true", children: card.attachments })
108
+ ] }),
109
+ card.assignees?.length > 0 && /* @__PURE__ */ jsx(
110
+ AvatarGroup,
111
+ {
112
+ max: MAX_VISIBLE_ASSIGNEES,
113
+ sx: { ml: "auto", "& .MuiAvatar-root": { width: ASSIGNEE_AVATAR_PIXELS, height: ASSIGNEE_AVATAR_PIXELS, fontSize: 11 } },
114
+ "aria-label": t("assignees", { names: card.assignees.map((person) => person.name).join(", ") }),
115
+ children: card.assignees.map((person) => /* @__PURE__ */ jsx(Tooltip, { title: person.name, children: /* @__PURE__ */ jsx(Avatar, { alt: person.name, src: person.avatarUrl, children: initialsOf(person.name) }) }, person.id))
116
+ }
117
+ )
118
+ ] })
18
119
  ] });
19
120
  }
20
- function KanbanBoard({ columns, cards, onMove, renderCard, onCardClick, ariaLabel }) {
21
- const { t } = useToolkitTranslation("kanban");
121
+ function QuickAdd({ columnTitle, onAdd, onClose, t }) {
122
+ const [title, setTitle] = useState("");
123
+ return /* @__PURE__ */ jsx(
124
+ TextField,
125
+ {
126
+ size: "small",
127
+ fullWidth: true,
128
+ autoFocus: true,
129
+ multiline: true,
130
+ maxRows: 4,
131
+ value: title,
132
+ placeholder: t("addCardPlaceholder"),
133
+ slotProps: { htmlInput: { "aria-label": t("addCard", { column: columnTitle }) } },
134
+ onChange: (event) => setTitle(event.target.value),
135
+ onBlur: () => !title.trim() && onClose(),
136
+ onKeyDown: (event) => {
137
+ if (event.key === "Escape") {
138
+ onClose();
139
+ }
140
+ if (event.key === "Enter" && !event.shiftKey) {
141
+ event.preventDefault();
142
+ if (title.trim()) {
143
+ onAdd(title.trim());
144
+ setTitle("");
145
+ }
146
+ }
147
+ }
148
+ }
149
+ );
150
+ }
151
+ function KanbanBoard({
152
+ columns,
153
+ cards,
154
+ onMove,
155
+ renderCard,
156
+ onCardClick,
157
+ onAddCard,
158
+ cardActions,
159
+ columnActions,
160
+ onCardComplete,
161
+ onColumnCollapse,
162
+ ariaLabel,
163
+ texts
164
+ }) {
165
+ const { t } = useToolkitTranslation("kanban", texts);
166
+ const [addingColumnId, setAddingColumnId] = useState(null);
167
+ const [collapsedIds, setCollapsedIds] = useState(() => new Set(columns.filter((column) => column.defaultCollapsed).map((column) => column.id)));
168
+ const toggleColumn = (columnId) => {
169
+ const collapsed = !collapsedIds.has(columnId);
170
+ setCollapsedIds((current) => {
171
+ const next = new Set(current);
172
+ if (collapsed) {
173
+ next.add(columnId);
174
+ } else {
175
+ next.delete(columnId);
176
+ }
177
+ return next;
178
+ });
179
+ onColumnCollapse?.(columnId, collapsed);
180
+ };
181
+ const today = todayIsoDateOf();
22
182
  const columnTitleOf = (columnId) => columns.find((column) => column.id === columnId)?.title ?? columnId;
23
183
  const cardTitleOf = (cardId) => cards.find((card) => card.id === cardId)?.title ?? cardId;
24
184
  const announceStart = (start, provided) => provided.announce(t("lifted", {
@@ -49,8 +209,49 @@ function KanbanBoard({ columns, cards, onMove, renderCard, onCardClick, ariaLabe
49
209
  alignItems: "flex-start"
50
210
  }, children: columns.map((column) => {
51
211
  const columnCards = cardsOfColumn(cards, column.id);
52
- const isOver = isOverLimit(column, columnCards.length);
53
- const count = Number.isInteger(column.limit) ? `${columnCards.length} / ${column.limit}` : String(columnCards.length);
212
+ const total = Number.isInteger(column.count) ? column.count : columnCards.length;
213
+ const isOver = isOverLimit(column, total);
214
+ const count = Number.isInteger(column.limit) ? `${total} / ${column.limit}` : String(total);
215
+ const isCollapsed = column.collapsible && collapsedIds.has(column.id);
216
+ if (isCollapsed) {
217
+ return /* @__PURE__ */ jsx(Droppable, { droppableId: column.id, children: (droppableProvided, droppableSnapshot) => /* @__PURE__ */ jsxs(
218
+ Paper,
219
+ {
220
+ ref: droppableProvided.innerRef,
221
+ ...droppableProvided.droppableProps,
222
+ variant: "outlined",
223
+ component: "section",
224
+ "aria-label": column.title,
225
+ sx: {
226
+ flex: "0 0 auto",
227
+ width: COLLAPSED_COLUMN_WIDTH_PIXELS,
228
+ py: 1,
229
+ borderRadius: 3,
230
+ display: "flex",
231
+ flexDirection: "column",
232
+ alignItems: "center",
233
+ gap: 1,
234
+ minHeight: EMPTY_COLUMN_MIN_HEIGHT * 2,
235
+ bgcolor: droppableSnapshot.isDraggingOver ? "action.hover" : void 0
236
+ },
237
+ children: [
238
+ /* @__PURE__ */ jsx(Tooltip, { title: t("expandColumn", { column: column.title }), placement: "right", children: /* @__PURE__ */ jsx(
239
+ IconButton,
240
+ {
241
+ size: "small",
242
+ "aria-label": t("expandColumn", { column: column.title }),
243
+ "aria-expanded": "false",
244
+ onClick: () => toggleColumn(column.id),
245
+ children: /* @__PURE__ */ jsx(KeyboardDoubleArrowRightRoundedIcon, { fontSize: "small" })
246
+ }
247
+ ) }),
248
+ /* @__PURE__ */ jsx(Chip, { size: "small", label: count, color: isOver ? "warning" : "default" }),
249
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", component: "h3", sx: { writingMode: "vertical-rl", whiteSpace: "nowrap" }, children: column.title }),
250
+ /* @__PURE__ */ jsx(Box, { sx: { display: "none" }, children: droppableProvided.placeholder })
251
+ ]
252
+ }
253
+ ) }, column.id);
254
+ }
54
255
  return /* @__PURE__ */ jsxs(
55
256
  Paper,
56
257
  {
@@ -59,8 +260,8 @@ function KanbanBoard({ columns, cards, onMove, renderCard, onCardClick, ariaLabe
59
260
  "aria-label": column.title,
60
261
  sx: { flex: "1 1 0", minWidth: COLUMN_MIN_WIDTH_PIXELS, p: 1.5, scrollSnapAlign: "start", borderRadius: 3 },
61
262
  children: [
62
- /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center", justifyContent: "space-between", mb: 1.5, px: 0.5 }, children: [
63
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", component: "h3", children: column.title }),
263
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, sx: { alignItems: "center", mb: 1.5, px: 0.5 }, children: [
264
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", component: "h3", sx: { flexGrow: 1, minWidth: 0 }, children: column.title }),
64
265
  /* @__PURE__ */ jsx(
65
266
  Chip,
66
267
  {
@@ -69,8 +270,29 @@ function KanbanBoard({ columns, cards, onMove, renderCard, onCardClick, ariaLabe
69
270
  color: isOver ? "warning" : "default",
70
271
  title: isOver ? t("overLimit", { limit: column.limit }) : void 0
71
272
  }
72
- )
273
+ ),
274
+ onAddCard && /* @__PURE__ */ jsx(Tooltip, { title: t("addCard", { column: column.title }), children: /* @__PURE__ */ jsx(IconButton, { size: "small", "aria-label": t("addCard", { column: column.title }), onClick: () => setAddingColumnId(column.id), children: /* @__PURE__ */ jsx(AddRoundedIcon, { fontSize: "small" }) }) }),
275
+ /* @__PURE__ */ jsx(ActionsMenu, { label: t("columnActions", { column: column.title }), actions: columnActions?.(column) }),
276
+ column.collapsible && /* @__PURE__ */ jsx(Tooltip, { title: t("collapseColumn", { column: column.title }), children: /* @__PURE__ */ jsx(
277
+ IconButton,
278
+ {
279
+ size: "small",
280
+ "aria-label": t("collapseColumn", { column: column.title }),
281
+ "aria-expanded": "true",
282
+ onClick: () => toggleColumn(column.id),
283
+ children: /* @__PURE__ */ jsx(KeyboardDoubleArrowLeftRoundedIcon, { fontSize: "small" })
284
+ }
285
+ ) })
73
286
  ] }),
287
+ addingColumnId === column.id && /* @__PURE__ */ jsx(Box, { sx: { mb: 1 }, children: /* @__PURE__ */ jsx(
288
+ QuickAdd,
289
+ {
290
+ columnTitle: column.title,
291
+ t,
292
+ onClose: () => setAddingColumnId(null),
293
+ onAdd: (title) => onAddCard({ columnId: column.id, title })
294
+ }
295
+ ) }),
74
296
  /* @__PURE__ */ jsx(Droppable, { droppableId: column.id, children: (droppableProvided, droppableSnapshot) => /* @__PURE__ */ jsxs(
75
297
  Stack,
76
298
  {
@@ -84,7 +306,7 @@ function KanbanBoard({ columns, cards, onMove, renderCard, onCardClick, ariaLabe
84
306
  bgcolor: droppableSnapshot.isDraggingOver ? "action.hover" : "transparent"
85
307
  },
86
308
  children: [
87
- columnCards.map((card, index) => /* @__PURE__ */ jsx(Draggable, { draggableId: card.id, index, children: (draggableProvided, draggableSnapshot) => /* @__PURE__ */ jsx(
309
+ columnCards.map((card, index) => /* @__PURE__ */ jsx(Draggable, { draggableId: card.id, index, children: (draggableProvided, draggableSnapshot) => /* @__PURE__ */ jsxs(
88
310
  Paper,
89
311
  {
90
312
  ref: draggableProvided.innerRef,
@@ -92,12 +314,15 @@ function KanbanBoard({ columns, cards, onMove, renderCard, onCardClick, ariaLabe
92
314
  ...draggableProvided.dragHandleProps,
93
315
  elevation: draggableSnapshot.isDragging ? 8 : 1,
94
316
  onClick: onCardClick ? () => onCardClick(card.id) : void 0,
95
- sx: { p: 1.5, borderRadius: 2, cursor: "grab", "&:focus-visible": { outline: 2, outlineColor: "primary.main" } },
96
- children: renderCard ? renderCard(card) : /* @__PURE__ */ jsx(DefaultCard, { card })
317
+ sx: { p: 1.5, borderRadius: 2, cursor: "grab", position: "relative", "&:focus-visible": { outline: 2, outlineColor: "primary.main" } },
318
+ children: [
319
+ cardActions && /* @__PURE__ */ jsx(Box, { sx: { position: "absolute", top: 4, right: 4 }, children: /* @__PURE__ */ jsx(ActionsMenu, { label: t("cardActions", { title: card.title }), actions: cardActions(card) }) }),
320
+ /* @__PURE__ */ jsx(Box, { sx: cardActions ? { pr: 3 } : void 0, children: renderCard ? renderCard(card) : /* @__PURE__ */ jsx(DefaultCard, { card, t, today, onComplete: onCardComplete }) })
321
+ ]
97
322
  }
98
323
  ) }, card.id)),
99
324
  droppableProvided.placeholder,
100
- columnCards.length === 0 && !droppableSnapshot.isDraggingOver && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", sx: { textAlign: "center", py: 3 }, children: t("empty") })
325
+ columnCards.length === 0 && !droppableSnapshot.isDraggingOver && addingColumnId !== column.id && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", sx: { textAlign: "center", py: 3 }, children: total > 0 ? t("emptyFiltered") : t("empty") })
101
326
  ]
102
327
  }
103
328
  ) })
@@ -1 +1 @@
1
- {"version":3,"file":"KanbanBoard.js","sources":["../../src/kanban/KanbanBoard.jsx"],"sourcesContent":["// Un tablero kanban (@stackcraftmx/calcita/kanban): columnas con tarjetas que se arrastran de una a otra con el ratón, con el\n// dedo o con el teclado (espacio para levantar, flechas para mover, espacio para soltar). Con @hello-pangea/dnd por dentro.\n//\n// <KanbanBoard columns={[{id: 'todo', title: 'Por hacer'}, {id: 'doing', title: 'En proceso', limit: 3}]}\n// cards={cards} onMove={(move) => api.post('/tasks/move', move)} ariaLabel=\"Tablero de tareas\" />\n//\n// El tablero no guarda nada: avisa la movida (onMove) y quien lo usa actualiza sus tarjetas (moveCard de kanbanMoves.js lo\n// hace sin esperar al servidor). Una columna con tope (limit, el trabajo en curso) avisa en ámbar cuando lo pasa.\n//\n// Accesible: el lector de pantalla anuncia en el idioma de la app qué se levantó, a dónde va y dónde quedó.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {DragDropContext, Draggable, Droppable} from '@hello-pangea/dnd';\nimport Box from '@mui/material/Box';\nimport Chip from '@mui/material/Chip';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\n\nimport {cardsOfColumn, isOverLimit} from '@/kanban/kanbanMoves.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\n\n// las columnas se reparten el ancho, sin bajar de este mínimo; si no caben, el tablero desliza de lado.\n// OJO: con el teclado, la librería solo mueve una tarjeta a columnas que se ven COMPLETAS: con columnas fijas de 300 px la\n// cuarta quedaba cortada en un escritorio y no se podía soltar ahí con el teclado\nconst COLUMN_MIN_WIDTH_PIXELS = 220;\n// lo alto que mide una columna vacía: lo justo para soltar ahí una tarjeta\nconst EMPTY_COLUMN_MIN_HEIGHT = 96;\n\n/**\n * Una tarjeta por omisión: el título, la descripción y sus etiquetas.\n *\n * @param {{card: {title: string, description?: string, tags?: string[]}}} props\n */\nfunction DefaultCard({card}) {\n return (\n <Stack spacing={0.75}>\n <Typography variant=\"subtitle2\" component=\"p\">{card.title}</Typography>\n {card.description && <Typography variant=\"body2\" color=\"text.secondary\">{card.description}</Typography>}\n {card.tags?.length > 0 && (\n <Stack direction=\"row\" spacing={0.5} useFlexGap sx={{flexWrap: 'wrap'}}>\n {card.tags.map((tag) => <Chip key={tag} label={tag} size=\"small\" />)}\n </Stack>\n )}\n </Stack>\n );\n}\n\n/**\n * @param {object} props\n * @param {Array<{id: string, title: string, limit?: number}>} props.columns en su orden\n * @param {Array<{id: string, columnId: string, title: string, description?: string, tags?: string[]}>} props.cards el orden\n * de cada columna es el orden en este arreglo\n * @param {(move: {cardId: string, fromColumnId: string, toColumnId: string, toIndex: number}) => void} props.onMove\n * @param {(card: any) => import('react').ReactNode} [props.renderCard] lo de adentro de cada tarjeta (recibe la tarjeta de cards)\n * @param {(cardId: string) => void} [props.onCardClick]\n * @param {string} props.ariaLabel ya traducido\n */\nexport default function KanbanBoard({columns, cards, onMove, renderCard, onCardClick, ariaLabel}) {\n const {t} = useToolkitTranslation('kanban');\n const columnTitleOf = (columnId) => columns.find((column) => column.id === columnId)?.title ?? columnId;\n const cardTitleOf = (cardId) => cards.find((card) => card.id === cardId)?.title ?? cardId;\n\n // lo que oye quien usa lector de pantalla (posiciones desde 1, como se cuentan)\n const announceStart = (start, provided) => provided.announce(t('lifted', {\n title: cardTitleOf(start.draggableId), column: columnTitleOf(start.source.droppableId), position: start.source.index + 1,\n }));\n const announceUpdate = (update, provided) => {\n if (update.destination) {\n provided.announce(t('moving', {column: columnTitleOf(update.destination.droppableId), position: update.destination.index + 1}));\n }\n };\n const finishMove = (result, provided) => {\n const {draggableId, source, destination} = result;\n // se soltó fuera de una columna o en el mismo lugar: nada que mover\n if (!destination || (destination.droppableId === source.droppableId && destination.index === source.index)) {\n provided.announce(t('cancelled', {title: cardTitleOf(draggableId)}));\n return;\n }\n provided.announce(t('dropped', {title: cardTitleOf(draggableId), column: columnTitleOf(destination.droppableId), position: destination.index + 1}));\n onMove({cardId: draggableId, fromColumnId: source.droppableId, toColumnId: destination.droppableId, toIndex: destination.index});\n };\n\n return (\n <DragDropContext onDragStart={announceStart} onDragUpdate={announceUpdate} onDragEnd={finishMove} dragHandleUsageInstructions={t('instructions')}>\n <Box role=\"region\" aria-label={ariaLabel} sx={{\n display: 'flex', gap: 2, overflowX: 'auto', pb: 1, scrollSnapType: 'x proximity', alignItems: 'flex-start',\n }}>\n {columns.map((column) => {\n const columnCards = cardsOfColumn(cards, column.id);\n const isOver = isOverLimit(column, columnCards.length);\n const count = Number.isInteger(column.limit) ? `${columnCards.length} / ${column.limit}` : String(columnCards.length);\n return (\n <Paper key={column.id} variant=\"outlined\" component=\"section\" aria-label={column.title}\n sx={{flex: '1 1 0', minWidth: COLUMN_MIN_WIDTH_PIXELS, p: 1.5, scrollSnapAlign: 'start', borderRadius: 3}}>\n <Stack direction=\"row\" spacing={1} sx={{alignItems: 'center', justifyContent: 'space-between', mb: 1.5, px: 0.5}}>\n <Typography variant=\"subtitle2\" component=\"h3\">{column.title}</Typography>\n <Chip size=\"small\" label={count} color={isOver ? 'warning' : 'default'}\n title={isOver ? t('overLimit', {limit: column.limit}) : undefined} />\n </Stack>\n <Droppable droppableId={column.id}>\n {(droppableProvided, droppableSnapshot) => (\n <Stack ref={droppableProvided.innerRef} {...droppableProvided.droppableProps} spacing={1}\n sx={{\n minHeight: EMPTY_COLUMN_MIN_HEIGHT, borderRadius: 2, transition: 'background-color 160ms',\n bgcolor: droppableSnapshot.isDraggingOver ? 'action.hover' : 'transparent',\n }}>\n {columnCards.map((card, index) => (\n <Draggable key={card.id} draggableId={card.id} index={index}>\n {(draggableProvided, draggableSnapshot) => (\n <Paper ref={draggableProvided.innerRef} {...draggableProvided.draggableProps} {...draggableProvided.dragHandleProps}\n elevation={draggableSnapshot.isDragging ? 8 : 1}\n onClick={onCardClick ? () => onCardClick(card.id) : undefined}\n sx={{p: 1.5, borderRadius: 2, cursor: 'grab', '&:focus-visible': {outline: 2, outlineColor: 'primary.main'}}}>\n {renderCard ? renderCard(card) : <DefaultCard card={card} />}\n </Paper>\n )}\n </Draggable>\n ))}\n {droppableProvided.placeholder}\n {columnCards.length === 0 && !droppableSnapshot.isDraggingOver && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{textAlign: 'center', py: 3}}>{t('empty')}</Typography>\n )}\n </Stack>\n )}\n </Droppable>\n </Paper>\n );\n })}\n </Box>\n </DragDropContext>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"KanbanBoard.js","sources":["../../src/kanban/KanbanBoard.jsx"],"sourcesContent":["// Un tablero kanban (@stackcraftmx/calcita/kanban): columnas con tarjetas que se arrastran de una a otra con el ratón, con el\n// dedo o con el teclado (espacio para levantar, flechas para mover, espacio para soltar). Con @hello-pangea/dnd por dentro.\n//\n// <KanbanBoard columns={[{id: 'todo', title: 'Por hacer'}, {id: 'doing', title: 'En proceso', limit: 3}]}\n// cards={cards} onMove={(move) => api.post('/tasks/move', move)} ariaLabel=\"Tablero de tareas\" />\n//\n// El tablero no guarda nada: avisa la movida (onMove) y quien lo usa actualiza sus tarjetas (moveCard de kanbanMoves.js lo\n// hace sin esperar al servidor). Una columna con tope (limit, el trabajo en curso) avisa en ámbar cuando lo pasa.\n//\n// Accesible: el lector de pantalla anuncia en el idioma de la app qué se levantó, a dónde va y dónde quedó.\n//\n// Lo de un producto, todo hacia afuera (el tablero no guarda nada ni llama a ningún servidor):\n// - la tarjeta por omisión pinta lo que traiga: etiquetas (texto o {label, color}), responsables con su monograma, la\n// fecha límite (roja si ya venció, ámbar si es hoy), el avance de su lista de pendientes, comentarios y adjuntos. Para\n// otra tarjeta: renderCard;\n// - «+» en cada columna para agregar escribiendo el título (onAddCard({columnId, title}));\n// - «⋯» en cada tarjeta y en cada columna con las acciones que dé la pantalla (cardActions, columnActions): editar,\n// asignarme, mover sin arrastrar, borrar…;\n// - terminar una tarea: con onCardComplete cada tarjeta lleva su círculo para marcarla (y desmarcarla); qué pasa al\n// terminarla (pasarla a «Listo», guardar la fecha) lo decide la pantalla. Una tarjeta con completed: true sale con su\n// palomita verde y su fecha límite ya no se pinta de rojo;\n// - columnas que se encogen (collapsible), como el congelador (icebox) de ideas para después: se quedan en una tira angosta\n// con su nombre y su cuenta, y se les puede soltar una tarjeta igual. defaultCollapsed la abre encogida y\n// onColumnCollapse avisa cada cambio (para guardarlo si la pantalla quiere);\n// - texts para cualquier texto (la forma de `kanban` en los textos del paquete).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {DragDropContext, Draggable, Droppable} from '@hello-pangea/dnd';\nimport Avatar from '@mui/material/Avatar';\nimport AvatarGroup from '@mui/material/AvatarGroup';\nimport Box from '@mui/material/Box';\nimport Chip from '@mui/material/Chip';\nimport IconButton from '@mui/material/IconButton';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport AttachFileRoundedIcon from '@mui/icons-material/AttachFileRounded';\nimport ChatBubbleOutlineRoundedIcon from '@mui/icons-material/ChatBubbleOutlineRounded';\nimport CheckBoxOutlinedIcon from '@mui/icons-material/CheckBoxOutlined';\nimport CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded';\nimport EventOutlinedIcon from '@mui/icons-material/EventOutlined';\nimport KeyboardDoubleArrowLeftRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowLeftRounded';\nimport KeyboardDoubleArrowRightRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowRightRounded';\nimport RadioButtonUncheckedRoundedIcon from '@mui/icons-material/RadioButtonUncheckedRounded';\n\nimport {initialsOf} from '@/appShell/menuItemText.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {DUE_STATUS, dueStatusOf, tagOf, todayIsoDateOf} from '@/kanban/kanbanCards.js';\nimport {cardsOfColumn, isOverLimit} from '@/kanban/kanbanMoves.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ActionsMenu from '@/ui/actions/ActionsMenu.jsx';\n\n// las columnas se reparten el ancho, sin bajar de este mínimo; si no caben, el tablero desliza de lado.\n// OJO: con el teclado, la librería solo mueve una tarjeta a columnas que se ven COMPLETAS: con columnas fijas de 300 px la\n// cuarta quedaba cortada en un escritorio y no se podía soltar ahí con el teclado\nconst COLUMN_MIN_WIDTH_PIXELS = 220;\n// lo alto que mide una columna vacía: lo justo para soltar ahí una tarjeta\nconst EMPTY_COLUMN_MIN_HEIGHT = 96;\n// cuántas caras de responsables se ven antes del «+2»\nconst MAX_VISIBLE_ASSIGNEES = 3;\nconst ASSIGNEE_AVATAR_PIXELS = 24;\n// lo ancho de una columna encogida: su nombre de lado, su cuenta y su botón para abrirla\nconst COLLAPSED_COLUMN_WIDTH_PIXELS = 52;\n// el color del texto de la fecha según cómo va\nconst DUE_COLOR = Object.freeze({[DUE_STATUS.overdue]: 'error.main', [DUE_STATUS.today]: 'warning.dark', [DUE_STATUS.upcoming]: 'text.secondary'});\n\n/**\n * El círculo para terminar una tarea (o reabrirla, si ya está terminada). El clic no levanta la tarjeta ni la abre.\n *\n * @param {{card: any, t: Function, onComplete: (card: any, completed: boolean) => void}} props\n */\nfunction CompleteButton({card, t, onComplete}) {\n const label = card.completed ? t('reopen', {title: card.title}) : t('complete', {title: card.title});\n return (\n <Tooltip title={label}>\n <IconButton size=\"small\" aria-label={label} aria-pressed={Boolean(card.completed)} sx={{m: -0.5, color: card.completed ? 'success.main' : 'text.secondary'}}\n onClick={(event) => {\n event.stopPropagation();\n onComplete(card, !card.completed);\n }}>\n {card.completed ? <CheckCircleRoundedIcon fontSize=\"small\" /> : <RadioButtonUncheckedRoundedIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n );\n}\n\n/**\n * Una tarjeta por omisión: lo que traiga, sin pedir nada (título, descripción, etiquetas, responsables, fecha, pendientes,\n * comentarios y adjuntos).\n *\n * @param {{card: any, t: Function, today: string, onComplete?: (card: any, completed: boolean) => void}} props\n */\nfunction DefaultCard({card, t, today, onComplete}) {\n const {formatDate} = useFormatters();\n // terminada, su fecha ya no apura: se pinta tenue, sin rojo ni ámbar\n const dueStatus = card.completed && card.dueDate ? DUE_STATUS.upcoming : dueStatusOf(card.dueDate, today);\n let dueText = '';\n if (card.completed && card.dueDate) {\n dueText = t('dueCompleted', {date: formatDate(card.dueDate)});\n } else if (dueStatus === DUE_STATUS.overdue) {\n dueText = t('dueOverdue', {date: formatDate(card.dueDate)});\n } else if (dueStatus === DUE_STATUS.today) {\n dueText = t('dueToday');\n } else if (dueStatus) {\n dueText = t('dueOn', {date: formatDate(card.dueDate)});\n }\n const hasFooter = dueStatus || card.checklist?.total > 0 || card.comments > 0 || card.attachments > 0 || card.assignees?.length > 0;\n\n return (\n <Stack spacing={0.75}>\n {card.tags?.length > 0 && (\n <Stack direction=\"row\" spacing={0.5} useFlexGap sx={{flexWrap: 'wrap'}}>\n {card.tags.map((rawTag) => {\n const tag = tagOf(rawTag);\n return <Chip key={tag.label} label={tag.label} size=\"small\" color={tag.color} variant={tag.color === 'default' ? 'filled' : 'outlined'} />;\n })}\n </Stack>\n )}\n <Stack direction=\"row\" spacing={1} sx={{alignItems: 'flex-start'}}>\n {onComplete && <CompleteButton card={card} t={t} onComplete={onComplete} />}\n {!onComplete && card.completed && (\n <CheckCircleRoundedIcon fontSize=\"small\" sx={{color: 'success.main'}} titleAccess={t('completed')} />\n )}\n <Typography variant=\"subtitle2\" component=\"p\" sx={{color: card.completed ? 'text.secondary' : undefined}}>{card.title}</Typography>\n </Stack>\n {card.description && <Typography variant=\"body2\" color=\"text.secondary\">{card.description}</Typography>}\n {hasFooter && (\n <Stack direction=\"row\" spacing={1.25} useFlexGap sx={{alignItems: 'center', flexWrap: 'wrap', color: 'text.secondary'}}>\n {dueStatus && (\n <Stack direction=\"row\" spacing={0.5} sx={{alignItems: 'center', color: DUE_COLOR[dueStatus]}}>\n <EventOutlinedIcon sx={{fontSize: 16}} />\n <Typography variant=\"caption\" sx={{fontWeight: dueStatus === DUE_STATUS.upcoming ? 400 : 600}}>{dueText}</Typography>\n </Stack>\n )}\n {card.checklist?.total > 0 && (\n <Stack direction=\"row\" spacing={0.5} sx={{alignItems: 'center'}}\n aria-label={t('checklist', {done: card.checklist.done, total: card.checklist.total})}>\n <CheckBoxOutlinedIcon sx={{fontSize: 16}} />\n <Typography variant=\"caption\" aria-hidden=\"true\">{card.checklist.done}/{card.checklist.total}</Typography>\n </Stack>\n )}\n {card.comments > 0 && (\n <Stack direction=\"row\" spacing={0.5} sx={{alignItems: 'center'}} aria-label={t('comments', {count: card.comments})}>\n <ChatBubbleOutlineRoundedIcon sx={{fontSize: 16}} />\n <Typography variant=\"caption\" aria-hidden=\"true\">{card.comments}</Typography>\n </Stack>\n )}\n {card.attachments > 0 && (\n <Stack direction=\"row\" spacing={0.5} sx={{alignItems: 'center'}} aria-label={t('attachments', {count: card.attachments})}>\n <AttachFileRoundedIcon sx={{fontSize: 16}} />\n <Typography variant=\"caption\" aria-hidden=\"true\">{card.attachments}</Typography>\n </Stack>\n )}\n {card.assignees?.length > 0 && (\n <AvatarGroup max={MAX_VISIBLE_ASSIGNEES} sx={{ml: 'auto', '& .MuiAvatar-root': {width: ASSIGNEE_AVATAR_PIXELS, height: ASSIGNEE_AVATAR_PIXELS, fontSize: 11}}}\n aria-label={t('assignees', {names: card.assignees.map((person) => person.name).join(', ')})}>\n {card.assignees.map((person) => (\n <Tooltip key={person.id} title={person.name}>\n <Avatar alt={person.name} src={person.avatarUrl}>{initialsOf(person.name)}</Avatar>\n </Tooltip>\n ))}\n </AvatarGroup>\n )}\n </Stack>\n )}\n </Stack>\n );\n}\n\n/**\n * Agregar una tarjeta escribiendo su título: Enter la agrega (y deja el campo listo para otra), Escape cierra.\n *\n * @param {{columnTitle: string, onAdd: (title: string) => void, onClose: () => void, t: Function}} props\n */\nfunction QuickAdd({columnTitle, onAdd, onClose, t}) {\n const [title, setTitle] = useState('');\n return (\n <TextField size=\"small\" fullWidth autoFocus multiline maxRows={4} value={title} placeholder={t('addCardPlaceholder')}\n slotProps={{htmlInput: {'aria-label': t('addCard', {column: columnTitle})}}}\n onChange={(event) => setTitle(event.target.value)}\n onBlur={() => !title.trim() && onClose()}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n onClose();\n }\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (title.trim()) {\n onAdd(title.trim());\n setTitle('');\n }\n }\n }} />\n );\n}\n\n/**\n * @param {object} props\n * @param {Array<{id: string, title: string, limit?: number, count?: number, collapsible?: boolean, defaultCollapsed?: boolean}>} props.columns\n * en su orden. count: cuántas tarjetas tiene de verdad cuando la pantalla le pasa solo las filtradas (el tope se cuenta\n * contra todas). collapsible: lleva su botón para encogerse (el congelador); defaultCollapsed: empieza encogida\n * @param {Array<{id: string, columnId: string, title: string, completed?: boolean, description?: string, tags?: Array<string|{label: string, color?: string}>, assignees?: Array<{id: string, name: string, avatarUrl?: string}>, dueDate?: string, checklist?: {done: number, total: number}, comments?: number, attachments?: number} & Record<string, any>>} props.cards\n * el orden de cada columna es el orden en este arreglo; cada tarjeta puede traer sus campos propios (llegan a renderCard,\n * a cardActions y a onCardClick tal cual). dueDate: AAAA-MM-DD\n * @param {(move: {cardId: string, fromColumnId: string, toColumnId: string, toIndex: number}) => void} props.onMove\n * @param {(card: any) => import('react').ReactNode} [props.renderCard] lo de adentro de cada tarjeta (recibe la tarjeta de cards)\n * @param {(cardId: string) => void} [props.onCardClick]\n * @param {(newCard: {columnId: string, title: string}) => void} [props.onAddCard] con él cada columna lleva su «+» para agregar\n * escribiendo el título\n * @param {(card: any) => Array<{key: string, label: string, icon?: import('react').ReactNode, color?: string, disabled?: boolean, onClick: () => void}>} [props.cardActions]\n * las acciones del «⋯» de cada tarjeta (editar, asignarme, borrar…); sin ellas no hay «⋯»\n * @param {(column: any) => Array<{key: string, label: string, icon?: import('react').ReactNode, color?: string, disabled?: boolean, onClick: () => void}>} [props.columnActions]\n * las acciones del «⋯» de cada columna (renombrar, limpiar…)\n * @param {(card: any, completed: boolean) => void} [props.onCardComplete] con él cada tarjeta lleva su círculo para terminarla\n * (completed true) o reabrirla (false); la pantalla decide qué más pasa (moverla a «Listo», guardar la fecha)\n * @param {(columnId: string, collapsed: boolean) => void} [props.onColumnCollapse] cada que una columna se encoge o se abre\n * @param {string} props.ariaLabel ya traducido\n * @param {object} [props.texts] los textos que cambian, con la forma de `kanban` en los textos del paquete\n */\nexport default function KanbanBoard({\n columns, cards, onMove, renderCard, onCardClick, onAddCard, cardActions, columnActions, onCardComplete, onColumnCollapse, ariaLabel, texts,\n}) {\n const {t} = useToolkitTranslation('kanban', texts);\n // la columna donde se está escribiendo una tarjeta nueva\n const [addingColumnId, setAddingColumnId] = useState(null);\n // las columnas encogidas: empiezan como dice defaultCollapsed y luego las mueve la persona\n const [collapsedIds, setCollapsedIds] = useState(() => new Set(columns.filter((column) => column.defaultCollapsed).map((column) => column.id)));\n const toggleColumn = (columnId) => {\n const collapsed = !collapsedIds.has(columnId);\n setCollapsedIds((current) => {\n const next = new Set(current);\n if (collapsed) {\n next.add(columnId);\n } else {\n next.delete(columnId);\n }\n return next;\n });\n onColumnCollapse?.(columnId, collapsed);\n };\n const today = todayIsoDateOf();\n const columnTitleOf = (columnId) => columns.find((column) => column.id === columnId)?.title ?? columnId;\n const cardTitleOf = (cardId) => cards.find((card) => card.id === cardId)?.title ?? cardId;\n\n // lo que oye quien usa lector de pantalla (posiciones desde 1, como se cuentan)\n const announceStart = (start, provided) => provided.announce(t('lifted', {\n title: cardTitleOf(start.draggableId), column: columnTitleOf(start.source.droppableId), position: start.source.index + 1,\n }));\n const announceUpdate = (update, provided) => {\n if (update.destination) {\n provided.announce(t('moving', {column: columnTitleOf(update.destination.droppableId), position: update.destination.index + 1}));\n }\n };\n const finishMove = (result, provided) => {\n const {draggableId, source, destination} = result;\n // se soltó fuera de una columna o en el mismo lugar: nada que mover\n if (!destination || (destination.droppableId === source.droppableId && destination.index === source.index)) {\n provided.announce(t('cancelled', {title: cardTitleOf(draggableId)}));\n return;\n }\n provided.announce(t('dropped', {title: cardTitleOf(draggableId), column: columnTitleOf(destination.droppableId), position: destination.index + 1}));\n onMove({cardId: draggableId, fromColumnId: source.droppableId, toColumnId: destination.droppableId, toIndex: destination.index});\n };\n\n return (\n <DragDropContext onDragStart={announceStart} onDragUpdate={announceUpdate} onDragEnd={finishMove} dragHandleUsageInstructions={t('instructions')}>\n <Box role=\"region\" aria-label={ariaLabel} sx={{\n display: 'flex', gap: 2, overflowX: 'auto', pb: 1, scrollSnapType: 'x proximity', alignItems: 'flex-start',\n }}>\n {columns.map((column) => {\n const columnCards = cardsOfColumn(cards, column.id);\n // con un filtro puesto la pantalla dice cuántas tiene de verdad: «1 / 3» mentía con la columna llena\n const total = Number.isInteger(column.count) ? column.count : columnCards.length;\n const isOver = isOverLimit(column, total);\n const count = Number.isInteger(column.limit) ? `${total} / ${column.limit}` : String(total);\n const isCollapsed = column.collapsible && collapsedIds.has(column.id);\n // encogida: una tira con su nombre de lado y su cuenta; se le puede soltar una tarjeta (queda arriba)\n if (isCollapsed) {\n return (\n <Droppable key={column.id} droppableId={column.id}>\n {(droppableProvided, droppableSnapshot) => (\n <Paper ref={droppableProvided.innerRef} {...droppableProvided.droppableProps} variant=\"outlined\" component=\"section\"\n aria-label={column.title}\n sx={{\n flex: '0 0 auto', width: COLLAPSED_COLUMN_WIDTH_PIXELS, py: 1, borderRadius: 3, display: 'flex',\n flexDirection: 'column', alignItems: 'center', gap: 1, minHeight: EMPTY_COLUMN_MIN_HEIGHT * 2,\n bgcolor: droppableSnapshot.isDraggingOver ? 'action.hover' : undefined,\n }}>\n <Tooltip title={t('expandColumn', {column: column.title})} placement=\"right\">\n <IconButton size=\"small\" aria-label={t('expandColumn', {column: column.title})} aria-expanded=\"false\"\n onClick={() => toggleColumn(column.id)}>\n <KeyboardDoubleArrowRightRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Chip size=\"small\" label={count} color={isOver ? 'warning' : 'default'} />\n <Typography variant=\"subtitle2\" component=\"h3\" sx={{writingMode: 'vertical-rl', whiteSpace: 'nowrap'}}>\n {column.title}\n </Typography>\n {/* el lugar de la tarjeta que se arrastra; encogida no la enseña */}\n <Box sx={{display: 'none'}}>{droppableProvided.placeholder}</Box>\n </Paper>\n )}\n </Droppable>\n );\n }\n return (\n <Paper key={column.id} variant=\"outlined\" component=\"section\" aria-label={column.title}\n sx={{flex: '1 1 0', minWidth: COLUMN_MIN_WIDTH_PIXELS, p: 1.5, scrollSnapAlign: 'start', borderRadius: 3}}>\n <Stack direction=\"row\" spacing={0.5} sx={{alignItems: 'center', mb: 1.5, px: 0.5}}>\n <Typography variant=\"subtitle2\" component=\"h3\" sx={{flexGrow: 1, minWidth: 0}}>{column.title}</Typography>\n <Chip size=\"small\" label={count} color={isOver ? 'warning' : 'default'}\n title={isOver ? t('overLimit', {limit: column.limit}) : undefined} />\n {onAddCard && (\n <Tooltip title={t('addCard', {column: column.title})}>\n <IconButton size=\"small\" aria-label={t('addCard', {column: column.title})} onClick={() => setAddingColumnId(column.id)}>\n <AddRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n <ActionsMenu label={t('columnActions', {column: column.title})} actions={columnActions?.(column)} />\n {column.collapsible && (\n <Tooltip title={t('collapseColumn', {column: column.title})}>\n <IconButton size=\"small\" aria-label={t('collapseColumn', {column: column.title})} aria-expanded=\"true\"\n onClick={() => toggleColumn(column.id)}>\n <KeyboardDoubleArrowLeftRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </Stack>\n {addingColumnId === column.id && (\n <Box sx={{mb: 1}}>\n <QuickAdd columnTitle={column.title} t={t} onClose={() => setAddingColumnId(null)}\n onAdd={(title) => onAddCard({columnId: column.id, title})} />\n </Box>\n )}\n <Droppable droppableId={column.id}>\n {(droppableProvided, droppableSnapshot) => (\n <Stack ref={droppableProvided.innerRef} {...droppableProvided.droppableProps} spacing={1}\n sx={{\n minHeight: EMPTY_COLUMN_MIN_HEIGHT, borderRadius: 2, transition: 'background-color 160ms',\n bgcolor: droppableSnapshot.isDraggingOver ? 'action.hover' : 'transparent',\n }}>\n {columnCards.map((card, index) => (\n <Draggable key={card.id} draggableId={card.id} index={index}>\n {(draggableProvided, draggableSnapshot) => (\n <Paper ref={draggableProvided.innerRef} {...draggableProvided.draggableProps} {...draggableProvided.dragHandleProps}\n elevation={draggableSnapshot.isDragging ? 8 : 1}\n onClick={onCardClick ? () => onCardClick(card.id) : undefined}\n sx={{p: 1.5, borderRadius: 2, cursor: 'grab', position: 'relative', '&:focus-visible': {outline: 2, outlineColor: 'primary.main'}}}>\n {/* el «⋯» arriba a la derecha; el contenido le deja su lugar */}\n {cardActions && (\n <Box sx={{position: 'absolute', top: 4, right: 4}}>\n <ActionsMenu label={t('cardActions', {title: card.title})} actions={cardActions(card)} />\n </Box>\n )}\n <Box sx={cardActions ? {pr: 3} : undefined}>\n {renderCard ? renderCard(card) : <DefaultCard card={card} t={t} today={today} onComplete={onCardComplete} />}\n </Box>\n </Paper>\n )}\n </Draggable>\n ))}\n {droppableProvided.placeholder}\n {/* vacía de verdad, o con tarjetas que el filtro de la pantalla esconde (no se dice «sin tarjetas») */}\n {columnCards.length === 0 && !droppableSnapshot.isDraggingOver && addingColumnId !== column.id && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{textAlign: 'center', py: 3}}>\n {total > 0 ? t('emptyFiltered') : t('empty')}\n </Typography>\n )}\n </Stack>\n )}\n </Droppable>\n </Paper>\n );\n })}\n </Box>\n </DragDropContext>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ const DUE_STATUS = Object.freeze({ overdue: "overdue", today: "today", upcoming: "upcoming" });
2
+ function todayIsoDateOf(now = /* @__PURE__ */ new Date()) {
3
+ return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
4
+ }
5
+ function dueStatusOf(dueDate, today) {
6
+ if (!dueDate) {
7
+ return null;
8
+ }
9
+ if (dueDate < today) {
10
+ return DUE_STATUS.overdue;
11
+ }
12
+ return dueDate === today ? DUE_STATUS.today : DUE_STATUS.upcoming;
13
+ }
14
+ export {
15
+ DUE_STATUS,
16
+ dueStatusOf,
17
+ todayIsoDateOf
18
+ };
19
+ //# sourceMappingURL=kanbanCards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kanbanCards.js","sources":["../../src/kanban/kanbanCards.js"],"sourcesContent":["// Lo que la tarjeta del tablero decide sin pintar nada: si su fecha ya venció, vence hoy o falta. Cómo se lee una etiqueta\n// (texto suelto o con su color) vive en ui/labels/tagOf.js y aquí se vuelve a exportar. Funciones puras: se prueban sin\n// navegador (kanbanCards.test.js).\n//\n// Funciones puras, no renderizan: function (regla de la casa).\n\n/** Cómo va la fecha límite de una tarjeta. */\nexport const DUE_STATUS = Object.freeze({overdue: 'overdue', today: 'today', upcoming: 'upcoming'});\n\n/**\n * El día de hoy como AAAA-MM-DD en la zona de este navegador (la fecha límite es un día, no un instante).\n *\n * @param {Date} [now]\n * @returns {string}\n */\nexport function todayIsoDateOf(now = new Date()) {\n return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;\n}\n\n/**\n * Cómo va una fecha límite contra hoy. AAAA-MM-DD se compara bien como texto.\n *\n * @param {string|null|undefined} dueDate AAAA-MM-DD\n * @param {string} today AAAA-MM-DD\n * @returns {'overdue'|'today'|'upcoming'|null} null sin fecha\n */\nexport function dueStatusOf(dueDate, today) {\n if (!dueDate) {\n return null;\n }\n if (dueDate < today) {\n return DUE_STATUS.overdue;\n }\n return dueDate === today ? DUE_STATUS.today : DUE_STATUS.upcoming;\n}\n\n// la regla de una etiqueta vive en lo compartido (la usan el tablero y la bandeja); aquí sigue a la mano\nexport {tagOf} from '@/ui/labels/tagOf.js';\n"],"names":[],"mappings":"AAOY,MAAC,aAAa,OAAO,OAAO,EAAC,SAAS,WAAW,OAAO,SAAS,UAAU,WAAU,CAAC;AAQ3F,SAAS,eAAe,MAAM,oBAAI,QAAQ;AAC7C,SAAO,GAAG,IAAI,YAAW,CAAE,IAAI,OAAO,IAAI,SAAQ,IAAK,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,IAAI,SAAS,EAAE,SAAS,GAAG,GAAG,CAAC;AACxH;AASO,SAAS,YAAY,SAAS,OAAO;AACxC,MAAI,CAAC,SAAS;AACV,WAAO;AAAA,EACX;AACA,MAAI,UAAU,OAAO;AACjB,WAAO,WAAW;AAAA,EACtB;AACA,SAAO,YAAY,QAAQ,WAAW,QAAQ,WAAW;AAC7D;"}
package/dist/kanban.js CHANGED
@@ -1,9 +1,15 @@
1
1
  import { default as default2 } from "./kanban/KanbanBoard.js";
2
2
  import { cardsOfColumn, isOverLimit, moveCard } from "./kanban/kanbanMoves.js";
3
+ import { DUE_STATUS, dueStatusOf, todayIsoDateOf } from "./kanban/kanbanCards.js";
4
+ import { tagOf } from "./ui/labels/tagOf.js";
3
5
  export {
6
+ DUE_STATUS,
4
7
  default2 as KanbanBoard,
5
8
  cardsOfColumn,
9
+ dueStatusOf,
6
10
  isOverLimit,
7
- moveCard
11
+ moveCard,
12
+ tagOf,
13
+ todayIsoDateOf
8
14
  };
9
15
  //# sourceMappingURL=kanban.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"kanban.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
1
+ {"version":3,"file":"kanban.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -38,6 +38,20 @@ const en = Object.freeze({
38
38
  "descending": "descending order",
39
39
  "clear": "Remove sorting"
40
40
  },
41
+ "selection": {
42
+ "count_one": "{{total}} selected",
43
+ "count_other": "{{total}} selected",
44
+ "allMatching": "All {{total}} matching are selected",
45
+ "allMatchingCapped": "All matching are selected",
46
+ "pageSelected_one": "The only row on this page is selected.",
47
+ "pageSelected_other": "The {{count}} on this page are selected.",
48
+ "selectAllMatching": "Select all {{total}} matching",
49
+ "selectAllMatchingCapped": "Select all matching",
50
+ "onlyThisPage": "Select only this page",
51
+ "clear": "Clear selection",
52
+ "summaryLabel": "The selection",
53
+ "actionsLabel": "Actions for the selected"
54
+ },
41
55
  "goToPage": {
42
56
  "page": "Page",
43
57
  "of_one": "of {{total}}",
@@ -110,6 +124,11 @@ const en = Object.freeze({
110
124
  "colorLowContrast": "With that color the text would be hard to read on white. {{suggestion}} is the same hue, darker.",
111
125
  "colorUseSuggestion": "Use {{color}}"
112
126
  },
127
+ "selection": {
128
+ "clear": "Clear selection",
129
+ "actionsLabel": "Actions for the selected",
130
+ "summaryLabel": "The selection"
131
+ },
113
132
  "wizard": {
114
133
  "next": "Next",
115
134
  "back": "Back",
@@ -122,7 +141,9 @@ const en = Object.freeze({
122
141
  "switchTo": {
123
142
  "es": "Switch to Spanish",
124
143
  "en": "Switch to English"
125
- }
144
+ },
145
+ "switchToNamed": "Switch to {{name}}",
146
+ "choose": "Language: {{name}}. Choose another"
126
147
  },
127
148
  "colorScheme": {
128
149
  "label": "Light or dark",
@@ -259,6 +280,7 @@ const en = Object.freeze({
259
280
  },
260
281
  "charts": {
261
282
  "viewAsTable": "View as table",
283
+ "legend": "What each series is",
262
284
  "viewAsChart": "View as chart",
263
285
  "less": "Less",
264
286
  "more": "More",
@@ -612,6 +634,29 @@ const en = Object.freeze({
612
634
  }
613
635
  },
614
636
  "calendar": {
637
+ "details": {
638
+ "when": "When",
639
+ "timeRange": "{{date}}, {{start}} to {{end}}",
640
+ "allDay": "{{date}}, all day",
641
+ "location": "Where",
642
+ "meeting": "Online meeting",
643
+ "join": "Join",
644
+ "attendees": "Guests",
645
+ "attendeesCount_one": "{{count}} guest",
646
+ "attendeesCount_other": "{{count}} guests",
647
+ "response": { "accepted": "Going", "declined": "Not going", "pending": "No answer" },
648
+ "reminder": "Reminder",
649
+ "reminderUnit": {
650
+ "atStart": "At start",
651
+ "minutes_one": "{{count}} minute before",
652
+ "minutes_other": "{{count}} minutes before",
653
+ "hours_one": "{{count}} hour before",
654
+ "hours_other": "{{count}} hours before",
655
+ "days_one": "{{count}} day before",
656
+ "days_other": "{{count}} days before"
657
+ },
658
+ "notes": "Notes"
659
+ },
615
660
  "previous": "Previous",
616
661
  "next": "Next",
617
662
  "today": "Today",
@@ -624,15 +669,43 @@ const en = Object.freeze({
624
669
  }
625
670
  },
626
671
  "kanban": {
672
+ "dueCompleted": "Was due {{date}}",
673
+ "complete": "Complete “{{title}}”",
674
+ "reopen": "Reopen “{{title}}”",
675
+ "completed": "Completed",
676
+ "collapseColumn": "Collapse “{{column}}”",
677
+ "expandColumn": "Expand “{{column}}”",
678
+ "addCard": "Add a card to {{column}}",
679
+ "addCardPlaceholder": "Card title (Enter to add)",
680
+ "cardActions": "Actions for “{{title}}”",
681
+ "columnActions": "Actions for {{column}}",
682
+ "dueOverdue": "Was due {{date}}",
683
+ "dueToday": "Due today",
684
+ "dueOn": "Due {{date}}",
685
+ "checklist": "{{done}} of {{total}} to-dos done",
686
+ "comments_one": "{{count}} comment",
687
+ "comments_other": "{{count}} comments",
688
+ "attachments_one": "{{count}} attachment",
689
+ "attachments_other": "{{count}} attachments",
690
+ "assignees": "Assigned to: {{names}}",
627
691
  "instructions": "To move a card with the keyboard: space to lift it, arrows to move it and space to drop it. Escape leaves it where it was.",
628
692
  "lifted": "You lifted “{{title}}”, in {{column}}, position {{position}}.",
629
693
  "moving": "Going to {{column}}, position {{position}}.",
630
694
  "dropped": "You dropped “{{title}}” in {{column}}, position {{position}}.",
631
695
  "cancelled": "“{{title}}” stayed where it was.",
632
696
  "overLimit": "Over the limit of {{limit}} cards.",
697
+ "emptyFiltered": "No card here matches the search.",
633
698
  "empty": "No cards. Drag one here."
634
699
  },
635
700
  "inbox": {
701
+ "labels": "Labels",
702
+ "select": "Select “{{subject}}”",
703
+ "messageActions": "Actions for “{{subject}}”",
704
+ "threadCount_one": "{{count}} message in the conversation",
705
+ "threadCount_other": "{{count}} messages in the conversation",
706
+ "cc": "Cc: {{cc}}",
707
+ "openAttachment": "Open {{name}}",
708
+ "expandMessage": "Open the message from {{name}} ({{date}})",
636
709
  "listLabel": "Messages",
637
710
  "folders": "Folders",
638
711
  "empty": "There are no messages here.",