@conduction/nextcloud-vue 2.79.0 → 2.80.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 (197) hide show
  1. package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js.map +1 -1
  2. package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js +3 -1
  3. package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js.map +1 -1
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +32 -3
  5. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  6. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +10 -8
  7. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  8. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +39 -3
  9. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
  10. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
  11. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +79 -1
  12. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  13. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +133 -96
  14. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  15. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  16. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +1 -0
  17. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  18. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +62 -4
  19. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  20. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  21. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +24 -0
  22. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  23. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +43 -4
  24. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  25. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +11 -0
  26. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js.map +1 -0
  27. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +736 -0
  28. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -0
  29. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +238 -0
  30. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -0
  31. package/dist/esm/components/CnFactsWidget/index.js +30 -0
  32. package/dist/esm/components/CnFactsWidget/index.js.map +1 -0
  33. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +10 -0
  34. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js.map +1 -0
  35. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +551 -0
  36. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -0
  37. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +183 -0
  38. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -0
  39. package/dist/esm/components/CnFieldListWidget/index.js +29 -0
  40. package/dist/esm/components/CnFieldListWidget/index.js.map +1 -0
  41. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +65 -17
  42. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  43. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +4 -4
  44. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  45. package/dist/esm/components/CnFormPage/CnFormPage.vue2.js +18 -3
  46. package/dist/esm/components/CnFormPage/CnFormPage.vue2.js.map +1 -1
  47. package/dist/esm/components/CnFormPage/CnFormPage.vue3.js.map +1 -1
  48. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +305 -72
  49. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  50. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +31 -13
  51. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  52. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +10 -0
  53. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js.map +1 -0
  54. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +99 -0
  55. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -0
  56. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +48 -0
  57. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -0
  58. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js +29 -1
  59. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  60. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  61. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +10 -0
  62. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js.map +1 -0
  63. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +387 -0
  64. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -0
  65. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +169 -0
  66. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -0
  67. package/dist/esm/components/CnRecordListWidget/index.js +31 -0
  68. package/dist/esm/components/CnRecordListWidget/index.js.map +1 -0
  69. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue.js +10 -0
  70. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue.js.map +1 -0
  71. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js +351 -0
  72. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js.map +1 -0
  73. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js +71 -0
  74. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js.map +1 -0
  75. package/dist/esm/components/CnSectionsWidget/index.js +35 -0
  76. package/dist/esm/components/CnSectionsWidget/index.js.map +1 -0
  77. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +81 -2
  78. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
  79. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
  80. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  81. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +1 -0
  82. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  83. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +122 -7
  84. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  85. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +84 -23
  86. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  87. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +4 -0
  88. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  89. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js +106 -2
  90. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js.map +1 -1
  91. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js +105 -53
  92. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js.map +1 -1
  93. package/dist/esm/composables/useFormDraft.js +140 -9
  94. package/dist/esm/composables/useFormDraft.js.map +1 -1
  95. package/dist/esm/index.js +4 -0
  96. package/dist/esm/index.js.map +1 -1
  97. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js +28 -20
  98. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js.map +1 -1
  99. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js +9 -0
  100. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js.map +1 -1
  101. package/dist/esm/integrations/builtin/field-inspection.js +21 -0
  102. package/dist/esm/integrations/builtin/field-inspection.js.map +1 -1
  103. package/dist/esm/integrations/offline/checklistSubmission.js +141 -0
  104. package/dist/esm/integrations/offline/checklistSubmission.js.map +1 -0
  105. package/dist/esm/integrations/offline/fieldCollectionHelpers.js +70 -5
  106. package/dist/esm/integrations/offline/fieldCollectionHelpers.js.map +1 -1
  107. package/dist/esm/integrations/offline/index.js +2 -1
  108. package/dist/esm/integrations/offline/index.js.map +1 -1
  109. package/dist/esm/integrations/offline/offlineDb.js +6 -1
  110. package/dist/esm/integrations/offline/offlineDb.js.map +1 -1
  111. package/dist/esm/integrations/offline/syncReplayService.js +8 -2
  112. package/dist/esm/integrations/offline/syncReplayService.js.map +1 -1
  113. package/dist/esm/l10n/en.json.js +12 -1
  114. package/dist/esm/l10n/en.json.js.map +1 -1
  115. package/dist/esm/l10n/nl.json.js +16 -2
  116. package/dist/esm/l10n/nl.json.js.map +1 -1
  117. package/dist/esm/nextcloud-vue.css +1000 -59
  118. package/dist/esm/utils/detailActionModel.js +60 -3
  119. package/dist/esm/utils/detailActionModel.js.map +1 -1
  120. package/dist/esm/utils/fillTemplate.js +114 -0
  121. package/dist/esm/utils/fillTemplate.js.map +1 -0
  122. package/dist/esm/utils/libraryWidgetKeys.js +4 -0
  123. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  124. package/dist/esm/utils/queryPresets.js +96 -0
  125. package/dist/esm/utils/queryPresets.js.map +1 -0
  126. package/dist/esm/utils/resolveFilterTokens.js +11 -0
  127. package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
  128. package/dist/esm/utils/schema.js +21 -0
  129. package/dist/esm/utils/schema.js.map +1 -1
  130. package/dist/esm/utils/sentinelTokens.js +3 -3
  131. package/dist/esm/utils/sentinelTokens.js.map +1 -1
  132. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  133. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  134. package/dist/esm/utils/widgetDispatch.js +7 -1
  135. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  136. package/dist/nextcloud-vue.cjs.js +12368 -7717
  137. package/dist/nextcloud-vue.cjs.js.map +2 -2
  138. package/dist/nextcloud-vue.css +1000 -59
  139. package/l10n/en.json +12 -1
  140. package/l10n/nl.json +16 -2
  141. package/package.json +1 -1
  142. package/src/components/CnActionButtons/CnActionButtons.vue +2 -0
  143. package/src/components/CnActionsBar/CnActionsBar.md +4 -0
  144. package/src/components/CnActionsBar/CnActionsBar.vue +42 -10
  145. package/src/components/CnBannerWidget/CnBannerWidget.vue +39 -3
  146. package/src/components/CnCellRenderer/CnCellRenderer.vue +188 -1
  147. package/src/components/CnDataTable/CnDataTable.vue +1 -0
  148. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  149. package/src/components/CnDetailPage/CnDetailPage.vue +63 -3
  150. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +66 -0
  151. package/src/components/CnFactsWidget/CnFactsWidget.vue +1050 -0
  152. package/src/components/CnFactsWidget/index.js +29 -0
  153. package/src/components/CnFieldListWidget/CnFieldListWidget.vue +746 -0
  154. package/src/components/CnFieldListWidget/index.js +28 -0
  155. package/src/components/CnFormDialog/CnFormDialog.md +9 -3
  156. package/src/components/CnFormDialog/CnFormDialog.vue +69 -21
  157. package/src/components/CnFormPage/CnFormPage.vue +18 -3
  158. package/src/components/CnIndexPage/CnIndexPage.vue +254 -6
  159. package/src/components/CnIndexPage/CnIndexPageWidgets.vue +169 -0
  160. package/src/components/CnPageRenderer/CnPageRenderer.vue +29 -1
  161. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +603 -0
  162. package/src/components/CnRecordListWidget/index.js +30 -0
  163. package/src/components/CnSectionsWidget/CnSectionsWidget.vue +489 -0
  164. package/src/components/CnSectionsWidget/index.js +34 -0
  165. package/src/components/CnStagesWidget/CnStagesWidget.vue +81 -2
  166. package/src/components/CnStatWidget/CnStatWidget.vue +1 -1
  167. package/src/components/CnTabsWidget/CnTabsWidget.vue +184 -8
  168. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +4 -0
  169. package/src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue +188 -4
  170. package/src/components/index.js +4 -0
  171. package/src/composables/__tests__/useFormDraft.spec.js +69 -0
  172. package/src/composables/useFormDraft.js +139 -8
  173. package/src/css/form-field.css +14 -0
  174. package/src/css/index-page.css +71 -0
  175. package/src/css/kpi-card.css +32 -0
  176. package/src/css/look-board-detail.css +77 -0
  177. package/src/css/look-board-index.css +51 -0
  178. package/src/css/look-board.css +37 -2
  179. package/src/css/table.css +19 -0
  180. package/src/index.js +4 -0
  181. package/src/integrations/builtin/field-inspection/CnFieldInspectionCard.vue +35 -20
  182. package/src/integrations/builtin/field-inspection.js +21 -0
  183. package/src/integrations/offline/checklistSubmission.js +137 -0
  184. package/src/integrations/offline/fieldCollectionHelpers.js +69 -4
  185. package/src/integrations/offline/index.js +3 -0
  186. package/src/integrations/offline/offlineDb.js +6 -1
  187. package/src/integrations/offline/syncReplayService.js +8 -2
  188. package/src/schemas/app-manifest-v2.schema.json +104 -5
  189. package/src/utils/detailActionModel.js +59 -2
  190. package/src/utils/fillTemplate.js +110 -0
  191. package/src/utils/libraryWidgetKeys.js +4 -0
  192. package/src/utils/queryPresets.js +93 -0
  193. package/src/utils/resolveFilterTokens.js +11 -0
  194. package/src/utils/schema.js +21 -0
  195. package/src/utils/sentinelTokens.js +3 -3
  196. package/src/utils/validateManifestV2.compiled.js +3 -3
  197. package/src/utils/widgetDispatch.js +7 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnRecordListWidget.vue3.js","sources":["../../../../src/components/CnRecordListWidget/CnRecordListWidget.vue?vue&type=template&id=7073b362&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tclass=\"cn-record-list\"\n\t\t:class=\"`cn-record-list--${presentation}`\"\n\t\tdata-testid=\"cn-record-list\">\n\t\t<p v-if=\"error\" class=\"cn-record-list__error\" data-testid=\"cn-record-list-error\">\n\t\t\t{{ errorLabel }}\n\t\t</p>\n\t\t<div v-else-if=\"loading && rows.length === 0\" class=\"cn-record-list__loading\">\n\t\t\t<NcLoadingIcon :size=\"20\" :name=\"loadingLabel\" />\n\t\t</div>\n\t\t<p v-else-if=\"rows.length === 0\" class=\"cn-record-list__empty\" data-testid=\"cn-record-list-empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<ul v-else class=\"cn-record-list__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"item in items\"\n\t\t\t\t:key=\"item.key\"\n\t\t\t\tclass=\"cn-record-list__item\"\n\t\t\t\tdata-testid=\"cn-record-list-item\">\n\t\t\t\t<!-- rows: title and meta, then the pill, the date and a chevron. -->\n\t\t\t\t<component\n\t\t\t\t\t:is=\"item.tag\"\n\t\t\t\t\tv-if=\"presentation === 'rows'\"\n\t\t\t\t\tclass=\"cn-record-list__row\"\n\t\t\t\t\t:class=\"{ 'cn-record-list__row--link': item.tag !== 'div' }\"\n\t\t\t\t\tv-bind=\"item.attrs\">\n\t\t\t\t\t<span class=\"cn-record-list__main\">\n\t\t\t\t\t\t<span v-if=\"item.title\" class=\"cn-record-list__title\">{{ item.title }}</span>\n\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-record-list__meta\">{{ item.meta }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"item.pill || item.trailing\" class=\"cn-record-list__aside\">\n\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\tv-if=\"item.pill\"\n\t\t\t\t\t\t\t:label=\"item.pill.label\"\n\t\t\t\t\t\t\t:variant=\"item.pill.variant\"\n\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t<span v-if=\"item.trailing\" class=\"cn-record-list__trailing\">{{ item.trailing }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<ChevronRight\n\t\t\t\t\t\tv-if=\"item.tag !== 'div'\"\n\t\t\t\t\t\tclass=\"cn-record-list__chevron\"\n\t\t\t\t\t\t:size=\"18\"\n\t\t\t\t\t\taria-hidden=\"true\" />\n\t\t\t\t</component>\n\n\t\t\t\t<!-- feed: a round icon, a meta line and the text. -->\n\t\t\t\t<div v-else-if=\"presentation === 'feed'\" class=\"cn-record-list__feed-row\">\n\t\t\t\t\t<span class=\"cn-record-list__feed-icon\" aria-hidden=\"true\">\n\t\t\t\t\t\t<CnIcon :name=\"item.icon\" :size=\"18\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<component :is=\"item.tag\" class=\"cn-record-list__main\" v-bind=\"item.attrs\">\n\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-record-list__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t<span v-if=\"item.text\" class=\"cn-record-list__text\">{{ item.text }}</span>\n\t\t\t\t\t</component>\n\t\t\t\t</div>\n\n\t\t\t\t<!-- inline: a label and the title, the title a link. -->\n\t\t\t\t<div v-else class=\"cn-record-list__inline-row\">\n\t\t\t\t\t<span v-if=\"item.label\" class=\"cn-record-list__label\">{{ item.label }}</span>\n\t\t\t\t\t<component :is=\"item.tag\" class=\"cn-record-list__inline-title\" v-bind=\"item.attrs\">\n\t\t\t\t\t\t{{ item.title }}\n\t\t\t\t\t</component>\n\t\t\t\t</div>\n\t\t\t</li>\n\t\t</ul>\n\t</div>\n</template>\n\n<script>\nimport { subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport { isBadgeVariant } from '../../utils/badgeVariants.js'\nimport { fillTemplate, firstFilled } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { dropOptionalUnresolved, hasUnresolvedTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\n\nconst PAGE_REFRESH_CHANNEL = 'cn:page:refresh'\nconst PRESENTATIONS = ['rows', 'feed', 'inline']\n\n/**\n * Unwrap a value that may be a ref.\n *\n * @param {unknown} value The value.\n * @return {unknown} The plain value.\n */\nfunction unwrap(value) {\n\treturn value && typeof value === 'object' && 'value' in value ? value.value : value\n}\n\n/**\n * CnRecordListWidget — the objects of another schema that point at this\n * record, drawn as the boards draw them (screens-relation-pages).\n *\n * A person page lists its open cases (\"Verlichting fietspad Lindelaan,\n * 2026-0082 · Woo-verzoek, In behandeling, Termijn 1 nov\"), its latest contact\n * moments (an icon by channel, a meta line, the summary) and its relations\n * (\"Secretaris van Buurtvereniging Oost\"). Each is a list of another schema's\n * objects filtered on a reference to this record. The source keys are those of\n * `object-list` (`register`, `schema`, `filter` with the `@objectId` /\n * `@object.<field>` / `@workspace.<key>` tokens, `sort`, `limit`, `extend`,\n * `rowRoute`); what differs is the drawing: `presentation` is `rows`, `feed`\n * or `inline`, and each line is a template (`\"{identifier} · {caseTypeName}\"`,\n * `\"Termijn {deadline|date}\"`).\n *\n * A content-only catalog type: on a card surface the detail host draws the\n * titled card. The widget emits `header` with `{ link, note }` (the\n * `headerLink` and `headerNote` with `{total}` filled in) for that card's\n * header.\n */\nexport default {\n\tname: 'CnRecordListWidget',\n\n\tcomponents: { ChevronRight, CnIcon, CnStatusBadge, NcLoadingIcon },\n\n\tinject: {\n\t\t/** Detail-page object context (`{ objectId, object, register, schema }`). */\n\t\tcnObjectContext: { default: null },\n\t\t/** Page workspace bag, for `@workspace.<key>` tokens. */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/** The host app's translate function. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The list config: `{ register, schema, filter?, sort?, limit?, extend?,\n\t\t * presentation?, title?, meta?, text?, label?, pill?, trailing?, icon?,\n\t\t * rowRoute?, rowIdField?, headerLink?, headerNote?, emptyText?, errorText? }`.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current record, for `@object.<field>` tokens. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['header'],\n\n\tdata() {\n\t\treturn {\n\t\t\trows: [],\n\t\t\ttotal: 0,\n\t\t\tloading: false,\n\t\t\terror: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} `rows`, `feed` or `inline`. */\n\t\tpresentation() {\n\t\t\tconst value = this.content?.presentation\n\t\t\treturn PRESENTATIONS.includes(value) ? value : 'rows'\n\t\t},\n\n\t\t/** @return {object} The token context: record, id and workspace. */\n\t\ttokenCtx() {\n\t\t\tconst injected = unwrap(this.cnObjectContext) || {}\n\t\t\treturn {\n\t\t\t\t...injected,\n\t\t\t\tobjectId: this.objectId ?? injected.objectId ?? this.objectData?.id ?? null,\n\t\t\t\tobject: this.objectData || injected.object || null,\n\t\t\t\tworkspace: unwrap(this.cnWorkspaceContext) || {},\n\t\t\t}\n\t\t},\n\n\t\t/** @return {object} The filter with its tokens resolved. */\n\t\tresolvedFilter() {\n\t\t\tconst filter = this.content?.filter\n\t\t\treturn dropOptionalUnresolved(resolveFilterTokens(filter && typeof filter === 'object' ? filter : {}, this.tokenCtx))\n\t\t},\n\n\t\t/** @return {boolean} A required token (the record id, say) has no value yet. */\n\t\twaiting() {\n\t\t\treturn hasUnresolvedTokens(this.resolvedFilter)\n\t\t},\n\n\t\t/** @return {number} The fetch cap. */\n\t\tlimit() {\n\t\t\tconst value = Number(this.content?.limit)\n\t\t\treturn Number.isFinite(value) && value > 0 ? Math.floor(value) : 5\n\t\t},\n\n\t\t/** @return {string} What a fetch depends on; a change fetches again. */\n\t\trequestKey() {\n\t\t\tconst c = this.content || {}\n\t\t\treturn JSON.stringify([c.register, c.schema, this.resolvedFilter, c.sort, this.limit, c.extend, this.waiting])\n\t\t},\n\n\t\t/** @return {Array<object>} The rows ready to draw. */\n\t\titems() {\n\t\t\tconst c = this.content || {}\n\t\t\treturn this.rows.slice(0, this.limit).map((row, index) => {\n\t\t\t\tconst link = this.rowLink(row)\n\t\t\t\treturn {\n\t\t\t\t\tkey: (row && (row.id || row['@self']?.id)) || `row-${index}`,\n\t\t\t\t\ttag: link ? 'router-link' : 'div',\n\t\t\t\t\tattrs: link ? { to: link } : {},\n\t\t\t\t\ttitle: this.fill(c.title, row),\n\t\t\t\t\tmeta: this.fill(c.meta, row),\n\t\t\t\t\ttext: this.fill(c.text, row),\n\t\t\t\t\tlabel: this.fill(c.label, row),\n\t\t\t\t\ttrailing: c.trailing ? firstFilled(c.trailing, row, this.translate) : '',\n\t\t\t\t\tpill: this.pillOf(row),\n\t\t\t\t\ticon: this.iconOf(row),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/** @return {object|null} The header link with `{total}` filled and tokens resolved. */\n\t\theaderLink() {\n\t\t\tconst link = this.content?.headerLink\n\t\t\tif (!link || typeof link !== 'object' || typeof link.label !== 'string' || link.label === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst resolved = { label: this.withTotal(link.label) }\n\t\t\tif (link.route) {\n\t\t\t\tresolved.route = link.route\n\t\t\t\tif (link.params && typeof link.params === 'object') {\n\t\t\t\t\tresolved.params = resolveFilterTokens(link.params, this.tokenCtx)\n\t\t\t\t}\n\t\t\t\tif (link.query && typeof link.query === 'object') {\n\t\t\t\t\tresolved.query = resolveFilterTokens(link.query, this.tokenCtx)\n\t\t\t\t}\n\t\t\t} else if (typeof link.href === 'string') {\n\t\t\t\tresolved.href = link.href\n\t\t\t}\n\t\t\treturn resolved\n\t\t},\n\n\t\t/** @return {string} The header note with `{total}` filled. */\n\t\theaderNote() {\n\t\t\tconst note = this.content?.headerNote\n\t\t\treturn typeof note === 'string' && note !== '' ? this.withTotal(note) : ''\n\t\t},\n\n\t\t/** @return {string} The empty line. */\n\t\temptyLabel() {\n\t\t\treturn this.content?.emptyText ? this.translate(this.content.emptyText) : t('nextcloud-vue', 'Nothing here yet')\n\t\t},\n\n\t\t/** @return {string} The error line. */\n\t\terrorLabel() {\n\t\t\treturn this.content?.errorText ? this.translate(this.content.errorText) : t('nextcloud-vue', 'This list could not be loaded.')\n\t\t},\n\n\t\t/** @return {string} The spinner's accessible name. */\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\t},\n\n\twatch: {\n\t\trequestKey() {\n\t\t\tthis.fetchRows()\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.onRefresh = () => this.fetchRows()\n\t\tsubscribe(PAGE_REFRESH_CHANNEL, this.onRefresh)\n\t\tthis.fetchRows()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe(PAGE_REFRESH_CHANNEL, this.onRefresh)\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Translate a manifest string through the host app.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string} The translation.\n\t\t */\n\t\ttranslate(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * Fill a template from a row, after translating it.\n\t\t *\n\t\t * @param {string} template The template.\n\t\t * @param {object} row The row.\n\t\t * @return {string} The text, '' when a token is empty.\n\t\t */\n\t\tfill(template, row) {\n\t\t\treturn typeof template === 'string' && template !== '' ? fillTemplate(this.translate(template), row) : ''\n\t\t},\n\n\t\t/**\n\t\t * Replace `{total}` in a translated label.\n\t\t *\n\t\t * @param {string} label The label.\n\t\t * @return {string} The text.\n\t\t */\n\t\twithTotal(label) {\n\t\t\treturn this.translate(label).replace(/\\{total\\}/g, String(this.total))\n\t\t},\n\n\t\t/**\n\t\t * The route a row opens: `rowRoute` with the id at `rowIdField`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {object|null} The router location, or null.\n\t\t */\n\t\trowLink(row) {\n\t\t\tconst route = this.content?.rowRoute\n\t\t\tif (!route || !this.$router || !row) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst field = this.content?.rowIdField\n\t\t\tconst id = field ? readPath(row, field) : (row.id || row['@self']?.id)\n\t\t\tif (id === null || id === undefined || id === '' || typeof id === 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn { name: route, params: { id: String(id) } }\n\t\t},\n\n\t\t/**\n\t\t * The row's pill: `{ field, labels?, colorMap?, variant? }`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {{label: string, variant: string}|null} The pill, or null.\n\t\t */\n\t\tpillOf(row) {\n\t\t\tconst pill = this.content?.pill\n\t\t\tif (!pill || typeof pill !== 'object' || !pill.field) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst raw = readPath(row, pill.field)\n\t\t\tif (raw === null || raw === undefined || raw === '' || typeof raw === 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst key = String(raw)\n\t\t\tconst labels = pill.labels && typeof pill.labels === 'object' ? pill.labels : {}\n\t\t\tconst map = pill.colorMap && typeof pill.colorMap === 'object' ? pill.colorMap : {}\n\t\t\tconst found = Object.keys(map).find((k) => k.toLowerCase() === key.toLowerCase())\n\t\t\tconst variant = found ? map[found] : pill.variant\n\t\t\treturn {\n\t\t\t\tlabel: labels[key] ? this.translate(labels[key]) : key,\n\t\t\t\tvariant: isBadgeVariant(variant) ? variant : 'default',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The feed icon: an icon name, or `{ field, map, default }`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {string} The MDI icon name.\n\t\t */\n\t\ticonOf(row) {\n\t\t\tconst icon = this.content?.icon\n\t\t\tif (typeof icon === 'string' && icon !== '') {\n\t\t\t\treturn icon\n\t\t\t}\n\t\t\tif (icon && typeof icon === 'object') {\n\t\t\t\tconst raw = icon.field ? readPath(row, icon.field) : undefined\n\t\t\t\tconst map = icon.map && typeof icon.map === 'object' ? icon.map : {}\n\t\t\t\tif (raw !== null && raw !== undefined && map[String(raw)]) {\n\t\t\t\t\treturn map[String(raw)]\n\t\t\t\t}\n\t\t\t\tif (typeof icon.default === 'string' && icon.default !== '') {\n\t\t\t\t\treturn icon.default\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn 'CircleSmall'\n\t\t},\n\n\t\t/** Tell the card around this list what its header shows. */\n\t\temitHeader() {\n\t\t\t/**\n\t\t\t * @event header Emitted after every read with the card header's parts.\n\t\t\t * @type {{link: (object|null), note: string}} The header link (resolved, with `{total}` filled) and the note.\n\t\t\t */\n\t\t\tthis.$emit('header', { link: this.headerLink, note: this.headerNote })\n\t\t},\n\n\t\t/**\n\t\t * Fetch the list. Sends nothing while a required token is unresolved\n\t\t * or the source is incomplete.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchRows() {\n\t\t\tconst c = this.content || {}\n\t\t\tif (!c.register || !c.schema || this.waiting) {\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.total = 0\n\t\t\t\tthis.error = false\n\t\t\t\tthis.emitHeader()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = false\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: c.register, schema: c.schema })\n\t\t\t\tconst params = { _limit: this.limit }\n\t\t\t\tif (c.sort && typeof c.sort === 'object' && c.sort.field) {\n\t\t\t\t\tparams[`_order[${c.sort.field}]`] = c.sort.dir === 'desc' ? 'desc' : 'asc'\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(c.extend)) {\n\t\t\t\t\tconst extend = c.extend.filter((e) => typeof e === 'string' && e !== '')\n\t\t\t\t\tif (extend.length > 0) {\n\t\t\t\t\t\tparams._extend = extend\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (const [key, value] of Object.entries(this.resolvedFilter)) {\n\t\t\t\t\tif (value && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t\t\t\tfor (const [op, operand] of Object.entries(value)) {\n\t\t\t\t\t\t\tparams[`${key}[${op}]`] = operand\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (value !== '' && value !== null && value !== undefined) {\n\t\t\t\t\t\tparams[key] = value\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(url, { params })\n\t\t\t\tconst data = response && response.data ? response.data : {}\n\t\t\t\tthis.rows = Array.isArray(data.results) ? data.results : []\n\t\t\t\tthis.total = typeof data.total === 'number' ? data.total : this.rows.length\n\t\t\t} catch (e) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnRecordListWidget] failed to load objects:', e)\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.total = 0\n\t\t\t\tthis.error = true\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.emitHeader()\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-record-list__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-record-list__empty,\n.cn-record-list__error {\n\tcolor: var(--color-text-maxcontrast);\n\tmargin: 0;\n}\n\n.cn-record-list__loading {\n\tdisplay: flex;\n\tjustify-content: center;\n\tpadding: 8px 0;\n}\n\n/* rows */\n.cn-record-list--rows .cn-record-list__item + .cn-record-list__item {\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-record-list__row {\n\talign-items: center;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tgap: 16px;\n\tpadding: 12px 0;\n\ttext-decoration: none;\n}\n\n.cn-record-list__row--link:hover .cn-record-list__title,\n.cn-record-list__row--link:focus-visible .cn-record-list__title {\n\ttext-decoration: underline;\n}\n\n.cn-record-list__main {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-record-list__title {\n\tfont-size: 15px;\n\tfont-weight: 700;\n}\n\n.cn-record-list__meta {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-record-list__aside {\n\talign-items: center;\n\tdisplay: flex;\n\tflex: none;\n\tgap: 16px;\n}\n\n.cn-record-list__trailing {\n\tfont-size: 14px;\n\twhite-space: nowrap;\n}\n\n.cn-record-list__chevron {\n\tcolor: var(--color-text-maxcontrast);\n\tflex: none;\n}\n\n/* feed */\n.cn-record-list--feed .cn-record-list__item + .cn-record-list__item {\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-record-list__feed-row {\n\talign-items: flex-start;\n\tdisplay: flex;\n\tgap: 14px;\n\tpadding: 12px 0;\n}\n\n.cn-record-list__feed-icon {\n\talign-items: center;\n\tbackground: var(--color-primary-element-light);\n\tborder-radius: 50%;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n\tdisplay: flex;\n\tflex: none;\n\theight: 36px;\n\tjustify-content: center;\n\twidth: 36px;\n}\n\n.cn-record-list__text {\n\tfont-size: 15px;\n}\n\n.cn-record-list--feed .cn-record-list__main {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n/* inline */\n.cn-record-list__inline-row {\n\tpadding: 4px 0;\n}\n\n.cn-record-list__label {\n\tmargin-inline-end: 4px;\n}\n\n.cn-record-list__inline-title {\n\tcolor: var(--color-main-text);\n}\n\na.cn-record-list__inline-title {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: underline;\n}\n</style>\n\n<style>\n/* In a narrow side column a row stacks: title, meta, then pill and date. */\n.cn-detail-page__side .cn-record-list__row {\n\talign-items: flex-start;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-detail-page__side .cn-record-list__row .cn-record-list__title {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: underline;\n}\n\n.cn-detail-page__side .cn-record-list__chevron {\n\tdisplay: none;\n}\n</style>\n"],"names":["_normalizeClass","_createElementBlock","_toDisplayString","_openBlock","_createVNode","_createBlock","_resolveDynamicComponent","_mergeProps","_createElementVNode","_createTextVNode"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import __sfc_main from './CnRecordListWidget.vue.js';
2
+ import { registerDashboardWidget } from '../CnWidgetGrid/dashboardWidgetRegistry.js';
3
+
4
+ /**
5
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
6
+ * SPDX-License-Identifier: EUPL-1.2
7
+ *
8
+ * CnRecordListWidget — self-registers the `record-list` widget type (the
9
+ * objects of another schema that point at this record, as board rows, a feed
10
+ * or inline links) into the shared dashboardWidgetRegistry at module load.
11
+ * Renderer only: the list is declared in the manifest.
12
+ */
13
+
14
+
15
+ registerDashboardWidget('record-list', {
16
+ renderer: __sfc_main,
17
+ form: null,
18
+ defaultContent: {
19
+ register: '',
20
+ schema: '',
21
+ filter: {},
22
+ presentation: 'rows',
23
+ limit: 5,
24
+ },
25
+ displayName: 'Record list',
26
+ icon: 'FormatListBulleted',
27
+ surfaces: ['detail-page', 'app-dashboard'],
28
+ });
29
+
30
+ export { __sfc_main as CnRecordListWidget, __sfc_main as default };
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../../src/components/CnRecordListWidget/index.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * CnRecordListWidget — self-registers the `record-list` widget type (the\n * objects of another schema that point at this record, as board rows, a feed\n * or inline links) into the shared dashboardWidgetRegistry at module load.\n * Renderer only: the list is declared in the manifest.\n */\n\nimport CnRecordListWidget from './CnRecordListWidget.vue'\nimport { registerDashboardWidget } from '../CnWidgetGrid/dashboardWidgetRegistry.js'\n\nregisterDashboardWidget('record-list', {\n\trenderer: CnRecordListWidget,\n\tform: null,\n\tdefaultContent: {\n\t\tregister: '',\n\t\tschema: '',\n\t\tfilter: {},\n\t\tpresentation: 'rows',\n\t\tlimit: 5,\n\t},\n\tdisplayName: 'Record list',\n\ticon: 'FormatListBulleted',\n\tsurfaces: ['detail-page', 'app-dashboard'],\n})\n\nexport { CnRecordListWidget }\nexport default CnRecordListWidget\n"],"names":["CnRecordListWidget"],"mappings":";;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA,uBAAuB,CAAC,aAAa,EAAE;AACvC,CAAC,QAAQ,EAAEA,UAAkB;AAC7B,CAAC,IAAI,EAAE,IAAI;AACX,CAAC,cAAc,EAAE;AACjB,EAAE,QAAQ,EAAE,EAAE;AACd,EAAE,MAAM,EAAE,EAAE;AACZ,EAAE,MAAM,EAAE,EAAE;AACZ,EAAE,YAAY,EAAE,MAAM;AACtB,EAAE,KAAK,EAAE,CAAC;AACV,EAAE;AACF,CAAC,WAAW,EAAE,aAAa;AAC3B,CAAC,IAAI,EAAE,oBAAoB;AAC3B,CAAC,QAAQ,EAAE,CAAC,aAAa,EAAE,eAAe,CAAC;AAC3C,CAAC;;;;"}
@@ -0,0 +1,10 @@
1
+ import script from './CnSectionsWidget.vue2.js';
2
+ import { render } from './CnSectionsWidget.vue3.js';
3
+
4
+ script.render = render;
5
+ script.__scopeId = "data-v-ea4f8722";
6
+ script.__file = "src/components/CnSectionsWidget/CnSectionsWidget.vue";
7
+ const __sfc_main = script;
8
+
9
+ export { __sfc_main as default };
10
+ //# sourceMappingURL=CnSectionsWidget.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnSectionsWidget.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
@@ -0,0 +1,351 @@
1
+ import __sfc_main from '../CnDetailWidgetHost/CnDetailWidgetHost.vue.js';
2
+
3
+ /** Counter for unique heading ids across instances. */
4
+ let instanceCounter = 0;
5
+
6
+ /**
7
+ * CnSectionsWidget — the `sections` widget: several widgets in one place,
8
+ * each under its own heading.
9
+ *
10
+ * A tab strip binds one widget per tab, and a tab often holds more than one
11
+ * thing: the documents list and the case folder (DqZaak), a portal's details
12
+ * form, house style and sign-in (PtPortalInstellingen). This widget stacks
13
+ * them as sections under headings with a rule between them (the default), or
14
+ * as one card per section (`cards: true`), optionally in a main and a side
15
+ * column (`column: "side"` on a section). A single column of separate titled
16
+ * cards in a tab is the tabs widget's own `widgetIds` stack; this widget is
17
+ * for headed sections, and for the two-column card grid a settings tab draws.
18
+ *
19
+ * ```json
20
+ * {
21
+ * "type": "sections",
22
+ * "content": {
23
+ * "sections": [
24
+ * { "title": "Documenten", "widgetId": "case-documents" },
25
+ * { "title": "Zaakmap", "widget": { "type": "files" } }
26
+ * ]
27
+ * }
28
+ * }
29
+ * ```
30
+ *
31
+ * A section names its widget inline (`widget`) or by id (`widgetId`, a
32
+ * sibling definition on the same surface). Children render through
33
+ * `CnDetailWidgetHost` in bare mode, the dispatch a tab panel uses, so a child
34
+ * behaves here as it does in a tab. A section whose widget draws nothing
35
+ * shows no heading and takes no space (`hideEmpty`, default true). Stacked
36
+ * children share one cell, so an object list in a section renders every
37
+ * fetched row (`content.fit: false`) unless its definition says otherwise.
38
+ *
39
+ * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md
40
+ */
41
+ var script = {
42
+ name: 'CnSectionsWidget',
43
+
44
+ components: { CnDetailWidgetHost: __sfc_main },
45
+
46
+ inject: {
47
+ cnTranslate: { default: () => (key) => key },
48
+ },
49
+
50
+ props: {
51
+ /**
52
+ * The widget configuration.
53
+ *
54
+ * - `sections` — `[{ key?, title?, description?, column?, widget? | widgetId? }]`, in order.
55
+ * `label` is accepted as an alias of `title`; `column` is `main` (default) or `side`.
56
+ * - `cards` — draw each section as its own card (default false: headings and a rule between sections).
57
+ * - `hideEmpty` — hide the heading and the space of a section whose widget drew nothing (default true).
58
+ *
59
+ * @type {{sections?: Array<object>, cards?: boolean, hideEmpty?: boolean}}
60
+ */
61
+ content: {
62
+ type: Object,
63
+ default: () => ({}),
64
+ },
65
+
66
+ /** Sibling widget definitions on the surface, for `widgetId` sections. */
67
+ availableWidgets: {
68
+ type: Array,
69
+ default: () => [],
70
+ },
71
+
72
+ /** The bound record's id. */
73
+ objectId: {
74
+ type: [String, Number],
75
+ default: '',
76
+ },
77
+
78
+ /** The loaded record, or null while it is still being fetched. */
79
+ objectData: {
80
+ type: Object,
81
+ default: null,
82
+ },
83
+
84
+ /** The resolved object-type slug. */
85
+ objectType: {
86
+ type: String,
87
+ default: '',
88
+ },
89
+
90
+ /** The resolved JSON Schema object, needed by a `data` child. */
91
+ schemaObject: {
92
+ type: Object,
93
+ default: null,
94
+ },
95
+
96
+ /** OpenRegister register slug of the surface. */
97
+ register: {
98
+ type: [String, Object],
99
+ default: '',
100
+ },
101
+
102
+ /** OpenRegister schema slug of the surface. */
103
+ schema: {
104
+ type: [String, Object],
105
+ default: '',
106
+ },
107
+
108
+ /** The effective object store. */
109
+ store: {
110
+ type: Object,
111
+ default: null,
112
+ },
113
+
114
+ /** Rendering surface forwarded to the children. */
115
+ surface: {
116
+ type: String,
117
+ default: 'detail-page',
118
+ },
119
+
120
+ /** Object context forwarded to integration children. */
121
+ integrationContext: {
122
+ type: Object,
123
+ default: null,
124
+ },
125
+
126
+ /** The consumer's component registry, for custom child widget types. */
127
+ cnRegistry: {
128
+ type: Object,
129
+ default: () => ({}),
130
+ },
131
+ },
132
+
133
+ data() {
134
+ instanceCounter += 1;
135
+ return {
136
+ uid: instanceCounter,
137
+ /**
138
+ * Section key to "has this section rendered anything".
139
+ *
140
+ * @type {Record<string, boolean>}
141
+ */
142
+ filled: {},
143
+ }
144
+ },
145
+
146
+ computed: {
147
+ /**
148
+ * Whether each section is its own card.
149
+ *
150
+ * @return {boolean}
151
+ */
152
+ cards() {
153
+ return this.content?.cards === true
154
+ },
155
+
156
+ /**
157
+ * Whether an empty section hides.
158
+ *
159
+ * @return {boolean}
160
+ */
161
+ hideEmpty() {
162
+ return this.content?.hideEmpty !== false
163
+ },
164
+
165
+ /**
166
+ * The sections to render: a stable key, a translated title, the column
167
+ * and the widget definition. A section whose widget cannot be found is
168
+ * dropped (with a development warning for an unknown id).
169
+ *
170
+ * @return {Array<{key: string, title: string, description: string, column: string, widget: object}>}
171
+ * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md#requirement-a-sections-widget-stacks-configured-widgets-under-headings
172
+ */
173
+ sections() {
174
+ const raw = Array.isArray(this.content?.sections) ? this.content.sections : [];
175
+ const out = [];
176
+ raw.forEach((entry, index) => {
177
+ if (!entry || typeof entry !== 'object') {
178
+ return
179
+ }
180
+ let widget = entry.widget && typeof entry.widget === 'object' ? entry.widget : null;
181
+ if (!widget && typeof entry.widgetId === 'string' && entry.widgetId !== '') {
182
+ widget = this.availableWidgets.find((w) => w && w.id === entry.widgetId) || null;
183
+ if (!widget) {
184
+ // eslint-disable-next-line no-console
185
+ console.warn(`[CnSectionsWidget] section widgetId "${entry.widgetId}" names no widget on this surface; section skipped.`);
186
+ }
187
+ }
188
+ if (!widget || !widget.type) {
189
+ return
190
+ }
191
+ out.push({
192
+ key: String(entry.key || widget.id || entry.widgetId || `${widget.type}-${index}`),
193
+ title: this.tr(entry.title || entry.label || ''),
194
+ description: this.tr(entry.description || ''),
195
+ column: entry.column === 'side' ? 'side' : 'main',
196
+ widget: this.shared(widget),
197
+ });
198
+ });
199
+ return out
200
+ },
201
+
202
+ /**
203
+ * Whether any section sits in the side column.
204
+ *
205
+ * @return {boolean}
206
+ */
207
+ twoColumn() {
208
+ return this.sections.some((section) => section.column === 'side')
209
+ },
210
+
211
+ /**
212
+ * The columns to draw, each with its sections in order.
213
+ *
214
+ * @return {Array<{id: string, sections: Array<object>}>}
215
+ * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md#requirement-a-sections-widget-can-draw-cards-in-a-main-and-a-side-column
216
+ */
217
+ columns() {
218
+ if (!this.twoColumn) {
219
+ return [{ id: 'main', sections: this.sections }]
220
+ }
221
+ return [
222
+ { id: 'main', sections: this.sections.filter((section) => section.column === 'main') },
223
+ { id: 'side', sections: this.sections.filter((section) => section.column === 'side') },
224
+ ]
225
+ },
226
+ },
227
+
228
+ beforeUnmount() {
229
+ this.stopObserving();
230
+ },
231
+
232
+ methods: {
233
+ /**
234
+ * Translate through the host app.
235
+ *
236
+ * @param {string} text The text.
237
+ * @return {string}
238
+ */
239
+ tr(text) {
240
+ if (typeof text !== 'string' || text === '') {
241
+ return ''
242
+ }
243
+ return typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text
244
+ },
245
+
246
+ /**
247
+ * The heading id of a section.
248
+ *
249
+ * @param {string} key The section key.
250
+ * @return {string}
251
+ */
252
+ headingId(key) {
253
+ return `cn-sections-${this.uid}-${key}`.replace(/[^\w-]/g, '-')
254
+ },
255
+
256
+ /**
257
+ * A child definition with the cell budget off: stacked children share
258
+ * one cell, so an object list must not size itself to that cell.
259
+ *
260
+ * @param {object} widget The definition.
261
+ * @return {object}
262
+ */
263
+ shared(widget) {
264
+ const content = widget.content || {};
265
+ if (Object.hasOwn(content, 'fit')) {
266
+ return widget
267
+ }
268
+ return { ...widget, content: { ...content, fit: false } }
269
+ },
270
+
271
+ /**
272
+ * Whether a section shows its heading and takes space.
273
+ *
274
+ * @param {string} key The section key.
275
+ * @return {boolean}
276
+ * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md#requirement-a-section-whose-widget-draws-nothing-stays-silent
277
+ */
278
+ isShown(key) {
279
+ return !this.hideEmpty || this.filled[key] === true
280
+ },
281
+
282
+ /**
283
+ * Watch one section's host for content, so its heading appears when
284
+ * the widget renders and stays away when it never does. A
285
+ * MutationObserver, because most widgets mount empty and fill after a
286
+ * fetch.
287
+ *
288
+ * @param {string} key The section key.
289
+ * @param {HTMLElement|null} el The host wrapper, or null on teardown.
290
+ * @return {void}
291
+ */
292
+ setHostRef(key, el) {
293
+ this.observers = this.observers || {};
294
+ if (this.observers[key]) {
295
+ this.observers[key].disconnect();
296
+ delete this.observers[key];
297
+ }
298
+ if (!el) {
299
+ return
300
+ }
301
+ // Assign only on a change: `filled` drives the template, so an
302
+ // unconditional write re-renders, mutates, and fires again.
303
+ const measure = () => {
304
+ const next = this.hasContent(el);
305
+ if (this.filled[key] === next) {
306
+ return
307
+ }
308
+ this.filled = { ...this.filled, [key]: next };
309
+ };
310
+ if (typeof MutationObserver === 'function') {
311
+ const observer = new MutationObserver(measure);
312
+ observer.observe(el, { childList: true, subtree: true, characterData: true });
313
+ this.observers[key] = observer;
314
+ }
315
+ // Not synchronously: a ref callback runs during the patch.
316
+ this.$nextTick(measure);
317
+ },
318
+
319
+ /**
320
+ * Whether a host rendered anything a reader would see: text (an empty
321
+ * state counts), or a graphical or interactive element.
322
+ *
323
+ * @param {HTMLElement} el The host wrapper.
324
+ * @return {boolean}
325
+ */
326
+ hasContent(el) {
327
+ if (!el) {
328
+ return false
329
+ }
330
+ if (el.textContent && el.textContent.trim().length > 0) {
331
+ return true
332
+ }
333
+ return el.querySelector('img, svg, canvas, table, input, button, select, textarea') !== null
334
+ },
335
+
336
+ /**
337
+ * Drop every observer.
338
+ *
339
+ * @return {void}
340
+ */
341
+ stopObserving() {
342
+ for (const observer of Object.values(this.observers || {})) {
343
+ observer.disconnect();
344
+ }
345
+ this.observers = {};
346
+ },
347
+ },
348
+ };
349
+
350
+ export { script as default };
351
+ //# sourceMappingURL=CnSectionsWidget.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnSectionsWidget.vue2.js","sources":["../../../../src/components/CnSectionsWidget/CnSectionsWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tclass=\"cn-sections-widget\"\n\t\t:class=\"{\n\t\t\t'cn-sections-widget--cards': cards,\n\t\t\t'cn-sections-widget--two-column': twoColumn,\n\t\t}\"\n\t\tdata-testid=\"cn-sections-widget\">\n\t\t<div\n\t\t\tv-for=\"column in columns\"\n\t\t\t:key=\"column.id\"\n\t\t\tclass=\"cn-sections-widget__column\"\n\t\t\t:class=\"`cn-sections-widget__column--${column.id}`\">\n\t\t\t<section\n\t\t\t\tv-for=\"section in column.sections\"\n\t\t\t\t:key=\"section.key\"\n\t\t\t\tclass=\"cn-sections-widget__section\"\n\t\t\t\t:class=\"{ 'cn-sections-widget__section--empty': !isShown(section.key) }\"\n\t\t\t\t:aria-labelledby=\"section.title && isShown(section.key) ? headingId(section.key) : undefined\"\n\t\t\t\t:data-testid=\"`cn-section-${section.key}`\">\n\t\t\t\t<!-- The heading waits for content: a widget type that does not\n\t\t\t\t resolve renders nothing, and a heading over nothing is a\n\t\t\t\t label on a void. -->\n\t\t\t\t<h3\n\t\t\t\t\tv-if=\"section.title && isShown(section.key)\"\n\t\t\t\t\t:id=\"headingId(section.key)\"\n\t\t\t\t\tclass=\"cn-sections-widget__heading\">\n\t\t\t\t\t{{ section.title }}\n\t\t\t\t</h3>\n\t\t\t\t<p\n\t\t\t\t\tv-if=\"section.description && isShown(section.key)\"\n\t\t\t\t\tclass=\"cn-sections-widget__description\">\n\t\t\t\t\t{{ section.description }}\n\t\t\t\t</p>\n\t\t\t\t<!-- The host always mounts, also while the section reads as\n\t\t\t\t empty: a widget that has not mounted cannot fetch, so it\n\t\t\t\t could never gain the content that would show it. -->\n\t\t\t\t<div :ref=\"(el) => setHostRef(section.key, el)\" class=\"cn-sections-widget__body\">\n\t\t\t\t\t<CnDetailWidgetHost\n\t\t\t\t\t\t:widget=\"section.widget\"\n\t\t\t\t\t\tchrome=\"bare\"\n\t\t\t\t\t\t:objectId=\"objectId\"\n\t\t\t\t\t\t:object=\"objectData\"\n\t\t\t\t\t\t:objectType=\"objectType\"\n\t\t\t\t\t\t:schemaObject=\"schemaObject\"\n\t\t\t\t\t\t:register=\"register\"\n\t\t\t\t\t\t:schema=\"schema\"\n\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t:surface=\"surface\"\n\t\t\t\t\t\t:integrationContext=\"integrationContext\"\n\t\t\t\t\t\t:cnRegistry=\"cnRegistry\"\n\t\t\t\t\t\t:availableWidgets=\"availableWidgets\" />\n\t\t\t\t</div>\n\t\t\t</section>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport CnDetailWidgetHost from '../CnDetailWidgetHost/CnDetailWidgetHost.vue'\n\n/** Counter for unique heading ids across instances. */\nlet instanceCounter = 0\n\n/**\n * CnSectionsWidget — the `sections` widget: several widgets in one place,\n * each under its own heading.\n *\n * A tab strip binds one widget per tab, and a tab often holds more than one\n * thing: the documents list and the case folder (DqZaak), a portal's details\n * form, house style and sign-in (PtPortalInstellingen). This widget stacks\n * them as sections under headings with a rule between them (the default), or\n * as one card per section (`cards: true`), optionally in a main and a side\n * column (`column: \"side\"` on a section). A single column of separate titled\n * cards in a tab is the tabs widget's own `widgetIds` stack; this widget is\n * for headed sections, and for the two-column card grid a settings tab draws.\n *\n * ```json\n * {\n * \"type\": \"sections\",\n * \"content\": {\n * \"sections\": [\n * { \"title\": \"Documenten\", \"widgetId\": \"case-documents\" },\n * { \"title\": \"Zaakmap\", \"widget\": { \"type\": \"files\" } }\n * ]\n * }\n * }\n * ```\n *\n * A section names its widget inline (`widget`) or by id (`widgetId`, a\n * sibling definition on the same surface). Children render through\n * `CnDetailWidgetHost` in bare mode, the dispatch a tab panel uses, so a child\n * behaves here as it does in a tab. A section whose widget draws nothing\n * shows no heading and takes no space (`hideEmpty`, default true). Stacked\n * children share one cell, so an object list in a section renders every\n * fetched row (`content.fit: false`) unless its definition says otherwise.\n *\n * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md\n */\nexport default {\n\tname: 'CnSectionsWidget',\n\n\tcomponents: { CnDetailWidgetHost },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `sections` — `[{ key?, title?, description?, column?, widget? | widgetId? }]`, in order.\n\t\t * `label` is accepted as an alias of `title`; `column` is `main` (default) or `side`.\n\t\t * - `cards` — draw each section as its own card (default false: headings and a rule between sections).\n\t\t * - `hideEmpty` — hide the heading and the space of a section whose widget drew nothing (default true).\n\t\t *\n\t\t * @type {{sections?: Array<object>, cards?: boolean, hideEmpty?: boolean}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Sibling widget definitions on the surface, for `widgetId` sections. */\n\t\tavailableWidgets: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** The bound record's id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The loaded record, or null while it is still being fetched. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The resolved object-type slug. */\n\t\tobjectType: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The resolved JSON Schema object, needed by a `data` child. */\n\t\tschemaObject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The effective object store. */\n\t\tstore: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Rendering surface forwarded to the children. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t},\n\n\t\t/** Object context forwarded to integration children. */\n\t\tintegrationContext: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The consumer's component registry, for custom child widget types. */\n\t\tcnRegistry: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\tdata() {\n\t\tinstanceCounter += 1\n\t\treturn {\n\t\t\tuid: instanceCounter,\n\t\t\t/**\n\t\t\t * Section key to \"has this section rendered anything\".\n\t\t\t *\n\t\t\t * @type {Record<string, boolean>}\n\t\t\t */\n\t\t\tfilled: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether each section is its own card.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tcards() {\n\t\t\treturn this.content?.cards === true\n\t\t},\n\n\t\t/**\n\t\t * Whether an empty section hides.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thideEmpty() {\n\t\t\treturn this.content?.hideEmpty !== false\n\t\t},\n\n\t\t/**\n\t\t * The sections to render: a stable key, a translated title, the column\n\t\t * and the widget definition. A section whose widget cannot be found is\n\t\t * dropped (with a development warning for an unknown id).\n\t\t *\n\t\t * @return {Array<{key: string, title: string, description: string, column: string, widget: object}>}\n\t\t * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md#requirement-a-sections-widget-stacks-configured-widgets-under-headings\n\t\t */\n\t\tsections() {\n\t\t\tconst raw = Array.isArray(this.content?.sections) ? this.content.sections : []\n\t\t\tconst out = []\n\t\t\traw.forEach((entry, index) => {\n\t\t\t\tif (!entry || typeof entry !== 'object') {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlet widget = entry.widget && typeof entry.widget === 'object' ? entry.widget : null\n\t\t\t\tif (!widget && typeof entry.widgetId === 'string' && entry.widgetId !== '') {\n\t\t\t\t\twidget = this.availableWidgets.find((w) => w && w.id === entry.widgetId) || null\n\t\t\t\t\tif (!widget) {\n\t\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\t\tconsole.warn(`[CnSectionsWidget] section widgetId \"${entry.widgetId}\" names no widget on this surface; section skipped.`)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!widget || !widget.type) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tout.push({\n\t\t\t\t\tkey: String(entry.key || widget.id || entry.widgetId || `${widget.type}-${index}`),\n\t\t\t\t\ttitle: this.tr(entry.title || entry.label || ''),\n\t\t\t\t\tdescription: this.tr(entry.description || ''),\n\t\t\t\t\tcolumn: entry.column === 'side' ? 'side' : 'main',\n\t\t\t\t\twidget: this.shared(widget),\n\t\t\t\t})\n\t\t\t})\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Whether any section sits in the side column.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\ttwoColumn() {\n\t\t\treturn this.sections.some((section) => section.column === 'side')\n\t\t},\n\n\t\t/**\n\t\t * The columns to draw, each with its sections in order.\n\t\t *\n\t\t * @return {Array<{id: string, sections: Array<object>}>}\n\t\t * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md#requirement-a-sections-widget-can-draw-cards-in-a-main-and-a-side-column\n\t\t */\n\t\tcolumns() {\n\t\t\tif (!this.twoColumn) {\n\t\t\t\treturn [{ id: 'main', sections: this.sections }]\n\t\t\t}\n\t\t\treturn [\n\t\t\t\t{ id: 'main', sections: this.sections.filter((section) => section.column === 'main') },\n\t\t\t\t{ id: 'side', sections: this.sections.filter((section) => section.column === 'side') },\n\t\t\t]\n\t\t},\n\t},\n\n\tbeforeUnmount() {\n\t\tthis.stopObserving()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Translate through the host app.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string}\n\t\t */\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The heading id of a section.\n\t\t *\n\t\t * @param {string} key The section key.\n\t\t * @return {string}\n\t\t */\n\t\theadingId(key) {\n\t\t\treturn `cn-sections-${this.uid}-${key}`.replace(/[^\\w-]/g, '-')\n\t\t},\n\n\t\t/**\n\t\t * A child definition with the cell budget off: stacked children share\n\t\t * one cell, so an object list must not size itself to that cell.\n\t\t *\n\t\t * @param {object} widget The definition.\n\t\t * @return {object}\n\t\t */\n\t\tshared(widget) {\n\t\t\tconst content = widget.content || {}\n\t\t\tif (Object.hasOwn(content, 'fit')) {\n\t\t\t\treturn widget\n\t\t\t}\n\t\t\treturn { ...widget, content: { ...content, fit: false } }\n\t\t},\n\n\t\t/**\n\t\t * Whether a section shows its heading and takes space.\n\t\t *\n\t\t * @param {string} key The section key.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md#requirement-a-section-whose-widget-draws-nothing-stays-silent\n\t\t */\n\t\tisShown(key) {\n\t\t\treturn !this.hideEmpty || this.filled[key] === true\n\t\t},\n\n\t\t/**\n\t\t * Watch one section's host for content, so its heading appears when\n\t\t * the widget renders and stays away when it never does. A\n\t\t * MutationObserver, because most widgets mount empty and fill after a\n\t\t * fetch.\n\t\t *\n\t\t * @param {string} key The section key.\n\t\t * @param {HTMLElement|null} el The host wrapper, or null on teardown.\n\t\t * @return {void}\n\t\t */\n\t\tsetHostRef(key, el) {\n\t\t\tthis.observers = this.observers || {}\n\t\t\tif (this.observers[key]) {\n\t\t\t\tthis.observers[key].disconnect()\n\t\t\t\tdelete this.observers[key]\n\t\t\t}\n\t\t\tif (!el) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Assign only on a change: `filled` drives the template, so an\n\t\t\t// unconditional write re-renders, mutates, and fires again.\n\t\t\tconst measure = () => {\n\t\t\t\tconst next = this.hasContent(el)\n\t\t\t\tif (this.filled[key] === next) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.filled = { ...this.filled, [key]: next }\n\t\t\t}\n\t\t\tif (typeof MutationObserver === 'function') {\n\t\t\t\tconst observer = new MutationObserver(measure)\n\t\t\t\tobserver.observe(el, { childList: true, subtree: true, characterData: true })\n\t\t\t\tthis.observers[key] = observer\n\t\t\t}\n\t\t\t// Not synchronously: a ref callback runs during the patch.\n\t\t\tthis.$nextTick(measure)\n\t\t},\n\n\t\t/**\n\t\t * Whether a host rendered anything a reader would see: text (an empty\n\t\t * state counts), or a graphical or interactive element.\n\t\t *\n\t\t * @param {HTMLElement} el The host wrapper.\n\t\t * @return {boolean}\n\t\t */\n\t\thasContent(el) {\n\t\t\tif (!el) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif (el.textContent && el.textContent.trim().length > 0) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn el.querySelector('img, svg, canvas, table, input, button, select, textarea') !== null\n\t\t},\n\n\t\t/**\n\t\t * Drop every observer.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tstopObserving() {\n\t\t\tfor (const observer of Object.values(this.observers || {})) {\n\t\t\t\tobserver.disconnect()\n\t\t\t}\n\t\t\tthis.observers = {}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sections-widget {\n\tmin-width: 0;\n}\n\n.cn-sections-widget__column {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(var(--default-grid-baseline, 4px) * 4);\n\tmin-width: 0;\n}\n\n/* A main and a side column (the settings boards: 1fr and 418px, 20px apart). */\n.cn-sections-widget--two-column {\n\tdisplay: grid;\n\tgrid-template-columns: minmax(0, 1fr) minmax(280px, 418px);\n\tgap: 20px;\n\talign-items: start;\n}\n\n@media (max-width: 1024px) {\n\t.cn-sections-widget--two-column {\n\t\tgrid-template-columns: minmax(0, 1fr);\n\t}\n}\n\n/* A host page may space every <section>; these sections are spaced by the column gap only. */\n.cn-sections-widget__section {\n\tmargin: 0;\n\tmin-width: 0;\n}\n\n/* A rule above a section that follows a shown one. */\n.cn-sections-widget:not(.cn-sections-widget--cards) .cn-sections-widget__section:not(.cn-sections-widget__section--empty) ~ .cn-sections-widget__section {\n\tpadding-top: calc(var(--default-grid-baseline, 4px) * 4);\n\tborder-top: 1px solid var(--color-border);\n}\n\n/*\n * An empty section keeps its host mounted (display: none still mounts it, so\n * the widget fetches and can fill later) but takes no space, gap or rule.\n */\n.cn-sections-widget__section--empty {\n\tdisplay: none;\n}\n\n.cn-sections-widget__heading {\n\tmargin: 0 0 calc(var(--default-grid-baseline, 4px) * 2);\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-sections-widget__description {\n\tmargin: calc(var(--default-grid-baseline, 4px) * -1) 0 calc(var(--default-grid-baseline, 4px) * 3);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* One card per section. */\n.cn-sections-widget--cards .cn-sections-widget__column {\n\tgap: 20px;\n}\n\n.cn-sections-widget--cards .cn-sections-widget__section {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--cn-board-card-radius, var(--border-radius-large, 12px));\n\tpadding: var(--cn-board-card-padding, 16px 20px);\n}\n\n.cn-sections-widget--cards .cn-sections-widget__heading {\n\tfont-size: 18px;\n\tmargin-bottom: 12px;\n}\n</style>\n"],"names":["CnDetailWidgetHost"],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { resolveComponent, openBlock, createElementBlock, normalizeClass, Fragment, renderList, toDisplayString, createCommentVNode, createElementVNode, createVNode } from 'vue';
2
+
3
+ const _hoisted_1 = ["aria-labelledby", "data-testid"];
4
+ const _hoisted_2 = ["id"];
5
+ const _hoisted_3 = {
6
+ key: 1,
7
+ class: "cn-sections-widget__description"
8
+ };
9
+
10
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
11
+ const _component_CnDetailWidgetHost = resolveComponent("CnDetailWidgetHost");
12
+
13
+ return (openBlock(), createElementBlock("div", {
14
+ class: normalizeClass(["cn-sections-widget", {
15
+ 'cn-sections-widget--cards': $options.cards,
16
+ 'cn-sections-widget--two-column': $options.twoColumn,
17
+ }]),
18
+ "data-testid": "cn-sections-widget"
19
+ }, [
20
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.columns, (column) => {
21
+ return (openBlock(), createElementBlock("div", {
22
+ key: column.id,
23
+ class: normalizeClass(["cn-sections-widget__column", `cn-sections-widget__column--${column.id}`])
24
+ }, [
25
+ (openBlock(true), createElementBlock(Fragment, null, renderList(column.sections, (section) => {
26
+ return (openBlock(), createElementBlock("section", {
27
+ key: section.key,
28
+ class: normalizeClass(["cn-sections-widget__section", { 'cn-sections-widget__section--empty': !$options.isShown(section.key) }]),
29
+ "aria-labelledby": section.title && $options.isShown(section.key) ? $options.headingId(section.key) : undefined,
30
+ "data-testid": `cn-section-${section.key}`
31
+ }, [
32
+ (section.title && $options.isShown(section.key))
33
+ ? (openBlock(), createElementBlock("h3", {
34
+ key: 0,
35
+ id: $options.headingId(section.key),
36
+ class: "cn-sections-widget__heading"
37
+ }, toDisplayString(section.title), 9 /* TEXT, PROPS */, _hoisted_2))
38
+ : createCommentVNode("v-if", true),
39
+ (section.description && $options.isShown(section.key))
40
+ ? (openBlock(), createElementBlock("p", _hoisted_3, toDisplayString(section.description), 1 /* TEXT */))
41
+ : createCommentVNode("v-if", true),
42
+ createElementVNode("div", {
43
+ ref_for: true,
44
+ ref: (el) => $options.setHostRef(section.key, el),
45
+ class: "cn-sections-widget__body"
46
+ }, [
47
+ createVNode(_component_CnDetailWidgetHost, {
48
+ widget: section.widget,
49
+ chrome: "bare",
50
+ objectId: $props.objectId,
51
+ object: $props.objectData,
52
+ objectType: $props.objectType,
53
+ schemaObject: $props.schemaObject,
54
+ register: $props.register,
55
+ schema: $props.schema,
56
+ store: $props.store,
57
+ surface: $props.surface,
58
+ integrationContext: $props.integrationContext,
59
+ cnRegistry: $props.cnRegistry,
60
+ availableWidgets: $props.availableWidgets
61
+ }, null, 8 /* PROPS */, ["widget", "objectId", "object", "objectType", "schemaObject", "register", "schema", "store", "surface", "integrationContext", "cnRegistry", "availableWidgets"])
62
+ ], 512 /* NEED_PATCH */)
63
+ ], 10 /* CLASS, PROPS */, _hoisted_1))
64
+ }), 128 /* KEYED_FRAGMENT */))
65
+ ], 2 /* CLASS */))
66
+ }), 128 /* KEYED_FRAGMENT */))
67
+ ], 2 /* CLASS */))
68
+ }
69
+
70
+ export { render };
71
+ //# sourceMappingURL=CnSectionsWidget.vue3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnSectionsWidget.vue3.js","sources":["../../../../src/components/CnSectionsWidget/CnSectionsWidget.vue?vue&type=template&id=ea4f8722&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tclass=\"cn-sections-widget\"\n\t\t:class=\"{\n\t\t\t'cn-sections-widget--cards': cards,\n\t\t\t'cn-sections-widget--two-column': twoColumn,\n\t\t}\"\n\t\tdata-testid=\"cn-sections-widget\">\n\t\t<div\n\t\t\tv-for=\"column in columns\"\n\t\t\t:key=\"column.id\"\n\t\t\tclass=\"cn-sections-widget__column\"\n\t\t\t:class=\"`cn-sections-widget__column--${column.id}`\">\n\t\t\t<section\n\t\t\t\tv-for=\"section in column.sections\"\n\t\t\t\t:key=\"section.key\"\n\t\t\t\tclass=\"cn-sections-widget__section\"\n\t\t\t\t:class=\"{ 'cn-sections-widget__section--empty': !isShown(section.key) }\"\n\t\t\t\t:aria-labelledby=\"section.title && isShown(section.key) ? headingId(section.key) : undefined\"\n\t\t\t\t:data-testid=\"`cn-section-${section.key}`\">\n\t\t\t\t<!-- The heading waits for content: a widget type that does not\n\t\t\t\t resolve renders nothing, and a heading over nothing is a\n\t\t\t\t label on a void. -->\n\t\t\t\t<h3\n\t\t\t\t\tv-if=\"section.title && isShown(section.key)\"\n\t\t\t\t\t:id=\"headingId(section.key)\"\n\t\t\t\t\tclass=\"cn-sections-widget__heading\">\n\t\t\t\t\t{{ section.title }}\n\t\t\t\t</h3>\n\t\t\t\t<p\n\t\t\t\t\tv-if=\"section.description && isShown(section.key)\"\n\t\t\t\t\tclass=\"cn-sections-widget__description\">\n\t\t\t\t\t{{ section.description }}\n\t\t\t\t</p>\n\t\t\t\t<!-- The host always mounts, also while the section reads as\n\t\t\t\t empty: a widget that has not mounted cannot fetch, so it\n\t\t\t\t could never gain the content that would show it. -->\n\t\t\t\t<div :ref=\"(el) => setHostRef(section.key, el)\" class=\"cn-sections-widget__body\">\n\t\t\t\t\t<CnDetailWidgetHost\n\t\t\t\t\t\t:widget=\"section.widget\"\n\t\t\t\t\t\tchrome=\"bare\"\n\t\t\t\t\t\t:objectId=\"objectId\"\n\t\t\t\t\t\t:object=\"objectData\"\n\t\t\t\t\t\t:objectType=\"objectType\"\n\t\t\t\t\t\t:schemaObject=\"schemaObject\"\n\t\t\t\t\t\t:register=\"register\"\n\t\t\t\t\t\t:schema=\"schema\"\n\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t:surface=\"surface\"\n\t\t\t\t\t\t:integrationContext=\"integrationContext\"\n\t\t\t\t\t\t:cnRegistry=\"cnRegistry\"\n\t\t\t\t\t\t:availableWidgets=\"availableWidgets\" />\n\t\t\t\t</div>\n\t\t\t</section>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport CnDetailWidgetHost from '../CnDetailWidgetHost/CnDetailWidgetHost.vue'\n\n/** Counter for unique heading ids across instances. */\nlet instanceCounter = 0\n\n/**\n * CnSectionsWidget — the `sections` widget: several widgets in one place,\n * each under its own heading.\n *\n * A tab strip binds one widget per tab, and a tab often holds more than one\n * thing: the documents list and the case folder (DqZaak), a portal's details\n * form, house style and sign-in (PtPortalInstellingen). This widget stacks\n * them as sections under headings with a rule between them (the default), or\n * as one card per section (`cards: true`), optionally in a main and a side\n * column (`column: \"side\"` on a section). A single column of separate titled\n * cards in a tab is the tabs widget's own `widgetIds` stack; this widget is\n * for headed sections, and for the two-column card grid a settings tab draws.\n *\n * ```json\n * {\n * \"type\": \"sections\",\n * \"content\": {\n * \"sections\": [\n * { \"title\": \"Documenten\", \"widgetId\": \"case-documents\" },\n * { \"title\": \"Zaakmap\", \"widget\": { \"type\": \"files\" } }\n * ]\n * }\n * }\n * ```\n *\n * A section names its widget inline (`widget`) or by id (`widgetId`, a\n * sibling definition on the same surface). Children render through\n * `CnDetailWidgetHost` in bare mode, the dispatch a tab panel uses, so a child\n * behaves here as it does in a tab. A section whose widget draws nothing\n * shows no heading and takes no space (`hideEmpty`, default true). Stacked\n * children share one cell, so an object list in a section renders every\n * fetched row (`content.fit: false`) unless its definition says otherwise.\n *\n * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md\n */\nexport default {\n\tname: 'CnSectionsWidget',\n\n\tcomponents: { CnDetailWidgetHost },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `sections` — `[{ key?, title?, description?, column?, widget? | widgetId? }]`, in order.\n\t\t * `label` is accepted as an alias of `title`; `column` is `main` (default) or `side`.\n\t\t * - `cards` — draw each section as its own card (default false: headings and a rule between sections).\n\t\t * - `hideEmpty` — hide the heading and the space of a section whose widget drew nothing (default true).\n\t\t *\n\t\t * @type {{sections?: Array<object>, cards?: boolean, hideEmpty?: boolean}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Sibling widget definitions on the surface, for `widgetId` sections. */\n\t\tavailableWidgets: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** The bound record's id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The loaded record, or null while it is still being fetched. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The resolved object-type slug. */\n\t\tobjectType: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The resolved JSON Schema object, needed by a `data` child. */\n\t\tschemaObject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The effective object store. */\n\t\tstore: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Rendering surface forwarded to the children. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t},\n\n\t\t/** Object context forwarded to integration children. */\n\t\tintegrationContext: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The consumer's component registry, for custom child widget types. */\n\t\tcnRegistry: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\tdata() {\n\t\tinstanceCounter += 1\n\t\treturn {\n\t\t\tuid: instanceCounter,\n\t\t\t/**\n\t\t\t * Section key to \"has this section rendered anything\".\n\t\t\t *\n\t\t\t * @type {Record<string, boolean>}\n\t\t\t */\n\t\t\tfilled: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether each section is its own card.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tcards() {\n\t\t\treturn this.content?.cards === true\n\t\t},\n\n\t\t/**\n\t\t * Whether an empty section hides.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thideEmpty() {\n\t\t\treturn this.content?.hideEmpty !== false\n\t\t},\n\n\t\t/**\n\t\t * The sections to render: a stable key, a translated title, the column\n\t\t * and the widget definition. A section whose widget cannot be found is\n\t\t * dropped (with a development warning for an unknown id).\n\t\t *\n\t\t * @return {Array<{key: string, title: string, description: string, column: string, widget: object}>}\n\t\t * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md#requirement-a-sections-widget-stacks-configured-widgets-under-headings\n\t\t */\n\t\tsections() {\n\t\t\tconst raw = Array.isArray(this.content?.sections) ? this.content.sections : []\n\t\t\tconst out = []\n\t\t\traw.forEach((entry, index) => {\n\t\t\t\tif (!entry || typeof entry !== 'object') {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlet widget = entry.widget && typeof entry.widget === 'object' ? entry.widget : null\n\t\t\t\tif (!widget && typeof entry.widgetId === 'string' && entry.widgetId !== '') {\n\t\t\t\t\twidget = this.availableWidgets.find((w) => w && w.id === entry.widgetId) || null\n\t\t\t\t\tif (!widget) {\n\t\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\t\tconsole.warn(`[CnSectionsWidget] section widgetId \"${entry.widgetId}\" names no widget on this surface; section skipped.`)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!widget || !widget.type) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tout.push({\n\t\t\t\t\tkey: String(entry.key || widget.id || entry.widgetId || `${widget.type}-${index}`),\n\t\t\t\t\ttitle: this.tr(entry.title || entry.label || ''),\n\t\t\t\t\tdescription: this.tr(entry.description || ''),\n\t\t\t\t\tcolumn: entry.column === 'side' ? 'side' : 'main',\n\t\t\t\t\twidget: this.shared(widget),\n\t\t\t\t})\n\t\t\t})\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Whether any section sits in the side column.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\ttwoColumn() {\n\t\t\treturn this.sections.some((section) => section.column === 'side')\n\t\t},\n\n\t\t/**\n\t\t * The columns to draw, each with its sections in order.\n\t\t *\n\t\t * @return {Array<{id: string, sections: Array<object>}>}\n\t\t * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md#requirement-a-sections-widget-can-draw-cards-in-a-main-and-a-side-column\n\t\t */\n\t\tcolumns() {\n\t\t\tif (!this.twoColumn) {\n\t\t\t\treturn [{ id: 'main', sections: this.sections }]\n\t\t\t}\n\t\t\treturn [\n\t\t\t\t{ id: 'main', sections: this.sections.filter((section) => section.column === 'main') },\n\t\t\t\t{ id: 'side', sections: this.sections.filter((section) => section.column === 'side') },\n\t\t\t]\n\t\t},\n\t},\n\n\tbeforeUnmount() {\n\t\tthis.stopObserving()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Translate through the host app.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string}\n\t\t */\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The heading id of a section.\n\t\t *\n\t\t * @param {string} key The section key.\n\t\t * @return {string}\n\t\t */\n\t\theadingId(key) {\n\t\t\treturn `cn-sections-${this.uid}-${key}`.replace(/[^\\w-]/g, '-')\n\t\t},\n\n\t\t/**\n\t\t * A child definition with the cell budget off: stacked children share\n\t\t * one cell, so an object list must not size itself to that cell.\n\t\t *\n\t\t * @param {object} widget The definition.\n\t\t * @return {object}\n\t\t */\n\t\tshared(widget) {\n\t\t\tconst content = widget.content || {}\n\t\t\tif (Object.hasOwn(content, 'fit')) {\n\t\t\t\treturn widget\n\t\t\t}\n\t\t\treturn { ...widget, content: { ...content, fit: false } }\n\t\t},\n\n\t\t/**\n\t\t * Whether a section shows its heading and takes space.\n\t\t *\n\t\t * @param {string} key The section key.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/abstract-sections-widget/specs/sections-widget/spec.md#requirement-a-section-whose-widget-draws-nothing-stays-silent\n\t\t */\n\t\tisShown(key) {\n\t\t\treturn !this.hideEmpty || this.filled[key] === true\n\t\t},\n\n\t\t/**\n\t\t * Watch one section's host for content, so its heading appears when\n\t\t * the widget renders and stays away when it never does. A\n\t\t * MutationObserver, because most widgets mount empty and fill after a\n\t\t * fetch.\n\t\t *\n\t\t * @param {string} key The section key.\n\t\t * @param {HTMLElement|null} el The host wrapper, or null on teardown.\n\t\t * @return {void}\n\t\t */\n\t\tsetHostRef(key, el) {\n\t\t\tthis.observers = this.observers || {}\n\t\t\tif (this.observers[key]) {\n\t\t\t\tthis.observers[key].disconnect()\n\t\t\t\tdelete this.observers[key]\n\t\t\t}\n\t\t\tif (!el) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Assign only on a change: `filled` drives the template, so an\n\t\t\t// unconditional write re-renders, mutates, and fires again.\n\t\t\tconst measure = () => {\n\t\t\t\tconst next = this.hasContent(el)\n\t\t\t\tif (this.filled[key] === next) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.filled = { ...this.filled, [key]: next }\n\t\t\t}\n\t\t\tif (typeof MutationObserver === 'function') {\n\t\t\t\tconst observer = new MutationObserver(measure)\n\t\t\t\tobserver.observe(el, { childList: true, subtree: true, characterData: true })\n\t\t\t\tthis.observers[key] = observer\n\t\t\t}\n\t\t\t// Not synchronously: a ref callback runs during the patch.\n\t\t\tthis.$nextTick(measure)\n\t\t},\n\n\t\t/**\n\t\t * Whether a host rendered anything a reader would see: text (an empty\n\t\t * state counts), or a graphical or interactive element.\n\t\t *\n\t\t * @param {HTMLElement} el The host wrapper.\n\t\t * @return {boolean}\n\t\t */\n\t\thasContent(el) {\n\t\t\tif (!el) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif (el.textContent && el.textContent.trim().length > 0) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn el.querySelector('img, svg, canvas, table, input, button, select, textarea') !== null\n\t\t},\n\n\t\t/**\n\t\t * Drop every observer.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tstopObserving() {\n\t\t\tfor (const observer of Object.values(this.observers || {})) {\n\t\t\t\tobserver.disconnect()\n\t\t\t}\n\t\t\tthis.observers = {}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sections-widget {\n\tmin-width: 0;\n}\n\n.cn-sections-widget__column {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(var(--default-grid-baseline, 4px) * 4);\n\tmin-width: 0;\n}\n\n/* A main and a side column (the settings boards: 1fr and 418px, 20px apart). */\n.cn-sections-widget--two-column {\n\tdisplay: grid;\n\tgrid-template-columns: minmax(0, 1fr) minmax(280px, 418px);\n\tgap: 20px;\n\talign-items: start;\n}\n\n@media (max-width: 1024px) {\n\t.cn-sections-widget--two-column {\n\t\tgrid-template-columns: minmax(0, 1fr);\n\t}\n}\n\n/* A host page may space every <section>; these sections are spaced by the column gap only. */\n.cn-sections-widget__section {\n\tmargin: 0;\n\tmin-width: 0;\n}\n\n/* A rule above a section that follows a shown one. */\n.cn-sections-widget:not(.cn-sections-widget--cards) .cn-sections-widget__section:not(.cn-sections-widget__section--empty) ~ .cn-sections-widget__section {\n\tpadding-top: calc(var(--default-grid-baseline, 4px) * 4);\n\tborder-top: 1px solid var(--color-border);\n}\n\n/*\n * An empty section keeps its host mounted (display: none still mounts it, so\n * the widget fetches and can fill later) but takes no space, gap or rule.\n */\n.cn-sections-widget__section--empty {\n\tdisplay: none;\n}\n\n.cn-sections-widget__heading {\n\tmargin: 0 0 calc(var(--default-grid-baseline, 4px) * 2);\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-sections-widget__description {\n\tmargin: calc(var(--default-grid-baseline, 4px) * -1) 0 calc(var(--default-grid-baseline, 4px) * 3);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* One card per section. */\n.cn-sections-widget--cards .cn-sections-widget__column {\n\tgap: 20px;\n}\n\n.cn-sections-widget--cards .cn-sections-widget__section {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--cn-board-card-radius, var(--border-radius-large, 12px));\n\tpadding: var(--cn-board-card-padding, 16px 20px);\n}\n\n.cn-sections-widget--cards .cn-sections-widget__heading {\n\tfont-size: 18px;\n\tmargin-bottom: 12px;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_openBlock","_renderList","_toDisplayString","_createElementVNode"],"mappings":";;;;;;AAyCS,EAAA,KAAC,EAAC,iCAAiC;;;;;;;AA7B1C,IAAA,KAAK,kBAAC,oBAAoB,EAAA;gCACvB,QAAA,CAAA,KAAA;qCAAA,QAAA,CAAA,SAAA;;iBAIQ,EAAC,oBAAoB;;sBAC/BA,8CACiB,QAAO,CAAA,OAAA,EAAA,CAAjB,MAAM,KAAA;2BADbA;QAEC,GAAG,EAAE,MAAM,CAAC,EAAE;AACd,QAAA,KAAI,EAACC,cAAA,CAAA,CAAA,4BAA4B,EACK,CAAA,4BAAA,EAAA,MAAM,CAAC,EAAC,CAAA,CAAA,CAAA,CAAA;;AAC9C,SAAAC,SAAA,CAAA,IAAA,CAAA,EAAAF,kBAAA,SACkB,EAAA,IAAA,EAAAG,UAAA,CAAA,MAAM,CAAC,QAAQ,GAA1B,OAAO,KAAA;+BADdH;YAEC,GAAI,EAAC,OAAO,CAAC,GAAG;iBACZ,kBAAC,6BAA4B,EAAA,EAAA,oCAAA,EAAA,CACV,gBAAA,CAAA,OAAA,CAAA,GAAA,CAAA,EAAA,CAAA,CAAA;AACvB,YAAA,iBAAC,EAAA,OAAA,CAAA,KAAA,IAAA,gBAAA,CAAA,OAAA,CAAA,GAAA,IAAA,QAAA,CAAA,SAAA,CAAA,OAAA,CAAA,GAAA,IAAA,SAAA;YACD,aAAW,EAAA,CAAA,WAAA,EAAgB,OAAO,CAAC,GAAG,CAAA,CAAA;;AAKtC,YAAA,CAAA,OAAA,CAAA,KAAA,IAAA,gBAAA,CAAA,OAAA,CAAA,GAAA,CAAA;8BADDA,kBAKG,CAAA,IAAA,EAAA;;AAHD,kBAAA,EAAE,EAAE,QAAA,CAAA,SAAS,CAAC,OAAO,CAAC,GAAG,CAAA;AAC1B,kBAAA,KAAK,EAAC,6BAA6B;AAChC,iBAAA,EAAAI,eAAA,CAAA,OAAO,CAAC,KAAK,CAAA,EAAA,CAAA,oBAAA,UAAA,CAAA;;AAGV,YAAA,CAAA,OAAO,CAAC,WAAW,IAAI,gBAAO,CAAC,OAAO,CAAC,GAAG,CAAA;AADjD,iBAAAF,SAAA,EAAA,EAAAF,kBAAA,CAII,GAJJ,EAAA,UAII,EADCI,eAAA,CAAA,OAAM,CAAC,WAAW,CAAA,EAAA,CAAA,YAAA;;YAKrBC;;cAAI,GAAG,EAAA,CAAG,EAAE,KAAK,QAAA,CAAA,UAAE,CAAA,OAAA,CAAA,GAAA,EAAA,EAAA,CAAA;AAAA,cAAA,KAAA,EAAA,0BAAA;;;gBAElB,MAAM,EAAE,OAAO,CAAC,MAAM;AACvB,gBAAA,MAAM,EAAC,MAAM;AACZ,gBAAA,QAAQ,EAAE,MAAI,CAAA,QAAA;AACd,gBAAA,MAAM,EAAE,MAAI,CAAA,UAAA;AACZ,gBAAA,UAAU,EAAE,MAAI,CAAA,UAAA;AAChB,gBAAA,YAAY,EAAE,MAAY,CAAA,YAAA;AAC1B,gBAAA,QAAQ,EAAE,MAAQ,CAAA,QAAA;AAClB,gBAAA,MAAM,EAAE,MAAM,CAAA,MAAA;AACd,gBAAA,KAAE,EAAA,MAAA,CAAA,KAAA;AACF,gBAAA,OAAK,EAAA,MAAA,CAAA,OAAA;AACL,gBAAA,kBAAA,EAAA,MAAA,CAAA,kBAAA;AACD,gBAAA,UAAA,EAAA,MAAA,CAAA,UAAA;;;;;;;;;;;;;"}