@conduction/nextcloud-vue 2.85.0 → 2.87.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 (301) hide show
  1. package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue.js +1 -1
  2. package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue2.js +3 -2
  3. package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue2.js.map +1 -1
  4. package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue.js +1 -1
  6. package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js +5 -4
  7. package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js.map +1 -1
  8. package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue.js +1 -1
  10. package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue2.js +2 -1
  11. package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue2.js.map +1 -1
  12. package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue3.js.map +1 -1
  13. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
  14. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +2 -1
  15. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
  16. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
  17. package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
  18. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +156 -14
  19. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  20. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +105 -74
  21. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  22. package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue.js +1 -1
  23. package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue2.js +2 -1
  24. package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue2.js.map +1 -1
  25. package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue3.js.map +1 -1
  26. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue.js +1 -1
  27. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js +2 -1
  28. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js.map +1 -1
  29. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js.map +1 -1
  30. package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
  31. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +6 -5
  32. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  33. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  34. package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue.js +1 -1
  35. package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue2.js +2 -1
  36. package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue2.js.map +1 -1
  37. package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue3.js.map +1 -1
  38. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
  39. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +2 -1
  40. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
  41. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
  42. package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue.js +1 -1
  43. package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js +2 -1
  44. package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js.map +1 -1
  45. package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js.map +1 -1
  46. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  47. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +2 -1
  48. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  49. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  50. package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue.js +1 -1
  51. package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue2.js +3 -1
  52. package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue2.js.map +1 -1
  53. package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue3.js.map +1 -1
  54. package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue2.js +2 -1
  55. package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue2.js.map +1 -1
  56. package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue3.js.map +1 -1
  57. package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue.js +1 -1
  58. package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue2.js +2 -1
  59. package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue2.js.map +1 -1
  60. package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue3.js.map +1 -1
  61. package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue.js +1 -1
  62. package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue2.js +3 -1
  63. package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue2.js.map +1 -1
  64. package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue3.js.map +1 -1
  65. package/dist/esm/components/CnFileManager/CnFileManager.vue.js +1 -1
  66. package/dist/esm/components/CnFileManager/CnFileManager.vue2.js +3 -1
  67. package/dist/esm/components/CnFileManager/CnFileManager.vue2.js.map +1 -1
  68. package/dist/esm/components/CnFileManager/CnFileManager.vue3.js.map +1 -1
  69. package/dist/esm/components/CnFilePreview/CnFilePreview.vue.js +1 -1
  70. package/dist/esm/components/CnFilePreview/CnFilePreview.vue2.js +2 -1
  71. package/dist/esm/components/CnFilePreview/CnFilePreview.vue2.js.map +1 -1
  72. package/dist/esm/components/CnFilePreview/CnFilePreview.vue3.js.map +1 -1
  73. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  74. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +49 -1
  75. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  76. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +3 -3
  77. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  78. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue.js +1 -1
  79. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js +2 -1
  80. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js.map +1 -1
  81. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue3.js.map +1 -1
  82. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -5
  83. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  84. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  85. package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
  86. package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +2 -1
  87. package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
  88. package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
  89. package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue.js +1 -1
  90. package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue2.js +3 -2
  91. package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue2.js.map +1 -1
  92. package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue3.js.map +1 -1
  93. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
  94. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +28 -0
  95. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  96. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +82 -75
  97. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  98. package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue.js +1 -1
  99. package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue2.js +5 -4
  100. package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue2.js.map +1 -1
  101. package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue3.js.map +1 -1
  102. package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue.js +1 -1
  103. package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue2.js +2 -1
  104. package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue2.js.map +1 -1
  105. package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue3.js.map +1 -1
  106. package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue.js +1 -1
  107. package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue2.js +2 -1
  108. package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue2.js.map +1 -1
  109. package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue3.js.map +1 -1
  110. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue.js +1 -1
  111. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +2 -1
  112. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
  113. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
  114. package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue.js +1 -1
  115. package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue2.js +2 -1
  116. package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue2.js.map +1 -1
  117. package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue3.js.map +1 -1
  118. package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue.js +1 -1
  119. package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue2.js +2 -1
  120. package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue2.js.map +1 -1
  121. package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue3.js.map +1 -1
  122. package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue.js +1 -1
  123. package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue2.js +2 -1
  124. package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue2.js.map +1 -1
  125. package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue3.js.map +1 -1
  126. package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue2.js +2 -0
  127. package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue2.js.map +1 -1
  128. package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue3.js +2 -2
  129. package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue3.js.map +1 -1
  130. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue.js +1 -1
  131. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js +2 -1
  132. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js.map +1 -1
  133. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js.map +1 -1
  134. package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue.js +1 -1
  135. package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue2.js +2 -1
  136. package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue2.js.map +1 -1
  137. package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue3.js.map +1 -1
  138. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  139. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +36 -0
  140. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  141. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +55 -40
  142. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  143. package/dist/esm/components/CnTasksCard/CnTasksCard.vue.js +1 -1
  144. package/dist/esm/components/CnTasksCard/CnTasksCard.vue2.js +2 -1
  145. package/dist/esm/components/CnTasksCard/CnTasksCard.vue2.js.map +1 -1
  146. package/dist/esm/components/CnTasksCard/CnTasksCard.vue3.js.map +1 -1
  147. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +1 -1
  148. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +2 -1
  149. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -1
  150. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -1
  151. package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue.js +1 -1
  152. package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue2.js +2 -1
  153. package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue2.js.map +1 -1
  154. package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue.js +1 -1
  155. package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue2.js +2 -1
  156. package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue2.js.map +1 -1
  157. package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue3.js.map +1 -1
  158. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
  159. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +3 -26
  160. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
  161. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
  162. package/dist/esm/dialogs/CnNoteHistoryDialog.vue.js +1 -1
  163. package/dist/esm/dialogs/CnNoteHistoryDialog.vue2.js +2 -1
  164. package/dist/esm/dialogs/CnNoteHistoryDialog.vue2.js.map +1 -1
  165. package/dist/esm/dialogs/CnNoteHistoryDialog.vue3.js.map +1 -1
  166. package/dist/esm/integrations/builtin/activity/CnActivityCard.vue.js +1 -1
  167. package/dist/esm/integrations/builtin/activity/CnActivityCard.vue2.js +3 -2
  168. package/dist/esm/integrations/builtin/activity/CnActivityCard.vue2.js.map +1 -1
  169. package/dist/esm/integrations/builtin/activity/CnActivityCard.vue3.js.map +1 -1
  170. package/dist/esm/integrations/builtin/activity/CnActivityTab.vue.js +1 -1
  171. package/dist/esm/integrations/builtin/activity/CnActivityTab.vue2.js +4 -3
  172. package/dist/esm/integrations/builtin/activity/CnActivityTab.vue2.js.map +1 -1
  173. package/dist/esm/integrations/builtin/activity/CnActivityTab.vue3.js.map +1 -1
  174. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue.js +1 -1
  175. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -2
  176. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  177. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  178. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue.js +1 -1
  179. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js +2 -1
  180. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js.map +1 -1
  181. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js.map +1 -1
  182. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue.js +1 -1
  183. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js +6 -5
  184. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js.map +1 -1
  185. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue3.js.map +1 -1
  186. package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue.js +1 -1
  187. package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue2.js +2 -1
  188. package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue2.js.map +1 -1
  189. package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue3.js.map +1 -1
  190. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue.js +1 -1
  191. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  192. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  193. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  194. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue.js +1 -1
  195. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  196. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  197. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  198. package/dist/esm/integrations/builtin/email/CnEmailCard.vue.js +1 -1
  199. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js +2 -1
  200. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  201. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  202. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue.js +1 -1
  203. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js +2 -1
  204. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js.map +1 -1
  205. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js.map +1 -1
  206. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue.js +1 -1
  207. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue2.js +2 -1
  208. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue2.js.map +1 -1
  209. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue3.js.map +1 -1
  210. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue.js +1 -1
  211. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  212. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  213. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  214. package/dist/esm/l10n/en.json.js +35 -2
  215. package/dist/esm/l10n/en.json.js.map +1 -1
  216. package/dist/esm/l10n/nl.json.js +38 -2
  217. package/dist/esm/l10n/nl.json.js.map +1 -1
  218. package/dist/esm/library-style.js +1 -1
  219. package/dist/esm/nextcloud-vue.css +1068 -962
  220. package/dist/esm/store/useObjectStore.js +7 -2
  221. package/dist/esm/store/useObjectStore.js.map +1 -1
  222. package/dist/esm/utils/boardColumns.js +50 -1
  223. package/dist/esm/utils/boardColumns.js.map +1 -1
  224. package/dist/esm/utils/boardReferenceColumns.js +115 -4
  225. package/dist/esm/utils/boardReferenceColumns.js.map +1 -1
  226. package/dist/esm/utils/contentHeaderLink.js +48 -1
  227. package/dist/esm/utils/contentHeaderLink.js.map +1 -1
  228. package/dist/esm/utils/schema.js +5 -4
  229. package/dist/esm/utils/schema.js.map +1 -1
  230. package/dist/esm/utils/userLocale.js +30 -0
  231. package/dist/esm/utils/userLocale.js.map +1 -0
  232. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  233. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  234. package/dist/nextcloud-vue.cjs.js +1088 -476
  235. package/dist/nextcloud-vue.cjs.js.map +2 -2
  236. package/dist/nextcloud-vue.css +1068 -962
  237. package/l10n/en.json +35 -2
  238. package/l10n/nl.json +38 -2
  239. package/package.json +1 -1
  240. package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +3 -2
  241. package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +5 -4
  242. package/src/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue +2 -1
  243. package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +2 -1
  244. package/src/components/CnBoardView/CnBoardView.vue +189 -24
  245. package/src/components/CnCalendarEventPicker/CnCalendarEventPicker.vue +2 -1
  246. package/src/components/CnCalendarWidget/CnCalendarWidget.vue +2 -1
  247. package/src/components/CnChartWidget/CnChartWidget.vue +6 -5
  248. package/src/components/CnCollectivePagePicker/CnCollectivePagePicker.vue +2 -1
  249. package/src/components/CnConversationThread/CnConversationThread.vue +2 -1
  250. package/src/components/CnCountdownWidget/CnCountdownWidget.vue +2 -1
  251. package/src/components/CnDashboardPage/CnDashboardPage.vue +2 -1
  252. package/src/components/CnDataMatrix/CnDataMatrix.vue +2 -1
  253. package/src/components/CnDetailPage/CnDetailHeaderChips.vue +2 -1
  254. package/src/components/CnEmailPicker/CnEmailPicker.vue +2 -1
  255. package/src/components/CnFederationStatus/CnFederationStatus.vue +3 -1
  256. package/src/components/CnFileManager/CnFileManager.vue +2 -1
  257. package/src/components/CnFilePreview/CnFilePreview.vue +2 -1
  258. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +54 -6
  259. package/src/components/CnFollowToggle/CnFollowToggle.vue +2 -1
  260. package/src/components/CnIndexPage/CnIndexPage.vue +30 -4
  261. package/src/components/CnNotesCard/CnNotesCard.vue +2 -1
  262. package/src/components/CnObjectCalendar/CnObjectCalendar.vue +3 -2
  263. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +36 -0
  264. package/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue +5 -4
  265. package/src/components/CnObjectSidebar/CnAuditTrailTab.vue +2 -1
  266. package/src/components/CnObjectSidebar/CnFlowTasksPanel.vue +2 -1
  267. package/src/components/CnObjectSidebar/CnNotesTab.vue +2 -1
  268. package/src/components/CnObjectSidebar/CnTasksTab.vue +2 -1
  269. package/src/components/CnPropertySourceField/CnPropertySourceField.vue +2 -1
  270. package/src/components/CnRoadmapItem/CnRoadmapItem.vue +2 -1
  271. package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +4 -2
  272. package/src/components/CnStatsBlock/CnStatsBlock.vue +2 -1
  273. package/src/components/CnSummaryAggregates/CnSummaryAggregates.vue +2 -1
  274. package/src/components/CnTabsWidget/CnTabsWidget.vue +71 -0
  275. package/src/components/CnTasksCard/CnTasksCard.vue +2 -1
  276. package/src/components/CnTimelineWidget/CnTimelineWidget.vue +2 -1
  277. package/src/components/CnTranslatedBadge/CnTranslatedBadge.vue +2 -1
  278. package/src/components/CnVersionHistory/CnVersionHistory.vue +2 -1
  279. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +3 -26
  280. package/src/css/board.css +40 -0
  281. package/src/dialogs/CnNoteHistoryDialog.vue +2 -1
  282. package/src/integrations/builtin/activity/CnActivityCard.vue +3 -2
  283. package/src/integrations/builtin/activity/CnActivityTab.vue +4 -3
  284. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +3 -2
  285. package/src/integrations/builtin/calendar/CnCalendarCard.vue +2 -1
  286. package/src/integrations/builtin/calendar/CnCalendarTab.vue +6 -5
  287. package/src/integrations/builtin/contactmoment/CnContactmomentCard.vue +2 -1
  288. package/src/integrations/builtin/cospend/CnCospendTab.vue +2 -1
  289. package/src/integrations/builtin/deck/CnDeckTab.vue +2 -1
  290. package/src/integrations/builtin/email/CnEmailCard.vue +2 -1
  291. package/src/integrations/builtin/field-inspection/CnFieldInspectionCard.vue +2 -1
  292. package/src/integrations/builtin/field-inspection/CnFieldInspectionTab.vue +2 -1
  293. package/src/integrations/builtin/photos/CnPhotosTab.vue +2 -1
  294. package/src/schemas/app-manifest-v2.schema.json +4 -1
  295. package/src/store/useObjectStore.js +7 -2
  296. package/src/utils/boardColumns.js +49 -0
  297. package/src/utils/boardReferenceColumns.js +114 -3
  298. package/src/utils/contentHeaderLink.js +47 -0
  299. package/src/utils/schema.js +5 -4
  300. package/src/utils/userLocale.js +26 -0
  301. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"CnObjectCalendar.vue2.js","sources":["../../../../src/components/CnObjectCalendar/CnObjectCalendar.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-object-calendar\">\n\t\t<header class=\"cn-object-calendar__header\">\n\t\t\t<NcButton :aria-label=\"prevMonthLabel\" @click=\"goToPreviousMonth\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ChevronLeft :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t\t<span class=\"cn-object-calendar__title\">{{ monthLabel }}</span>\n\t\t\t<NcButton :aria-label=\"nextMonthLabel\" @click=\"goToNextMonth\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ChevronRight :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t</header>\n\n\t\t<div v-if=\"loading\" class=\"cn-object-calendar__loading\">\n\t\t\t<NcLoadingIcon :size=\"32\" />\n\t\t</div>\n\n\t\t<div\n\t\t\tv-else\n\t\t\tclass=\"cn-object-calendar__month\"\n\t\t\trole=\"grid\"\n\t\t\t:aria-label=\"monthLabel\">\n\t\t\t<div class=\"cn-object-calendar__week\" role=\"row\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"(weekday, idx) in weekdayHeaders\"\n\t\t\t\t\t:key=\"'wh-' + idx\"\n\t\t\t\t\tclass=\"cn-object-calendar__month-header\"\n\t\t\t\t\trole=\"columnheader\">\n\t\t\t\t\t{{ weekday }}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tv-for=\"(week, w) in weeks\"\n\t\t\t\t:key=\"'w-' + w\"\n\t\t\t\tclass=\"cn-object-calendar__week\"\n\t\t\t\trole=\"row\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"day in week\"\n\t\t\t\t\t:key=\"day.iso\"\n\t\t\t\t\tclass=\"cn-object-calendar__month-cell\"\n\t\t\t\t\t:class=\"{ 'is-today': day.isToday, 'is-other-month': day.isOtherMonth }\"\n\t\t\t\t\trole=\"gridcell\"\n\t\t\t\t\t:data-iso=\"day.iso\"\n\t\t\t\t\t:tabindex=\"day.iso === activeIso ? 0 : -1\"\n\t\t\t\t\t:aria-label=\"dayLabel(day)\"\n\t\t\t\t\t@focus=\"focusedIso = day.iso\"\n\t\t\t\t\t@keydown=\"onCellKeydown($event, day)\">\n\t\t\t\t\t<span class=\"cn-object-calendar__month-day\">{{ day.dayNum }}</span>\n\t\t\t\t\t<ul v-if=\"day.objects.length\" class=\"cn-object-calendar__month-events\">\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-for=\"object in day.objects.slice(0, maxEventsPerDay)\"\n\t\t\t\t\t\t\t:key=\"objectKey(object) + '-' + day.iso\"\n\t\t\t\t\t\t\tclass=\"cn-object-calendar__event-item\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-calendar__event\"\n\t\t\t\t\t\t\t\t:title=\"objectTitle(object)\"\n\t\t\t\t\t\t\t\t@click=\"onObjectClick(object)\">\n\t\t\t\t\t\t\t\t<!-- @slot day-event Override a single day's event entry. -->\n\t\t\t\t\t\t\t\t<!-- @binding {object} object The plotted object. -->\n\t\t\t\t\t\t\t\t<!-- @binding {object} day The day cell ({ iso, dayNum, isToday, isOtherMonth }). -->\n\t\t\t\t\t\t\t\t<slot name=\"day-event\" :object=\"object\" :day=\"day\">\n\t\t\t\t\t\t\t\t\t{{ objectTitle(object) }}\n\t\t\t\t\t\t\t\t</slot>\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-if=\"day.objects.length > maxEventsPerDay\"\n\t\t\t\t\t\t\tclass=\"cn-object-calendar__overflow-item\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-calendar__overflow\"\n\t\t\t\t\t\t\t\t:aria-label=\"overflowLabel(day)\"\n\t\t\t\t\t\t\t\t@click=\"$emit('day-select', day.iso)\">\n\t\t\t\t\t\t\t\t+{{ day.objects.length - maxEventsPerDay }}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport ChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\n\n/**\n * CnObjectCalendar — plots objects on a month calendar by a date property.\n *\n * Places each object on `dateField`; when `endDateField` is also configured,\n * an object spans every day from `dateField` to `endDateField` inclusive\n * (REQ-VIEW-CAL-04). The component only renders a window it is given —\n * `objects` is expected to already be scoped to the visible range (e.g. via\n * `GET /api/views/{id}/calendar?start=&end=`). Navigating months emits\n * `range-change` with the new window so the host re-fetches; the component\n * does not fetch anything itself.\n *\n * ```vue\n * <CnObjectCalendar\n * :objects=\"objects\"\n * date-field=\"dueDate\"\n * end-date-field=\"endDate\"\n * v-model:visible-date=\"visibleDate\"\n * @range-change=\"fetchCalendarObjects\"\n * @object-click=\"openObject\" />\n * ```\n */\nexport default {\n\tname: 'CnObjectCalendar',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tChevronLeft,\n\t\tChevronRight,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Objects to plot. Expected to already be scoped to the visible range —\n\t\t * e.g. the response of `GET /api/views/{id}/calendar?start=&end=`.\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\tobjects: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** The date property an object is plotted on. */\n\t\tdateField: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Optional end-date property — when set, an object spans `dateField`..`endDateField`. */\n\t\tendDateField: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Any day within the currently visible month (`.sync`-compatible).\n\t\t * Defaults to today when omitted.\n\t\t *\n\t\t * @type {string|Date|null}\n\t\t */\n\t\tvisibleDate: {\n\t\t\ttype: [String, Date],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Object property used as a title fallback and as each object's identity. */\n\t\ttitleField: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Object property used as each object's identity (for `:key` and click payload matching). */\n\t\trowKey: {\n\t\t\ttype: String,\n\t\t\tdefault: 'id',\n\t\t},\n\n\t\t/** Loading state (host is (re)fetching the visible range). */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Maximum events shown per day cell before \"+N\" overflow. */\n\t\tmaxEventsPerDay: {\n\t\t\ttype: Number,\n\t\t\tdefault: 3,\n\t\t},\n\t},\n\n\temits: [\n\t\t'object-click',\n\t\t'range-change',\n\t\t'update:visibleDate',\n\t\t/**\n\t\t * The \"+N\" button of a busy day was activated. Payload: the day as `YYYY-MM-DD`.\n\t\t *\n\t\t * @event day-select\n\t\t * @type {string}\n\t\t */\n\t\t'day-select',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tinternalDate: this.parseDate(this.visibleDate) || new Date(),\n\t\t\t// The day cell that holds focus (roving tabindex); empty = today or the 1st.\n\t\t\tfocusedIso: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tmonthLabel() {\n\t\t\treturn this.internalDate.toLocaleDateString(undefined, { month: 'long', year: 'numeric' })\n\t\t},\n\n\t\tprevMonthLabel() {\n\t\t\treturn t('nextcloud-vue', 'Previous month')\n\t\t},\n\n\t\tnextMonthLabel() {\n\t\t\treturn t('nextcloud-vue', 'Next month')\n\t\t},\n\n\t\t/**\n\t\t * Localised short weekday names (Sun-first, matching CnCalendarWidget).\n\t\t *\n\t\t * @return {string[]}\n\t\t */\n\t\tweekdayHeaders() {\n\t\t\treturn [\n\t\t\t\tt('nextcloud-vue', 'Sun'),\n\t\t\t\tt('nextcloud-vue', 'Mon'),\n\t\t\t\tt('nextcloud-vue', 'Tue'),\n\t\t\t\tt('nextcloud-vue', 'Wed'),\n\t\t\t\tt('nextcloud-vue', 'Thu'),\n\t\t\t\tt('nextcloud-vue', 'Fri'),\n\t\t\t\tt('nextcloud-vue', 'Sat'),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * The first/last day of the visible month.\n\t\t *\n\t\t * @return {{from: Date, to: Date}}\n\t\t */\n\t\tmonthRange() {\n\t\t\tconst d = this.internalDate\n\t\t\tconst first = new Date(d.getFullYear(), d.getMonth(), 1)\n\t\t\tconst last = new Date(d.getFullYear(), d.getMonth() + 1, 0)\n\t\t\treturn { from: first, to: last }\n\t\t},\n\n\t\t/**\n\t\t * The full displayed grid window (month padded to whole Sun–Sat weeks) —\n\t\t * this is the range emitted by `range-change`, since leading/trailing\n\t\t * days from adjacent months are visible and should be requested too.\n\t\t *\n\t\t * @return {{from: Date, to: Date}}\n\t\t */\n\t\tgridRange() {\n\t\t\tconst { from, to } = this.monthRange\n\t\t\tconst gridStart = new Date(from)\n\t\t\tgridStart.setDate(from.getDate() - from.getDay())\n\t\t\tconst totalDays = Math.ceil((to.getDate() + from.getDay()) / 7) * 7\n\t\t\tconst gridEnd = new Date(gridStart)\n\t\t\tgridEnd.setDate(gridStart.getDate() + totalDays - 1)\n\t\t\treturn { from: gridStart, to: gridEnd }\n\t\t},\n\n\t\t/**\n\t\t * Objects bucketed by every `YYYY-MM-DD` they occupy — a single day for\n\t\t * a plain `dateField` object, or every day from `dateField` to\n\t\t * `endDateField` inclusive when spanning.\n\t\t *\n\t\t * @return {{[iso: string]: object[]}}\n\t\t */\n\t\tobjectsByDay() {\n\t\t\tconst buckets = {}\n\t\t\tconst { from: gridStart, to: gridEnd } = this.gridRange\n\n\t\t\tfor (const object of this.objects) {\n\t\t\t\tif (!object) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst start = this.parseDate(object[this.dateField])\n\t\t\t\tif (!start) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst rawEnd = this.endDateField ? this.parseDate(object[this.endDateField]) : null\n\t\t\t\tconst end = rawEnd && rawEnd >= start ? rawEnd : start\n\n\t\t\t\tconst spanStart = start < gridStart ? gridStart : start\n\t\t\t\tconst spanEnd = end > gridEnd ? gridEnd : end\n\n\t\t\t\tfor (const iso of this.isoDateRange(spanStart, spanEnd)) {\n\t\t\t\t\tif (!buckets[iso]) {\n\t\t\t\t\t\tbuckets[iso] = []\n\t\t\t\t\t}\n\t\t\t\t\tbuckets[iso].push(object)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn buckets\n\t\t},\n\n\t\t/**\n\t\t * The month grid cut into weeks, for the grid/row roles.\n\t\t *\n\t\t * @return {Array<Array<object>>}\n\t\t */\n\t\tweeks() {\n\t\t\tconst rows = []\n\t\t\tfor (let i = 0; i < this.monthGrid.length; i += 7) {\n\t\t\t\trows.push(this.monthGrid.slice(i, i + 7))\n\t\t\t}\n\t\t\treturn rows\n\t\t},\n\n\t\t/**\n\t\t * The day cell that takes the tab stop: the focused one when it is in\n\t\t * the grid, else today, else the 1st of the month.\n\t\t *\n\t\t * @return {string} `YYYY-MM-DD`.\n\t\t */\n\t\tactiveIso() {\n\t\t\tconst isos = this.monthGrid.map((d) => d.iso)\n\t\t\tif (this.focusedIso && isos.includes(this.focusedIso)) {\n\t\t\t\treturn this.focusedIso\n\t\t\t}\n\t\t\tconst today = this.toIsoDate(new Date())\n\t\t\tif (isos.includes(today)) {\n\t\t\t\treturn today\n\t\t\t}\n\t\t\treturn this.toIsoDate(this.monthRange.from)\n\t\t},\n\n\t\t/**\n\t\t * The 7-column month grid (leading/trailing days padded to whole weeks).\n\t\t *\n\t\t * @return {Array<{iso: string, dayNum: number, isToday: boolean, isOtherMonth: boolean, objects: object[]}>}\n\t\t */\n\t\tmonthGrid() {\n\t\t\tconst { from: gridStart, to: gridEnd } = this.gridRange\n\t\t\tconst { from: monthStart } = this.monthRange\n\t\t\tconst today = this.toIsoDate(new Date())\n\t\t\tconst cells = []\n\t\t\tfor (const iso of this.isoDateRange(gridStart, gridEnd)) {\n\t\t\t\tconst cellDate = this.parseDate(iso)\n\t\t\t\tcells.push({\n\t\t\t\t\tiso,\n\t\t\t\t\tdayNum: cellDate.getDate(),\n\t\t\t\t\tisToday: today === iso,\n\t\t\t\t\tisOtherMonth: cellDate.getMonth() !== monthStart.getMonth(),\n\t\t\t\t\tobjects: this.objectsByDay[iso] || [],\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn cells\n\t\t},\n\t},\n\n\twatch: {\n\t\tvisibleDate(newValue) {\n\t\t\tconst parsed = this.parseDate(newValue)\n\t\t\tif (!parsed) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.toIsoDate(parsed).slice(0, 7) === this.toIsoDate(this.internalDate).slice(0, 7)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.internalDate = parsed\n\t\t\tthis.emitRangeChange()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.emitRangeChange()\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Parse a date-ish value (Date instance, ISO string, or nullish) into a\n\t\t * `Date`, or `null` when it can't be parsed.\n\t\t *\n\t\t * @param {string|Date|null|undefined} value The value to parse.\n\t\t * @return {Date|null}\n\t\t */\n\t\tparseDate(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst date = value instanceof Date ? value : new Date(value)\n\t\t\treturn Number.isNaN(date.getTime()) ? null : date\n\t\t},\n\n\t\t/**\n\t\t * Format a `Date` as `YYYY-MM-DD` in local time (never UTC, so the grid\n\t\t * and the bucketing agree regardless of timezone offset).\n\t\t *\n\t\t * @param {Date} date The date to format.\n\t\t * @return {string}\n\t\t */\n\t\ttoIsoDate(date) {\n\t\t\tconst y = date.getFullYear()\n\t\t\tconst m = String(date.getMonth() + 1).padStart(2, '0')\n\t\t\tconst d = String(date.getDate()).padStart(2, '0')\n\t\t\treturn `${y}-${m}-${d}`\n\t\t},\n\n\t\t/**\n\t\t * Every `YYYY-MM-DD` from `start` to `end` inclusive (both truncated to\n\t\t * whole days), as a plain array — used so day-stepping loops reassign a\n\t\t * counter rather than mutating a `Date` in a `while` condition.\n\t\t *\n\t\t * @param {Date} start The range start (inclusive).\n\t\t * @param {Date} end The range end (inclusive).\n\t\t * @return {string[]}\n\t\t */\n\t\tisoDateRange(start, end) {\n\t\t\tconst startDay = new Date(start.getFullYear(), start.getMonth(), start.getDate())\n\t\t\tconst endDay = new Date(end.getFullYear(), end.getMonth(), end.getDate())\n\t\t\tconst dayCount = Math.round((endDay.getTime() - startDay.getTime()) / 86400000) + 1\n\t\t\tconst isoDates = []\n\t\t\tfor (let i = 0; i < dayCount; i++) {\n\t\t\t\tisoDates.push(this.toIsoDate(new Date(startDay.getFullYear(), startDay.getMonth(), startDay.getDate() + i)))\n\t\t\t}\n\t\t\treturn isoDates\n\t\t},\n\n\t\t/**\n\t\t * The object's identity, per `rowKey`.\n\t\t *\n\t\t * @param {object} object The object.\n\t\t * @return {unknown}\n\t\t */\n\t\tobjectKey(object) {\n\t\t\treturn object?.[this.rowKey]\n\t\t},\n\n\t\t/**\n\t\t * Best-effort display title: `titleField` when configured, else\n\t\t * `title`/`name`/the row key.\n\t\t *\n\t\t * @param {object} object The object.\n\t\t * @return {string}\n\t\t */\n\t\tobjectTitle(object) {\n\t\t\tif (this.titleField && object[this.titleField]) {\n\t\t\t\treturn String(object[this.titleField])\n\t\t\t}\n\t\t\treturn String(object.title || object.name || object[this.rowKey] || '—')\n\t\t},\n\n\t\t/**\n\t\t * Accessible name of a day cell: the date and how many records it holds.\n\t\t *\n\t\t * @param {{iso: string, objects: object[]}} day The day.\n\t\t * @return {string}\n\t\t */\n\t\tdayLabel(day) {\n\t\t\tconst date = this.parseDate(day.iso).toLocaleDateString(undefined, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })\n\t\t\treturn day.objects.length === 0 ? date : `${date}, ${t('nextcloud-vue', '{count} records', { count: day.objects.length })}`\n\t\t},\n\n\t\t/**\n\t\t * Accessible name of the \"+N\" button.\n\t\t *\n\t\t * @param {{iso: string, objects: object[]}} day The day.\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel(day) {\n\t\t\treturn t('nextcloud-vue', 'Show all {count} records on {date}', { count: day.objects.length, date: day.iso })\n\t\t},\n\n\t\t/**\n\t\t * Move between day cells with the arrow keys, Home and End. Past the\n\t\t * edge of the grid the month moves with it.\n\t\t *\n\t\t * @param {KeyboardEvent} event The key event.\n\t\t * @param {{iso: string}} day The focused day.\n\t\t */\n\t\tonCellKeydown(event, day) {\n\t\t\tif (event.target !== event.currentTarget) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst steps = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -7, ArrowDown: 7 }\n\t\t\tconst here = this.parseDate(day.iso)\n\t\t\tlet target = null\n\t\t\tif (event.key in steps) {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() + steps[event.key])\n\t\t\t} else if (event.key === 'Home') {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() - here.getDay())\n\t\t\t} else if (event.key === 'End') {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() + (6 - here.getDay()))\n\t\t\t}\n\t\t\tif (!target) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tevent.preventDefault()\n\t\t\tconst iso = this.toIsoDate(target)\n\t\t\tif (!this.monthGrid.some((d) => d.iso === iso)) {\n\t\t\t\t// Off the edge: move to the month that holds the day.\n\t\t\t\tthis.internalDate = new Date(target.getFullYear(), target.getMonth(), 1)\n\t\t\t\tthis.afterNavigate()\n\t\t\t}\n\t\t\tthis.focusedIso = iso\n\t\t\tthis.$nextTick(() => {\n\t\t\t\tconst cell = this.$el.querySelector(`[data-iso=\"${iso}\"]`)\n\t\t\t\tif (cell) {\n\t\t\t\t\tcell.focus()\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Navigate to the previous month.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgoToPreviousMonth() {\n\t\t\tconst d = this.internalDate\n\t\t\tthis.internalDate = new Date(d.getFullYear(), d.getMonth() - 1, 1)\n\t\t\tthis.afterNavigate()\n\t\t},\n\n\t\t/**\n\t\t * Navigate to the next month.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgoToNextMonth() {\n\t\t\tconst d = this.internalDate\n\t\t\tthis.internalDate = new Date(d.getFullYear(), d.getMonth() + 1, 1)\n\t\t\tthis.afterNavigate()\n\t\t},\n\n\t\t/**\n\t\t * Sync `.sync` and notify the host to re-fetch after a month navigation.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tafterNavigate() {\n\t\t\t// Description goes ABOVE `@event`, not inline after it:\n\t\t\t// vue-docgen-api's event-name splitter stops at the first `:`, so\n\t\t\t// `@event update:visibleDate <description>` is read as one long\n\t\t\t// event NAME and the generated docs show an empty description.\n\t\t\t// Only colon-bearing (`update:*`) names are affected.\n\t\t\t/**\n\t\t\t * Emitted on month navigation, for `v-model:visible-date` binding.\n\t\t\t *\n\t\t\t * @event update:visibleDate\n\t\t\t * @type {Date}\n\t\t\t */\n\t\t\tthis.$emit('update:visibleDate', this.internalDate)\n\t\t\tthis.emitRangeChange()\n\t\t},\n\n\t\t/**\n\t\t * Emit the currently visible grid window (padded to whole weeks) as\n\t\t * ISO date strings, matching the OpenRegister calendar endpoint's\n\t\t * `rangeStart`/`rangeEnd` query params.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\temitRangeChange() {\n\t\t\tconst { from, to } = this.gridRange\n\t\t\t/**\n\t\t\t * @event range-change Emitted on mount and after every month\n\t\t\t * navigation so the host can re-fetch objects for the new window.\n\t\t\t * @type {{ rangeStart: string, rangeEnd: string }}\n\t\t\t */\n\t\t\tthis.$emit('range-change', {\n\t\t\t\trangeStart: this.toIsoDate(from),\n\t\t\t\trangeEnd: this.toIsoDate(to),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Handle an event entry click.\n\t\t *\n\t\t * @param {object} object The clicked object.\n\t\t * @return {void}\n\t\t */\n\t\tonObjectClick(object) {\n\t\t\t/**\n\t\t\t * @event object-click Emitted when a plotted object is clicked.\n\t\t\t * @type {object} The clicked object.\n\t\t\t */\n\t\t\tthis.$emit('object-click', object)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-calendar__header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 12px;\n\tpadding: 8px 0 16px;\n}\n\n.cn-object-calendar__title {\n\tmin-width: 160px;\n\ttext-align: center;\n\tfont-weight: 600;\n\tfont-size: 16px;\n\ttext-transform: capitalize;\n}\n\n.cn-object-calendar__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 40px;\n}\n\n.cn-object-calendar__month {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(7, 1fr);\n\tgap: 1px;\n\tbackground: var(--color-border);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius, 8px);\n\toverflow: hidden;\n}\n\n.cn-object-calendar__month-header {\n\tbackground: var(--color-background-dark);\n\tpadding: 6px 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\ttext-align: center;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-calendar__month-cell {\n\tbackground: var(--color-main-background);\n\tmin-height: 90px;\n\tpadding: 4px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-object-calendar__month-cell.is-other-month {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-calendar__month-day {\n\tfont-size: 12px;\n\twidth: 20px;\n\theight: 20px;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.cn-object-calendar__month-cell.is-today .cn-object-calendar__month-day {\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tborder-radius: 50%;\n}\n\n.cn-object-calendar__month-events {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-object-calendar__event {\n\tfont-size: 11px;\n\tpadding: 1px 4px;\n\tborder-radius: 4px;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-main-text);\n\tcursor: pointer;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-calendar__overflow {\n\tfont-size: 11px;\n\tcolor: var(--color-text-maxcontrast);\n\tpadding: 0 4px;\n}\n\n.cn-object-calendar__week {\n\tdisplay: contents;\n}\n\n.cn-object-calendar__month-cell:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: -2px;\n}\n\nbutton.cn-object-calendar__event,\nbutton.cn-object-calendar__overflow {\n\tdisplay: block;\n\twidth: 100%;\n\tmin-height: 0;\n\tborder: 0;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text);\n\tborder-radius: var(--border-radius, 4px);\n\tpadding: 1px 6px;\n\tfont: inherit;\n\tfont-size: 12px;\n\ttext-align: start;\n\tcursor: pointer;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\nbutton.cn-object-calendar__overflow {\n\tbackground: transparent;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["t"],"mappings":"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"}
1
+ {"version":3,"file":"CnObjectCalendar.vue2.js","sources":["../../../../src/components/CnObjectCalendar/CnObjectCalendar.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-object-calendar\">\n\t\t<header class=\"cn-object-calendar__header\">\n\t\t\t<NcButton :aria-label=\"prevMonthLabel\" @click=\"goToPreviousMonth\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ChevronLeft :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t\t<span class=\"cn-object-calendar__title\">{{ monthLabel }}</span>\n\t\t\t<NcButton :aria-label=\"nextMonthLabel\" @click=\"goToNextMonth\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ChevronRight :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t</header>\n\n\t\t<div v-if=\"loading\" class=\"cn-object-calendar__loading\">\n\t\t\t<NcLoadingIcon :size=\"32\" />\n\t\t</div>\n\n\t\t<div\n\t\t\tv-else\n\t\t\tclass=\"cn-object-calendar__month\"\n\t\t\trole=\"grid\"\n\t\t\t:aria-label=\"monthLabel\">\n\t\t\t<div class=\"cn-object-calendar__week\" role=\"row\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"(weekday, idx) in weekdayHeaders\"\n\t\t\t\t\t:key=\"'wh-' + idx\"\n\t\t\t\t\tclass=\"cn-object-calendar__month-header\"\n\t\t\t\t\trole=\"columnheader\">\n\t\t\t\t\t{{ weekday }}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tv-for=\"(week, w) in weeks\"\n\t\t\t\t:key=\"'w-' + w\"\n\t\t\t\tclass=\"cn-object-calendar__week\"\n\t\t\t\trole=\"row\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"day in week\"\n\t\t\t\t\t:key=\"day.iso\"\n\t\t\t\t\tclass=\"cn-object-calendar__month-cell\"\n\t\t\t\t\t:class=\"{ 'is-today': day.isToday, 'is-other-month': day.isOtherMonth }\"\n\t\t\t\t\trole=\"gridcell\"\n\t\t\t\t\t:data-iso=\"day.iso\"\n\t\t\t\t\t:tabindex=\"day.iso === activeIso ? 0 : -1\"\n\t\t\t\t\t:aria-label=\"dayLabel(day)\"\n\t\t\t\t\t@focus=\"focusedIso = day.iso\"\n\t\t\t\t\t@keydown=\"onCellKeydown($event, day)\">\n\t\t\t\t\t<span class=\"cn-object-calendar__month-day\">{{ day.dayNum }}</span>\n\t\t\t\t\t<ul v-if=\"day.objects.length\" class=\"cn-object-calendar__month-events\">\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-for=\"object in day.objects.slice(0, maxEventsPerDay)\"\n\t\t\t\t\t\t\t:key=\"objectKey(object) + '-' + day.iso\"\n\t\t\t\t\t\t\tclass=\"cn-object-calendar__event-item\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-calendar__event\"\n\t\t\t\t\t\t\t\t:title=\"objectTitle(object)\"\n\t\t\t\t\t\t\t\t@click=\"onObjectClick(object)\">\n\t\t\t\t\t\t\t\t<!-- @slot day-event Override a single day's event entry. -->\n\t\t\t\t\t\t\t\t<!-- @binding {object} object The plotted object. -->\n\t\t\t\t\t\t\t\t<!-- @binding {object} day The day cell ({ iso, dayNum, isToday, isOtherMonth }). -->\n\t\t\t\t\t\t\t\t<slot name=\"day-event\" :object=\"object\" :day=\"day\">\n\t\t\t\t\t\t\t\t\t{{ objectTitle(object) }}\n\t\t\t\t\t\t\t\t</slot>\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-if=\"day.objects.length > maxEventsPerDay\"\n\t\t\t\t\t\t\tclass=\"cn-object-calendar__overflow-item\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-calendar__overflow\"\n\t\t\t\t\t\t\t\t:aria-label=\"overflowLabel(day)\"\n\t\t\t\t\t\t\t\t@click=\"$emit('day-select', day.iso)\">\n\t\t\t\t\t\t\t\t+{{ day.objects.length - maxEventsPerDay }}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport ChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnObjectCalendar — plots objects on a month calendar by a date property.\n *\n * Places each object on `dateField`; when `endDateField` is also configured,\n * an object spans every day from `dateField` to `endDateField` inclusive\n * (REQ-VIEW-CAL-04). The component only renders a window it is given —\n * `objects` is expected to already be scoped to the visible range (e.g. via\n * `GET /api/views/{id}/calendar?start=&end=`). Navigating months emits\n * `range-change` with the new window so the host re-fetches; the component\n * does not fetch anything itself.\n *\n * ```vue\n * <CnObjectCalendar\n * :objects=\"objects\"\n * date-field=\"dueDate\"\n * end-date-field=\"endDate\"\n * v-model:visible-date=\"visibleDate\"\n * @range-change=\"fetchCalendarObjects\"\n * @object-click=\"openObject\" />\n * ```\n */\nexport default {\n\tname: 'CnObjectCalendar',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tChevronLeft,\n\t\tChevronRight,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Objects to plot. Expected to already be scoped to the visible range —\n\t\t * e.g. the response of `GET /api/views/{id}/calendar?start=&end=`.\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\tobjects: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** The date property an object is plotted on. */\n\t\tdateField: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Optional end-date property — when set, an object spans `dateField`..`endDateField`. */\n\t\tendDateField: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Any day within the currently visible month (`.sync`-compatible).\n\t\t * Defaults to today when omitted.\n\t\t *\n\t\t * @type {string|Date|null}\n\t\t */\n\t\tvisibleDate: {\n\t\t\ttype: [String, Date],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Object property used as a title fallback and as each object's identity. */\n\t\ttitleField: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Object property used as each object's identity (for `:key` and click payload matching). */\n\t\trowKey: {\n\t\t\ttype: String,\n\t\t\tdefault: 'id',\n\t\t},\n\n\t\t/** Loading state (host is (re)fetching the visible range). */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Maximum events shown per day cell before \"+N\" overflow. */\n\t\tmaxEventsPerDay: {\n\t\t\ttype: Number,\n\t\t\tdefault: 3,\n\t\t},\n\t},\n\n\temits: [\n\t\t'object-click',\n\t\t'range-change',\n\t\t'update:visibleDate',\n\t\t/**\n\t\t * The \"+N\" button of a busy day was activated. Payload: the day as `YYYY-MM-DD`.\n\t\t *\n\t\t * @event day-select\n\t\t * @type {string}\n\t\t */\n\t\t'day-select',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tinternalDate: this.parseDate(this.visibleDate) || new Date(),\n\t\t\t// The day cell that holds focus (roving tabindex); empty = today or the 1st.\n\t\t\tfocusedIso: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tmonthLabel() {\n\t\t\treturn this.internalDate.toLocaleDateString(userLocale(), { month: 'long', year: 'numeric' })\n\t\t},\n\n\t\tprevMonthLabel() {\n\t\t\treturn t('nextcloud-vue', 'Previous month')\n\t\t},\n\n\t\tnextMonthLabel() {\n\t\t\treturn t('nextcloud-vue', 'Next month')\n\t\t},\n\n\t\t/**\n\t\t * Localised short weekday names (Sun-first, matching CnCalendarWidget).\n\t\t *\n\t\t * @return {string[]}\n\t\t */\n\t\tweekdayHeaders() {\n\t\t\treturn [\n\t\t\t\tt('nextcloud-vue', 'Sun'),\n\t\t\t\tt('nextcloud-vue', 'Mon'),\n\t\t\t\tt('nextcloud-vue', 'Tue'),\n\t\t\t\tt('nextcloud-vue', 'Wed'),\n\t\t\t\tt('nextcloud-vue', 'Thu'),\n\t\t\t\tt('nextcloud-vue', 'Fri'),\n\t\t\t\tt('nextcloud-vue', 'Sat'),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * The first/last day of the visible month.\n\t\t *\n\t\t * @return {{from: Date, to: Date}}\n\t\t */\n\t\tmonthRange() {\n\t\t\tconst d = this.internalDate\n\t\t\tconst first = new Date(d.getFullYear(), d.getMonth(), 1)\n\t\t\tconst last = new Date(d.getFullYear(), d.getMonth() + 1, 0)\n\t\t\treturn { from: first, to: last }\n\t\t},\n\n\t\t/**\n\t\t * The full displayed grid window (month padded to whole Sun–Sat weeks) —\n\t\t * this is the range emitted by `range-change`, since leading/trailing\n\t\t * days from adjacent months are visible and should be requested too.\n\t\t *\n\t\t * @return {{from: Date, to: Date}}\n\t\t */\n\t\tgridRange() {\n\t\t\tconst { from, to } = this.monthRange\n\t\t\tconst gridStart = new Date(from)\n\t\t\tgridStart.setDate(from.getDate() - from.getDay())\n\t\t\tconst totalDays = Math.ceil((to.getDate() + from.getDay()) / 7) * 7\n\t\t\tconst gridEnd = new Date(gridStart)\n\t\t\tgridEnd.setDate(gridStart.getDate() + totalDays - 1)\n\t\t\treturn { from: gridStart, to: gridEnd }\n\t\t},\n\n\t\t/**\n\t\t * Objects bucketed by every `YYYY-MM-DD` they occupy — a single day for\n\t\t * a plain `dateField` object, or every day from `dateField` to\n\t\t * `endDateField` inclusive when spanning.\n\t\t *\n\t\t * @return {{[iso: string]: object[]}}\n\t\t */\n\t\tobjectsByDay() {\n\t\t\tconst buckets = {}\n\t\t\tconst { from: gridStart, to: gridEnd } = this.gridRange\n\n\t\t\tfor (const object of this.objects) {\n\t\t\t\tif (!object) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst start = this.parseDate(object[this.dateField])\n\t\t\t\tif (!start) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst rawEnd = this.endDateField ? this.parseDate(object[this.endDateField]) : null\n\t\t\t\tconst end = rawEnd && rawEnd >= start ? rawEnd : start\n\n\t\t\t\tconst spanStart = start < gridStart ? gridStart : start\n\t\t\t\tconst spanEnd = end > gridEnd ? gridEnd : end\n\n\t\t\t\tfor (const iso of this.isoDateRange(spanStart, spanEnd)) {\n\t\t\t\t\tif (!buckets[iso]) {\n\t\t\t\t\t\tbuckets[iso] = []\n\t\t\t\t\t}\n\t\t\t\t\tbuckets[iso].push(object)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn buckets\n\t\t},\n\n\t\t/**\n\t\t * The month grid cut into weeks, for the grid/row roles.\n\t\t *\n\t\t * @return {Array<Array<object>>}\n\t\t */\n\t\tweeks() {\n\t\t\tconst rows = []\n\t\t\tfor (let i = 0; i < this.monthGrid.length; i += 7) {\n\t\t\t\trows.push(this.monthGrid.slice(i, i + 7))\n\t\t\t}\n\t\t\treturn rows\n\t\t},\n\n\t\t/**\n\t\t * The day cell that takes the tab stop: the focused one when it is in\n\t\t * the grid, else today, else the 1st of the month.\n\t\t *\n\t\t * @return {string} `YYYY-MM-DD`.\n\t\t */\n\t\tactiveIso() {\n\t\t\tconst isos = this.monthGrid.map((d) => d.iso)\n\t\t\tif (this.focusedIso && isos.includes(this.focusedIso)) {\n\t\t\t\treturn this.focusedIso\n\t\t\t}\n\t\t\tconst today = this.toIsoDate(new Date())\n\t\t\tif (isos.includes(today)) {\n\t\t\t\treturn today\n\t\t\t}\n\t\t\treturn this.toIsoDate(this.monthRange.from)\n\t\t},\n\n\t\t/**\n\t\t * The 7-column month grid (leading/trailing days padded to whole weeks).\n\t\t *\n\t\t * @return {Array<{iso: string, dayNum: number, isToday: boolean, isOtherMonth: boolean, objects: object[]}>}\n\t\t */\n\t\tmonthGrid() {\n\t\t\tconst { from: gridStart, to: gridEnd } = this.gridRange\n\t\t\tconst { from: monthStart } = this.monthRange\n\t\t\tconst today = this.toIsoDate(new Date())\n\t\t\tconst cells = []\n\t\t\tfor (const iso of this.isoDateRange(gridStart, gridEnd)) {\n\t\t\t\tconst cellDate = this.parseDate(iso)\n\t\t\t\tcells.push({\n\t\t\t\t\tiso,\n\t\t\t\t\tdayNum: cellDate.getDate(),\n\t\t\t\t\tisToday: today === iso,\n\t\t\t\t\tisOtherMonth: cellDate.getMonth() !== monthStart.getMonth(),\n\t\t\t\t\tobjects: this.objectsByDay[iso] || [],\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn cells\n\t\t},\n\t},\n\n\twatch: {\n\t\tvisibleDate(newValue) {\n\t\t\tconst parsed = this.parseDate(newValue)\n\t\t\tif (!parsed) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.toIsoDate(parsed).slice(0, 7) === this.toIsoDate(this.internalDate).slice(0, 7)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.internalDate = parsed\n\t\t\tthis.emitRangeChange()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.emitRangeChange()\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Parse a date-ish value (Date instance, ISO string, or nullish) into a\n\t\t * `Date`, or `null` when it can't be parsed.\n\t\t *\n\t\t * @param {string|Date|null|undefined} value The value to parse.\n\t\t * @return {Date|null}\n\t\t */\n\t\tparseDate(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst date = value instanceof Date ? value : new Date(value)\n\t\t\treturn Number.isNaN(date.getTime()) ? null : date\n\t\t},\n\n\t\t/**\n\t\t * Format a `Date` as `YYYY-MM-DD` in local time (never UTC, so the grid\n\t\t * and the bucketing agree regardless of timezone offset).\n\t\t *\n\t\t * @param {Date} date The date to format.\n\t\t * @return {string}\n\t\t */\n\t\ttoIsoDate(date) {\n\t\t\tconst y = date.getFullYear()\n\t\t\tconst m = String(date.getMonth() + 1).padStart(2, '0')\n\t\t\tconst d = String(date.getDate()).padStart(2, '0')\n\t\t\treturn `${y}-${m}-${d}`\n\t\t},\n\n\t\t/**\n\t\t * Every `YYYY-MM-DD` from `start` to `end` inclusive (both truncated to\n\t\t * whole days), as a plain array — used so day-stepping loops reassign a\n\t\t * counter rather than mutating a `Date` in a `while` condition.\n\t\t *\n\t\t * @param {Date} start The range start (inclusive).\n\t\t * @param {Date} end The range end (inclusive).\n\t\t * @return {string[]}\n\t\t */\n\t\tisoDateRange(start, end) {\n\t\t\tconst startDay = new Date(start.getFullYear(), start.getMonth(), start.getDate())\n\t\t\tconst endDay = new Date(end.getFullYear(), end.getMonth(), end.getDate())\n\t\t\tconst dayCount = Math.round((endDay.getTime() - startDay.getTime()) / 86400000) + 1\n\t\t\tconst isoDates = []\n\t\t\tfor (let i = 0; i < dayCount; i++) {\n\t\t\t\tisoDates.push(this.toIsoDate(new Date(startDay.getFullYear(), startDay.getMonth(), startDay.getDate() + i)))\n\t\t\t}\n\t\t\treturn isoDates\n\t\t},\n\n\t\t/**\n\t\t * The object's identity, per `rowKey`.\n\t\t *\n\t\t * @param {object} object The object.\n\t\t * @return {unknown}\n\t\t */\n\t\tobjectKey(object) {\n\t\t\treturn object?.[this.rowKey]\n\t\t},\n\n\t\t/**\n\t\t * Best-effort display title: `titleField` when configured, else\n\t\t * `title`/`name`/the row key.\n\t\t *\n\t\t * @param {object} object The object.\n\t\t * @return {string}\n\t\t */\n\t\tobjectTitle(object) {\n\t\t\tif (this.titleField && object[this.titleField]) {\n\t\t\t\treturn String(object[this.titleField])\n\t\t\t}\n\t\t\treturn String(object.title || object.name || object[this.rowKey] || '—')\n\t\t},\n\n\t\t/**\n\t\t * Accessible name of a day cell: the date and how many records it holds.\n\t\t *\n\t\t * @param {{iso: string, objects: object[]}} day The day.\n\t\t * @return {string}\n\t\t */\n\t\tdayLabel(day) {\n\t\t\tconst date = this.parseDate(day.iso).toLocaleDateString(userLocale(), { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })\n\t\t\treturn day.objects.length === 0 ? date : `${date}, ${t('nextcloud-vue', '{count} records', { count: day.objects.length })}`\n\t\t},\n\n\t\t/**\n\t\t * Accessible name of the \"+N\" button.\n\t\t *\n\t\t * @param {{iso: string, objects: object[]}} day The day.\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel(day) {\n\t\t\treturn t('nextcloud-vue', 'Show all {count} records on {date}', { count: day.objects.length, date: day.iso })\n\t\t},\n\n\t\t/**\n\t\t * Move between day cells with the arrow keys, Home and End. Past the\n\t\t * edge of the grid the month moves with it.\n\t\t *\n\t\t * @param {KeyboardEvent} event The key event.\n\t\t * @param {{iso: string}} day The focused day.\n\t\t */\n\t\tonCellKeydown(event, day) {\n\t\t\tif (event.target !== event.currentTarget) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst steps = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -7, ArrowDown: 7 }\n\t\t\tconst here = this.parseDate(day.iso)\n\t\t\tlet target = null\n\t\t\tif (event.key in steps) {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() + steps[event.key])\n\t\t\t} else if (event.key === 'Home') {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() - here.getDay())\n\t\t\t} else if (event.key === 'End') {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() + (6 - here.getDay()))\n\t\t\t}\n\t\t\tif (!target) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tevent.preventDefault()\n\t\t\tconst iso = this.toIsoDate(target)\n\t\t\tif (!this.monthGrid.some((d) => d.iso === iso)) {\n\t\t\t\t// Off the edge: move to the month that holds the day.\n\t\t\t\tthis.internalDate = new Date(target.getFullYear(), target.getMonth(), 1)\n\t\t\t\tthis.afterNavigate()\n\t\t\t}\n\t\t\tthis.focusedIso = iso\n\t\t\tthis.$nextTick(() => {\n\t\t\t\tconst cell = this.$el.querySelector(`[data-iso=\"${iso}\"]`)\n\t\t\t\tif (cell) {\n\t\t\t\t\tcell.focus()\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Navigate to the previous month.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgoToPreviousMonth() {\n\t\t\tconst d = this.internalDate\n\t\t\tthis.internalDate = new Date(d.getFullYear(), d.getMonth() - 1, 1)\n\t\t\tthis.afterNavigate()\n\t\t},\n\n\t\t/**\n\t\t * Navigate to the next month.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgoToNextMonth() {\n\t\t\tconst d = this.internalDate\n\t\t\tthis.internalDate = new Date(d.getFullYear(), d.getMonth() + 1, 1)\n\t\t\tthis.afterNavigate()\n\t\t},\n\n\t\t/**\n\t\t * Sync `.sync` and notify the host to re-fetch after a month navigation.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tafterNavigate() {\n\t\t\t// Description goes ABOVE `@event`, not inline after it:\n\t\t\t// vue-docgen-api's event-name splitter stops at the first `:`, so\n\t\t\t// `@event update:visibleDate <description>` is read as one long\n\t\t\t// event NAME and the generated docs show an empty description.\n\t\t\t// Only colon-bearing (`update:*`) names are affected.\n\t\t\t/**\n\t\t\t * Emitted on month navigation, for `v-model:visible-date` binding.\n\t\t\t *\n\t\t\t * @event update:visibleDate\n\t\t\t * @type {Date}\n\t\t\t */\n\t\t\tthis.$emit('update:visibleDate', this.internalDate)\n\t\t\tthis.emitRangeChange()\n\t\t},\n\n\t\t/**\n\t\t * Emit the currently visible grid window (padded to whole weeks) as\n\t\t * ISO date strings, matching the OpenRegister calendar endpoint's\n\t\t * `rangeStart`/`rangeEnd` query params.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\temitRangeChange() {\n\t\t\tconst { from, to } = this.gridRange\n\t\t\t/**\n\t\t\t * @event range-change Emitted on mount and after every month\n\t\t\t * navigation so the host can re-fetch objects for the new window.\n\t\t\t * @type {{ rangeStart: string, rangeEnd: string }}\n\t\t\t */\n\t\t\tthis.$emit('range-change', {\n\t\t\t\trangeStart: this.toIsoDate(from),\n\t\t\t\trangeEnd: this.toIsoDate(to),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Handle an event entry click.\n\t\t *\n\t\t * @param {object} object The clicked object.\n\t\t * @return {void}\n\t\t */\n\t\tonObjectClick(object) {\n\t\t\t/**\n\t\t\t * @event object-click Emitted when a plotted object is clicked.\n\t\t\t * @type {object} The clicked object.\n\t\t\t */\n\t\t\tthis.$emit('object-click', object)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-calendar__header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 12px;\n\tpadding: 8px 0 16px;\n}\n\n.cn-object-calendar__title {\n\tmin-width: 160px;\n\ttext-align: center;\n\tfont-weight: 600;\n\tfont-size: 16px;\n\ttext-transform: capitalize;\n}\n\n.cn-object-calendar__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 40px;\n}\n\n.cn-object-calendar__month {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(7, 1fr);\n\tgap: 1px;\n\tbackground: var(--color-border);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius, 8px);\n\toverflow: hidden;\n}\n\n.cn-object-calendar__month-header {\n\tbackground: var(--color-background-dark);\n\tpadding: 6px 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\ttext-align: center;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-calendar__month-cell {\n\tbackground: var(--color-main-background);\n\tmin-height: 90px;\n\tpadding: 4px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-object-calendar__month-cell.is-other-month {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-calendar__month-day {\n\tfont-size: 12px;\n\twidth: 20px;\n\theight: 20px;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.cn-object-calendar__month-cell.is-today .cn-object-calendar__month-day {\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tborder-radius: 50%;\n}\n\n.cn-object-calendar__month-events {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-object-calendar__event {\n\tfont-size: 11px;\n\tpadding: 1px 4px;\n\tborder-radius: 4px;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-main-text);\n\tcursor: pointer;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-calendar__overflow {\n\tfont-size: 11px;\n\tcolor: var(--color-text-maxcontrast);\n\tpadding: 0 4px;\n}\n\n.cn-object-calendar__week {\n\tdisplay: contents;\n}\n\n.cn-object-calendar__month-cell:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: -2px;\n}\n\nbutton.cn-object-calendar__event,\nbutton.cn-object-calendar__overflow {\n\tdisplay: block;\n\twidth: 100%;\n\tmin-height: 0;\n\tborder: 0;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text);\n\tborder-radius: var(--border-radius, 4px);\n\tpadding: 1px 6px;\n\tfont: inherit;\n\tfont-size: 12px;\n\ttext-align: start;\n\tcursor: pointer;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\nbutton.cn-object-calendar__overflow {\n\tbackground: transparent;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["t"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnObjectCalendar.vue3.js","sources":["../../../../src/components/CnObjectCalendar/CnObjectCalendar.vue?vue&type=template&id=2735e5ef&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-object-calendar\">\n\t\t<header class=\"cn-object-calendar__header\">\n\t\t\t<NcButton :aria-label=\"prevMonthLabel\" @click=\"goToPreviousMonth\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ChevronLeft :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t\t<span class=\"cn-object-calendar__title\">{{ monthLabel }}</span>\n\t\t\t<NcButton :aria-label=\"nextMonthLabel\" @click=\"goToNextMonth\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ChevronRight :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t</header>\n\n\t\t<div v-if=\"loading\" class=\"cn-object-calendar__loading\">\n\t\t\t<NcLoadingIcon :size=\"32\" />\n\t\t</div>\n\n\t\t<div\n\t\t\tv-else\n\t\t\tclass=\"cn-object-calendar__month\"\n\t\t\trole=\"grid\"\n\t\t\t:aria-label=\"monthLabel\">\n\t\t\t<div class=\"cn-object-calendar__week\" role=\"row\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"(weekday, idx) in weekdayHeaders\"\n\t\t\t\t\t:key=\"'wh-' + idx\"\n\t\t\t\t\tclass=\"cn-object-calendar__month-header\"\n\t\t\t\t\trole=\"columnheader\">\n\t\t\t\t\t{{ weekday }}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tv-for=\"(week, w) in weeks\"\n\t\t\t\t:key=\"'w-' + w\"\n\t\t\t\tclass=\"cn-object-calendar__week\"\n\t\t\t\trole=\"row\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"day in week\"\n\t\t\t\t\t:key=\"day.iso\"\n\t\t\t\t\tclass=\"cn-object-calendar__month-cell\"\n\t\t\t\t\t:class=\"{ 'is-today': day.isToday, 'is-other-month': day.isOtherMonth }\"\n\t\t\t\t\trole=\"gridcell\"\n\t\t\t\t\t:data-iso=\"day.iso\"\n\t\t\t\t\t:tabindex=\"day.iso === activeIso ? 0 : -1\"\n\t\t\t\t\t:aria-label=\"dayLabel(day)\"\n\t\t\t\t\t@focus=\"focusedIso = day.iso\"\n\t\t\t\t\t@keydown=\"onCellKeydown($event, day)\">\n\t\t\t\t\t<span class=\"cn-object-calendar__month-day\">{{ day.dayNum }}</span>\n\t\t\t\t\t<ul v-if=\"day.objects.length\" class=\"cn-object-calendar__month-events\">\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-for=\"object in day.objects.slice(0, maxEventsPerDay)\"\n\t\t\t\t\t\t\t:key=\"objectKey(object) + '-' + day.iso\"\n\t\t\t\t\t\t\tclass=\"cn-object-calendar__event-item\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-calendar__event\"\n\t\t\t\t\t\t\t\t:title=\"objectTitle(object)\"\n\t\t\t\t\t\t\t\t@click=\"onObjectClick(object)\">\n\t\t\t\t\t\t\t\t<!-- @slot day-event Override a single day's event entry. -->\n\t\t\t\t\t\t\t\t<!-- @binding {object} object The plotted object. -->\n\t\t\t\t\t\t\t\t<!-- @binding {object} day The day cell ({ iso, dayNum, isToday, isOtherMonth }). -->\n\t\t\t\t\t\t\t\t<slot name=\"day-event\" :object=\"object\" :day=\"day\">\n\t\t\t\t\t\t\t\t\t{{ objectTitle(object) }}\n\t\t\t\t\t\t\t\t</slot>\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-if=\"day.objects.length > maxEventsPerDay\"\n\t\t\t\t\t\t\tclass=\"cn-object-calendar__overflow-item\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-calendar__overflow\"\n\t\t\t\t\t\t\t\t:aria-label=\"overflowLabel(day)\"\n\t\t\t\t\t\t\t\t@click=\"$emit('day-select', day.iso)\">\n\t\t\t\t\t\t\t\t+{{ day.objects.length - maxEventsPerDay }}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport ChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\n\n/**\n * CnObjectCalendar — plots objects on a month calendar by a date property.\n *\n * Places each object on `dateField`; when `endDateField` is also configured,\n * an object spans every day from `dateField` to `endDateField` inclusive\n * (REQ-VIEW-CAL-04). The component only renders a window it is given —\n * `objects` is expected to already be scoped to the visible range (e.g. via\n * `GET /api/views/{id}/calendar?start=&end=`). Navigating months emits\n * `range-change` with the new window so the host re-fetches; the component\n * does not fetch anything itself.\n *\n * ```vue\n * <CnObjectCalendar\n * :objects=\"objects\"\n * date-field=\"dueDate\"\n * end-date-field=\"endDate\"\n * v-model:visible-date=\"visibleDate\"\n * @range-change=\"fetchCalendarObjects\"\n * @object-click=\"openObject\" />\n * ```\n */\nexport default {\n\tname: 'CnObjectCalendar',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tChevronLeft,\n\t\tChevronRight,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Objects to plot. Expected to already be scoped to the visible range —\n\t\t * e.g. the response of `GET /api/views/{id}/calendar?start=&end=`.\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\tobjects: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** The date property an object is plotted on. */\n\t\tdateField: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Optional end-date property — when set, an object spans `dateField`..`endDateField`. */\n\t\tendDateField: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Any day within the currently visible month (`.sync`-compatible).\n\t\t * Defaults to today when omitted.\n\t\t *\n\t\t * @type {string|Date|null}\n\t\t */\n\t\tvisibleDate: {\n\t\t\ttype: [String, Date],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Object property used as a title fallback and as each object's identity. */\n\t\ttitleField: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Object property used as each object's identity (for `:key` and click payload matching). */\n\t\trowKey: {\n\t\t\ttype: String,\n\t\t\tdefault: 'id',\n\t\t},\n\n\t\t/** Loading state (host is (re)fetching the visible range). */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Maximum events shown per day cell before \"+N\" overflow. */\n\t\tmaxEventsPerDay: {\n\t\t\ttype: Number,\n\t\t\tdefault: 3,\n\t\t},\n\t},\n\n\temits: [\n\t\t'object-click',\n\t\t'range-change',\n\t\t'update:visibleDate',\n\t\t/**\n\t\t * The \"+N\" button of a busy day was activated. Payload: the day as `YYYY-MM-DD`.\n\t\t *\n\t\t * @event day-select\n\t\t * @type {string}\n\t\t */\n\t\t'day-select',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tinternalDate: this.parseDate(this.visibleDate) || new Date(),\n\t\t\t// The day cell that holds focus (roving tabindex); empty = today or the 1st.\n\t\t\tfocusedIso: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tmonthLabel() {\n\t\t\treturn this.internalDate.toLocaleDateString(undefined, { month: 'long', year: 'numeric' })\n\t\t},\n\n\t\tprevMonthLabel() {\n\t\t\treturn t('nextcloud-vue', 'Previous month')\n\t\t},\n\n\t\tnextMonthLabel() {\n\t\t\treturn t('nextcloud-vue', 'Next month')\n\t\t},\n\n\t\t/**\n\t\t * Localised short weekday names (Sun-first, matching CnCalendarWidget).\n\t\t *\n\t\t * @return {string[]}\n\t\t */\n\t\tweekdayHeaders() {\n\t\t\treturn [\n\t\t\t\tt('nextcloud-vue', 'Sun'),\n\t\t\t\tt('nextcloud-vue', 'Mon'),\n\t\t\t\tt('nextcloud-vue', 'Tue'),\n\t\t\t\tt('nextcloud-vue', 'Wed'),\n\t\t\t\tt('nextcloud-vue', 'Thu'),\n\t\t\t\tt('nextcloud-vue', 'Fri'),\n\t\t\t\tt('nextcloud-vue', 'Sat'),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * The first/last day of the visible month.\n\t\t *\n\t\t * @return {{from: Date, to: Date}}\n\t\t */\n\t\tmonthRange() {\n\t\t\tconst d = this.internalDate\n\t\t\tconst first = new Date(d.getFullYear(), d.getMonth(), 1)\n\t\t\tconst last = new Date(d.getFullYear(), d.getMonth() + 1, 0)\n\t\t\treturn { from: first, to: last }\n\t\t},\n\n\t\t/**\n\t\t * The full displayed grid window (month padded to whole Sun–Sat weeks) —\n\t\t * this is the range emitted by `range-change`, since leading/trailing\n\t\t * days from adjacent months are visible and should be requested too.\n\t\t *\n\t\t * @return {{from: Date, to: Date}}\n\t\t */\n\t\tgridRange() {\n\t\t\tconst { from, to } = this.monthRange\n\t\t\tconst gridStart = new Date(from)\n\t\t\tgridStart.setDate(from.getDate() - from.getDay())\n\t\t\tconst totalDays = Math.ceil((to.getDate() + from.getDay()) / 7) * 7\n\t\t\tconst gridEnd = new Date(gridStart)\n\t\t\tgridEnd.setDate(gridStart.getDate() + totalDays - 1)\n\t\t\treturn { from: gridStart, to: gridEnd }\n\t\t},\n\n\t\t/**\n\t\t * Objects bucketed by every `YYYY-MM-DD` they occupy — a single day for\n\t\t * a plain `dateField` object, or every day from `dateField` to\n\t\t * `endDateField` inclusive when spanning.\n\t\t *\n\t\t * @return {{[iso: string]: object[]}}\n\t\t */\n\t\tobjectsByDay() {\n\t\t\tconst buckets = {}\n\t\t\tconst { from: gridStart, to: gridEnd } = this.gridRange\n\n\t\t\tfor (const object of this.objects) {\n\t\t\t\tif (!object) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst start = this.parseDate(object[this.dateField])\n\t\t\t\tif (!start) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst rawEnd = this.endDateField ? this.parseDate(object[this.endDateField]) : null\n\t\t\t\tconst end = rawEnd && rawEnd >= start ? rawEnd : start\n\n\t\t\t\tconst spanStart = start < gridStart ? gridStart : start\n\t\t\t\tconst spanEnd = end > gridEnd ? gridEnd : end\n\n\t\t\t\tfor (const iso of this.isoDateRange(spanStart, spanEnd)) {\n\t\t\t\t\tif (!buckets[iso]) {\n\t\t\t\t\t\tbuckets[iso] = []\n\t\t\t\t\t}\n\t\t\t\t\tbuckets[iso].push(object)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn buckets\n\t\t},\n\n\t\t/**\n\t\t * The month grid cut into weeks, for the grid/row roles.\n\t\t *\n\t\t * @return {Array<Array<object>>}\n\t\t */\n\t\tweeks() {\n\t\t\tconst rows = []\n\t\t\tfor (let i = 0; i < this.monthGrid.length; i += 7) {\n\t\t\t\trows.push(this.monthGrid.slice(i, i + 7))\n\t\t\t}\n\t\t\treturn rows\n\t\t},\n\n\t\t/**\n\t\t * The day cell that takes the tab stop: the focused one when it is in\n\t\t * the grid, else today, else the 1st of the month.\n\t\t *\n\t\t * @return {string} `YYYY-MM-DD`.\n\t\t */\n\t\tactiveIso() {\n\t\t\tconst isos = this.monthGrid.map((d) => d.iso)\n\t\t\tif (this.focusedIso && isos.includes(this.focusedIso)) {\n\t\t\t\treturn this.focusedIso\n\t\t\t}\n\t\t\tconst today = this.toIsoDate(new Date())\n\t\t\tif (isos.includes(today)) {\n\t\t\t\treturn today\n\t\t\t}\n\t\t\treturn this.toIsoDate(this.monthRange.from)\n\t\t},\n\n\t\t/**\n\t\t * The 7-column month grid (leading/trailing days padded to whole weeks).\n\t\t *\n\t\t * @return {Array<{iso: string, dayNum: number, isToday: boolean, isOtherMonth: boolean, objects: object[]}>}\n\t\t */\n\t\tmonthGrid() {\n\t\t\tconst { from: gridStart, to: gridEnd } = this.gridRange\n\t\t\tconst { from: monthStart } = this.monthRange\n\t\t\tconst today = this.toIsoDate(new Date())\n\t\t\tconst cells = []\n\t\t\tfor (const iso of this.isoDateRange(gridStart, gridEnd)) {\n\t\t\t\tconst cellDate = this.parseDate(iso)\n\t\t\t\tcells.push({\n\t\t\t\t\tiso,\n\t\t\t\t\tdayNum: cellDate.getDate(),\n\t\t\t\t\tisToday: today === iso,\n\t\t\t\t\tisOtherMonth: cellDate.getMonth() !== monthStart.getMonth(),\n\t\t\t\t\tobjects: this.objectsByDay[iso] || [],\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn cells\n\t\t},\n\t},\n\n\twatch: {\n\t\tvisibleDate(newValue) {\n\t\t\tconst parsed = this.parseDate(newValue)\n\t\t\tif (!parsed) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.toIsoDate(parsed).slice(0, 7) === this.toIsoDate(this.internalDate).slice(0, 7)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.internalDate = parsed\n\t\t\tthis.emitRangeChange()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.emitRangeChange()\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Parse a date-ish value (Date instance, ISO string, or nullish) into a\n\t\t * `Date`, or `null` when it can't be parsed.\n\t\t *\n\t\t * @param {string|Date|null|undefined} value The value to parse.\n\t\t * @return {Date|null}\n\t\t */\n\t\tparseDate(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst date = value instanceof Date ? value : new Date(value)\n\t\t\treturn Number.isNaN(date.getTime()) ? null : date\n\t\t},\n\n\t\t/**\n\t\t * Format a `Date` as `YYYY-MM-DD` in local time (never UTC, so the grid\n\t\t * and the bucketing agree regardless of timezone offset).\n\t\t *\n\t\t * @param {Date} date The date to format.\n\t\t * @return {string}\n\t\t */\n\t\ttoIsoDate(date) {\n\t\t\tconst y = date.getFullYear()\n\t\t\tconst m = String(date.getMonth() + 1).padStart(2, '0')\n\t\t\tconst d = String(date.getDate()).padStart(2, '0')\n\t\t\treturn `${y}-${m}-${d}`\n\t\t},\n\n\t\t/**\n\t\t * Every `YYYY-MM-DD` from `start` to `end` inclusive (both truncated to\n\t\t * whole days), as a plain array — used so day-stepping loops reassign a\n\t\t * counter rather than mutating a `Date` in a `while` condition.\n\t\t *\n\t\t * @param {Date} start The range start (inclusive).\n\t\t * @param {Date} end The range end (inclusive).\n\t\t * @return {string[]}\n\t\t */\n\t\tisoDateRange(start, end) {\n\t\t\tconst startDay = new Date(start.getFullYear(), start.getMonth(), start.getDate())\n\t\t\tconst endDay = new Date(end.getFullYear(), end.getMonth(), end.getDate())\n\t\t\tconst dayCount = Math.round((endDay.getTime() - startDay.getTime()) / 86400000) + 1\n\t\t\tconst isoDates = []\n\t\t\tfor (let i = 0; i < dayCount; i++) {\n\t\t\t\tisoDates.push(this.toIsoDate(new Date(startDay.getFullYear(), startDay.getMonth(), startDay.getDate() + i)))\n\t\t\t}\n\t\t\treturn isoDates\n\t\t},\n\n\t\t/**\n\t\t * The object's identity, per `rowKey`.\n\t\t *\n\t\t * @param {object} object The object.\n\t\t * @return {unknown}\n\t\t */\n\t\tobjectKey(object) {\n\t\t\treturn object?.[this.rowKey]\n\t\t},\n\n\t\t/**\n\t\t * Best-effort display title: `titleField` when configured, else\n\t\t * `title`/`name`/the row key.\n\t\t *\n\t\t * @param {object} object The object.\n\t\t * @return {string}\n\t\t */\n\t\tobjectTitle(object) {\n\t\t\tif (this.titleField && object[this.titleField]) {\n\t\t\t\treturn String(object[this.titleField])\n\t\t\t}\n\t\t\treturn String(object.title || object.name || object[this.rowKey] || '—')\n\t\t},\n\n\t\t/**\n\t\t * Accessible name of a day cell: the date and how many records it holds.\n\t\t *\n\t\t * @param {{iso: string, objects: object[]}} day The day.\n\t\t * @return {string}\n\t\t */\n\t\tdayLabel(day) {\n\t\t\tconst date = this.parseDate(day.iso).toLocaleDateString(undefined, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })\n\t\t\treturn day.objects.length === 0 ? date : `${date}, ${t('nextcloud-vue', '{count} records', { count: day.objects.length })}`\n\t\t},\n\n\t\t/**\n\t\t * Accessible name of the \"+N\" button.\n\t\t *\n\t\t * @param {{iso: string, objects: object[]}} day The day.\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel(day) {\n\t\t\treturn t('nextcloud-vue', 'Show all {count} records on {date}', { count: day.objects.length, date: day.iso })\n\t\t},\n\n\t\t/**\n\t\t * Move between day cells with the arrow keys, Home and End. Past the\n\t\t * edge of the grid the month moves with it.\n\t\t *\n\t\t * @param {KeyboardEvent} event The key event.\n\t\t * @param {{iso: string}} day The focused day.\n\t\t */\n\t\tonCellKeydown(event, day) {\n\t\t\tif (event.target !== event.currentTarget) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst steps = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -7, ArrowDown: 7 }\n\t\t\tconst here = this.parseDate(day.iso)\n\t\t\tlet target = null\n\t\t\tif (event.key in steps) {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() + steps[event.key])\n\t\t\t} else if (event.key === 'Home') {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() - here.getDay())\n\t\t\t} else if (event.key === 'End') {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() + (6 - here.getDay()))\n\t\t\t}\n\t\t\tif (!target) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tevent.preventDefault()\n\t\t\tconst iso = this.toIsoDate(target)\n\t\t\tif (!this.monthGrid.some((d) => d.iso === iso)) {\n\t\t\t\t// Off the edge: move to the month that holds the day.\n\t\t\t\tthis.internalDate = new Date(target.getFullYear(), target.getMonth(), 1)\n\t\t\t\tthis.afterNavigate()\n\t\t\t}\n\t\t\tthis.focusedIso = iso\n\t\t\tthis.$nextTick(() => {\n\t\t\t\tconst cell = this.$el.querySelector(`[data-iso=\"${iso}\"]`)\n\t\t\t\tif (cell) {\n\t\t\t\t\tcell.focus()\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Navigate to the previous month.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgoToPreviousMonth() {\n\t\t\tconst d = this.internalDate\n\t\t\tthis.internalDate = new Date(d.getFullYear(), d.getMonth() - 1, 1)\n\t\t\tthis.afterNavigate()\n\t\t},\n\n\t\t/**\n\t\t * Navigate to the next month.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgoToNextMonth() {\n\t\t\tconst d = this.internalDate\n\t\t\tthis.internalDate = new Date(d.getFullYear(), d.getMonth() + 1, 1)\n\t\t\tthis.afterNavigate()\n\t\t},\n\n\t\t/**\n\t\t * Sync `.sync` and notify the host to re-fetch after a month navigation.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tafterNavigate() {\n\t\t\t// Description goes ABOVE `@event`, not inline after it:\n\t\t\t// vue-docgen-api's event-name splitter stops at the first `:`, so\n\t\t\t// `@event update:visibleDate <description>` is read as one long\n\t\t\t// event NAME and the generated docs show an empty description.\n\t\t\t// Only colon-bearing (`update:*`) names are affected.\n\t\t\t/**\n\t\t\t * Emitted on month navigation, for `v-model:visible-date` binding.\n\t\t\t *\n\t\t\t * @event update:visibleDate\n\t\t\t * @type {Date}\n\t\t\t */\n\t\t\tthis.$emit('update:visibleDate', this.internalDate)\n\t\t\tthis.emitRangeChange()\n\t\t},\n\n\t\t/**\n\t\t * Emit the currently visible grid window (padded to whole weeks) as\n\t\t * ISO date strings, matching the OpenRegister calendar endpoint's\n\t\t * `rangeStart`/`rangeEnd` query params.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\temitRangeChange() {\n\t\t\tconst { from, to } = this.gridRange\n\t\t\t/**\n\t\t\t * @event range-change Emitted on mount and after every month\n\t\t\t * navigation so the host can re-fetch objects for the new window.\n\t\t\t * @type {{ rangeStart: string, rangeEnd: string }}\n\t\t\t */\n\t\t\tthis.$emit('range-change', {\n\t\t\t\trangeStart: this.toIsoDate(from),\n\t\t\t\trangeEnd: this.toIsoDate(to),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Handle an event entry click.\n\t\t *\n\t\t * @param {object} object The clicked object.\n\t\t * @return {void}\n\t\t */\n\t\tonObjectClick(object) {\n\t\t\t/**\n\t\t\t * @event object-click Emitted when a plotted object is clicked.\n\t\t\t * @type {object} The clicked object.\n\t\t\t */\n\t\t\tthis.$emit('object-click', object)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-calendar__header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 12px;\n\tpadding: 8px 0 16px;\n}\n\n.cn-object-calendar__title {\n\tmin-width: 160px;\n\ttext-align: center;\n\tfont-weight: 600;\n\tfont-size: 16px;\n\ttext-transform: capitalize;\n}\n\n.cn-object-calendar__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 40px;\n}\n\n.cn-object-calendar__month {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(7, 1fr);\n\tgap: 1px;\n\tbackground: var(--color-border);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius, 8px);\n\toverflow: hidden;\n}\n\n.cn-object-calendar__month-header {\n\tbackground: var(--color-background-dark);\n\tpadding: 6px 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\ttext-align: center;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-calendar__month-cell {\n\tbackground: var(--color-main-background);\n\tmin-height: 90px;\n\tpadding: 4px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-object-calendar__month-cell.is-other-month {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-calendar__month-day {\n\tfont-size: 12px;\n\twidth: 20px;\n\theight: 20px;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.cn-object-calendar__month-cell.is-today .cn-object-calendar__month-day {\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tborder-radius: 50%;\n}\n\n.cn-object-calendar__month-events {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-object-calendar__event {\n\tfont-size: 11px;\n\tpadding: 1px 4px;\n\tborder-radius: 4px;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-main-text);\n\tcursor: pointer;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-calendar__overflow {\n\tfont-size: 11px;\n\tcolor: var(--color-text-maxcontrast);\n\tpadding: 0 4px;\n}\n\n.cn-object-calendar__week {\n\tdisplay: contents;\n}\n\n.cn-object-calendar__month-cell:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: -2px;\n}\n\nbutton.cn-object-calendar__event,\nbutton.cn-object-calendar__overflow {\n\tdisplay: block;\n\twidth: 100%;\n\tmin-height: 0;\n\tborder: 0;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text);\n\tborder-radius: var(--border-radius, 4px);\n\tpadding: 1px 6px;\n\tfont: inherit;\n\tfont-size: 12px;\n\ttext-align: start;\n\tcursor: pointer;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\nbutton.cn-object-calendar__overflow {\n\tbackground: transparent;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_createVNode","_createElementVNode","_toDisplayString","_Fragment","_renderList","_openBlock","_createElementBlock","_normalizeClass","_renderSlot","_createTextVNode"],"mappings":"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"}
1
+ {"version":3,"file":"CnObjectCalendar.vue3.js","sources":["../../../../src/components/CnObjectCalendar/CnObjectCalendar.vue?vue&type=template&id=e1c69ee2&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-object-calendar\">\n\t\t<header class=\"cn-object-calendar__header\">\n\t\t\t<NcButton :aria-label=\"prevMonthLabel\" @click=\"goToPreviousMonth\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ChevronLeft :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t\t<span class=\"cn-object-calendar__title\">{{ monthLabel }}</span>\n\t\t\t<NcButton :aria-label=\"nextMonthLabel\" @click=\"goToNextMonth\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ChevronRight :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcButton>\n\t\t</header>\n\n\t\t<div v-if=\"loading\" class=\"cn-object-calendar__loading\">\n\t\t\t<NcLoadingIcon :size=\"32\" />\n\t\t</div>\n\n\t\t<div\n\t\t\tv-else\n\t\t\tclass=\"cn-object-calendar__month\"\n\t\t\trole=\"grid\"\n\t\t\t:aria-label=\"monthLabel\">\n\t\t\t<div class=\"cn-object-calendar__week\" role=\"row\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"(weekday, idx) in weekdayHeaders\"\n\t\t\t\t\t:key=\"'wh-' + idx\"\n\t\t\t\t\tclass=\"cn-object-calendar__month-header\"\n\t\t\t\t\trole=\"columnheader\">\n\t\t\t\t\t{{ weekday }}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tv-for=\"(week, w) in weeks\"\n\t\t\t\t:key=\"'w-' + w\"\n\t\t\t\tclass=\"cn-object-calendar__week\"\n\t\t\t\trole=\"row\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"day in week\"\n\t\t\t\t\t:key=\"day.iso\"\n\t\t\t\t\tclass=\"cn-object-calendar__month-cell\"\n\t\t\t\t\t:class=\"{ 'is-today': day.isToday, 'is-other-month': day.isOtherMonth }\"\n\t\t\t\t\trole=\"gridcell\"\n\t\t\t\t\t:data-iso=\"day.iso\"\n\t\t\t\t\t:tabindex=\"day.iso === activeIso ? 0 : -1\"\n\t\t\t\t\t:aria-label=\"dayLabel(day)\"\n\t\t\t\t\t@focus=\"focusedIso = day.iso\"\n\t\t\t\t\t@keydown=\"onCellKeydown($event, day)\">\n\t\t\t\t\t<span class=\"cn-object-calendar__month-day\">{{ day.dayNum }}</span>\n\t\t\t\t\t<ul v-if=\"day.objects.length\" class=\"cn-object-calendar__month-events\">\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-for=\"object in day.objects.slice(0, maxEventsPerDay)\"\n\t\t\t\t\t\t\t:key=\"objectKey(object) + '-' + day.iso\"\n\t\t\t\t\t\t\tclass=\"cn-object-calendar__event-item\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-calendar__event\"\n\t\t\t\t\t\t\t\t:title=\"objectTitle(object)\"\n\t\t\t\t\t\t\t\t@click=\"onObjectClick(object)\">\n\t\t\t\t\t\t\t\t<!-- @slot day-event Override a single day's event entry. -->\n\t\t\t\t\t\t\t\t<!-- @binding {object} object The plotted object. -->\n\t\t\t\t\t\t\t\t<!-- @binding {object} day The day cell ({ iso, dayNum, isToday, isOtherMonth }). -->\n\t\t\t\t\t\t\t\t<slot name=\"day-event\" :object=\"object\" :day=\"day\">\n\t\t\t\t\t\t\t\t\t{{ objectTitle(object) }}\n\t\t\t\t\t\t\t\t</slot>\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-if=\"day.objects.length > maxEventsPerDay\"\n\t\t\t\t\t\t\tclass=\"cn-object-calendar__overflow-item\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-calendar__overflow\"\n\t\t\t\t\t\t\t\t:aria-label=\"overflowLabel(day)\"\n\t\t\t\t\t\t\t\t@click=\"$emit('day-select', day.iso)\">\n\t\t\t\t\t\t\t\t+{{ day.objects.length - maxEventsPerDay }}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport ChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnObjectCalendar — plots objects on a month calendar by a date property.\n *\n * Places each object on `dateField`; when `endDateField` is also configured,\n * an object spans every day from `dateField` to `endDateField` inclusive\n * (REQ-VIEW-CAL-04). The component only renders a window it is given —\n * `objects` is expected to already be scoped to the visible range (e.g. via\n * `GET /api/views/{id}/calendar?start=&end=`). Navigating months emits\n * `range-change` with the new window so the host re-fetches; the component\n * does not fetch anything itself.\n *\n * ```vue\n * <CnObjectCalendar\n * :objects=\"objects\"\n * date-field=\"dueDate\"\n * end-date-field=\"endDate\"\n * v-model:visible-date=\"visibleDate\"\n * @range-change=\"fetchCalendarObjects\"\n * @object-click=\"openObject\" />\n * ```\n */\nexport default {\n\tname: 'CnObjectCalendar',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tChevronLeft,\n\t\tChevronRight,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Objects to plot. Expected to already be scoped to the visible range —\n\t\t * e.g. the response of `GET /api/views/{id}/calendar?start=&end=`.\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\tobjects: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** The date property an object is plotted on. */\n\t\tdateField: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Optional end-date property — when set, an object spans `dateField`..`endDateField`. */\n\t\tendDateField: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Any day within the currently visible month (`.sync`-compatible).\n\t\t * Defaults to today when omitted.\n\t\t *\n\t\t * @type {string|Date|null}\n\t\t */\n\t\tvisibleDate: {\n\t\t\ttype: [String, Date],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Object property used as a title fallback and as each object's identity. */\n\t\ttitleField: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Object property used as each object's identity (for `:key` and click payload matching). */\n\t\trowKey: {\n\t\t\ttype: String,\n\t\t\tdefault: 'id',\n\t\t},\n\n\t\t/** Loading state (host is (re)fetching the visible range). */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Maximum events shown per day cell before \"+N\" overflow. */\n\t\tmaxEventsPerDay: {\n\t\t\ttype: Number,\n\t\t\tdefault: 3,\n\t\t},\n\t},\n\n\temits: [\n\t\t'object-click',\n\t\t'range-change',\n\t\t'update:visibleDate',\n\t\t/**\n\t\t * The \"+N\" button of a busy day was activated. Payload: the day as `YYYY-MM-DD`.\n\t\t *\n\t\t * @event day-select\n\t\t * @type {string}\n\t\t */\n\t\t'day-select',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tinternalDate: this.parseDate(this.visibleDate) || new Date(),\n\t\t\t// The day cell that holds focus (roving tabindex); empty = today or the 1st.\n\t\t\tfocusedIso: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tmonthLabel() {\n\t\t\treturn this.internalDate.toLocaleDateString(userLocale(), { month: 'long', year: 'numeric' })\n\t\t},\n\n\t\tprevMonthLabel() {\n\t\t\treturn t('nextcloud-vue', 'Previous month')\n\t\t},\n\n\t\tnextMonthLabel() {\n\t\t\treturn t('nextcloud-vue', 'Next month')\n\t\t},\n\n\t\t/**\n\t\t * Localised short weekday names (Sun-first, matching CnCalendarWidget).\n\t\t *\n\t\t * @return {string[]}\n\t\t */\n\t\tweekdayHeaders() {\n\t\t\treturn [\n\t\t\t\tt('nextcloud-vue', 'Sun'),\n\t\t\t\tt('nextcloud-vue', 'Mon'),\n\t\t\t\tt('nextcloud-vue', 'Tue'),\n\t\t\t\tt('nextcloud-vue', 'Wed'),\n\t\t\t\tt('nextcloud-vue', 'Thu'),\n\t\t\t\tt('nextcloud-vue', 'Fri'),\n\t\t\t\tt('nextcloud-vue', 'Sat'),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * The first/last day of the visible month.\n\t\t *\n\t\t * @return {{from: Date, to: Date}}\n\t\t */\n\t\tmonthRange() {\n\t\t\tconst d = this.internalDate\n\t\t\tconst first = new Date(d.getFullYear(), d.getMonth(), 1)\n\t\t\tconst last = new Date(d.getFullYear(), d.getMonth() + 1, 0)\n\t\t\treturn { from: first, to: last }\n\t\t},\n\n\t\t/**\n\t\t * The full displayed grid window (month padded to whole Sun–Sat weeks) —\n\t\t * this is the range emitted by `range-change`, since leading/trailing\n\t\t * days from adjacent months are visible and should be requested too.\n\t\t *\n\t\t * @return {{from: Date, to: Date}}\n\t\t */\n\t\tgridRange() {\n\t\t\tconst { from, to } = this.monthRange\n\t\t\tconst gridStart = new Date(from)\n\t\t\tgridStart.setDate(from.getDate() - from.getDay())\n\t\t\tconst totalDays = Math.ceil((to.getDate() + from.getDay()) / 7) * 7\n\t\t\tconst gridEnd = new Date(gridStart)\n\t\t\tgridEnd.setDate(gridStart.getDate() + totalDays - 1)\n\t\t\treturn { from: gridStart, to: gridEnd }\n\t\t},\n\n\t\t/**\n\t\t * Objects bucketed by every `YYYY-MM-DD` they occupy — a single day for\n\t\t * a plain `dateField` object, or every day from `dateField` to\n\t\t * `endDateField` inclusive when spanning.\n\t\t *\n\t\t * @return {{[iso: string]: object[]}}\n\t\t */\n\t\tobjectsByDay() {\n\t\t\tconst buckets = {}\n\t\t\tconst { from: gridStart, to: gridEnd } = this.gridRange\n\n\t\t\tfor (const object of this.objects) {\n\t\t\t\tif (!object) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst start = this.parseDate(object[this.dateField])\n\t\t\t\tif (!start) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst rawEnd = this.endDateField ? this.parseDate(object[this.endDateField]) : null\n\t\t\t\tconst end = rawEnd && rawEnd >= start ? rawEnd : start\n\n\t\t\t\tconst spanStart = start < gridStart ? gridStart : start\n\t\t\t\tconst spanEnd = end > gridEnd ? gridEnd : end\n\n\t\t\t\tfor (const iso of this.isoDateRange(spanStart, spanEnd)) {\n\t\t\t\t\tif (!buckets[iso]) {\n\t\t\t\t\t\tbuckets[iso] = []\n\t\t\t\t\t}\n\t\t\t\t\tbuckets[iso].push(object)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn buckets\n\t\t},\n\n\t\t/**\n\t\t * The month grid cut into weeks, for the grid/row roles.\n\t\t *\n\t\t * @return {Array<Array<object>>}\n\t\t */\n\t\tweeks() {\n\t\t\tconst rows = []\n\t\t\tfor (let i = 0; i < this.monthGrid.length; i += 7) {\n\t\t\t\trows.push(this.monthGrid.slice(i, i + 7))\n\t\t\t}\n\t\t\treturn rows\n\t\t},\n\n\t\t/**\n\t\t * The day cell that takes the tab stop: the focused one when it is in\n\t\t * the grid, else today, else the 1st of the month.\n\t\t *\n\t\t * @return {string} `YYYY-MM-DD`.\n\t\t */\n\t\tactiveIso() {\n\t\t\tconst isos = this.monthGrid.map((d) => d.iso)\n\t\t\tif (this.focusedIso && isos.includes(this.focusedIso)) {\n\t\t\t\treturn this.focusedIso\n\t\t\t}\n\t\t\tconst today = this.toIsoDate(new Date())\n\t\t\tif (isos.includes(today)) {\n\t\t\t\treturn today\n\t\t\t}\n\t\t\treturn this.toIsoDate(this.monthRange.from)\n\t\t},\n\n\t\t/**\n\t\t * The 7-column month grid (leading/trailing days padded to whole weeks).\n\t\t *\n\t\t * @return {Array<{iso: string, dayNum: number, isToday: boolean, isOtherMonth: boolean, objects: object[]}>}\n\t\t */\n\t\tmonthGrid() {\n\t\t\tconst { from: gridStart, to: gridEnd } = this.gridRange\n\t\t\tconst { from: monthStart } = this.monthRange\n\t\t\tconst today = this.toIsoDate(new Date())\n\t\t\tconst cells = []\n\t\t\tfor (const iso of this.isoDateRange(gridStart, gridEnd)) {\n\t\t\t\tconst cellDate = this.parseDate(iso)\n\t\t\t\tcells.push({\n\t\t\t\t\tiso,\n\t\t\t\t\tdayNum: cellDate.getDate(),\n\t\t\t\t\tisToday: today === iso,\n\t\t\t\t\tisOtherMonth: cellDate.getMonth() !== monthStart.getMonth(),\n\t\t\t\t\tobjects: this.objectsByDay[iso] || [],\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn cells\n\t\t},\n\t},\n\n\twatch: {\n\t\tvisibleDate(newValue) {\n\t\t\tconst parsed = this.parseDate(newValue)\n\t\t\tif (!parsed) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.toIsoDate(parsed).slice(0, 7) === this.toIsoDate(this.internalDate).slice(0, 7)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.internalDate = parsed\n\t\t\tthis.emitRangeChange()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.emitRangeChange()\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Parse a date-ish value (Date instance, ISO string, or nullish) into a\n\t\t * `Date`, or `null` when it can't be parsed.\n\t\t *\n\t\t * @param {string|Date|null|undefined} value The value to parse.\n\t\t * @return {Date|null}\n\t\t */\n\t\tparseDate(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst date = value instanceof Date ? value : new Date(value)\n\t\t\treturn Number.isNaN(date.getTime()) ? null : date\n\t\t},\n\n\t\t/**\n\t\t * Format a `Date` as `YYYY-MM-DD` in local time (never UTC, so the grid\n\t\t * and the bucketing agree regardless of timezone offset).\n\t\t *\n\t\t * @param {Date} date The date to format.\n\t\t * @return {string}\n\t\t */\n\t\ttoIsoDate(date) {\n\t\t\tconst y = date.getFullYear()\n\t\t\tconst m = String(date.getMonth() + 1).padStart(2, '0')\n\t\t\tconst d = String(date.getDate()).padStart(2, '0')\n\t\t\treturn `${y}-${m}-${d}`\n\t\t},\n\n\t\t/**\n\t\t * Every `YYYY-MM-DD` from `start` to `end` inclusive (both truncated to\n\t\t * whole days), as a plain array — used so day-stepping loops reassign a\n\t\t * counter rather than mutating a `Date` in a `while` condition.\n\t\t *\n\t\t * @param {Date} start The range start (inclusive).\n\t\t * @param {Date} end The range end (inclusive).\n\t\t * @return {string[]}\n\t\t */\n\t\tisoDateRange(start, end) {\n\t\t\tconst startDay = new Date(start.getFullYear(), start.getMonth(), start.getDate())\n\t\t\tconst endDay = new Date(end.getFullYear(), end.getMonth(), end.getDate())\n\t\t\tconst dayCount = Math.round((endDay.getTime() - startDay.getTime()) / 86400000) + 1\n\t\t\tconst isoDates = []\n\t\t\tfor (let i = 0; i < dayCount; i++) {\n\t\t\t\tisoDates.push(this.toIsoDate(new Date(startDay.getFullYear(), startDay.getMonth(), startDay.getDate() + i)))\n\t\t\t}\n\t\t\treturn isoDates\n\t\t},\n\n\t\t/**\n\t\t * The object's identity, per `rowKey`.\n\t\t *\n\t\t * @param {object} object The object.\n\t\t * @return {unknown}\n\t\t */\n\t\tobjectKey(object) {\n\t\t\treturn object?.[this.rowKey]\n\t\t},\n\n\t\t/**\n\t\t * Best-effort display title: `titleField` when configured, else\n\t\t * `title`/`name`/the row key.\n\t\t *\n\t\t * @param {object} object The object.\n\t\t * @return {string}\n\t\t */\n\t\tobjectTitle(object) {\n\t\t\tif (this.titleField && object[this.titleField]) {\n\t\t\t\treturn String(object[this.titleField])\n\t\t\t}\n\t\t\treturn String(object.title || object.name || object[this.rowKey] || '—')\n\t\t},\n\n\t\t/**\n\t\t * Accessible name of a day cell: the date and how many records it holds.\n\t\t *\n\t\t * @param {{iso: string, objects: object[]}} day The day.\n\t\t * @return {string}\n\t\t */\n\t\tdayLabel(day) {\n\t\t\tconst date = this.parseDate(day.iso).toLocaleDateString(userLocale(), { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })\n\t\t\treturn day.objects.length === 0 ? date : `${date}, ${t('nextcloud-vue', '{count} records', { count: day.objects.length })}`\n\t\t},\n\n\t\t/**\n\t\t * Accessible name of the \"+N\" button.\n\t\t *\n\t\t * @param {{iso: string, objects: object[]}} day The day.\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel(day) {\n\t\t\treturn t('nextcloud-vue', 'Show all {count} records on {date}', { count: day.objects.length, date: day.iso })\n\t\t},\n\n\t\t/**\n\t\t * Move between day cells with the arrow keys, Home and End. Past the\n\t\t * edge of the grid the month moves with it.\n\t\t *\n\t\t * @param {KeyboardEvent} event The key event.\n\t\t * @param {{iso: string}} day The focused day.\n\t\t */\n\t\tonCellKeydown(event, day) {\n\t\t\tif (event.target !== event.currentTarget) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst steps = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -7, ArrowDown: 7 }\n\t\t\tconst here = this.parseDate(day.iso)\n\t\t\tlet target = null\n\t\t\tif (event.key in steps) {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() + steps[event.key])\n\t\t\t} else if (event.key === 'Home') {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() - here.getDay())\n\t\t\t} else if (event.key === 'End') {\n\t\t\t\ttarget = new Date(here.getFullYear(), here.getMonth(), here.getDate() + (6 - here.getDay()))\n\t\t\t}\n\t\t\tif (!target) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tevent.preventDefault()\n\t\t\tconst iso = this.toIsoDate(target)\n\t\t\tif (!this.monthGrid.some((d) => d.iso === iso)) {\n\t\t\t\t// Off the edge: move to the month that holds the day.\n\t\t\t\tthis.internalDate = new Date(target.getFullYear(), target.getMonth(), 1)\n\t\t\t\tthis.afterNavigate()\n\t\t\t}\n\t\t\tthis.focusedIso = iso\n\t\t\tthis.$nextTick(() => {\n\t\t\t\tconst cell = this.$el.querySelector(`[data-iso=\"${iso}\"]`)\n\t\t\t\tif (cell) {\n\t\t\t\t\tcell.focus()\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Navigate to the previous month.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgoToPreviousMonth() {\n\t\t\tconst d = this.internalDate\n\t\t\tthis.internalDate = new Date(d.getFullYear(), d.getMonth() - 1, 1)\n\t\t\tthis.afterNavigate()\n\t\t},\n\n\t\t/**\n\t\t * Navigate to the next month.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgoToNextMonth() {\n\t\t\tconst d = this.internalDate\n\t\t\tthis.internalDate = new Date(d.getFullYear(), d.getMonth() + 1, 1)\n\t\t\tthis.afterNavigate()\n\t\t},\n\n\t\t/**\n\t\t * Sync `.sync` and notify the host to re-fetch after a month navigation.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tafterNavigate() {\n\t\t\t// Description goes ABOVE `@event`, not inline after it:\n\t\t\t// vue-docgen-api's event-name splitter stops at the first `:`, so\n\t\t\t// `@event update:visibleDate <description>` is read as one long\n\t\t\t// event NAME and the generated docs show an empty description.\n\t\t\t// Only colon-bearing (`update:*`) names are affected.\n\t\t\t/**\n\t\t\t * Emitted on month navigation, for `v-model:visible-date` binding.\n\t\t\t *\n\t\t\t * @event update:visibleDate\n\t\t\t * @type {Date}\n\t\t\t */\n\t\t\tthis.$emit('update:visibleDate', this.internalDate)\n\t\t\tthis.emitRangeChange()\n\t\t},\n\n\t\t/**\n\t\t * Emit the currently visible grid window (padded to whole weeks) as\n\t\t * ISO date strings, matching the OpenRegister calendar endpoint's\n\t\t * `rangeStart`/`rangeEnd` query params.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\temitRangeChange() {\n\t\t\tconst { from, to } = this.gridRange\n\t\t\t/**\n\t\t\t * @event range-change Emitted on mount and after every month\n\t\t\t * navigation so the host can re-fetch objects for the new window.\n\t\t\t * @type {{ rangeStart: string, rangeEnd: string }}\n\t\t\t */\n\t\t\tthis.$emit('range-change', {\n\t\t\t\trangeStart: this.toIsoDate(from),\n\t\t\t\trangeEnd: this.toIsoDate(to),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Handle an event entry click.\n\t\t *\n\t\t * @param {object} object The clicked object.\n\t\t * @return {void}\n\t\t */\n\t\tonObjectClick(object) {\n\t\t\t/**\n\t\t\t * @event object-click Emitted when a plotted object is clicked.\n\t\t\t * @type {object} The clicked object.\n\t\t\t */\n\t\t\tthis.$emit('object-click', object)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-calendar__header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 12px;\n\tpadding: 8px 0 16px;\n}\n\n.cn-object-calendar__title {\n\tmin-width: 160px;\n\ttext-align: center;\n\tfont-weight: 600;\n\tfont-size: 16px;\n\ttext-transform: capitalize;\n}\n\n.cn-object-calendar__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 40px;\n}\n\n.cn-object-calendar__month {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(7, 1fr);\n\tgap: 1px;\n\tbackground: var(--color-border);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius, 8px);\n\toverflow: hidden;\n}\n\n.cn-object-calendar__month-header {\n\tbackground: var(--color-background-dark);\n\tpadding: 6px 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\ttext-align: center;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-calendar__month-cell {\n\tbackground: var(--color-main-background);\n\tmin-height: 90px;\n\tpadding: 4px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-object-calendar__month-cell.is-other-month {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-calendar__month-day {\n\tfont-size: 12px;\n\twidth: 20px;\n\theight: 20px;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.cn-object-calendar__month-cell.is-today .cn-object-calendar__month-day {\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tborder-radius: 50%;\n}\n\n.cn-object-calendar__month-events {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-object-calendar__event {\n\tfont-size: 11px;\n\tpadding: 1px 4px;\n\tborder-radius: 4px;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-main-text);\n\tcursor: pointer;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-calendar__overflow {\n\tfont-size: 11px;\n\tcolor: var(--color-text-maxcontrast);\n\tpadding: 0 4px;\n}\n\n.cn-object-calendar__week {\n\tdisplay: contents;\n}\n\n.cn-object-calendar__month-cell:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: -2px;\n}\n\nbutton.cn-object-calendar__event,\nbutton.cn-object-calendar__overflow {\n\tdisplay: block;\n\twidth: 100%;\n\tmin-height: 0;\n\tborder: 0;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text);\n\tborder-radius: var(--border-radius, 4px);\n\tpadding: 1px 6px;\n\tfont: inherit;\n\tfont-size: 12px;\n\ttext-align: start;\n\tcursor: pointer;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\nbutton.cn-object-calendar__overflow {\n\tbackground: transparent;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_createVNode","_createElementVNode","_toDisplayString","_Fragment","_renderList","_openBlock","_createElementBlock","_normalizeClass","_renderSlot","_createTextVNode"],"mappings":"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"}
@@ -2,7 +2,7 @@ import script from './CnObjectDataWidget.vue2.js';
2
2
  import { render } from './CnObjectDataWidget.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-324e1a00";
5
+ script.__scopeId = "data-v-6883a5c4";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -717,12 +717,14 @@ var script = {
717
717
  }
718
718
  // Resolve relation display names whenever the object changes.
719
719
  this.resolveRelations();
720
+ this.resolveUserNames();
720
721
  },
721
722
  },
722
723
 
723
724
  schema: {
724
725
  handler() {
725
726
  this.resolveRelations();
727
+ this.resolveUserNames();
726
728
  },
727
729
  },
728
730
 
@@ -746,6 +748,7 @@ var script = {
746
748
 
747
749
  mounted() {
748
750
  this.resolveRelations();
751
+ this.resolveUserNames();
749
752
  this.publishPanelActions();
750
753
  this.observeCell();
751
754
  this.scheduleFit();
@@ -1774,6 +1777,31 @@ var script = {
1774
1777
  return list.filter((v) => typeof v === 'string' && v !== '')
1775
1778
  },
1776
1779
 
1780
+ /**
1781
+ * The uids a user field holds, for the display mode. The same list
1782
+ * shape a group field holds.
1783
+ *
1784
+ * @spec openspec/changes/a-user-field-reads-its-display-name/specs/data-display/spec.md#requirement-a-user-field-shows-the-users-display-name
1785
+ * @param {object} field Field descriptor.
1786
+ * @return {string[]}
1787
+ */
1788
+ userIdsOf(field) {
1789
+ return this.groupIdsOf(field)
1790
+ },
1791
+
1792
+ /**
1793
+ * Look up the display names of every user field's value, so the read
1794
+ * mode shows "Thomas Kuiper" rather than `thomas.kuiper`. Each uid is
1795
+ * asked once per widget.
1796
+ *
1797
+ * @spec openspec/changes/a-user-field-reads-its-display-name/specs/data-display/spec.md#requirement-a-user-field-shows-the-users-display-name
1798
+ * @return {Promise<void>}
1799
+ */
1800
+ async resolveUserNames() {
1801
+ const fields = (this.resolvedFields || []).filter((field) => this.isUserPicker(field));
1802
+ await Promise.all(fields.map((field) => this.resolvePersonLabels(field, this.rawOf(field))));
1803
+ },
1804
+
1777
1805
  /**
1778
1806
  * The display name of a group id or uid, falling back to the id.
1779
1807
  *