@conduction/nextcloud-vue 2.100.0 → 2.102.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 (168) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +22 -0
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +8 -6
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
  6. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +29 -4
  7. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  8. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js +9 -1
  9. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  10. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
  11. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js +22 -1
  12. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
  13. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js +26 -16
  14. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
  15. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  16. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +70 -6
  17. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  18. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +105 -74
  19. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  20. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue.js +9 -0
  21. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue.js.map +1 -0
  22. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue2.js +139 -0
  23. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue2.js.map +1 -0
  24. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue3.js +76 -0
  25. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue3.js.map +1 -0
  26. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  27. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +160 -2
  28. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  29. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +206 -94
  30. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  31. package/dist/esm/components/CnFilesBrowser/filesReview.js +61 -0
  32. package/dist/esm/components/CnFilesBrowser/filesReview.js.map +1 -0
  33. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js +9 -0
  34. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js.map +1 -0
  35. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js +279 -0
  36. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js.map +1 -0
  37. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js +122 -0
  38. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js.map +1 -0
  39. package/dist/esm/components/CnGroupedCardsWidget/index.js +29 -0
  40. package/dist/esm/components/CnGroupedCardsWidget/index.js.map +1 -0
  41. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +320 -74
  42. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  43. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +323 -213
  44. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  45. package/dist/esm/components/CnIndexPage/useNamedSource.js +30 -3
  46. package/dist/esm/components/CnIndexPage/useNamedSource.js.map +1 -1
  47. package/dist/esm/components/CnMapWidget/CnMapWidget.vue.js +1 -1
  48. package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js +15 -0
  49. package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js.map +1 -1
  50. package/dist/esm/components/CnMapWidget/CnMapWidget.vue3.js.map +1 -1
  51. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue.js +1 -1
  52. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue2.js +25 -1
  53. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue2.js.map +1 -1
  54. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue3.js.map +1 -1
  55. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
  56. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +14 -1
  57. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  58. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +14 -6
  59. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  60. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
  61. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +10 -0
  62. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  63. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +6 -1
  64. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  65. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js +1 -1
  66. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js +91 -4
  67. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js.map +1 -1
  68. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js +63 -38
  69. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js.map +1 -1
  70. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue.js +1 -1
  71. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +106 -4
  72. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
  73. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js +70 -25
  74. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
  75. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js +9 -0
  76. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js.map +1 -0
  77. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js +175 -0
  78. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js.map +1 -0
  79. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js +77 -0
  80. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js.map +1 -0
  81. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
  82. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +35 -2
  83. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  84. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  85. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +4 -0
  86. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
  87. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
  88. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  89. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
  90. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +2 -23
  91. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
  92. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
  93. package/dist/esm/composables/indexSources.js +176 -20
  94. package/dist/esm/composables/indexSources.js.map +1 -1
  95. package/dist/esm/composables/useEndpointSource.js +28 -6
  96. package/dist/esm/composables/useEndpointSource.js.map +1 -1
  97. package/dist/esm/index.js +1 -0
  98. package/dist/esm/index.js.map +1 -1
  99. package/dist/esm/l10n/en.json.js +41 -1
  100. package/dist/esm/l10n/en.json.js.map +1 -1
  101. package/dist/esm/l10n/nl.json.js +39 -1
  102. package/dist/esm/l10n/nl.json.js.map +1 -1
  103. package/dist/esm/library-style.js +1 -1
  104. package/dist/esm/nextcloud-vue.css +939 -376
  105. package/dist/esm/utils/builtInFormatters.js +24 -4
  106. package/dist/esm/utils/builtInFormatters.js.map +1 -1
  107. package/dist/esm/utils/languageMapText.js +50 -0
  108. package/dist/esm/utils/languageMapText.js.map +1 -0
  109. package/dist/esm/utils/libraryWidgetKeys.js +3 -0
  110. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  111. package/dist/esm/utils/mapList.js +71 -0
  112. package/dist/esm/utils/mapList.js.map +1 -0
  113. package/dist/esm/utils/rowClassRules.js +43 -0
  114. package/dist/esm/utils/rowClassRules.js.map +1 -0
  115. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  116. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  117. package/dist/esm/utils/visibleWhen.js +19 -2
  118. package/dist/esm/utils/visibleWhen.js.map +1 -1
  119. package/dist/nextcloud-vue.cjs.js +9681 -7136
  120. package/dist/nextcloud-vue.cjs.js.map +2 -2
  121. package/dist/nextcloud-vue.css +939 -376
  122. package/l10n/en.json +41 -1
  123. package/l10n/nl.json +39 -1
  124. package/package.json +1 -1
  125. package/src/components/CnActionsBar/CnActionsBar.md +1 -0
  126. package/src/components/CnActionsBar/CnActionsBar.vue +31 -4
  127. package/src/components/CnChartWidget/CnChartWidget.md +3 -2
  128. package/src/components/CnChartWidget/CnChartWidget.vue +42 -4
  129. package/src/components/CnChoiceCards/CnChoiceCards.md +39 -0
  130. package/src/components/CnChoiceCards/CnChoiceCards.vue +93 -16
  131. package/src/components/CnDashboardPage/CnDashboardPage.vue +110 -21
  132. package/src/components/CnExportsWidget/CnExportsWidget.vue +233 -0
  133. package/src/components/CnExportsWidget/index.js +7 -0
  134. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +324 -0
  135. package/src/components/CnFilesBrowser/filesReview.js +57 -0
  136. package/src/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue +433 -0
  137. package/src/components/CnGroupedCardsWidget/index.js +28 -0
  138. package/src/components/CnIndexPage/CnIndexPage.md +5 -1
  139. package/src/components/CnIndexPage/CnIndexPage.vue +313 -9
  140. package/src/components/CnIndexPage/useNamedSource.js +30 -3
  141. package/src/components/CnMapWidget/CnMapWidget.vue +37 -0
  142. package/src/components/CnMenuWidget/CnMenuWidget.vue +25 -1
  143. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +29 -1
  144. package/src/components/CnObjectSidebar/CnFilesTab.vue +15 -0
  145. package/src/components/CnOrderedListField/CnOrderedListField.vue +151 -5
  146. package/src/components/CnQuickFilterBar/CnQuickFilterBar.md +1 -0
  147. package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +159 -5
  148. package/src/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue +272 -0
  149. package/src/components/CnSavedViewAlertWidget/index.js +7 -0
  150. package/src/components/CnSetupWizard/CnSetupWizard.vue +35 -2
  151. package/src/components/CnWidgetGrid/builtInWidgets.js +4 -0
  152. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
  153. package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +2 -23
  154. package/src/components/index.js +3 -0
  155. package/src/composables/indexSources.js +175 -19
  156. package/src/composables/useEndpointSource.js +28 -6
  157. package/src/css/index-page.css +117 -0
  158. package/src/css/look-board-index.css +10 -0
  159. package/src/css/look-board.css +44 -0
  160. package/src/index.js +1 -0
  161. package/src/schemas/app-manifest-v2.schema.json +85 -3
  162. package/src/utils/builtInFormatters.js +24 -4
  163. package/src/utils/languageMapText.js +46 -0
  164. package/src/utils/libraryWidgetKeys.js +3 -0
  165. package/src/utils/mapList.js +67 -0
  166. package/src/utils/rowClassRules.js +39 -0
  167. package/src/utils/validateManifestV2.compiled.js +3 -3
  168. package/src/utils/visibleWhen.js +19 -2
@@ -1 +1 @@
1
- {"version":3,"file":"CnMenuWidget.vue3.js","sources":["../../../../src/components/CnMenuWidget/CnMenuWidget.vue?vue&type=template&id=2a4e786e&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-menu-widget\"\n\t\t:class=\"rootClasses\"\n\t\t@keydown.esc.stop=\"closeAll\">\n\t\t<!-- Empty state -->\n\t\t<div\n\t\t\tv-if=\"isEmpty\"\n\t\t\tclass=\"cn-menu-widget__empty\"\n\t\t\t:class=\"{ 'cn-menu-widget__empty--clickable': isInEditMode }\"\n\t\t\t:role=\"isInEditMode ? 'button' : null\"\n\t\t\t:tabindex=\"isInEditMode ? 0 : -1\"\n\t\t\t@click=\"onEmptyStateClick\"\n\t\t\t@keyup.enter=\"onEmptyStateClick\"\n\t\t\t@keyup.space=\"onEmptyStateClick\">\n\t\t\t<span class=\"cn-menu-widget__empty-icon\" aria-hidden=\"true\">⚙</span>\n\t\t\t<span>{{ t('nextcloud-vue', 'No menu items yet — click the gear icon to add some.') }}</span>\n\t\t</div>\n\n\t\t<!-- Tree style -->\n\t\t<ul\n\t\t\tv-else-if=\"effectiveStyle === 'tree'\"\n\t\t\tclass=\"cn-menu-widget__tree\"\n\t\t\trole=\"tree\">\n\t\t\t<CnMenuTreeNode\n\t\t\t\tv-for=\"(item, idx) in items\"\n\t\t\t\t:key=\"`tree-${idx}`\"\n\t\t\t\t:item=\"item\"\n\t\t\t\t:depth=\"1\"\n\t\t\t\t:showIcons=\"showIcons\"\n\t\t\t\t:expandedByDefault=\"expandedByDefault\"\n\t\t\t\t:activePath=\"activePath\"\n\t\t\t\t:activeLeafKey=\"activeLeafKey\"\n\t\t\t\t:currentKey=\"`${idx}`\"\n\t\t\t\t:activeHighlight=\"activeItemHighlight\"\n\t\t\t\t@navigate=\"onTreeNavigate\" />\n\t\t</ul>\n\n\t\t<!-- Megamenu style -->\n\t\t<div\n\t\t\tv-else-if=\"effectiveStyle === 'megamenu'\"\n\t\t\tclass=\"cn-menu-widget__megamenu\">\n\t\t\t<ul\n\t\t\t\tclass=\"cn-menu-widget__bar\"\n\t\t\t\trole=\"menubar\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"(item, idx) in items\"\n\t\t\t\t\t:key=\"`mega-top-${idx}`\"\n\t\t\t\t\trole=\"none\"\n\t\t\t\t\tclass=\"cn-menu-widget__bar-item\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"isTopLink(item) ? 'a' : 'button'\"\n\t\t\t\t\t\t:ref=\"(el) => setTopRef(el, idx)\"\n\t\t\t\t\t\tv-bind=\"isTopLink(item) ? linkAttrs(item) : { type: 'button' }\"\n\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\tclass=\"cn-menu-widget__bar-button\"\n\t\t\t\t\t\t:class=\"topItemClass(`${idx}`)\"\n\t\t\t\t\t\t:aria-haspopup=\"hasChildren(item) ? 'menu' : null\"\n\t\t\t\t\t\t:aria-expanded=\"megaOpenIndex === idx ? 'true' : 'false'\"\n\t\t\t\t\t\t@click=\"isTopLink(item) ? onLinkClick($event, item) : onMegaTopClick(idx, item)\"\n\t\t\t\t\t\t@keydown=\"onMegaTopKey($event, idx, item)\">\n\t\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !item.icon }\">\n\t\t\t\t\t\t\t<CnMenuItemIcon v-if=\"item.icon\" :icon=\"item.icon\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ item.label }}</span>\n\t\t\t\t\t</component>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div\n\t\t\t\tv-if=\"megaOpenIndex !== null && hasChildren(items[megaOpenIndex])\"\n\t\t\t\tref=\"megaPanel\"\n\t\t\t\tclass=\"cn-menu-widget__mega-panel\"\n\t\t\t\trole=\"menu\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"(child, childIdx) in items[megaOpenIndex].children\"\n\t\t\t\t\t:key=\"`mega-group-${childIdx}`\"\n\t\t\t\t\tclass=\"cn-menu-widget__mega-group\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"isLink(child) ? 'a' : 'button'\"\n\t\t\t\t\t\tv-bind=\"itemAttrs(child)\"\n\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\tclass=\"cn-menu-widget__mega-group-title\"\n\t\t\t\t\t\t:class=\"topItemClass(`${megaOpenIndex}.${childIdx}`)\"\n\t\t\t\t\t\t@click=\"onLinkClick($event, child)\">\n\t\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !child.icon }\">\n\t\t\t\t\t\t\t<CnMenuItemIcon v-if=\"child.icon\" :icon=\"child.icon\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ child.label }}</span>\n\t\t\t\t\t</component>\n\t\t\t\t\t<ul\n\t\t\t\t\t\tv-if=\"hasChildren(child)\"\n\t\t\t\t\t\tclass=\"cn-menu-widget__mega-leaves\">\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-for=\"(leaf, leafIdx) in child.children\"\n\t\t\t\t\t\t\t:key=\"`mega-leaf-${leafIdx}`\"\n\t\t\t\t\t\t\trole=\"none\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"isLink(leaf) ? 'a' : 'button'\"\n\t\t\t\t\t\t\t\tv-bind=\"itemAttrs(leaf)\"\n\t\t\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\t\t\tclass=\"cn-menu-widget__mega-leaf\"\n\t\t\t\t\t\t\t\t:class=\"topItemClass(`${megaOpenIndex}.${childIdx}.${leafIdx}`)\"\n\t\t\t\t\t\t\t\t@click=\"onLinkClick($event, leaf)\">\n\t\t\t\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !leaf.icon }\">\n\t\t\t\t\t\t\t\t\t<CnMenuItemIcon v-if=\"leaf.icon\" :icon=\"leaf.icon\" />\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ leaf.label }}</span>\n\t\t\t\t\t\t\t</component>\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\n\t\t<!-- Dropdown style (default) -->\n\t\t<ul\n\t\t\tv-else\n\t\t\tclass=\"cn-menu-widget__bar\"\n\t\t\t:class=\"{ 'cn-menu-widget__bar--vertical': orientation === 'vertical' }\"\n\t\t\trole=\"menubar\">\n\t\t\t<li\n\t\t\t\tv-for=\"(item, idx) in items\"\n\t\t\t\t:key=\"`drop-top-${idx}`\"\n\t\t\t\t:ref=\"(el) => setBarItemRef(el, idx)\"\n\t\t\t\trole=\"none\"\n\t\t\t\tclass=\"cn-menu-widget__bar-item\">\n\t\t\t\t<component\n\t\t\t\t\t:is=\"isTopLink(item) ? 'a' : 'button'\"\n\t\t\t\t\t:ref=\"(el) => setTopRef(el, idx)\"\n\t\t\t\t\tv-bind=\"isTopLink(item) ? linkAttrs(item) : { type: 'button' }\"\n\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\tclass=\"cn-menu-widget__bar-button\"\n\t\t\t\t\t:class=\"topItemClass(`${idx}`)\"\n\t\t\t\t\t:aria-haspopup=\"hasChildren(item) ? 'menu' : null\"\n\t\t\t\t\t:aria-expanded=\"dropOpenIndex === idx ? 'true' : 'false'\"\n\t\t\t\t\t@click=\"isTopLink(item) ? onLinkClick($event, item) : onDropdownTopClick(idx, item)\"\n\t\t\t\t\t@keydown.tab=\"closeAll\"\n\t\t\t\t\t@keydown.enter=\"onDropdownTopEnter($event, idx, item)\"\n\t\t\t\t\t@keydown.space.prevent=\"onDropdownTopClick(idx, item)\"\n\t\t\t\t\t@keydown.down.prevent=\"openDropdown(idx)\">\n\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !item.icon }\">\n\t\t\t\t\t\t<CnMenuItemIcon v-if=\"item.icon\" :icon=\"item.icon\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ item.label }}</span>\n\t\t\t\t\t<span v-if=\"hasChildren(item)\" class=\"cn-menu-widget__caret\" aria-hidden=\"true\">▾</span>\n\t\t\t\t</component>\n\t\t\t\t<ul\n\t\t\t\t\tv-if=\"dropOpenIndex === idx && hasChildren(item)\"\n\t\t\t\t\tclass=\"cn-menu-widget__dropdown\"\n\t\t\t\t\trole=\"menu\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"(child, childIdx) in item.children\"\n\t\t\t\t\t\t:key=\"`drop-child-${childIdx}`\"\n\t\t\t\t\t\trole=\"none\"\n\t\t\t\t\t\tclass=\"cn-menu-widget__dropdown-item-wrap\"\n\t\t\t\t\t\t@mouseenter=\"hasChildren(child) && (flyoutOpenKey = `${idx}.${childIdx}`)\">\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"isLink(child) ? 'a' : 'button'\"\n\t\t\t\t\t\t\tv-bind=\"itemAttrs(child)\"\n\t\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\t\tclass=\"cn-menu-widget__dropdown-item\"\n\t\t\t\t\t\t\t:class=\"topItemClass(`${idx}.${childIdx}`)\"\n\t\t\t\t\t\t\t@click=\"onLinkClick($event, child)\">\n\t\t\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !child.icon }\">\n\t\t\t\t\t\t\t\t<CnMenuItemIcon v-if=\"child.icon\" :icon=\"child.icon\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ child.label }}</span>\n\t\t\t\t\t\t\t<span v-if=\"hasChildren(child)\" class=\"cn-menu-widget__caret cn-menu-widget__caret--right\" aria-hidden=\"true\">▸</span>\n\t\t\t\t\t\t</component>\n\t\t\t\t\t\t<ul\n\t\t\t\t\t\t\tv-if=\"flyoutOpenKey === `${idx}.${childIdx}` && hasChildren(child)\"\n\t\t\t\t\t\t\tclass=\"cn-menu-widget__flyout\"\n\t\t\t\t\t\t\trole=\"menu\">\n\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\tv-for=\"(leaf, leafIdx) in child.children\"\n\t\t\t\t\t\t\t\t:key=\"`drop-leaf-${leafIdx}`\"\n\t\t\t\t\t\t\t\trole=\"none\">\n\t\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t\t:is=\"isLink(leaf) ? 'a' : 'button'\"\n\t\t\t\t\t\t\t\t\tv-bind=\"itemAttrs(leaf)\"\n\t\t\t\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-menu-widget__dropdown-item\"\n\t\t\t\t\t\t\t\t\t:class=\"topItemClass(`${idx}.${childIdx}.${leafIdx}`)\"\n\t\t\t\t\t\t\t\t\t@click=\"onLinkClick($event, leaf)\">\n\t\t\t\t\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !leaf.icon }\">\n\t\t\t\t\t\t\t\t\t\t<CnMenuItemIcon v-if=\"leaf.icon\" :icon=\"leaf.icon\" />\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ leaf.label }}</span>\n\t\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</li>\n\t\t</ul>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport CnMenuItemIcon from './CnMenuItemIcon.vue'\nimport CnMenuTreeNode from './CnMenuTreeNode.vue'\nimport { followLinkClick } from '../../utils/linkNavigation.js'\nimport { computeActivePath, isActiveItem, isRouterPath, menuLinkAttrs } from './menuActive.js'\n\nconst VALID_STYLES = ['dropdown', 'megamenu', 'tree']\nconst VALID_ORIENTATIONS = ['horizontal', 'vertical']\nconst VALID_HIGHLIGHTS = ['background', 'underline', 'left-bar', 'none']\n\n/**\n * CnMenuWidget — renders a hierarchical navigation widget with three visual\n * styles (dropdown, megamenu, tree) and active-item highlighting based on\n * `window.location.pathname`.\n *\n * Active-item detection runs on mount and whenever `items` or the URL change;\n * ancestors of the active leaf are flagged \"in-path\" so the configured\n * highlight (`underline`, `background`, `left-bar`, `none`) renders\n * consistently. Keyboard navigation follows the WAI-ARIA Menu/Menubar pattern.\n *\n * Open dropdown/megamenu panels close on: re-clicking the toggle, Escape,\n * Tab, navigating a leaf, and clicking ANYWHERE else — including empty space\n * elsewhere in the widget itself, not just outside it entirely (a\n * document-level listener that checks containment against the open toggle\n * button + its own panel specifically, since the panels are plain in-DOM\n * markup, not a teleported popover with its own outside-click handling).\n *\n * @spec openspec/changes/cn-widget-library/specs/cn-widget-library/spec.md\n */\nexport default {\n\tname: 'CnMenuWidget',\n\n\tcomponents: {\n\t\tCnMenuTreeNode,\n\t\tCnMenuItemIcon,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted widget content `{items, style, orientation, showIcons,\n\t\t * expandedByDefault, activeItemHighlight}`.\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/** Whether the current user is an admin (pairs with `canEdit`). */\n\t\tisAdmin: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether the surrounding shell is in edit mode. */\n\t\tcanEdit: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: [\n\t\t/** Fired when the empty-state gear is clicked in edit mode. */\n\t\t'edit-request',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tdropOpenIndex: null,\n\t\t\tflyoutOpenKey: null,\n\t\t\tmegaOpenIndex: null,\n\t\t\tcurrentLocation: this.readLocation(),\n\t\t\ttopRefs: [],\n\t\t\tbarItemRefs: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The configured menu items.\n\t\t *\n\t\t * @return {object[]} the items array.\n\t\t */\n\t\titems() {\n\t\t\tconst arr = this.content?.items\n\t\t\treturn Array.isArray(arr) ? arr : []\n\t\t},\n\n\t\t/**\n\t\t * Whether the menu has no items.\n\t\t *\n\t\t * @return {boolean} true when empty.\n\t\t */\n\t\tisEmpty() {\n\t\t\treturn this.items.length === 0\n\t\t},\n\n\t\t/**\n\t\t * The validated visual style (default `dropdown`).\n\t\t *\n\t\t * @return {string} one of dropdown/megamenu/tree.\n\t\t */\n\t\teffectiveStyle() {\n\t\t\tconst s = this.content?.style\n\t\t\treturn VALID_STYLES.includes(s) ? s : 'dropdown'\n\t\t},\n\n\t\t/**\n\t\t * The validated orientation (tree is always vertical).\n\t\t *\n\t\t * @return {string} `horizontal` or `vertical`.\n\t\t */\n\t\torientation() {\n\t\t\tconst o = this.content?.orientation\n\t\t\tif (this.effectiveStyle === 'tree') {\n\t\t\t\treturn 'vertical'\n\t\t\t}\n\t\t\treturn VALID_ORIENTATIONS.includes(o) ? o : 'horizontal'\n\t\t},\n\n\t\t/**\n\t\t * Whether item icons render (default true).\n\t\t *\n\t\t * @return {boolean} the showIcons flag.\n\t\t */\n\t\tshowIcons() {\n\t\t\treturn this.content?.showIcons !== false\n\t\t},\n\n\t\t/**\n\t\t * Whether tree nodes start expanded.\n\t\t *\n\t\t * @return {boolean} the expandedByDefault flag.\n\t\t */\n\t\texpandedByDefault() {\n\t\t\treturn this.content?.expandedByDefault === true\n\t\t},\n\n\t\t/**\n\t\t * The validated active-item highlight style (default `underline`).\n\t\t *\n\t\t * @return {string} one of background/underline/left-bar/none.\n\t\t */\n\t\tactiveItemHighlight() {\n\t\t\tconst h = this.content?.activeItemHighlight\n\t\t\treturn VALID_HIGHLIGHTS.includes(h) ? h : 'underline'\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget is in edit mode (empty-state gear clickable).\n\t\t *\n\t\t * @return {boolean} true when admin + canEdit.\n\t\t */\n\t\tisInEditMode() {\n\t\t\treturn this.isAdmin === true && this.canEdit === true\n\t\t},\n\n\t\t/**\n\t\t * The root style/highlight/orientation CSS classes.\n\t\t *\n\t\t * @return {object} the class map.\n\t\t */\n\t\trootClasses() {\n\t\t\treturn {\n\t\t\t\t[`cn-menu-widget--style-${this.effectiveStyle}`]: true,\n\t\t\t\t[`cn-menu-widget--highlight-${this.activeItemHighlight}`]: true,\n\t\t\t\t[`cn-menu-widget--orientation-${this.orientation}`]: true,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The dotted-key path map for the current location.\n\t\t *\n\t\t * @return {{path: object, leafKey: string|null}} the active-path map.\n\t\t */\n\t\tactivePathMap() {\n\t\t\treturn computeActivePath({\n\t\t\t\titems: this.items,\n\t\t\t\tcurrentLocation: this.currentLocation,\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The dotted-key → state map.\n\t\t *\n\t\t * @return {Record<string, string>} the path map.\n\t\t */\n\t\tactivePath() {\n\t\t\treturn this.activePathMap.path\n\t\t},\n\n\t\t/**\n\t\t * The key of the deepest active leaf.\n\t\t *\n\t\t * @return {string|null} the leaf key.\n\t\t */\n\t\tactiveLeafKey() {\n\t\t\treturn this.activePathMap.leafKey\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.boundLocationListener = () => {\n\t\t\tthis.currentLocation = this.readLocation()\n\t\t}\n\t\tif (typeof window !== 'undefined') {\n\t\t\twindow.addEventListener('popstate', this.boundLocationListener)\n\t\t\twindow.addEventListener('hashchange', this.boundLocationListener)\n\t\t}\n\t\tthis.boundOutsideClickListener = this.onOutsideClick\n\t\tif (typeof document !== 'undefined') {\n\t\t\tdocument.addEventListener('click', this.boundOutsideClickListener)\n\t\t}\n\t},\n\n\tbeforeUnmount() {\n\t\tif (typeof window !== 'undefined' && this.boundLocationListener) {\n\t\t\twindow.removeEventListener('popstate', this.boundLocationListener)\n\t\t\twindow.removeEventListener('hashchange', this.boundLocationListener)\n\t\t}\n\t\tif (typeof document !== 'undefined' && this.boundOutsideClickListener) {\n\t\t\tdocument.removeEventListener('click', this.boundOutsideClickListener)\n\t\t}\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the current browser location into a small bag.\n\t\t *\n\t\t * @return {{pathname: string, host: string}} the location bag.\n\t\t */\n\t\treadLocation() {\n\t\t\tif (typeof window === 'undefined' || !window.location) {\n\t\t\t\treturn { pathname: '/', host: '' }\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tpathname: window.location.pathname || '/',\n\t\t\t\thost: window.location.host || '',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Stash a top-level button ref by index.\n\t\t *\n\t\t * @param {HTMLElement} el the button element.\n\t\t * @param {number} idx the item index.\n\t\t * @return {void}\n\t\t */\n\t\tsetTopRef(el, idx) {\n\t\t\tif (el) {\n\t\t\t\tthis.topRefs[idx] = el\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Stash a dropdown-style top-level `<li>` ref by index. This `<li>`\n\t\t * contains both the toggle button and its dropdown/flyout panel, so a\n\t\t * single containment check against it covers the whole open structure.\n\t\t *\n\t\t * @param {HTMLElement} el the `<li>` element.\n\t\t * @param {number} idx the item index.\n\t\t * @return {void}\n\t\t */\n\t\tsetBarItemRef(el, idx) {\n\t\t\tif (el) {\n\t\t\t\tthis.barItemRefs[idx] = el\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an item has children.\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {boolean} true when it has a non-empty children array.\n\t\t */\n\t\thasChildren(item) {\n\t\t\treturn item && Array.isArray(item.children) && item.children.length > 0\n\t\t},\n\n\t\t/**\n\t\t * The active-state class for a dotted key.\n\t\t *\n\t\t * @param {string} key the dotted item key.\n\t\t * @return {string} the class name (or `''`).\n\t\t */\n\t\ttopItemClass(key) {\n\t\t\tconst state = this.activePath[key]\n\t\t\tif (state === 'active' || key === this.activeLeafKey) {\n\t\t\t\treturn 'cn-menu-widget__item--active'\n\t\t\t}\n\t\t\tif (state === 'in-path') {\n\t\t\t\treturn 'cn-menu-widget__item--in-path'\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\t/**\n\t\t * Top-level dropdown click — navigate a leaf or toggle the dropdown.\n\t\t *\n\t\t * @param {number} idx the item index.\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonDropdownTopClick(idx, item) {\n\t\t\tif (!this.hasChildren(item)) {\n\t\t\t\tthis.onNavigate(item)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.dropOpenIndex === idx) {\n\t\t\t\tthis.dropOpenIndex = null\n\t\t\t\tthis.flyoutOpenKey = null\n\t\t\t} else {\n\t\t\t\tthis.dropOpenIndex = idx\n\t\t\t\tthis.flyoutOpenKey = null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Open the dropdown at an index when it has children.\n\t\t *\n\t\t * @param {number} idx the item index.\n\t\t * @return {void}\n\t\t */\n\t\topenDropdown(idx) {\n\t\t\tif (this.hasChildren(this.items[idx])) {\n\t\t\t\tthis.dropOpenIndex = idx\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Top-level megamenu click — navigate a leaf or toggle the panel.\n\t\t *\n\t\t * @param {number} idx the item index.\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonMegaTopClick(idx, item) {\n\t\t\tif (!this.hasChildren(item)) {\n\t\t\t\tthis.onNavigate(item)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.megaOpenIndex = this.megaOpenIndex === idx ? null : idx\n\t\t},\n\n\t\t/**\n\t\t * Keyboard handler for megamenu top items.\n\t\t *\n\t\t * @param {KeyboardEvent} event the key event.\n\t\t * @param {number} idx the item index.\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonMegaTopKey(event, idx, item) {\n\t\t\t// Enter on a link clicks it natively.\n\t\t\tif (event.key === 'Enter' && this.isTopLink(item)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown') {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tthis.onMegaTopClick(idx, item)\n\t\t\t} else if (event.key === 'Tab') {\n\t\t\t\tthis.megaOpenIndex = null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Close every open dropdown/flyout/panel.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tcloseAll() {\n\t\t\tthis.dropOpenIndex = null\n\t\t\tthis.flyoutOpenKey = null\n\t\t\tthis.megaOpenIndex = null\n\t\t},\n\n\t\t/**\n\t\t * Document-level click handler — closes any open dropdown/flyout/panel\n\t\t * when the click lands outside its own toggle button + panel, INCLUDING\n\t\t * empty space elsewhere in the widget (e.g. bar padding, gaps between\n\t\t * items) — not just outside the whole widget. The toggle button's own\n\t\t * `@click` handler manages opening/closing for its own clicks, so a\n\t\t * click still inside the open button/panel is left alone — otherwise\n\t\t * every open-toggle click would immediately re-close itself via this\n\t\t * same listener.\n\t\t *\n\t\t * @param {MouseEvent} event the document click event.\n\t\t * @return {void}\n\t\t */\n\t\tonOutsideClick(event) {\n\t\t\tconst target = event.target\n\t\t\tif (this.effectiveStyle === 'megamenu') {\n\t\t\t\tif (this.megaOpenIndex === null) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst button = this.topRefs[this.megaOpenIndex]\n\t\t\t\tconst panel = this.$refs.megaPanel\n\t\t\t\tconst insideButton = Boolean(button && button.contains(target))\n\t\t\t\tconst insidePanel = Boolean(panel && panel.contains(target))\n\t\t\t\tif (!insideButton && !insidePanel) {\n\t\t\t\t\tthis.closeAll()\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Dropdown style — the button and its dropdown/flyout panel share\n\t\t\t// the same top-level `<li>`, so one containment check covers both.\n\t\t\tif (this.dropOpenIndex === null) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst barItem = this.barItemRefs[this.dropOpenIndex]\n\t\t\tif (barItem && !barItem.contains(target)) {\n\t\t\t\tthis.closeAll()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an item renders as a link (it has a URL).\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {boolean} true when the item carries a non-empty URL.\n\t\t */\n\t\tisLink(item) {\n\t\t\treturn Boolean(item) && typeof item.url === 'string' && item.url !== ''\n\t\t},\n\n\t\t/**\n\t\t * Whether a top-level item renders as a link. One with children\n\t\t * stays a button, because its click toggles the panel.\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {boolean} true for a top-level leaf with a URL.\n\t\t */\n\t\tisTopLink(item) {\n\t\t\treturn this.isLink(item) && !this.hasChildren(item)\n\t\t},\n\n\t\t/**\n\t\t * Anchor attributes for an item's URL: external URLs open in a new tab.\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {object} the `href` (plus `target` / `rel` for external URLs).\n\t\t */\n\t\tlinkAttrs(item) {\n\t\t\treturn menuLinkAttrs(item.url, this.$router)\n\t\t},\n\n\t\t/**\n\t\t * Attributes for a panel item: link attributes, or `type=\"button\"`.\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {object} the element attributes.\n\t\t */\n\t\titemAttrs(item) {\n\t\t\treturn this.isLink(item) ? this.linkAttrs(item) : { type: 'button' }\n\t\t},\n\n\t\t/**\n\t\t * Click on an item link: close the menus, then let the browser open\n\t\t * an external URL or a modified click, and route a plain click on an\n\t\t * internal one. A no-op for an item without a URL.\n\t\t *\n\t\t * @param {MouseEvent} event the click event.\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonLinkClick(event, item) {\n\t\t\tif (!this.isLink(item)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.closeAll()\n\t\t\tif (isRouterPath(item.url)) {\n\t\t\t\tfollowLinkClick(event, item.url, this.$router)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Enter on a dropdown top item: a link follows natively (Enter\n\t\t * clicks it); a button toggles or navigates.\n\t\t *\n\t\t * @param {KeyboardEvent} event the key event.\n\t\t * @param {number} idx the item index.\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonDropdownTopEnter(event, idx, item) {\n\t\t\tif (this.isTopLink(item)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tevent.preventDefault()\n\t\t\tthis.onDropdownTopClick(idx, item)\n\t\t},\n\n\t\t/**\n\t\t * Navigation request from a tree node: a link click goes through the\n\t\t * link handler, a request without an event navigates directly.\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @param {MouseEvent} [event] the click event, when the node's link was clicked.\n\t\t * @return {void}\n\t\t */\n\t\tonTreeNavigate(item, event) {\n\t\t\tif (event) {\n\t\t\t\tthis.onLinkClick(event, item)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.onNavigate(item)\n\t\t},\n\n\t\t/**\n\t\t * Navigate to an item's URL (router push for internal, new tab for\n\t\t * external), closing any open menus first. Used where no link click\n\t\t * is involved (keyboard activation of a menu item).\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonNavigate(item) {\n\t\t\tif (!item || typeof item.url !== 'string' || item.url === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.closeAll()\n\t\t\tconst url = item.url\n\t\t\tconst { href } = menuLinkAttrs(url, this.$router)\n\t\t\tif (this.isExternal(url)) {\n\t\t\t\tif (typeof window !== 'undefined' && typeof window.open === 'function') {\n\t\t\t\t\twindow.open(href, '_blank', 'noopener,noreferrer')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (isRouterPath(url) && this.$router && typeof this.$router.push === 'function') {\n\t\t\t\ttry {\n\t\t\t\t\tthis.$router.push(url)\n\t\t\t\t\treturn\n\t\t\t\t} catch {\n\t\t\t\t\t// Fall through to location assignment.\n\t\t\t\t}\n\t\t\t}\n\t\t\t// href is safeHref-checked, so a javascript: URL never reaches location.\n\t\t\tif (href !== '#' && typeof window !== 'undefined' && window.location) {\n\t\t\t\twindow.location.href = href\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether a URL is external (http/https).\n\t\t *\n\t\t * @param {string} url the URL.\n\t\t * @return {boolean} true for absolute http(s) URLs.\n\t\t */\n\t\tisExternal(url) {\n\t\t\treturn typeof url === 'string' && /^https?:\\/\\//i.test(url)\n\t\t},\n\n\t\t/**\n\t\t * Empty-state click — request edit when in edit mode.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonEmptyStateClick() {\n\t\t\tif (this.isInEditMode) {\n\t\t\t\tthis.$emit('edit-request')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Test helper — whether a URL is active for the current location.\n\t\t *\n\t\t * @param {string} itemUrl the URL to test.\n\t\t * @return {boolean} true when active.\n\t\t */\n\t\t__isActive(itemUrl) {\n\t\t\treturn isActiveItem(itemUrl, this.currentLocation)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-menu-widget {\n\twidth: 100%;\n\theight: 100%;\n\tpadding: 4px;\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n}\n\n.cn-menu-widget__empty {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-style: italic;\n\tborder: 1px dashed var(--color-border);\n\tborder-radius: var(--border-radius);\n}\n\n.cn-menu-widget__empty--clickable {\n\tcursor: pointer;\n}\n\n.cn-menu-widget__empty-icon {\n\tfont-size: 18px;\n}\n\n.cn-menu-widget__bar {\n\tdisplay: flex;\n\tflex-direction: row;\n\tgap: 4px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-menu-widget__bar--vertical {\n\tflex-direction: column;\n}\n\n.cn-menu-widget__bar-item {\n\tposition: relative;\n\tlist-style: none;\n}\n\n.cn-menu-widget__bar-button,\n.cn-menu-widget__dropdown-item,\n.cn-menu-widget__mega-group-title,\n.cn-menu-widget__mega-leaf {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 6px 10px;\n\tbackground: transparent;\n\tborder: none;\n\tborder-radius: var(--border-radius);\n\tcolor: inherit;\n\tfont-size: 14px;\n\tcursor: pointer;\n\ttext-align: left;\n\ttext-decoration: none;\n\tbox-sizing: border-box;\n\twidth: 100%;\n}\n\n.cn-menu-widget__mega-group-title {\n\tfont-weight: 600;\n}\n\n.cn-menu-widget__bar-button:hover,\n.cn-menu-widget__dropdown-item:hover,\n.cn-menu-widget__mega-group-title:hover,\n.cn-menu-widget__mega-leaf:hover {\n\tbackground: var(--color-background-hover);\n}\n\n.cn-menu-widget__bar-button:focus-visible,\n.cn-menu-widget__dropdown-item:focus-visible {\n\toutline: 2px solid var(--color-primary);\n\toutline-offset: 2px;\n}\n\n.cn-menu-widget__icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 20px;\n\theight: 20px;\n}\n\n.cn-menu-widget__icon--hidden {\n\tvisibility: hidden;\n}\n\n.cn-menu-widget__caret {\n\tmargin-left: auto;\n\tfont-size: 10px;\n}\n\n.cn-menu-widget__dropdown {\n\tposition: absolute;\n\ttop: 100%;\n\tleft: 0;\n\tz-index: 50;\n\tmargin: 4px 0 0;\n\tpadding: 4px;\n\tmin-width: 180px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n\tlist-style: none;\n}\n\n.cn-menu-widget__dropdown-item-wrap {\n\tposition: relative;\n}\n\n.cn-menu-widget__flyout {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 100%;\n\tmargin-left: 2px;\n\tpadding: 4px;\n\tmin-width: 160px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n\tlist-style: none;\n}\n\n.cn-menu-widget__mega-panel {\n\tmargin-top: 4px;\n\tpadding: 12px;\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n\tgap: 12px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n}\n\n.cn-menu-widget__mega-leaves {\n\tmargin: 4px 0 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-menu-widget__tree {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n/* Active-item highlight variants. */\n.cn-menu-widget--highlight-underline .cn-menu-widget__item--active {\n\tborder-bottom: 3px solid var(--color-primary);\n}\n\n.cn-menu-widget--highlight-underline .cn-menu-widget__item--in-path {\n\tborder-bottom: 2px solid var(--color-primary);\n\topacity: 0.85;\n}\n\n.cn-menu-widget--highlight-background .cn-menu-widget__item--active,\n.cn-menu-widget--highlight-background .cn-menu-widget__item--in-path {\n\tbackground: var(--color-primary-element-light, rgba(0, 112, 192, 0.1));\n\tcolor: var(--color-primary);\n}\n\n.cn-menu-widget--highlight-left-bar .cn-menu-widget__item--active {\n\tborder-left: 5px solid var(--color-primary);\n\tpadding-left: 6px;\n}\n\n.cn-menu-widget--highlight-left-bar .cn-menu-widget__item--in-path {\n\tborder-left: 4px solid var(--color-primary);\n\tpadding-left: 7px;\n\topacity: 0.85;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_openBlock","_Fragment","_renderList","_createBlock","_resolveDynamicComponent","_mergeProps","_toDisplayString","_withKeys","_withModifiers"],"mappings":"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"}
1
+ {"version":3,"file":"CnMenuWidget.vue3.js","sources":["../../../../src/components/CnMenuWidget/CnMenuWidget.vue?vue&type=template&id=2edac2f0&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-menu-widget\"\n\t\t:class=\"rootClasses\"\n\t\t@keydown.esc.stop=\"closeAll\">\n\t\t<!-- Empty state -->\n\t\t<div\n\t\t\tv-if=\"isEmpty\"\n\t\t\tclass=\"cn-menu-widget__empty\"\n\t\t\t:class=\"{ 'cn-menu-widget__empty--clickable': isInEditMode }\"\n\t\t\t:role=\"isInEditMode ? 'button' : null\"\n\t\t\t:tabindex=\"isInEditMode ? 0 : -1\"\n\t\t\t@click=\"onEmptyStateClick\"\n\t\t\t@keyup.enter=\"onEmptyStateClick\"\n\t\t\t@keyup.space=\"onEmptyStateClick\">\n\t\t\t<span class=\"cn-menu-widget__empty-icon\" aria-hidden=\"true\">⚙</span>\n\t\t\t<span>{{ t('nextcloud-vue', 'No menu items yet — click the gear icon to add some.') }}</span>\n\t\t</div>\n\n\t\t<!-- Tree style -->\n\t\t<ul\n\t\t\tv-else-if=\"effectiveStyle === 'tree'\"\n\t\t\tclass=\"cn-menu-widget__tree\"\n\t\t\trole=\"tree\">\n\t\t\t<CnMenuTreeNode\n\t\t\t\tv-for=\"(item, idx) in items\"\n\t\t\t\t:key=\"`tree-${idx}`\"\n\t\t\t\t:item=\"item\"\n\t\t\t\t:depth=\"1\"\n\t\t\t\t:showIcons=\"showIcons\"\n\t\t\t\t:expandedByDefault=\"expandedByDefault\"\n\t\t\t\t:activePath=\"activePath\"\n\t\t\t\t:activeLeafKey=\"activeLeafKey\"\n\t\t\t\t:currentKey=\"`${idx}`\"\n\t\t\t\t:activeHighlight=\"activeItemHighlight\"\n\t\t\t\t@navigate=\"onTreeNavigate\" />\n\t\t</ul>\n\n\t\t<!-- Megamenu style -->\n\t\t<div\n\t\t\tv-else-if=\"effectiveStyle === 'megamenu'\"\n\t\t\tclass=\"cn-menu-widget__megamenu\">\n\t\t\t<ul\n\t\t\t\tclass=\"cn-menu-widget__bar\"\n\t\t\t\trole=\"menubar\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"(item, idx) in items\"\n\t\t\t\t\t:key=\"`mega-top-${idx}`\"\n\t\t\t\t\trole=\"none\"\n\t\t\t\t\tclass=\"cn-menu-widget__bar-item\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"isTopLink(item) ? 'a' : 'button'\"\n\t\t\t\t\t\t:ref=\"(el) => setTopRef(el, idx)\"\n\t\t\t\t\t\tv-bind=\"isTopLink(item) ? linkAttrs(item) : { type: 'button' }\"\n\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\tclass=\"cn-menu-widget__bar-button\"\n\t\t\t\t\t\t:class=\"topItemClass(`${idx}`)\"\n\t\t\t\t\t\t:aria-haspopup=\"hasChildren(item) ? 'menu' : null\"\n\t\t\t\t\t\t:aria-expanded=\"megaOpenIndex === idx ? 'true' : 'false'\"\n\t\t\t\t\t\t@click=\"isTopLink(item) ? onLinkClick($event, item) : onMegaTopClick(idx, item)\"\n\t\t\t\t\t\t@keydown=\"onMegaTopKey($event, idx, item)\">\n\t\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !item.icon }\">\n\t\t\t\t\t\t\t<CnMenuItemIcon v-if=\"item.icon\" :icon=\"item.icon\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ item.label }}</span>\n\t\t\t\t\t</component>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div\n\t\t\t\tv-if=\"megaOpenIndex !== null && hasChildren(items[megaOpenIndex])\"\n\t\t\t\tref=\"megaPanel\"\n\t\t\t\tclass=\"cn-menu-widget__mega-panel\"\n\t\t\t\trole=\"menu\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"(child, childIdx) in items[megaOpenIndex].children\"\n\t\t\t\t\t:key=\"`mega-group-${childIdx}`\"\n\t\t\t\t\tclass=\"cn-menu-widget__mega-group\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"isLink(child) ? 'a' : 'button'\"\n\t\t\t\t\t\tv-bind=\"itemAttrs(child)\"\n\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\tclass=\"cn-menu-widget__mega-group-title\"\n\t\t\t\t\t\t:class=\"topItemClass(`${megaOpenIndex}.${childIdx}`)\"\n\t\t\t\t\t\t@click=\"onLinkClick($event, child)\">\n\t\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !child.icon }\">\n\t\t\t\t\t\t\t<CnMenuItemIcon v-if=\"child.icon\" :icon=\"child.icon\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ child.label }}</span>\n\t\t\t\t\t</component>\n\t\t\t\t\t<ul\n\t\t\t\t\t\tv-if=\"hasChildren(child)\"\n\t\t\t\t\t\tclass=\"cn-menu-widget__mega-leaves\">\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-for=\"(leaf, leafIdx) in child.children\"\n\t\t\t\t\t\t\t:key=\"`mega-leaf-${leafIdx}`\"\n\t\t\t\t\t\t\trole=\"none\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"isLink(leaf) ? 'a' : 'button'\"\n\t\t\t\t\t\t\t\tv-bind=\"itemAttrs(leaf)\"\n\t\t\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\t\t\tclass=\"cn-menu-widget__mega-leaf\"\n\t\t\t\t\t\t\t\t:class=\"topItemClass(`${megaOpenIndex}.${childIdx}.${leafIdx}`)\"\n\t\t\t\t\t\t\t\t@click=\"onLinkClick($event, leaf)\">\n\t\t\t\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !leaf.icon }\">\n\t\t\t\t\t\t\t\t\t<CnMenuItemIcon v-if=\"leaf.icon\" :icon=\"leaf.icon\" />\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ leaf.label }}</span>\n\t\t\t\t\t\t\t</component>\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\n\t\t<!-- Dropdown style (default) -->\n\t\t<ul\n\t\t\tv-else\n\t\t\tclass=\"cn-menu-widget__bar\"\n\t\t\t:class=\"{ 'cn-menu-widget__bar--vertical': orientation === 'vertical' }\"\n\t\t\trole=\"menubar\">\n\t\t\t<li\n\t\t\t\tv-for=\"(item, idx) in items\"\n\t\t\t\t:key=\"`drop-top-${idx}`\"\n\t\t\t\t:ref=\"(el) => setBarItemRef(el, idx)\"\n\t\t\t\trole=\"none\"\n\t\t\t\tclass=\"cn-menu-widget__bar-item\">\n\t\t\t\t<component\n\t\t\t\t\t:is=\"isTopLink(item) ? 'a' : 'button'\"\n\t\t\t\t\t:ref=\"(el) => setTopRef(el, idx)\"\n\t\t\t\t\tv-bind=\"isTopLink(item) ? linkAttrs(item) : { type: 'button' }\"\n\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\tclass=\"cn-menu-widget__bar-button\"\n\t\t\t\t\t:class=\"topItemClass(`${idx}`)\"\n\t\t\t\t\t:aria-haspopup=\"hasChildren(item) ? 'menu' : null\"\n\t\t\t\t\t:aria-expanded=\"dropOpenIndex === idx ? 'true' : 'false'\"\n\t\t\t\t\t@click=\"isTopLink(item) ? onLinkClick($event, item) : onDropdownTopClick(idx, item)\"\n\t\t\t\t\t@keydown.tab=\"closeAll\"\n\t\t\t\t\t@keydown.enter=\"onDropdownTopEnter($event, idx, item)\"\n\t\t\t\t\t@keydown.space.prevent=\"onDropdownTopClick(idx, item)\"\n\t\t\t\t\t@keydown.down.prevent=\"openDropdown(idx)\">\n\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !item.icon }\">\n\t\t\t\t\t\t<CnMenuItemIcon v-if=\"item.icon\" :icon=\"item.icon\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ item.label }}</span>\n\t\t\t\t\t<span v-if=\"hasChildren(item)\" class=\"cn-menu-widget__caret\" aria-hidden=\"true\">▾</span>\n\t\t\t\t</component>\n\t\t\t\t<ul\n\t\t\t\t\tv-if=\"dropOpenIndex === idx && hasChildren(item)\"\n\t\t\t\t\tclass=\"cn-menu-widget__dropdown\"\n\t\t\t\t\trole=\"menu\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"(child, childIdx) in item.children\"\n\t\t\t\t\t\t:key=\"`drop-child-${childIdx}`\"\n\t\t\t\t\t\trole=\"none\"\n\t\t\t\t\t\tclass=\"cn-menu-widget__dropdown-item-wrap\"\n\t\t\t\t\t\t@mouseenter=\"hasChildren(child) && (flyoutOpenKey = `${idx}.${childIdx}`)\">\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"isLink(child) ? 'a' : 'button'\"\n\t\t\t\t\t\t\tv-bind=\"itemAttrs(child)\"\n\t\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\t\tclass=\"cn-menu-widget__dropdown-item\"\n\t\t\t\t\t\t\t:class=\"topItemClass(`${idx}.${childIdx}`)\"\n\t\t\t\t\t\t\t@click=\"onLinkClick($event, child)\">\n\t\t\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !child.icon }\">\n\t\t\t\t\t\t\t\t<CnMenuItemIcon v-if=\"child.icon\" :icon=\"child.icon\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ child.label }}</span>\n\t\t\t\t\t\t\t<span v-if=\"hasChildren(child)\" class=\"cn-menu-widget__caret cn-menu-widget__caret--right\" aria-hidden=\"true\">▸</span>\n\t\t\t\t\t\t</component>\n\t\t\t\t\t\t<ul\n\t\t\t\t\t\t\tv-if=\"flyoutOpenKey === `${idx}.${childIdx}` && hasChildren(child)\"\n\t\t\t\t\t\t\tclass=\"cn-menu-widget__flyout\"\n\t\t\t\t\t\t\trole=\"menu\">\n\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\tv-for=\"(leaf, leafIdx) in child.children\"\n\t\t\t\t\t\t\t\t:key=\"`drop-leaf-${leafIdx}`\"\n\t\t\t\t\t\t\t\trole=\"none\">\n\t\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t\t:is=\"isLink(leaf) ? 'a' : 'button'\"\n\t\t\t\t\t\t\t\t\tv-bind=\"itemAttrs(leaf)\"\n\t\t\t\t\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-menu-widget__dropdown-item\"\n\t\t\t\t\t\t\t\t\t:class=\"topItemClass(`${idx}.${childIdx}.${leafIdx}`)\"\n\t\t\t\t\t\t\t\t\t@click=\"onLinkClick($event, leaf)\">\n\t\t\t\t\t\t\t\t\t<span v-if=\"showIcons\" class=\"cn-menu-widget__icon\" :class=\"{ 'cn-menu-widget__icon--hidden': !leaf.icon }\">\n\t\t\t\t\t\t\t\t\t\t<CnMenuItemIcon v-if=\"leaf.icon\" :icon=\"leaf.icon\" />\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t<span class=\"cn-menu-widget__label\">{{ leaf.label }}</span>\n\t\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</li>\n\t\t</ul>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport CnMenuItemIcon from './CnMenuItemIcon.vue'\nimport CnMenuTreeNode from './CnMenuTreeNode.vue'\nimport { followLinkClick } from '../../utils/linkNavigation.js'\nimport { computeActivePath, isActiveItem, isRouterPath, menuLinkAttrs } from './menuActive.js'\n\nconst VALID_STYLES = ['dropdown', 'megamenu', 'tree']\nconst VALID_ORIENTATIONS = ['horizontal', 'vertical']\nconst VALID_HIGHLIGHTS = ['background', 'underline', 'left-bar', 'none']\n\n/**\n * CnMenuWidget — renders a hierarchical navigation widget with three visual\n * styles (dropdown, megamenu, tree) and active-item highlighting based on\n * `window.location.pathname`.\n *\n * Active-item detection runs on mount and whenever `items` or the URL change;\n * ancestors of the active leaf are flagged \"in-path\" so the configured\n * highlight (`underline`, `background`, `left-bar`, `none`) renders\n * consistently. Keyboard navigation follows the WAI-ARIA Menu/Menubar pattern.\n *\n * Open dropdown/megamenu panels close on: re-clicking the toggle, Escape,\n * Tab, navigating a leaf, and clicking ANYWHERE else — including empty space\n * elsewhere in the widget itself, not just outside it entirely (a\n * document-level listener that checks containment against the open toggle\n * button + its own panel specifically, since the panels are plain in-DOM\n * markup, not a teleported popover with its own outside-click handling).\n *\n * @spec openspec/changes/cn-widget-library/specs/cn-widget-library/spec.md\n */\nexport default {\n\tname: 'CnMenuWidget',\n\n\tcomponents: {\n\t\tCnMenuTreeNode,\n\t\tCnMenuItemIcon,\n\t},\n\n\tinject: {\n\t\t/** Host translate function provided by CnAppRoot, for the item labels. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted widget content `{items, style, orientation, showIcons,\n\t\t * expandedByDefault, activeItemHighlight}`.\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/** Whether the current user is an admin (pairs with `canEdit`). */\n\t\tisAdmin: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether the surrounding shell is in edit mode. */\n\t\tcanEdit: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: [\n\t\t/** Fired when the empty-state gear is clicked in edit mode. */\n\t\t'edit-request',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tdropOpenIndex: null,\n\t\t\tflyoutOpenKey: null,\n\t\t\tmegaOpenIndex: null,\n\t\t\tcurrentLocation: this.readLocation(),\n\t\t\ttopRefs: [],\n\t\t\tbarItemRefs: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The configured menu items.\n\t\t *\n\t\t * @return {object[]} the items array.\n\t\t */\n\t\titems() {\n\t\t\tconst arr = this.content?.items\n\t\t\tif (!Array.isArray(arr)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\t// Labels are manifest strings: they go through the app's translate,\n\t\t\t// children included, so \"Case types\" reads \"Zaaktypen\" (DqCatalogus).\n\t\t\tconst translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (key) => key\n\t\t\tconst translated = (list) => list.map((item) => {\n\t\t\t\tif (!item || typeof item !== 'object') {\n\t\t\t\t\treturn item\n\t\t\t\t}\n\t\t\t\tconst out = { ...item }\n\t\t\t\tif (typeof item.label === 'string' && item.label !== '') {\n\t\t\t\t\tout.label = translate(item.label)\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(item.children)) {\n\t\t\t\t\tout.children = translated(item.children)\n\t\t\t\t}\n\t\t\t\treturn out\n\t\t\t})\n\t\t\treturn translated(arr)\n\t\t},\n\n\t\t/**\n\t\t * Whether the menu has no items.\n\t\t *\n\t\t * @return {boolean} true when empty.\n\t\t */\n\t\tisEmpty() {\n\t\t\treturn this.items.length === 0\n\t\t},\n\n\t\t/**\n\t\t * The validated visual style (default `dropdown`).\n\t\t *\n\t\t * @return {string} one of dropdown/megamenu/tree.\n\t\t */\n\t\teffectiveStyle() {\n\t\t\tconst s = this.content?.style\n\t\t\treturn VALID_STYLES.includes(s) ? s : 'dropdown'\n\t\t},\n\n\t\t/**\n\t\t * The validated orientation (tree is always vertical).\n\t\t *\n\t\t * @return {string} `horizontal` or `vertical`.\n\t\t */\n\t\torientation() {\n\t\t\tconst o = this.content?.orientation\n\t\t\tif (this.effectiveStyle === 'tree') {\n\t\t\t\treturn 'vertical'\n\t\t\t}\n\t\t\treturn VALID_ORIENTATIONS.includes(o) ? o : 'horizontal'\n\t\t},\n\n\t\t/**\n\t\t * Whether item icons render (default true).\n\t\t *\n\t\t * @return {boolean} the showIcons flag.\n\t\t */\n\t\tshowIcons() {\n\t\t\treturn this.content?.showIcons !== false\n\t\t},\n\n\t\t/**\n\t\t * Whether tree nodes start expanded.\n\t\t *\n\t\t * @return {boolean} the expandedByDefault flag.\n\t\t */\n\t\texpandedByDefault() {\n\t\t\treturn this.content?.expandedByDefault === true\n\t\t},\n\n\t\t/**\n\t\t * The validated active-item highlight style (default `underline`).\n\t\t *\n\t\t * @return {string} one of background/underline/left-bar/none.\n\t\t */\n\t\tactiveItemHighlight() {\n\t\t\tconst h = this.content?.activeItemHighlight\n\t\t\treturn VALID_HIGHLIGHTS.includes(h) ? h : 'underline'\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget is in edit mode (empty-state gear clickable).\n\t\t *\n\t\t * @return {boolean} true when admin + canEdit.\n\t\t */\n\t\tisInEditMode() {\n\t\t\treturn this.isAdmin === true && this.canEdit === true\n\t\t},\n\n\t\t/**\n\t\t * The root style/highlight/orientation CSS classes.\n\t\t *\n\t\t * @return {object} the class map.\n\t\t */\n\t\trootClasses() {\n\t\t\treturn {\n\t\t\t\t[`cn-menu-widget--style-${this.effectiveStyle}`]: true,\n\t\t\t\t[`cn-menu-widget--highlight-${this.activeItemHighlight}`]: true,\n\t\t\t\t[`cn-menu-widget--orientation-${this.orientation}`]: true,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The dotted-key path map for the current location.\n\t\t *\n\t\t * @return {{path: object, leafKey: string|null}} the active-path map.\n\t\t */\n\t\tactivePathMap() {\n\t\t\treturn computeActivePath({\n\t\t\t\titems: this.items,\n\t\t\t\tcurrentLocation: this.currentLocation,\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The dotted-key → state map.\n\t\t *\n\t\t * @return {Record<string, string>} the path map.\n\t\t */\n\t\tactivePath() {\n\t\t\treturn this.activePathMap.path\n\t\t},\n\n\t\t/**\n\t\t * The key of the deepest active leaf.\n\t\t *\n\t\t * @return {string|null} the leaf key.\n\t\t */\n\t\tactiveLeafKey() {\n\t\t\treturn this.activePathMap.leafKey\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.boundLocationListener = () => {\n\t\t\tthis.currentLocation = this.readLocation()\n\t\t}\n\t\tif (typeof window !== 'undefined') {\n\t\t\twindow.addEventListener('popstate', this.boundLocationListener)\n\t\t\twindow.addEventListener('hashchange', this.boundLocationListener)\n\t\t}\n\t\tthis.boundOutsideClickListener = this.onOutsideClick\n\t\tif (typeof document !== 'undefined') {\n\t\t\tdocument.addEventListener('click', this.boundOutsideClickListener)\n\t\t}\n\t},\n\n\tbeforeUnmount() {\n\t\tif (typeof window !== 'undefined' && this.boundLocationListener) {\n\t\t\twindow.removeEventListener('popstate', this.boundLocationListener)\n\t\t\twindow.removeEventListener('hashchange', this.boundLocationListener)\n\t\t}\n\t\tif (typeof document !== 'undefined' && this.boundOutsideClickListener) {\n\t\t\tdocument.removeEventListener('click', this.boundOutsideClickListener)\n\t\t}\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the current browser location into a small bag.\n\t\t *\n\t\t * @return {{pathname: string, host: string}} the location bag.\n\t\t */\n\t\treadLocation() {\n\t\t\tif (typeof window === 'undefined' || !window.location) {\n\t\t\t\treturn { pathname: '/', host: '' }\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tpathname: window.location.pathname || '/',\n\t\t\t\thost: window.location.host || '',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Stash a top-level button ref by index.\n\t\t *\n\t\t * @param {HTMLElement} el the button element.\n\t\t * @param {number} idx the item index.\n\t\t * @return {void}\n\t\t */\n\t\tsetTopRef(el, idx) {\n\t\t\tif (el) {\n\t\t\t\tthis.topRefs[idx] = el\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Stash a dropdown-style top-level `<li>` ref by index. This `<li>`\n\t\t * contains both the toggle button and its dropdown/flyout panel, so a\n\t\t * single containment check against it covers the whole open structure.\n\t\t *\n\t\t * @param {HTMLElement} el the `<li>` element.\n\t\t * @param {number} idx the item index.\n\t\t * @return {void}\n\t\t */\n\t\tsetBarItemRef(el, idx) {\n\t\t\tif (el) {\n\t\t\t\tthis.barItemRefs[idx] = el\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an item has children.\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {boolean} true when it has a non-empty children array.\n\t\t */\n\t\thasChildren(item) {\n\t\t\treturn item && Array.isArray(item.children) && item.children.length > 0\n\t\t},\n\n\t\t/**\n\t\t * The active-state class for a dotted key.\n\t\t *\n\t\t * @param {string} key the dotted item key.\n\t\t * @return {string} the class name (or `''`).\n\t\t */\n\t\ttopItemClass(key) {\n\t\t\tconst state = this.activePath[key]\n\t\t\tif (state === 'active' || key === this.activeLeafKey) {\n\t\t\t\treturn 'cn-menu-widget__item--active'\n\t\t\t}\n\t\t\tif (state === 'in-path') {\n\t\t\t\treturn 'cn-menu-widget__item--in-path'\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\t/**\n\t\t * Top-level dropdown click — navigate a leaf or toggle the dropdown.\n\t\t *\n\t\t * @param {number} idx the item index.\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonDropdownTopClick(idx, item) {\n\t\t\tif (!this.hasChildren(item)) {\n\t\t\t\tthis.onNavigate(item)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.dropOpenIndex === idx) {\n\t\t\t\tthis.dropOpenIndex = null\n\t\t\t\tthis.flyoutOpenKey = null\n\t\t\t} else {\n\t\t\t\tthis.dropOpenIndex = idx\n\t\t\t\tthis.flyoutOpenKey = null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Open the dropdown at an index when it has children.\n\t\t *\n\t\t * @param {number} idx the item index.\n\t\t * @return {void}\n\t\t */\n\t\topenDropdown(idx) {\n\t\t\tif (this.hasChildren(this.items[idx])) {\n\t\t\t\tthis.dropOpenIndex = idx\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Top-level megamenu click — navigate a leaf or toggle the panel.\n\t\t *\n\t\t * @param {number} idx the item index.\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonMegaTopClick(idx, item) {\n\t\t\tif (!this.hasChildren(item)) {\n\t\t\t\tthis.onNavigate(item)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.megaOpenIndex = this.megaOpenIndex === idx ? null : idx\n\t\t},\n\n\t\t/**\n\t\t * Keyboard handler for megamenu top items.\n\t\t *\n\t\t * @param {KeyboardEvent} event the key event.\n\t\t * @param {number} idx the item index.\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonMegaTopKey(event, idx, item) {\n\t\t\t// Enter on a link clicks it natively.\n\t\t\tif (event.key === 'Enter' && this.isTopLink(item)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown') {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tthis.onMegaTopClick(idx, item)\n\t\t\t} else if (event.key === 'Tab') {\n\t\t\t\tthis.megaOpenIndex = null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Close every open dropdown/flyout/panel.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tcloseAll() {\n\t\t\tthis.dropOpenIndex = null\n\t\t\tthis.flyoutOpenKey = null\n\t\t\tthis.megaOpenIndex = null\n\t\t},\n\n\t\t/**\n\t\t * Document-level click handler — closes any open dropdown/flyout/panel\n\t\t * when the click lands outside its own toggle button + panel, INCLUDING\n\t\t * empty space elsewhere in the widget (e.g. bar padding, gaps between\n\t\t * items) — not just outside the whole widget. The toggle button's own\n\t\t * `@click` handler manages opening/closing for its own clicks, so a\n\t\t * click still inside the open button/panel is left alone — otherwise\n\t\t * every open-toggle click would immediately re-close itself via this\n\t\t * same listener.\n\t\t *\n\t\t * @param {MouseEvent} event the document click event.\n\t\t * @return {void}\n\t\t */\n\t\tonOutsideClick(event) {\n\t\t\tconst target = event.target\n\t\t\tif (this.effectiveStyle === 'megamenu') {\n\t\t\t\tif (this.megaOpenIndex === null) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst button = this.topRefs[this.megaOpenIndex]\n\t\t\t\tconst panel = this.$refs.megaPanel\n\t\t\t\tconst insideButton = Boolean(button && button.contains(target))\n\t\t\t\tconst insidePanel = Boolean(panel && panel.contains(target))\n\t\t\t\tif (!insideButton && !insidePanel) {\n\t\t\t\t\tthis.closeAll()\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Dropdown style — the button and its dropdown/flyout panel share\n\t\t\t// the same top-level `<li>`, so one containment check covers both.\n\t\t\tif (this.dropOpenIndex === null) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst barItem = this.barItemRefs[this.dropOpenIndex]\n\t\t\tif (barItem && !barItem.contains(target)) {\n\t\t\t\tthis.closeAll()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an item renders as a link (it has a URL).\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {boolean} true when the item carries a non-empty URL.\n\t\t */\n\t\tisLink(item) {\n\t\t\treturn Boolean(item) && typeof item.url === 'string' && item.url !== ''\n\t\t},\n\n\t\t/**\n\t\t * Whether a top-level item renders as a link. One with children\n\t\t * stays a button, because its click toggles the panel.\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {boolean} true for a top-level leaf with a URL.\n\t\t */\n\t\tisTopLink(item) {\n\t\t\treturn this.isLink(item) && !this.hasChildren(item)\n\t\t},\n\n\t\t/**\n\t\t * Anchor attributes for an item's URL: external URLs open in a new tab.\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {object} the `href` (plus `target` / `rel` for external URLs).\n\t\t */\n\t\tlinkAttrs(item) {\n\t\t\treturn menuLinkAttrs(item.url, this.$router)\n\t\t},\n\n\t\t/**\n\t\t * Attributes for a panel item: link attributes, or `type=\"button\"`.\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {object} the element attributes.\n\t\t */\n\t\titemAttrs(item) {\n\t\t\treturn this.isLink(item) ? this.linkAttrs(item) : { type: 'button' }\n\t\t},\n\n\t\t/**\n\t\t * Click on an item link: close the menus, then let the browser open\n\t\t * an external URL or a modified click, and route a plain click on an\n\t\t * internal one. A no-op for an item without a URL.\n\t\t *\n\t\t * @param {MouseEvent} event the click event.\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonLinkClick(event, item) {\n\t\t\tif (!this.isLink(item)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.closeAll()\n\t\t\tif (isRouterPath(item.url)) {\n\t\t\t\tfollowLinkClick(event, item.url, this.$router)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Enter on a dropdown top item: a link follows natively (Enter\n\t\t * clicks it); a button toggles or navigates.\n\t\t *\n\t\t * @param {KeyboardEvent} event the key event.\n\t\t * @param {number} idx the item index.\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonDropdownTopEnter(event, idx, item) {\n\t\t\tif (this.isTopLink(item)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tevent.preventDefault()\n\t\t\tthis.onDropdownTopClick(idx, item)\n\t\t},\n\n\t\t/**\n\t\t * Navigation request from a tree node: a link click goes through the\n\t\t * link handler, a request without an event navigates directly.\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @param {MouseEvent} [event] the click event, when the node's link was clicked.\n\t\t * @return {void}\n\t\t */\n\t\tonTreeNavigate(item, event) {\n\t\t\tif (event) {\n\t\t\t\tthis.onLinkClick(event, item)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.onNavigate(item)\n\t\t},\n\n\t\t/**\n\t\t * Navigate to an item's URL (router push for internal, new tab for\n\t\t * external), closing any open menus first. Used where no link click\n\t\t * is involved (keyboard activation of a menu item).\n\t\t *\n\t\t * @param {object} item the menu item.\n\t\t * @return {void}\n\t\t */\n\t\tonNavigate(item) {\n\t\t\tif (!item || typeof item.url !== 'string' || item.url === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.closeAll()\n\t\t\tconst url = item.url\n\t\t\tconst { href } = menuLinkAttrs(url, this.$router)\n\t\t\tif (this.isExternal(url)) {\n\t\t\t\tif (typeof window !== 'undefined' && typeof window.open === 'function') {\n\t\t\t\t\twindow.open(href, '_blank', 'noopener,noreferrer')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (isRouterPath(url) && this.$router && typeof this.$router.push === 'function') {\n\t\t\t\ttry {\n\t\t\t\t\tthis.$router.push(url)\n\t\t\t\t\treturn\n\t\t\t\t} catch {\n\t\t\t\t\t// Fall through to location assignment.\n\t\t\t\t}\n\t\t\t}\n\t\t\t// href is safeHref-checked, so a javascript: URL never reaches location.\n\t\t\tif (href !== '#' && typeof window !== 'undefined' && window.location) {\n\t\t\t\twindow.location.href = href\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether a URL is external (http/https).\n\t\t *\n\t\t * @param {string} url the URL.\n\t\t * @return {boolean} true for absolute http(s) URLs.\n\t\t */\n\t\tisExternal(url) {\n\t\t\treturn typeof url === 'string' && /^https?:\\/\\//i.test(url)\n\t\t},\n\n\t\t/**\n\t\t * Empty-state click — request edit when in edit mode.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonEmptyStateClick() {\n\t\t\tif (this.isInEditMode) {\n\t\t\t\tthis.$emit('edit-request')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Test helper — whether a URL is active for the current location.\n\t\t *\n\t\t * @param {string} itemUrl the URL to test.\n\t\t * @return {boolean} true when active.\n\t\t */\n\t\t__isActive(itemUrl) {\n\t\t\treturn isActiveItem(itemUrl, this.currentLocation)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-menu-widget {\n\twidth: 100%;\n\theight: 100%;\n\tpadding: 4px;\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n}\n\n.cn-menu-widget__empty {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-style: italic;\n\tborder: 1px dashed var(--color-border);\n\tborder-radius: var(--border-radius);\n}\n\n.cn-menu-widget__empty--clickable {\n\tcursor: pointer;\n}\n\n.cn-menu-widget__empty-icon {\n\tfont-size: 18px;\n}\n\n.cn-menu-widget__bar {\n\tdisplay: flex;\n\tflex-direction: row;\n\tgap: 4px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-menu-widget__bar--vertical {\n\tflex-direction: column;\n}\n\n.cn-menu-widget__bar-item {\n\tposition: relative;\n\tlist-style: none;\n}\n\n.cn-menu-widget__bar-button,\n.cn-menu-widget__dropdown-item,\n.cn-menu-widget__mega-group-title,\n.cn-menu-widget__mega-leaf {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 6px 10px;\n\tbackground: transparent;\n\tborder: none;\n\tborder-radius: var(--border-radius);\n\tcolor: inherit;\n\tfont-size: 14px;\n\tcursor: pointer;\n\ttext-align: left;\n\ttext-decoration: none;\n\tbox-sizing: border-box;\n\twidth: 100%;\n}\n\n.cn-menu-widget__mega-group-title {\n\tfont-weight: 600;\n}\n\n.cn-menu-widget__bar-button:hover,\n.cn-menu-widget__dropdown-item:hover,\n.cn-menu-widget__mega-group-title:hover,\n.cn-menu-widget__mega-leaf:hover {\n\tbackground: var(--color-background-hover);\n}\n\n.cn-menu-widget__bar-button:focus-visible,\n.cn-menu-widget__dropdown-item:focus-visible {\n\toutline: 2px solid var(--color-primary);\n\toutline-offset: 2px;\n}\n\n.cn-menu-widget__icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 20px;\n\theight: 20px;\n}\n\n.cn-menu-widget__icon--hidden {\n\tvisibility: hidden;\n}\n\n.cn-menu-widget__caret {\n\tmargin-left: auto;\n\tfont-size: 10px;\n}\n\n.cn-menu-widget__dropdown {\n\tposition: absolute;\n\ttop: 100%;\n\tleft: 0;\n\tz-index: 50;\n\tmargin: 4px 0 0;\n\tpadding: 4px;\n\tmin-width: 180px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n\tlist-style: none;\n}\n\n.cn-menu-widget__dropdown-item-wrap {\n\tposition: relative;\n}\n\n.cn-menu-widget__flyout {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 100%;\n\tmargin-left: 2px;\n\tpadding: 4px;\n\tmin-width: 160px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n\tlist-style: none;\n}\n\n.cn-menu-widget__mega-panel {\n\tmargin-top: 4px;\n\tpadding: 12px;\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n\tgap: 12px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n}\n\n.cn-menu-widget__mega-leaves {\n\tmargin: 4px 0 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-menu-widget__tree {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n/* Active-item highlight variants. */\n.cn-menu-widget--highlight-underline .cn-menu-widget__item--active {\n\tborder-bottom: 3px solid var(--color-primary);\n}\n\n.cn-menu-widget--highlight-underline .cn-menu-widget__item--in-path {\n\tborder-bottom: 2px solid var(--color-primary);\n\topacity: 0.85;\n}\n\n.cn-menu-widget--highlight-background .cn-menu-widget__item--active,\n.cn-menu-widget--highlight-background .cn-menu-widget__item--in-path {\n\tbackground: var(--color-primary-element-light, rgba(0, 112, 192, 0.1));\n\tcolor: var(--color-primary);\n}\n\n.cn-menu-widget--highlight-left-bar .cn-menu-widget__item--active {\n\tborder-left: 5px solid var(--color-primary);\n\tpadding-left: 6px;\n}\n\n.cn-menu-widget--highlight-left-bar .cn-menu-widget__item--in-path {\n\tborder-left: 4px solid var(--color-primary);\n\tpadding-left: 7px;\n\topacity: 0.85;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_openBlock","_Fragment","_renderList","_createBlock","_resolveDynamicComponent","_mergeProps","_toDisplayString","_withKeys","_withModifiers"],"mappings":"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"}
@@ -2,7 +2,7 @@ import script from './CnObjectListWidget.vue2.js';
2
2
  import { render } from './CnObjectListWidget.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-535337c7";
5
+ script.__scopeId = "data-v-aeadc210";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -140,8 +140,10 @@ var script = {
140
140
  * `hideHeader: true` drops the table's column header row (CnDataTable's
141
141
  * `hideHeader`), for a short list that reads as rows, not as a table.
142
142
  *
143
+ * `footnote` is a line under the table, through the host translate.
144
+ *
143
145
  * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-small-opt-ins-from-the-decidiq-and-learniq-lanes
144
- * @type {{register?: string, schema?: string, filter?: object, sort?: {field?: string, dir?: string}, limit?: number, extend?: Array<string>, columns?: Array, rowActions?: Array<object>, dropZone?: object, upload?: boolean, groupBy?: string, groupLabel?: string, groupLabelResolve?: {register: string, schema: string, labelField?: string}, selectable?: boolean, bulkActions?: Array<object>, sortable?: boolean, facet?: {field: string, label?: string}, rowRoute?: string, prompt?: string, emptyText?: string, viewAllRoute?: string, viewAllQuery?: object, hideHeader?: boolean}}
146
+ * @type {{register?: string, schema?: string, filter?: object, sort?: {field?: string, dir?: string}, limit?: number, extend?: Array<string>, columns?: Array, rowActions?: Array<object>, dropZone?: object, upload?: boolean, groupBy?: string, groupLabel?: string, groupLabelResolve?: {register: string, schema: string, labelField?: string}, selectable?: boolean, bulkActions?: Array<object>, sortable?: boolean, facet?: {field: string, label?: string}, rowRoute?: string, prompt?: string, emptyText?: string, footnote?: string, viewAllRoute?: string, viewAllQuery?: object, hideHeader?: boolean}}
145
147
  */
146
148
  content: {
147
149
  type: Object,
@@ -628,6 +630,17 @@ var script = {
628
630
  return this.emptyText ? fn(this.emptyText) : this.emptyText
629
631
  },
630
632
 
633
+ /**
634
+ * `content.footnote` run through the host translate function, or ''.
635
+ *
636
+ * @return {string}
637
+ */
638
+ resolvedFootnote() {
639
+ const note = typeof this.content.footnote === 'string' ? this.content.footnote : '';
640
+ const fn = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k;
641
+ return note ? fn(note) : ''
642
+ },
643
+
631
644
  /**
632
645
  * The rows actually rendered: capped to what fits the host grid cell
633
646
  * (ADR-062 — content adapts to the cell, never a nested scrollbar).