@conduction/nextcloud-vue 2.101.0 → 2.103.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 (140) 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/CnConversationThread/CnConversationThread.vue.js +1 -1
  11. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +73 -0
  12. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
  13. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +99 -64
  14. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
  15. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
  16. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +46 -0
  17. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
  18. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +37 -2
  19. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
  20. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  21. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +49 -6
  22. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  23. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +1 -1
  24. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  25. package/dist/esm/components/CnFormDialog/CnFormDialog.vue.js +1 -1
  26. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +113 -20
  27. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  28. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +387 -359
  29. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  30. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +84 -4
  31. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  32. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +8 -6
  33. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  34. package/dist/esm/components/CnIndexPage/useNamedSource.js +26 -2
  35. package/dist/esm/components/CnIndexPage/useNamedSource.js.map +1 -1
  36. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue.js +1 -1
  37. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue2.js +25 -1
  38. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue2.js.map +1 -1
  39. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue3.js.map +1 -1
  40. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
  41. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +10 -1
  42. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  43. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  44. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue.js +1 -1
  45. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +106 -4
  46. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
  47. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js +70 -25
  48. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
  49. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  50. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +97 -3
  51. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  52. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +46 -2
  53. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  54. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue.js +9 -0
  55. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue.js.map +1 -0
  56. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue2.js +165 -0
  57. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue2.js.map +1 -0
  58. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue3.js +85 -0
  59. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue3.js.map +1 -0
  60. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
  61. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +54 -6
  62. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  63. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +3 -1
  64. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  65. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  66. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +8 -1
  67. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  68. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  69. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
  70. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +2 -23
  71. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
  72. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
  73. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue.js +1 -1
  74. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js +19 -0
  75. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js.map +1 -1
  76. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js +1 -1
  77. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js.map +1 -1
  78. package/dist/esm/composables/indexSources.js +9 -0
  79. package/dist/esm/composables/indexSources.js.map +1 -1
  80. package/dist/esm/index.js +1 -0
  81. package/dist/esm/index.js.map +1 -1
  82. package/dist/esm/l10n/en.json.js +5 -1
  83. package/dist/esm/l10n/en.json.js.map +1 -1
  84. package/dist/esm/l10n/nl.json.js +5 -1
  85. package/dist/esm/l10n/nl.json.js.map +1 -1
  86. package/dist/esm/library-style.js +1 -1
  87. package/dist/esm/mixins/pageViews.js +8 -1
  88. package/dist/esm/mixins/pageViews.js.map +1 -1
  89. package/dist/esm/nextcloud-vue.css +593 -459
  90. package/dist/esm/utils/builtInFormatters.js +24 -4
  91. package/dist/esm/utils/builtInFormatters.js.map +1 -1
  92. package/dist/esm/utils/rowClassRules.js +43 -0
  93. package/dist/esm/utils/rowClassRules.js.map +1 -0
  94. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  95. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  96. package/dist/esm/utils/visibleWhen.js +32 -4
  97. package/dist/esm/utils/visibleWhen.js.map +1 -1
  98. package/dist/nextcloud-vue.cjs.js +10093 -8858
  99. package/dist/nextcloud-vue.cjs.js.map +2 -2
  100. package/dist/nextcloud-vue.css +593 -459
  101. package/l10n/en.json +5 -1
  102. package/l10n/nl.json +5 -1
  103. package/package.json +1 -1
  104. package/src/components/CnActionsBar/CnActionsBar.md +1 -0
  105. package/src/components/CnActionsBar/CnActionsBar.vue +31 -4
  106. package/src/components/CnChartWidget/CnChartWidget.md +3 -2
  107. package/src/components/CnChartWidget/CnChartWidget.vue +42 -4
  108. package/src/components/CnConversationThread/CnConversationThread.md +17 -0
  109. package/src/components/CnConversationThread/CnConversationThread.vue +113 -8
  110. package/src/components/CnConversationThread/CnConversationWidget.vue +60 -1
  111. package/src/components/CnDashboardPage/CnDashboardPage.md +4 -1
  112. package/src/components/CnDashboardPage/CnDashboardPage.vue +50 -7
  113. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  114. package/src/components/CnFormDialog/CnFormDialog.md +1 -1
  115. package/src/components/CnFormDialog/CnFormDialog.vue +127 -0
  116. package/src/components/CnIndexPage/CnIndexPage.md +15 -1
  117. package/src/components/CnIndexPage/CnIndexPage.vue +92 -9
  118. package/src/components/CnIndexPage/useNamedSource.js +26 -2
  119. package/src/components/CnMenuWidget/CnMenuWidget.vue +25 -1
  120. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +10 -1
  121. package/src/components/CnQuickFilterBar/CnQuickFilterBar.md +1 -0
  122. package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +159 -5
  123. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +134 -2
  124. package/src/components/CnSearchSelect/CnSearchSelect.vue +283 -0
  125. package/src/components/CnSearchSelect/index.js +12 -0
  126. package/src/components/CnSetupWizard/CnSetupWizard.vue +56 -6
  127. package/src/components/CnTabsWidget/CnTabsWidget.vue +8 -1
  128. package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +2 -23
  129. package/src/components/CnWizardDialog/CnWizardDialog.vue +20 -1
  130. package/src/components/index.js +1 -0
  131. package/src/composables/indexSources.js +9 -0
  132. package/src/css/dialog.css +5 -3
  133. package/src/css/look-board-index.css +10 -0
  134. package/src/index.js +1 -0
  135. package/src/mixins/pageViews.js +8 -1
  136. package/src/schemas/app-manifest-v2.schema.json +107 -8
  137. package/src/utils/builtInFormatters.js +24 -4
  138. package/src/utils/rowClassRules.js +39 -0
  139. package/src/utils/validateManifestV2.compiled.js +3 -3
  140. package/src/utils/visibleWhen.js +32 -4
@@ -149,6 +149,19 @@ var script = {
149
149
  type: [Object, Array],
150
150
  default: null,
151
151
  },
152
+
153
+ /**
154
+ * Chips mode only: show as many chips as the bar's own width holds and
155
+ * move the rest into the overflow chip, measured again whenever the
156
+ * width, the tabs or the counts change. The bar takes the room it is
157
+ * given (CnIndexPage's `quickFilterPlacement: "toolbar"` gives it what
158
+ * the Filter button and the view switch leave on their row). With
159
+ * `maxVisible` too, the smaller of the two wins.
160
+ */
161
+ fit: {
162
+ type: Boolean,
163
+ default: false,
164
+ },
152
165
  },
153
166
 
154
167
  emits: ['update:active-index', 'update:selected-indices'],
@@ -157,6 +170,8 @@ var script = {
157
170
  return {
158
171
  /** Whether the overflow chip's panel is open. */
159
172
  moreOpen: false,
173
+ /** With `fit`: how many chips the width holds; null before the first measure. */
174
+ fitCount: null,
160
175
  }
161
176
  },
162
177
 
@@ -186,10 +201,24 @@ var script = {
186
201
  * @return {Array<{tab: object, index: number}>}
187
202
  */
188
203
  visibleEntries() {
189
- if (!this.maxVisible || this.tabs.length <= this.maxVisible) {
204
+ const limit = this.effectiveMax;
205
+ if (!limit || this.tabs.length <= limit) {
190
206
  return this.entries
191
207
  }
192
- return this.entries.slice(0, this.maxVisible)
208
+ return this.entries.slice(0, limit)
209
+ },
210
+
211
+ /**
212
+ * How many chips render: `maxVisible`, and with `fit` no more than the
213
+ * width holds; 0 for no limit.
214
+ *
215
+ * @return {number}
216
+ */
217
+ effectiveMax() {
218
+ if (!this.fit || this.fitCount === null) {
219
+ return this.maxVisible
220
+ }
221
+ return this.maxVisible ? Math.min(this.maxVisible, this.fitCount) : this.fitCount
193
222
  },
194
223
 
195
224
  /**
@@ -199,10 +228,11 @@ var script = {
199
228
  * @return {Array<{tab: object, index: number}>}
200
229
  */
201
230
  overflowEntries() {
202
- if (!this.maxVisible || this.tabs.length <= this.maxVisible) {
231
+ const limit = this.effectiveMax;
232
+ if (!limit || this.tabs.length <= limit) {
203
233
  return []
204
234
  }
205
- return this.entries.slice(this.maxVisible)
235
+ return this.entries.slice(limit)
206
236
  },
207
237
 
208
238
  /**
@@ -282,7 +312,79 @@ var script = {
282
312
  },
283
313
  },
284
314
 
315
+ watch: {
316
+ tabs() {
317
+ this.scheduleFit();
318
+ },
319
+
320
+ counts: {
321
+ deep: true,
322
+ handler() {
323
+ this.scheduleFit();
324
+ },
325
+ },
326
+ },
327
+
328
+ mounted() {
329
+ if (this.fit && typeof ResizeObserver === 'function' && this.$refs.chipsRoot) {
330
+ this.fitObserver = new ResizeObserver(() => this.measureFit());
331
+ this.fitObserver.observe(this.$refs.chipsRoot);
332
+ }
333
+ this.scheduleFit();
334
+ },
335
+
336
+ beforeUnmount() {
337
+ if (this.fitObserver) {
338
+ this.fitObserver.disconnect();
339
+ this.fitObserver = null;
340
+ }
341
+ },
342
+
285
343
  methods: {
344
+ /** Measure the fit after the next render. */
345
+ scheduleFit() {
346
+ if (this.fit) {
347
+ this.$nextTick(() => this.measureFit());
348
+ }
349
+ },
350
+
351
+ /**
352
+ * Work out how many chips the bar's width holds, from the invisible
353
+ * copy: every chip that fits, and when not all do, room left for the
354
+ * overflow chip. At least one chip always shows.
355
+ */
356
+ measureFit() {
357
+ const box = this.$refs.measure;
358
+ const root = this.$refs.chipsRoot;
359
+ if (!this.fit || !box || !root) {
360
+ return
361
+ }
362
+ const available = root.clientWidth;
363
+ const chips = [...box.querySelectorAll('[data-measure="chip"]')].map((el) => el.offsetWidth);
364
+ const more = box.querySelector('[data-measure="more"]');
365
+ const moreWidth = more ? more.offsetWidth : 0;
366
+ const gap = parseFloat(getComputedStyle(box).columnGap) || 8;
367
+ if (available <= 0 || chips.length === 0) {
368
+ this.fitCount = null;
369
+ return
370
+ }
371
+ const total = chips.reduce((sum, width) => sum + width, 0) + gap * (chips.length - 1);
372
+ if (total <= available) {
373
+ this.fitCount = null;
374
+ return
375
+ }
376
+ let used = moreWidth;
377
+ let count = 0;
378
+ for (const width of chips) {
379
+ if (used + gap + width > available) {
380
+ break
381
+ }
382
+ used += gap + width;
383
+ count++;
384
+ }
385
+ this.fitCount = Math.max(1, count);
386
+ },
387
+
286
388
  /**
287
389
  * A manifest string through the host's label lookup (`cnTranslate`), so a key
288
390
  * such as "Mine" reads in the user's language.
@@ -1 +1 @@
1
- {"version":3,"file":"CnQuickFilterBar.vue2.js","sources":["../../../../src/components/CnQuickFilterBar/CnQuickFilterBar.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: AGPL-3.0-or-later\n -->\n\n<template>\n\t<!-- Dropdown mode: a single NcSelect (multi or single) instead of the chip strip. -->\n\t<div\n\t\tv-if=\"mode === 'dropdown'\"\n\t\tclass=\"cn-quick-filter-bar cn-quick-filter-bar--dropdown\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<NcSelect\n\t\t\t:modelValue=\"dropdownValue\"\n\t\t\t:options=\"dropdownOptions\"\n\t\t\t:multiple=\"multiple\"\n\t\t\t:keepOpen=\"multiple\"\n\t\t\t:clearable=\"true\"\n\t\t\tlabel=\"label\"\n\t\t\tclass=\"cn-quick-filter-bar__select\"\n\t\t\t:inputLabel=\"selectLabel\"\n\t\t\t:aria-label-combobox=\"selectLabel\"\n\t\t\t:placeholder=\"placeholder || selectLabel\"\n\t\t\t@update:modelValue=\"onSelectInput\" />\n\t</div>\n\t<!-- Chips mode (default): the clickable tab strip. -->\n\t<div v-else\n\t\tclass=\"cn-quick-filter-bar\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<!-- The tablist holds ONLY tabs: the overflow chip is a sibling, not a\n\t\t child, because a role=\"tablist\" may not contain a menu button. -->\n\t\t<!-- Board look: the tabs are chips, pressed buttons in a group, not a\n\t\t tablist (the chips filter the list, they do not switch a panel). -->\n\t\t<div class=\"cn-quick-filter-bar__tabs\" :role=\"isBoardLook ? 'group' : 'tablist'\" :aria-label=\"isBoardLook ? t('nextcloud-vue', 'Quick filters') : null\">\n\t\t\t<button\n\t\t\t\tv-for=\"entry in visibleEntries\"\n\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\ttype=\"button\"\n\t\t\t\t:role=\"isBoardLook ? null : 'tab'\"\n\t\t\t\t:aria-selected=\"isBoardLook ? null : (isChipActive(entry.index) ? 'true' : 'false')\"\n\t\t\t\t:aria-pressed=\"isBoardLook ? (isChipActive(entry.index) ? 'true' : 'false') : null\"\n\t\t\t\tclass=\"cn-quick-filter-bar__tab\"\n\t\t\t\t:class=\"[{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }]\"\n\t\t\t\t@click=\"onClick(entry.index)\">\n\t\t\t\t<CnIcon\n\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t:size=\"16\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ tl(entry.tab.label) }}</span>\n\t\t\t\t<span\n\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t</button>\n\t\t</div>\n\t\t<!-- The overflow is a CHIP and not a toolbar button: it is one of the\n\t\t lenses, so it carries the same pill, the same active fill and the\n\t\t label of whichever hidden lens is on. -->\n\t\t<NcPopover\n\t\t\tv-if=\"overflowEntries.length > 0\"\n\t\t\tv-model:shown=\"moreOpen\"\n\t\t\t:triggers=\"[]\"\n\t\t\tpopupRole=\"dialog\"\n\t\t\tplacement=\"bottom-end\"\n\t\t\tpopoverBaseClass=\"cn-quick-filter-bar__popper\">\n\t\t\t<template #trigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-more\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more\"\n\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t'cn-quick-filter-bar__tab--active': activeOverflowEntries.length > 0,\n\t\t\t\t\t\t'cn-quick-filter-bar__more--icon-only': !overflowLabel,\n\t\t\t\t\t}\"\n\t\t\t\t\t:aria-expanded=\"moreOpen ? 'true' : 'false'\"\n\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t\t:aria-label=\"overflowAriaLabel\"\n\t\t\t\t\t:title=\"overflowAriaLabel\"\n\t\t\t\t\t@click=\"moreOpen = !moreOpen\">\n\t\t\t\t\t<span v-if=\"overflowLabel\" class=\"cn-quick-filter-bar__label\">{{ overflowLabel }}</span>\n\t\t\t\t\t<DotsHorizontal :size=\"16\" class=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t</button>\n\t\t\t</template>\n\t\t\t<div\n\t\t\t\tclass=\"cn-quick-filter-bar__more-panel\"\n\t\t\t\t@keydown.escape.stop=\"moreOpen = false\">\n\t\t\t\t<p class=\"cn-quick-filter-bar__more-heading\">\n\t\t\t\t\t{{ moreHeading }}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"cn-quick-filter-bar__more-list\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-for=\"entry in overflowEntries\"\n\t\t\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tdata-testid=\"cn-quick-filter-more-item\"\n\t\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more-item\"\n\t\t\t\t\t\t:class=\"{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }\"\n\t\t\t\t\t\t:aria-pressed=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\t\t\t@click=\"onOverflowClick(entry.index)\">\n\t\t\t\t\t\t<CnIcon\n\t\t\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:size=\"16\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ tl(entry.tab.label) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</div>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcPopover, NcSelect } from '@nextcloud/vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport { normalizeLook } from '../../composables/useLook.js'\n\n/**\n * CnQuickFilterBar — quick-filter control rendered above a `type:\"index\"`\n * page's table. Each tab carries a manifest `filter` map that `CnIndexPage`\n * merges into the `useListView` fetch when the tab is active.\n *\n * Two presentations, chosen by `mode`:\n * - `'chips'` (default) — a horizontal row of pill-shaped buttons; the\n * active one is filled, the rest outlined. `maxVisible` caps how many\n * pills render and moves the rest into an overflow menu.\n * - `'dropdown'` — a single `NcSelect`. The \"All\" / empty-filter tab is\n * dropped from the options (an empty selection means \"all\").\n *\n * Two selection cardinalities, chosen by `multiple`:\n * - single (default) — one active tab; uses the `activeIndex` v-model\n * (`update:active-index`).\n * - `multiple` — several tabs at once; uses the `selectedIndices` array\n * prop + `update:selected-indices` event. `CnIndexPage` ORs the selected\n * tabs' filters together.\n *\n * Implementation is deliberately a thin styled `<button>` list (chips) /\n * `NcSelect` (dropdown) rather than `NcAppNavigation*` — this lives INSIDE\n * the index page, not as the app's main nav.\n */\nexport default {\n\tname: 'CnQuickFilterBar',\n\n\tcomponents: { CnIcon, DotsHorizontal, NcPopover, NcSelect },\n\n\tinject: {\n\t\t/** The look CnAppRoot provides; `board` draws the tabs as pressed chips. */\n\t\tcnLook: { default: 'nextcloud' },\n\t\t/**\n\t\t * The host's label lookup (CnAppRoot provides it); identity without one, so a\n\t\t * label that is not a key renders as written.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\t// NO `model: { prop, event }` OPTION.\n\t//\n\t// The Vue-2 `model` option is REMOVED in Vue 3 — read by nothing, warned\n\t// about by nothing — so it survived the migration as a declaration that\n\t// looked authoritative while doing exactly zero. The component's real\n\t// contract is the explicit `:active-index` / `@update:active-index` pair\n\t// (and `:selected-indices` / `@update:selected-indices` in `multiple`\n\t// mode), which is what `CnIndexPage` binds. Surfaced by\n\t// `vue/no-deprecated-model-definition`, which this repo now arms through\n\t// its own published preset.\n\n\tprops: {\n\t\t/**\n\t\t * Tab definitions — same shape `pages[].config.quickFilters[]` uses.\n\t\t * `filter` is consumed by the parent (CnIndexPage), not this component.\n\t\t */\n\t\ttabs: {\n\t\t\ttype: Array,\n\t\t\trequired: true,\n\t\t\tvalidator: (arr) => Array.isArray(arr) && arr.every((t) => t && typeof t.label === 'string'),\n\t\t},\n\n\t\t/**\n\t\t * Render bare (no padding / bottom border / background) for embedding\n\t\t * inline inside another bar — e.g. the `#filters` slot of `CnActionsBar`,\n\t\t * so the tabs sit beside the view toggle instead of as a separate row.\n\t\t */\n\t\tinline: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Index of the currently active tab, or `null` for none active. Single-select only. */\n\t\tactiveIndex: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Presentation: `'chips'` (pill button strip, default) or\n\t\t * `'dropdown'` (a single `NcSelect`).\n\t\t *\n\t\t * @type {'chips'|'dropdown'}\n\t\t */\n\t\tmode: {\n\t\t\ttype: String,\n\t\t\tdefault: 'chips',\n\t\t\tvalidator: (v) => ['chips', 'dropdown'].includes(v),\n\t\t},\n\n\t\t/**\n\t\t * Allow more than one tab active at once. Selection is exposed via\n\t\t * `selectedIndices` + `update:selected-indices`; the parent ORs the\n\t\t * selected tabs' filters together.\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Active tab indices when `multiple` is set (the array v-model).\n\t\t *\n\t\t * @type {number[]}\n\t\t */\n\t\tselectedIndices: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Accessible label / placeholder for the dropdown control. */\n\t\tselectLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'Filter',\n\t\t},\n\n\t\t/** Placeholder text for the dropdown (falls back to `selectLabel`). */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Chips mode only: how many pills render inline before the rest move\n\t\t * into an overflow menu. `0` (the default) renders every tab, which is\n\t\t * the behaviour this component has always had. The visible set is the\n\t\t * FIRST `maxVisible` tabs in declared order — reorder `tabs` to change\n\t\t * which ones stay out. Ignored in `dropdown` mode.\n\t\t */\n\t\tmaxVisible: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t\tvalidator: (v) => Number.isFinite(v) && v >= 0,\n\t\t},\n\n\t\t/**\n\t\t * How many records each tab matches, keyed by tab index (an array in\n\t\t * tab order works too). A tab with a number here shows it after its\n\t\t * label; a tab without one shows no count. A tab can also carry its\n\t\t * own `count`. `null` (the default) shows no counts at all.\n\t\t *\n\t\t * @type {{[index: number]: number}|Array<number|null>|null}\n\t\t */\n\t\tcounts: {\n\t\t\ttype: [Object, Array],\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['update:active-index', 'update:selected-indices'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow chip's panel is open. */\n\t\t\tmoreOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the tabs draw as board chips (`aria-pressed`, no tablist).\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tisBoardLook() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/**\n\t\t * Every tab paired with its own index, so the overflow split can slice\n\t\t * the list without losing the index the parent's filters are keyed on.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tentries() {\n\t\t\treturn this.tabs.map((tab, index) => ({ tab, index }))\n\t\t},\n\n\t\t/**\n\t\t * The tabs rendered as pills — all of them unless `maxVisible` caps it.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tvisibleEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.slice(0, this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The tabs moved into the overflow menu (empty when `maxVisible` is 0\n\t\t * or there is nothing to hide).\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\toverflowEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.entries.slice(this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The active tabs that live in the overflow menu.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tactiveOverflowEntries() {\n\t\t\treturn this.overflowEntries.filter((e) => this.isChipActive(e.index))\n\t\t},\n\n\t\t/**\n\t\t * Text on the overflow chip — an active hidden tab names itself there,\n\t\t * so the strip never reads \"All\" while the list is narrowed. Nothing\n\t\t * active leaves the chip as the bare `⋯` glyph.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel() {\n\t\t\tconst active = this.activeOverflowEntries\n\t\t\tif (active.length === 1) {\n\t\t\t\treturn this.tl(active[0].tab.label)\n\t\t\t}\n\t\t\tif (active.length > 1) {\n\t\t\t\treturn t('nextcloud-vue', '{count} filters', { count: active.length })\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\t/** @return {string} Accessible name for the overflow chip. */\n\t\toverflowAriaLabel() {\n\t\t\tif (this.overflowLabel) {\n\t\t\t\treturn t('nextcloud-vue', '{label} — show the other filters', { label: this.overflowLabel })\n\t\t\t}\n\t\t\tconst count = this.overflowEntries.length\n\t\t\treturn n('nextcloud-vue', '{count} more filter', '{count} more filters', count, { count })\n\t\t},\n\n\t\t/** @return {string} Heading above the hidden chips in the panel. */\n\t\tmoreHeading() {\n\t\t\treturn t('nextcloud-vue', 'More filters')\n\t\t},\n\n\t\t/**\n\t\t * Dropdown options: every tab that carries a non-empty `filter`,\n\t\t * tagged with its original index. The \"All\" / empty-filter tab is\n\t\t * omitted — an empty selection already means \"all\".\n\t\t *\n\t\t * @return {Array<{label: string, index: number, icon: string}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tdropdownOptions() {\n\t\t\treturn this.tabs\n\t\t\t\t.map((tab, index) => {\n\t\t\t\t\tconst count = this.countOf({ tab, index })\n\t\t\t\t\treturn {\n\t\t\t\t\t\tlabel: count === null ? this.tl(tab.label) : `${this.tl(tab.label)} (${count})`,\n\t\t\t\t\t\ticon: tab.icon,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\t_empty: this.isEmptyFilter(tab),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((o) => !o._empty)\n\t\t},\n\n\t\t/**\n\t\t * Current NcSelect value — an array of option objects when\n\t\t * `multiple`, a single option object (or null) otherwise.\n\t\t *\n\t\t * @return {object|object[]|null}\n\t\t */\n\t\tdropdownValue() {\n\t\t\tif (this.multiple) {\n\t\t\t\treturn this.dropdownOptions.filter((o) => this.selectedIndices.includes(o.index))\n\t\t\t}\n\t\t\treturn this.dropdownOptions.find((o) => o.index === this.activeIndex) || null\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A manifest string through the host's label lookup (`cnTranslate`), so a key\n\t\t * such as \"Mine\" reads in the user's language.\n\t\t *\n\t\t * @param {string} text The text as written in the manifest.\n\t\t * @return {string} The translated text.\n\t\t */\n\t\ttl(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\tt,\n\n\t\t/**\n\t\t * The count to show on a tab, or null for none: `counts[index]`\n\t\t * first, else the tab's own `count`.\n\t\t *\n\t\t * @param {{tab: object, index: number}} entry The tab and its index.\n\t\t * @return {number|null}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tcountOf(entry) {\n\t\t\tconst fromProp = this.counts ? this.counts[entry.index] : undefined\n\t\t\tconst value = (fromProp !== undefined && fromProp !== null) ? fromProp : entry.tab.count\n\t\t\treturn (typeof value === 'number' && Number.isFinite(value)) ? value : null\n\t\t},\n\n\t\t/**\n\t\t * Is tab `i` rendered active in chips mode (handles both single\n\t\t * `activeIndex` and `multiple` `selectedIndices`).\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t * @return {boolean}\n\t\t */\n\t\tisChipActive(i) {\n\t\t\treturn this.multiple ? this.selectedIndices.includes(i) : i === this.activeIndex\n\t\t},\n\n\t\t/**\n\t\t * Whether a tab's `filter` map is absent/empty (the \"All\" tab).\n\t\t *\n\t\t * @param {{label: string, filter?: object}} tab An entry from the `tabs` prop.\n\t\t * @return {boolean} True when the tab applies no filter, so selecting it\n\t\t * clears the multi-selection rather than adding to it.\n\t\t */\n\t\tisEmptyFilter(tab) {\n\t\t\treturn !tab || !tab.filter || Object.keys(tab.filter).length === 0\n\t\t},\n\n\t\t/**\n\t\t * Chip-click handler. In single mode emits the new active index; in\n\t\t * multiple mode toggles the index in/out of the selection. Clicking\n\t\t * an empty-filter (\"All\") chip clears the multi-selection.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonClick(i) {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (this.isEmptyFilter(this.tabs[i])) {\n\t\t\t\t\t/**\n\t\t\t\t\t * @event update:selected-indices Active tab indices changed (multiple mode).\n\t\t\t\t\t * @type {number[]}\n\t\t\t\t\t */\n\t\t\t\t\tthis.$emit('update:selected-indices', [])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst next = this.selectedIndices.includes(i)\n\t\t\t\t\t? this.selectedIndices.filter((x) => x !== i)\n\t\t\t\t\t: [...this.selectedIndices, i]\n\t\t\t\tthis.$emit('update:selected-indices', next)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (i === this.activeIndex) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', i)\n\t\t},\n\n\t\t/**\n\t\t * A chip clicked inside the overflow panel. Single-select closes the\n\t\t * panel on the way out; multi-select keeps it open so several lenses\n\t\t * can be toggled in one visit.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonOverflowClick(i) {\n\t\t\tthis.onClick(i)\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.moreOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler — normalises the option object(s) back to\n\t\t * indices and emits the matching model event.\n\t\t *\n\t\t * @param {object|object[]|null} val Selected option object(s).\n\t\t */\n\t\tonSelectInput(val) {\n\t\t\tif (this.multiple) {\n\t\t\t\tconst arr = Array.isArray(val) ? val : []\n\t\t\t\tthis.$emit('update:selected-indices', arr.map((o) => o.index))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', val ? val.index : null)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-quick-filter-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tbackground: var(--color-main-background);\n}\n\n.cn-quick-filter-bar__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n/* Inline variant — bare strip for embedding inside another bar (e.g. the\n CnActionsBar #filters slot), so it reads as a control beside the view toggle\n rather than a separate bordered row. */\n.cn-quick-filter-bar--inline {\n\tpadding: 0;\n\tborder-bottom: none;\n\tbackground: transparent;\n}\n\n/* Dropdown variant — give the NcSelect a sensible minimum so multi-select\n chips have room without stretching the whole bar. */\n.cn-quick-filter-bar--dropdown {\n\talign-items: center;\n}\n\n.cn-quick-filter-bar__select {\n\tmin-width: 220px;\n}\n\n.cn-quick-filter-bar__tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: background-color 120ms, color 120ms, border-color 120ms;\n}\n\n.cn-quick-filter-bar__tab:hover,\n.cn-quick-filter-bar__tab:focus-visible {\n\tbackground: var(--color-background-hover);\n\toutline: none;\n}\n\n.cn-quick-filter-bar__tab--active {\n\tbackground: var(--color-primary-element, var(--color-primary, #4376fc));\n\tcolor: var(--color-primary-element-text, #fff);\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__icon {\n\tdisplay: inline-flex;\n}\n\n.cn-quick-filter-bar__label {\n\tline-height: 1;\n}\n\n/* Inherits the chip's own text colour, so it stays readable on the active\n (primary) fill as well as on the resting one. The count's text starts with\n a space: the chip is a flex row, so the space is not drawn, but it keeps a\n screen reader from reading label and count as one word. */\n.cn-quick-filter-bar__count {\n\tmin-width: 1.5em;\n\tpadding: 2px 6px;\n\tborder: 1px solid currentColor;\n\tborder-radius: var(--border-radius-pill, 10px);\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tline-height: 1;\n\ttext-align: center;\n}\n\n/* NcPopover wraps its trigger in a plain `<div class=\"v-popper\">`, which as a\n block would drop the chip onto its own line under the strip. */\n.cn-quick-filter-bar > :deep(.v-popper) {\n\tdisplay: inline-flex;\n}\n\n/* The `⋯` glyph is the chip's whole content while no hidden lens is on, so the\n pill tightens to a circle rather than sitting as a wide empty capsule. */\n.cn-quick-filter-bar__more {\n\tgap: 4px;\n}\n\n.cn-quick-filter-bar__more--icon-only {\n\tpadding: 4px 8px;\n}\n\n.cn-quick-filter-bar__more[aria-expanded='true'] {\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__more-panel {\n\tpadding: 10px 12px 12px;\n\tmax-width: 280px;\n}\n\n.cn-quick-filter-bar__more-heading {\n\tmargin: 0 0 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* The hidden lenses stay chips — the panel is more of the strip, not a\n different control that happens to hold the same filters. */\n.cn-quick-filter-bar__more-list {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmax-height: 320px;\n\toverflow-y: auto;\n}\n\n.cn-quick-filter-bar__more-item {\n\tmax-width: 100%;\n}\n\n.cn-quick-filter-bar__more-item .cn-quick-filter-bar__label {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["CnIcon","t","n"],"mappings":"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"}
1
+ {"version":3,"file":"CnQuickFilterBar.vue2.js","sources":["../../../../src/components/CnQuickFilterBar/CnQuickFilterBar.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: AGPL-3.0-or-later\n -->\n\n<template>\n\t<!-- Dropdown mode: a single NcSelect (multi or single) instead of the chip strip. -->\n\t<div\n\t\tv-if=\"mode === 'dropdown'\"\n\t\tclass=\"cn-quick-filter-bar cn-quick-filter-bar--dropdown\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<NcSelect\n\t\t\t:modelValue=\"dropdownValue\"\n\t\t\t:options=\"dropdownOptions\"\n\t\t\t:multiple=\"multiple\"\n\t\t\t:keepOpen=\"multiple\"\n\t\t\t:clearable=\"true\"\n\t\t\tlabel=\"label\"\n\t\t\tclass=\"cn-quick-filter-bar__select\"\n\t\t\t:inputLabel=\"selectLabel\"\n\t\t\t:aria-label-combobox=\"selectLabel\"\n\t\t\t:placeholder=\"placeholder || selectLabel\"\n\t\t\t@update:modelValue=\"onSelectInput\" />\n\t</div>\n\t<!-- Chips mode (default): the clickable tab strip. -->\n\t<div v-else\n\t\tref=\"chipsRoot\"\n\t\tclass=\"cn-quick-filter-bar\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline, 'cn-quick-filter-bar--fit': fit }\">\n\t\t<!-- With `fit`: an invisible copy of every chip and the overflow chip,\n\t\t measured to work out how many chips the bar's width holds. -->\n\t\t<div v-if=\"fit\"\n\t\t\tref=\"measure\"\n\t\t\tclass=\"cn-quick-filter-bar__measure\"\n\t\t\taria-hidden=\"true\">\n\t\t\t<span v-for=\"entry in entries\"\n\t\t\t\t:key=\"'m:' + entry.tab.label + ':' + entry.index\"\n\t\t\t\tclass=\"cn-quick-filter-bar__tab\"\n\t\t\t\t:class=\"{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }\"\n\t\t\t\tdata-measure=\"chip\">\n\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ tl(entry.tab.label) }}</span>\n\t\t\t\t<span v-if=\"countOf(entry) !== null\" class=\"cn-quick-filter-bar__count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t</span>\n\t\t\t<span class=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more\" data-measure=\"more\">\n\t\t\t\t<span v-if=\"overflowLabel\" class=\"cn-quick-filter-bar__label\">{{ overflowLabel }}</span>\n\t\t\t\t<DotsHorizontal :size=\"16\" class=\"cn-quick-filter-bar__icon\" />\n\t\t\t</span>\n\t\t</div>\n\t\t<!-- The tablist holds ONLY tabs: the overflow chip is a sibling, not a\n\t\t child, because a role=\"tablist\" may not contain a menu button. -->\n\t\t<!-- Board look: the tabs are chips, pressed buttons in a group, not a\n\t\t tablist (the chips filter the list, they do not switch a panel). -->\n\t\t<div class=\"cn-quick-filter-bar__tabs\" :role=\"isBoardLook ? 'group' : 'tablist'\" :aria-label=\"isBoardLook ? t('nextcloud-vue', 'Quick filters') : null\">\n\t\t\t<button\n\t\t\t\tv-for=\"entry in visibleEntries\"\n\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\ttype=\"button\"\n\t\t\t\t:role=\"isBoardLook ? null : 'tab'\"\n\t\t\t\t:aria-selected=\"isBoardLook ? null : (isChipActive(entry.index) ? 'true' : 'false')\"\n\t\t\t\t:aria-pressed=\"isBoardLook ? (isChipActive(entry.index) ? 'true' : 'false') : null\"\n\t\t\t\tclass=\"cn-quick-filter-bar__tab\"\n\t\t\t\t:class=\"[{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }]\"\n\t\t\t\t@click=\"onClick(entry.index)\">\n\t\t\t\t<CnIcon\n\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t:size=\"16\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ tl(entry.tab.label) }}</span>\n\t\t\t\t<span\n\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t</button>\n\t\t</div>\n\t\t<!-- The overflow is a CHIP and not a toolbar button: it is one of the\n\t\t lenses, so it carries the same pill, the same active fill and the\n\t\t label of whichever hidden lens is on. -->\n\t\t<NcPopover\n\t\t\tv-if=\"overflowEntries.length > 0\"\n\t\t\tv-model:shown=\"moreOpen\"\n\t\t\t:triggers=\"[]\"\n\t\t\tpopupRole=\"dialog\"\n\t\t\tplacement=\"bottom-end\"\n\t\t\tpopoverBaseClass=\"cn-quick-filter-bar__popper\">\n\t\t\t<template #trigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-more\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more\"\n\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t'cn-quick-filter-bar__tab--active': activeOverflowEntries.length > 0,\n\t\t\t\t\t\t'cn-quick-filter-bar__more--icon-only': !overflowLabel,\n\t\t\t\t\t}\"\n\t\t\t\t\t:aria-expanded=\"moreOpen ? 'true' : 'false'\"\n\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t\t:aria-label=\"overflowAriaLabel\"\n\t\t\t\t\t:title=\"overflowAriaLabel\"\n\t\t\t\t\t@click=\"moreOpen = !moreOpen\">\n\t\t\t\t\t<span v-if=\"overflowLabel\" class=\"cn-quick-filter-bar__label\">{{ overflowLabel }}</span>\n\t\t\t\t\t<DotsHorizontal :size=\"16\" class=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t</button>\n\t\t\t</template>\n\t\t\t<div\n\t\t\t\tclass=\"cn-quick-filter-bar__more-panel\"\n\t\t\t\t@keydown.escape.stop=\"moreOpen = false\">\n\t\t\t\t<p class=\"cn-quick-filter-bar__more-heading\">\n\t\t\t\t\t{{ moreHeading }}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"cn-quick-filter-bar__more-list\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-for=\"entry in overflowEntries\"\n\t\t\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tdata-testid=\"cn-quick-filter-more-item\"\n\t\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more-item\"\n\t\t\t\t\t\t:class=\"{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }\"\n\t\t\t\t\t\t:aria-pressed=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\t\t\t@click=\"onOverflowClick(entry.index)\">\n\t\t\t\t\t\t<CnIcon\n\t\t\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:size=\"16\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ tl(entry.tab.label) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</div>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcPopover, NcSelect } from '@nextcloud/vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport { normalizeLook } from '../../composables/useLook.js'\n\n/**\n * CnQuickFilterBar — quick-filter control rendered above a `type:\"index\"`\n * page's table. Each tab carries a manifest `filter` map that `CnIndexPage`\n * merges into the `useListView` fetch when the tab is active.\n *\n * Two presentations, chosen by `mode`:\n * - `'chips'` (default) — a horizontal row of pill-shaped buttons; the\n * active one is filled, the rest outlined. `maxVisible` caps how many\n * pills render and moves the rest into an overflow menu.\n * - `'dropdown'` — a single `NcSelect`. The \"All\" / empty-filter tab is\n * dropped from the options (an empty selection means \"all\").\n *\n * Two selection cardinalities, chosen by `multiple`:\n * - single (default) — one active tab; uses the `activeIndex` v-model\n * (`update:active-index`).\n * - `multiple` — several tabs at once; uses the `selectedIndices` array\n * prop + `update:selected-indices` event. `CnIndexPage` ORs the selected\n * tabs' filters together.\n *\n * Implementation is deliberately a thin styled `<button>` list (chips) /\n * `NcSelect` (dropdown) rather than `NcAppNavigation*` — this lives INSIDE\n * the index page, not as the app's main nav.\n */\nexport default {\n\tname: 'CnQuickFilterBar',\n\n\tcomponents: { CnIcon, DotsHorizontal, NcPopover, NcSelect },\n\n\tinject: {\n\t\t/** The look CnAppRoot provides; `board` draws the tabs as pressed chips. */\n\t\tcnLook: { default: 'nextcloud' },\n\t\t/**\n\t\t * The host's label lookup (CnAppRoot provides it); identity without one, so a\n\t\t * label that is not a key renders as written.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\t// NO `model: { prop, event }` OPTION.\n\t//\n\t// The Vue-2 `model` option is REMOVED in Vue 3 — read by nothing, warned\n\t// about by nothing — so it survived the migration as a declaration that\n\t// looked authoritative while doing exactly zero. The component's real\n\t// contract is the explicit `:active-index` / `@update:active-index` pair\n\t// (and `:selected-indices` / `@update:selected-indices` in `multiple`\n\t// mode), which is what `CnIndexPage` binds. Surfaced by\n\t// `vue/no-deprecated-model-definition`, which this repo now arms through\n\t// its own published preset.\n\n\tprops: {\n\t\t/**\n\t\t * Tab definitions — same shape `pages[].config.quickFilters[]` uses.\n\t\t * `filter` is consumed by the parent (CnIndexPage), not this component.\n\t\t */\n\t\ttabs: {\n\t\t\ttype: Array,\n\t\t\trequired: true,\n\t\t\tvalidator: (arr) => Array.isArray(arr) && arr.every((t) => t && typeof t.label === 'string'),\n\t\t},\n\n\t\t/**\n\t\t * Render bare (no padding / bottom border / background) for embedding\n\t\t * inline inside another bar — e.g. the `#filters` slot of `CnActionsBar`,\n\t\t * so the tabs sit beside the view toggle instead of as a separate row.\n\t\t */\n\t\tinline: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Index of the currently active tab, or `null` for none active. Single-select only. */\n\t\tactiveIndex: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Presentation: `'chips'` (pill button strip, default) or\n\t\t * `'dropdown'` (a single `NcSelect`).\n\t\t *\n\t\t * @type {'chips'|'dropdown'}\n\t\t */\n\t\tmode: {\n\t\t\ttype: String,\n\t\t\tdefault: 'chips',\n\t\t\tvalidator: (v) => ['chips', 'dropdown'].includes(v),\n\t\t},\n\n\t\t/**\n\t\t * Allow more than one tab active at once. Selection is exposed via\n\t\t * `selectedIndices` + `update:selected-indices`; the parent ORs the\n\t\t * selected tabs' filters together.\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Active tab indices when `multiple` is set (the array v-model).\n\t\t *\n\t\t * @type {number[]}\n\t\t */\n\t\tselectedIndices: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Accessible label / placeholder for the dropdown control. */\n\t\tselectLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'Filter',\n\t\t},\n\n\t\t/** Placeholder text for the dropdown (falls back to `selectLabel`). */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Chips mode only: how many pills render inline before the rest move\n\t\t * into an overflow menu. `0` (the default) renders every tab, which is\n\t\t * the behaviour this component has always had. The visible set is the\n\t\t * FIRST `maxVisible` tabs in declared order — reorder `tabs` to change\n\t\t * which ones stay out. Ignored in `dropdown` mode.\n\t\t */\n\t\tmaxVisible: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t\tvalidator: (v) => Number.isFinite(v) && v >= 0,\n\t\t},\n\n\t\t/**\n\t\t * How many records each tab matches, keyed by tab index (an array in\n\t\t * tab order works too). A tab with a number here shows it after its\n\t\t * label; a tab without one shows no count. A tab can also carry its\n\t\t * own `count`. `null` (the default) shows no counts at all.\n\t\t *\n\t\t * @type {{[index: number]: number}|Array<number|null>|null}\n\t\t */\n\t\tcounts: {\n\t\t\ttype: [Object, Array],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Chips mode only: show as many chips as the bar's own width holds and\n\t\t * move the rest into the overflow chip, measured again whenever the\n\t\t * width, the tabs or the counts change. The bar takes the room it is\n\t\t * given (CnIndexPage's `quickFilterPlacement: \"toolbar\"` gives it what\n\t\t * the Filter button and the view switch leave on their row). With\n\t\t * `maxVisible` too, the smaller of the two wins.\n\t\t */\n\t\tfit: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['update:active-index', 'update:selected-indices'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow chip's panel is open. */\n\t\t\tmoreOpen: false,\n\t\t\t/** With `fit`: how many chips the width holds; null before the first measure. */\n\t\t\tfitCount: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the tabs draw as board chips (`aria-pressed`, no tablist).\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tisBoardLook() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/**\n\t\t * Every tab paired with its own index, so the overflow split can slice\n\t\t * the list without losing the index the parent's filters are keyed on.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tentries() {\n\t\t\treturn this.tabs.map((tab, index) => ({ tab, index }))\n\t\t},\n\n\t\t/**\n\t\t * The tabs rendered as pills — all of them unless `maxVisible` caps it.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tvisibleEntries() {\n\t\t\tconst limit = this.effectiveMax\n\t\t\tif (!limit || this.tabs.length <= limit) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.slice(0, limit)\n\t\t},\n\n\t\t/**\n\t\t * How many chips render: `maxVisible`, and with `fit` no more than the\n\t\t * width holds; 0 for no limit.\n\t\t *\n\t\t * @return {number}\n\t\t */\n\t\teffectiveMax() {\n\t\t\tif (!this.fit || this.fitCount === null) {\n\t\t\t\treturn this.maxVisible\n\t\t\t}\n\t\t\treturn this.maxVisible ? Math.min(this.maxVisible, this.fitCount) : this.fitCount\n\t\t},\n\n\t\t/**\n\t\t * The tabs moved into the overflow menu (empty when `maxVisible` is 0\n\t\t * or there is nothing to hide).\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\toverflowEntries() {\n\t\t\tconst limit = this.effectiveMax\n\t\t\tif (!limit || this.tabs.length <= limit) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.entries.slice(limit)\n\t\t},\n\n\t\t/**\n\t\t * The active tabs that live in the overflow menu.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tactiveOverflowEntries() {\n\t\t\treturn this.overflowEntries.filter((e) => this.isChipActive(e.index))\n\t\t},\n\n\t\t/**\n\t\t * Text on the overflow chip — an active hidden tab names itself there,\n\t\t * so the strip never reads \"All\" while the list is narrowed. Nothing\n\t\t * active leaves the chip as the bare `⋯` glyph.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel() {\n\t\t\tconst active = this.activeOverflowEntries\n\t\t\tif (active.length === 1) {\n\t\t\t\treturn this.tl(active[0].tab.label)\n\t\t\t}\n\t\t\tif (active.length > 1) {\n\t\t\t\treturn t('nextcloud-vue', '{count} filters', { count: active.length })\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\t/** @return {string} Accessible name for the overflow chip. */\n\t\toverflowAriaLabel() {\n\t\t\tif (this.overflowLabel) {\n\t\t\t\treturn t('nextcloud-vue', '{label} — show the other filters', { label: this.overflowLabel })\n\t\t\t}\n\t\t\tconst count = this.overflowEntries.length\n\t\t\treturn n('nextcloud-vue', '{count} more filter', '{count} more filters', count, { count })\n\t\t},\n\n\t\t/** @return {string} Heading above the hidden chips in the panel. */\n\t\tmoreHeading() {\n\t\t\treturn t('nextcloud-vue', 'More filters')\n\t\t},\n\n\t\t/**\n\t\t * Dropdown options: every tab that carries a non-empty `filter`,\n\t\t * tagged with its original index. The \"All\" / empty-filter tab is\n\t\t * omitted — an empty selection already means \"all\".\n\t\t *\n\t\t * @return {Array<{label: string, index: number, icon: string}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tdropdownOptions() {\n\t\t\treturn this.tabs\n\t\t\t\t.map((tab, index) => {\n\t\t\t\t\tconst count = this.countOf({ tab, index })\n\t\t\t\t\treturn {\n\t\t\t\t\t\tlabel: count === null ? this.tl(tab.label) : `${this.tl(tab.label)} (${count})`,\n\t\t\t\t\t\ticon: tab.icon,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\t_empty: this.isEmptyFilter(tab),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((o) => !o._empty)\n\t\t},\n\n\t\t/**\n\t\t * Current NcSelect value — an array of option objects when\n\t\t * `multiple`, a single option object (or null) otherwise.\n\t\t *\n\t\t * @return {object|object[]|null}\n\t\t */\n\t\tdropdownValue() {\n\t\t\tif (this.multiple) {\n\t\t\t\treturn this.dropdownOptions.filter((o) => this.selectedIndices.includes(o.index))\n\t\t\t}\n\t\t\treturn this.dropdownOptions.find((o) => o.index === this.activeIndex) || null\n\t\t},\n\t},\n\n\twatch: {\n\t\ttabs() {\n\t\t\tthis.scheduleFit()\n\t\t},\n\n\t\tcounts: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.scheduleFit()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tif (this.fit && typeof ResizeObserver === 'function' && this.$refs.chipsRoot) {\n\t\t\tthis.fitObserver = new ResizeObserver(() => this.measureFit())\n\t\t\tthis.fitObserver.observe(this.$refs.chipsRoot)\n\t\t}\n\t\tthis.scheduleFit()\n\t},\n\n\tbeforeUnmount() {\n\t\tif (this.fitObserver) {\n\t\t\tthis.fitObserver.disconnect()\n\t\t\tthis.fitObserver = null\n\t\t}\n\t},\n\n\tmethods: {\n\t\t/** Measure the fit after the next render. */\n\t\tscheduleFit() {\n\t\t\tif (this.fit) {\n\t\t\t\tthis.$nextTick(() => this.measureFit())\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Work out how many chips the bar's width holds, from the invisible\n\t\t * copy: every chip that fits, and when not all do, room left for the\n\t\t * overflow chip. At least one chip always shows.\n\t\t */\n\t\tmeasureFit() {\n\t\t\tconst box = this.$refs.measure\n\t\t\tconst root = this.$refs.chipsRoot\n\t\t\tif (!this.fit || !box || !root) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst available = root.clientWidth\n\t\t\tconst chips = [...box.querySelectorAll('[data-measure=\"chip\"]')].map((el) => el.offsetWidth)\n\t\t\tconst more = box.querySelector('[data-measure=\"more\"]')\n\t\t\tconst moreWidth = more ? more.offsetWidth : 0\n\t\t\tconst gap = parseFloat(getComputedStyle(box).columnGap) || 8\n\t\t\tif (available <= 0 || chips.length === 0) {\n\t\t\t\tthis.fitCount = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst total = chips.reduce((sum, width) => sum + width, 0) + gap * (chips.length - 1)\n\t\t\tif (total <= available) {\n\t\t\t\tthis.fitCount = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet used = moreWidth\n\t\t\tlet count = 0\n\t\t\tfor (const width of chips) {\n\t\t\t\tif (used + gap + width > available) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tused += gap + width\n\t\t\t\tcount++\n\t\t\t}\n\t\t\tthis.fitCount = Math.max(1, count)\n\t\t},\n\n\t\t/**\n\t\t * A manifest string through the host's label lookup (`cnTranslate`), so a key\n\t\t * such as \"Mine\" reads in the user's language.\n\t\t *\n\t\t * @param {string} text The text as written in the manifest.\n\t\t * @return {string} The translated text.\n\t\t */\n\t\ttl(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\tt,\n\n\t\t/**\n\t\t * The count to show on a tab, or null for none: `counts[index]`\n\t\t * first, else the tab's own `count`.\n\t\t *\n\t\t * @param {{tab: object, index: number}} entry The tab and its index.\n\t\t * @return {number|null}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tcountOf(entry) {\n\t\t\tconst fromProp = this.counts ? this.counts[entry.index] : undefined\n\t\t\tconst value = (fromProp !== undefined && fromProp !== null) ? fromProp : entry.tab.count\n\t\t\treturn (typeof value === 'number' && Number.isFinite(value)) ? value : null\n\t\t},\n\n\t\t/**\n\t\t * Is tab `i` rendered active in chips mode (handles both single\n\t\t * `activeIndex` and `multiple` `selectedIndices`).\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t * @return {boolean}\n\t\t */\n\t\tisChipActive(i) {\n\t\t\treturn this.multiple ? this.selectedIndices.includes(i) : i === this.activeIndex\n\t\t},\n\n\t\t/**\n\t\t * Whether a tab's `filter` map is absent/empty (the \"All\" tab).\n\t\t *\n\t\t * @param {{label: string, filter?: object}} tab An entry from the `tabs` prop.\n\t\t * @return {boolean} True when the tab applies no filter, so selecting it\n\t\t * clears the multi-selection rather than adding to it.\n\t\t */\n\t\tisEmptyFilter(tab) {\n\t\t\treturn !tab || !tab.filter || Object.keys(tab.filter).length === 0\n\t\t},\n\n\t\t/**\n\t\t * Chip-click handler. In single mode emits the new active index; in\n\t\t * multiple mode toggles the index in/out of the selection. Clicking\n\t\t * an empty-filter (\"All\") chip clears the multi-selection.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonClick(i) {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (this.isEmptyFilter(this.tabs[i])) {\n\t\t\t\t\t/**\n\t\t\t\t\t * @event update:selected-indices Active tab indices changed (multiple mode).\n\t\t\t\t\t * @type {number[]}\n\t\t\t\t\t */\n\t\t\t\t\tthis.$emit('update:selected-indices', [])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst next = this.selectedIndices.includes(i)\n\t\t\t\t\t? this.selectedIndices.filter((x) => x !== i)\n\t\t\t\t\t: [...this.selectedIndices, i]\n\t\t\t\tthis.$emit('update:selected-indices', next)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (i === this.activeIndex) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', i)\n\t\t},\n\n\t\t/**\n\t\t * A chip clicked inside the overflow panel. Single-select closes the\n\t\t * panel on the way out; multi-select keeps it open so several lenses\n\t\t * can be toggled in one visit.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonOverflowClick(i) {\n\t\t\tthis.onClick(i)\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.moreOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler — normalises the option object(s) back to\n\t\t * indices and emits the matching model event.\n\t\t *\n\t\t * @param {object|object[]|null} val Selected option object(s).\n\t\t */\n\t\tonSelectInput(val) {\n\t\t\tif (this.multiple) {\n\t\t\t\tconst arr = Array.isArray(val) ? val : []\n\t\t\t\tthis.$emit('update:selected-indices', arr.map((o) => o.index))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', val ? val.index : null)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-quick-filter-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tbackground: var(--color-main-background);\n}\n\n.cn-quick-filter-bar__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n/* Inline variant — bare strip for embedding inside another bar (e.g. the\n CnActionsBar #filters slot), so it reads as a control beside the view toggle\n rather than a separate bordered row. */\n/* With `fit`: one line, as wide as it is given; the chips it cannot hold\n are in the overflow chip. The measuring copy takes no room and is never\n seen or read. */\n.cn-quick-filter-bar--fit {\n\tposition: relative;\n\tflex-wrap: nowrap;\n\tmin-width: 0;\n}\n\n.cn-quick-filter-bar--fit .cn-quick-filter-bar__tabs {\n\tflex-wrap: nowrap;\n\tmin-width: 0;\n}\n\n.cn-quick-filter-bar__measure {\n\tposition: absolute;\n\tinset-block-start: 0;\n\tinset-inline-start: 0;\n\tdisplay: flex;\n\tgap: 8px;\n\twidth: 0;\n\theight: 0;\n\toverflow: hidden;\n\tvisibility: hidden;\n\tpointer-events: none;\n\twhite-space: nowrap;\n}\n\n.cn-quick-filter-bar__measure > * {\n\tflex: none;\n}\n\n.cn-quick-filter-bar--inline {\n\tpadding: 0;\n\tborder-bottom: none;\n\tbackground: transparent;\n}\n\n/* Dropdown variant — give the NcSelect a sensible minimum so multi-select\n chips have room without stretching the whole bar. */\n.cn-quick-filter-bar--dropdown {\n\talign-items: center;\n}\n\n.cn-quick-filter-bar__select {\n\tmin-width: 220px;\n}\n\n.cn-quick-filter-bar__tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: background-color 120ms, color 120ms, border-color 120ms;\n}\n\n.cn-quick-filter-bar__tab:hover,\n.cn-quick-filter-bar__tab:focus-visible {\n\tbackground: var(--color-background-hover);\n\toutline: none;\n}\n\n.cn-quick-filter-bar__tab--active {\n\tbackground: var(--color-primary-element, var(--color-primary, #4376fc));\n\tcolor: var(--color-primary-element-text, #fff);\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__icon {\n\tdisplay: inline-flex;\n}\n\n.cn-quick-filter-bar__label {\n\tline-height: 1;\n}\n\n/* Inherits the chip's own text colour, so it stays readable on the active\n (primary) fill as well as on the resting one. The count's text starts with\n a space: the chip is a flex row, so the space is not drawn, but it keeps a\n screen reader from reading label and count as one word. */\n.cn-quick-filter-bar__count {\n\tmin-width: 1.5em;\n\tpadding: 2px 6px;\n\tborder: 1px solid currentColor;\n\tborder-radius: var(--border-radius-pill, 10px);\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tline-height: 1;\n\ttext-align: center;\n}\n\n/* NcPopover wraps its trigger in a plain `<div class=\"v-popper\">`, which as a\n block would drop the chip onto its own line under the strip. */\n.cn-quick-filter-bar > :deep(.v-popper) {\n\tdisplay: inline-flex;\n}\n\n/* The `⋯` glyph is the chip's whole content while no hidden lens is on, so the\n pill tightens to a circle rather than sitting as a wide empty capsule. */\n.cn-quick-filter-bar__more {\n\tgap: 4px;\n}\n\n.cn-quick-filter-bar__more--icon-only {\n\tpadding: 4px 8px;\n}\n\n.cn-quick-filter-bar__more[aria-expanded='true'] {\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__more-panel {\n\tpadding: 10px 12px 12px;\n\tmax-width: 280px;\n}\n\n.cn-quick-filter-bar__more-heading {\n\tmargin: 0 0 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* The hidden lenses stay chips — the panel is more of the strip, not a\n different control that happens to hold the same filters. */\n.cn-quick-filter-bar__more-list {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmax-height: 320px;\n\toverflow-y: auto;\n}\n\n.cn-quick-filter-bar__more-item {\n\tmax-width: 100%;\n}\n\n.cn-quick-filter-bar__more-item .cn-quick-filter-bar__label {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["CnIcon","t","n"],"mappings":"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"}
@@ -1,23 +1,42 @@
1
- import { resolveComponent, openBlock, createElementBlock, normalizeClass, createVNode, createElementVNode, Fragment, renderList, createBlock, createCommentVNode, toDisplayString, withCtx, withKeys, withModifiers } from 'vue';
1
+ import { resolveComponent, openBlock, createElementBlock, normalizeClass, createVNode, Fragment, renderList, createElementVNode, toDisplayString, createCommentVNode, createBlock, withCtx, withKeys, withModifiers } from 'vue';
2
2
 
3
- const _hoisted_1 = ["role", "aria-label"];
4
- const _hoisted_2 = ["role", "aria-selected", "aria-pressed", "onClick"];
5
- const _hoisted_3 = { class: "cn-quick-filter-bar__label" };
3
+ const _hoisted_1 = {
4
+ key: 0,
5
+ ref: "measure",
6
+ class: "cn-quick-filter-bar__measure",
7
+ "aria-hidden": "true"
8
+ };
9
+ const _hoisted_2 = { class: "cn-quick-filter-bar__label" };
10
+ const _hoisted_3 = {
11
+ key: 0,
12
+ class: "cn-quick-filter-bar__count"
13
+ };
6
14
  const _hoisted_4 = {
15
+ class: "cn-quick-filter-bar__tab cn-quick-filter-bar__more",
16
+ "data-measure": "more"
17
+ };
18
+ const _hoisted_5 = {
19
+ key: 0,
20
+ class: "cn-quick-filter-bar__label"
21
+ };
22
+ const _hoisted_6 = ["role", "aria-label"];
23
+ const _hoisted_7 = ["role", "aria-selected", "aria-pressed", "onClick"];
24
+ const _hoisted_8 = { class: "cn-quick-filter-bar__label" };
25
+ const _hoisted_9 = {
7
26
  key: 1,
8
27
  class: "cn-quick-filter-bar__count",
9
28
  "data-testid": "cn-quick-filter-count"
10
29
  };
11
- const _hoisted_5 = ["aria-expanded", "aria-label", "title"];
12
- const _hoisted_6 = {
30
+ const _hoisted_10 = ["aria-expanded", "aria-label", "title"];
31
+ const _hoisted_11 = {
13
32
  key: 0,
14
33
  class: "cn-quick-filter-bar__label"
15
34
  };
16
- const _hoisted_7 = { class: "cn-quick-filter-bar__more-heading" };
17
- const _hoisted_8 = { class: "cn-quick-filter-bar__more-list" };
18
- const _hoisted_9 = ["aria-pressed", "onClick"];
19
- const _hoisted_10 = { class: "cn-quick-filter-bar__label" };
20
- const _hoisted_11 = {
35
+ const _hoisted_12 = { class: "cn-quick-filter-bar__more-heading" };
36
+ const _hoisted_13 = { class: "cn-quick-filter-bar__more-list" };
37
+ const _hoisted_14 = ["aria-pressed", "onClick"];
38
+ const _hoisted_15 = { class: "cn-quick-filter-bar__label" };
39
+ const _hoisted_16 = {
21
40
  key: 1,
22
41
  class: "cn-quick-filter-bar__count",
23
42
  "data-testid": "cn-quick-filter-count"
@@ -25,8 +44,8 @@ const _hoisted_11 = {
25
44
 
26
45
  function render(_ctx, _cache, $props, $setup, $data, $options) {
27
46
  const _component_NcSelect = resolveComponent("NcSelect");
28
- const _component_CnIcon = resolveComponent("CnIcon");
29
47
  const _component_DotsHorizontal = resolveComponent("DotsHorizontal");
48
+ const _component_CnIcon = resolveComponent("CnIcon");
30
49
  const _component_NcPopover = resolveComponent("NcPopover");
31
50
 
32
51
  return ($props.mode === 'dropdown')
@@ -50,8 +69,34 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
50
69
  ], 2 /* CLASS */))
51
70
  : (openBlock(), createElementBlock("div", {
52
71
  key: 1,
53
- class: normalizeClass(["cn-quick-filter-bar", { 'cn-quick-filter-bar--inline': $props.inline }])
72
+ ref: "chipsRoot",
73
+ class: normalizeClass(["cn-quick-filter-bar", { 'cn-quick-filter-bar--inline': $props.inline, 'cn-quick-filter-bar--fit': $props.fit }])
54
74
  }, [
75
+ ($props.fit)
76
+ ? (openBlock(), createElementBlock("div", _hoisted_1, [
77
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.entries, (entry) => {
78
+ return (openBlock(), createElementBlock("span", {
79
+ key: 'm:' + entry.tab.label + ':' + entry.index,
80
+ class: normalizeClass(["cn-quick-filter-bar__tab", { 'cn-quick-filter-bar__tab--active': $options.isChipActive(entry.index) }]),
81
+ "data-measure": "chip"
82
+ }, [
83
+ createElementVNode("span", _hoisted_2, toDisplayString($options.tl(entry.tab.label)), 1 /* TEXT */),
84
+ ($options.countOf(entry) !== null)
85
+ ? (openBlock(), createElementBlock("span", _hoisted_3, toDisplayString(' ' + $options.countOf(entry)), 1 /* TEXT */))
86
+ : createCommentVNode("v-if", true)
87
+ ], 2 /* CLASS */))
88
+ }), 128 /* KEYED_FRAGMENT */)),
89
+ createElementVNode("span", _hoisted_4, [
90
+ ($options.overflowLabel)
91
+ ? (openBlock(), createElementBlock("span", _hoisted_5, toDisplayString($options.overflowLabel), 1 /* TEXT */))
92
+ : createCommentVNode("v-if", true),
93
+ createVNode(_component_DotsHorizontal, {
94
+ size: 16,
95
+ class: "cn-quick-filter-bar__icon"
96
+ })
97
+ ])
98
+ ], 512 /* NEED_PATCH */))
99
+ : createCommentVNode("v-if", true),
55
100
  createElementVNode("div", {
56
101
  class: "cn-quick-filter-bar__tabs",
57
102
  role: $options.isBoardLook ? 'group' : 'tablist',
@@ -75,16 +120,16 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
75
120
  class: "cn-quick-filter-bar__icon"
76
121
  }, null, 8 /* PROPS */, ["name"]))
77
122
  : createCommentVNode("v-if", true),
78
- createElementVNode("span", _hoisted_3, toDisplayString($options.tl(entry.tab.label)), 1 /* TEXT */),
123
+ createElementVNode("span", _hoisted_8, toDisplayString($options.tl(entry.tab.label)), 1 /* TEXT */),
79
124
  ($options.countOf(entry) !== null)
80
- ? (openBlock(), createElementBlock("span", _hoisted_4, toDisplayString(' ' + $options.countOf(entry)), 1 /* TEXT */))
125
+ ? (openBlock(), createElementBlock("span", _hoisted_9, toDisplayString(' ' + $options.countOf(entry)), 1 /* TEXT */))
81
126
  : createCommentVNode("v-if", true)
82
- ], 10 /* CLASS, PROPS */, _hoisted_2))
127
+ ], 10 /* CLASS, PROPS */, _hoisted_7))
83
128
  }), 128 /* KEYED_FRAGMENT */))
84
- ], 8 /* PROPS */, _hoisted_1),
129
+ ], 8 /* PROPS */, _hoisted_6),
85
130
  ($options.overflowEntries.length > 0)
86
131
  ? (openBlock(), createBlock(_component_NcPopover, {
87
- key: 0,
132
+ key: 1,
88
133
  shown: $data.moreOpen,
89
134
  "onUpdate:shown": _cache[2] || (_cache[2] = $event => (($data.moreOpen) = $event)),
90
135
  triggers: [],
@@ -107,21 +152,21 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
107
152
  onClick: _cache[0] || (_cache[0] = $event => ($data.moreOpen = !$data.moreOpen))
108
153
  }, [
109
154
  ($options.overflowLabel)
110
- ? (openBlock(), createElementBlock("span", _hoisted_6, toDisplayString($options.overflowLabel), 1 /* TEXT */))
155
+ ? (openBlock(), createElementBlock("span", _hoisted_11, toDisplayString($options.overflowLabel), 1 /* TEXT */))
111
156
  : createCommentVNode("v-if", true),
112
157
  createVNode(_component_DotsHorizontal, {
113
158
  size: 16,
114
159
  class: "cn-quick-filter-bar__icon"
115
160
  })
116
- ], 10 /* CLASS, PROPS */, _hoisted_5)
161
+ ], 10 /* CLASS, PROPS */, _hoisted_10)
117
162
  ]),
118
163
  default: withCtx(() => [
119
164
  createElementVNode("div", {
120
165
  class: "cn-quick-filter-bar__more-panel",
121
166
  onKeydown: _cache[1] || (_cache[1] = withKeys(withModifiers($event => ($data.moreOpen = false), ["stop"]), ["escape"]))
122
167
  }, [
123
- createElementVNode("p", _hoisted_7, toDisplayString($options.moreHeading), 1 /* TEXT */),
124
- createElementVNode("div", _hoisted_8, [
168
+ createElementVNode("p", _hoisted_12, toDisplayString($options.moreHeading), 1 /* TEXT */),
169
+ createElementVNode("div", _hoisted_13, [
125
170
  (openBlock(true), createElementBlock(Fragment, null, renderList($options.overflowEntries, (entry) => {
126
171
  return (openBlock(), createElementBlock("button", {
127
172
  key: entry.tab.label + ':' + entry.index,
@@ -139,11 +184,11 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
139
184
  class: "cn-quick-filter-bar__icon"
140
185
  }, null, 8 /* PROPS */, ["name"]))
141
186
  : createCommentVNode("v-if", true),
142
- createElementVNode("span", _hoisted_10, toDisplayString($options.tl(entry.tab.label)), 1 /* TEXT */),
187
+ createElementVNode("span", _hoisted_15, toDisplayString($options.tl(entry.tab.label)), 1 /* TEXT */),
143
188
  ($options.countOf(entry) !== null)
144
- ? (openBlock(), createElementBlock("span", _hoisted_11, toDisplayString(' ' + $options.countOf(entry)), 1 /* TEXT */))
189
+ ? (openBlock(), createElementBlock("span", _hoisted_16, toDisplayString(' ' + $options.countOf(entry)), 1 /* TEXT */))
145
190
  : createCommentVNode("v-if", true)
146
- ], 10 /* CLASS, PROPS */, _hoisted_9))
191
+ ], 10 /* CLASS, PROPS */, _hoisted_14))
147
192
  }), 128 /* KEYED_FRAGMENT */))
148
193
  ])
149
194
  ], 32 /* NEED_HYDRATION */)
@@ -1 +1 @@
1
- {"version":3,"file":"CnQuickFilterBar.vue3.js","sources":["../../../../src/components/CnQuickFilterBar/CnQuickFilterBar.vue?vue&type=template&id=ed2d2a38&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: AGPL-3.0-or-later\n -->\n\n<template>\n\t<!-- Dropdown mode: a single NcSelect (multi or single) instead of the chip strip. -->\n\t<div\n\t\tv-if=\"mode === 'dropdown'\"\n\t\tclass=\"cn-quick-filter-bar cn-quick-filter-bar--dropdown\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<NcSelect\n\t\t\t:modelValue=\"dropdownValue\"\n\t\t\t:options=\"dropdownOptions\"\n\t\t\t:multiple=\"multiple\"\n\t\t\t:keepOpen=\"multiple\"\n\t\t\t:clearable=\"true\"\n\t\t\tlabel=\"label\"\n\t\t\tclass=\"cn-quick-filter-bar__select\"\n\t\t\t:inputLabel=\"selectLabel\"\n\t\t\t:aria-label-combobox=\"selectLabel\"\n\t\t\t:placeholder=\"placeholder || selectLabel\"\n\t\t\t@update:modelValue=\"onSelectInput\" />\n\t</div>\n\t<!-- Chips mode (default): the clickable tab strip. -->\n\t<div v-else\n\t\tclass=\"cn-quick-filter-bar\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<!-- The tablist holds ONLY tabs: the overflow chip is a sibling, not a\n\t\t child, because a role=\"tablist\" may not contain a menu button. -->\n\t\t<!-- Board look: the tabs are chips, pressed buttons in a group, not a\n\t\t tablist (the chips filter the list, they do not switch a panel). -->\n\t\t<div class=\"cn-quick-filter-bar__tabs\" :role=\"isBoardLook ? 'group' : 'tablist'\" :aria-label=\"isBoardLook ? t('nextcloud-vue', 'Quick filters') : null\">\n\t\t\t<button\n\t\t\t\tv-for=\"entry in visibleEntries\"\n\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\ttype=\"button\"\n\t\t\t\t:role=\"isBoardLook ? null : 'tab'\"\n\t\t\t\t:aria-selected=\"isBoardLook ? null : (isChipActive(entry.index) ? 'true' : 'false')\"\n\t\t\t\t:aria-pressed=\"isBoardLook ? (isChipActive(entry.index) ? 'true' : 'false') : null\"\n\t\t\t\tclass=\"cn-quick-filter-bar__tab\"\n\t\t\t\t:class=\"[{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }]\"\n\t\t\t\t@click=\"onClick(entry.index)\">\n\t\t\t\t<CnIcon\n\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t:size=\"16\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ tl(entry.tab.label) }}</span>\n\t\t\t\t<span\n\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t</button>\n\t\t</div>\n\t\t<!-- The overflow is a CHIP and not a toolbar button: it is one of the\n\t\t lenses, so it carries the same pill, the same active fill and the\n\t\t label of whichever hidden lens is on. -->\n\t\t<NcPopover\n\t\t\tv-if=\"overflowEntries.length > 0\"\n\t\t\tv-model:shown=\"moreOpen\"\n\t\t\t:triggers=\"[]\"\n\t\t\tpopupRole=\"dialog\"\n\t\t\tplacement=\"bottom-end\"\n\t\t\tpopoverBaseClass=\"cn-quick-filter-bar__popper\">\n\t\t\t<template #trigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-more\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more\"\n\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t'cn-quick-filter-bar__tab--active': activeOverflowEntries.length > 0,\n\t\t\t\t\t\t'cn-quick-filter-bar__more--icon-only': !overflowLabel,\n\t\t\t\t\t}\"\n\t\t\t\t\t:aria-expanded=\"moreOpen ? 'true' : 'false'\"\n\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t\t:aria-label=\"overflowAriaLabel\"\n\t\t\t\t\t:title=\"overflowAriaLabel\"\n\t\t\t\t\t@click=\"moreOpen = !moreOpen\">\n\t\t\t\t\t<span v-if=\"overflowLabel\" class=\"cn-quick-filter-bar__label\">{{ overflowLabel }}</span>\n\t\t\t\t\t<DotsHorizontal :size=\"16\" class=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t</button>\n\t\t\t</template>\n\t\t\t<div\n\t\t\t\tclass=\"cn-quick-filter-bar__more-panel\"\n\t\t\t\t@keydown.escape.stop=\"moreOpen = false\">\n\t\t\t\t<p class=\"cn-quick-filter-bar__more-heading\">\n\t\t\t\t\t{{ moreHeading }}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"cn-quick-filter-bar__more-list\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-for=\"entry in overflowEntries\"\n\t\t\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tdata-testid=\"cn-quick-filter-more-item\"\n\t\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more-item\"\n\t\t\t\t\t\t:class=\"{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }\"\n\t\t\t\t\t\t:aria-pressed=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\t\t\t@click=\"onOverflowClick(entry.index)\">\n\t\t\t\t\t\t<CnIcon\n\t\t\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:size=\"16\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ tl(entry.tab.label) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</div>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcPopover, NcSelect } from '@nextcloud/vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport { normalizeLook } from '../../composables/useLook.js'\n\n/**\n * CnQuickFilterBar — quick-filter control rendered above a `type:\"index\"`\n * page's table. Each tab carries a manifest `filter` map that `CnIndexPage`\n * merges into the `useListView` fetch when the tab is active.\n *\n * Two presentations, chosen by `mode`:\n * - `'chips'` (default) — a horizontal row of pill-shaped buttons; the\n * active one is filled, the rest outlined. `maxVisible` caps how many\n * pills render and moves the rest into an overflow menu.\n * - `'dropdown'` — a single `NcSelect`. The \"All\" / empty-filter tab is\n * dropped from the options (an empty selection means \"all\").\n *\n * Two selection cardinalities, chosen by `multiple`:\n * - single (default) — one active tab; uses the `activeIndex` v-model\n * (`update:active-index`).\n * - `multiple` — several tabs at once; uses the `selectedIndices` array\n * prop + `update:selected-indices` event. `CnIndexPage` ORs the selected\n * tabs' filters together.\n *\n * Implementation is deliberately a thin styled `<button>` list (chips) /\n * `NcSelect` (dropdown) rather than `NcAppNavigation*` — this lives INSIDE\n * the index page, not as the app's main nav.\n */\nexport default {\n\tname: 'CnQuickFilterBar',\n\n\tcomponents: { CnIcon, DotsHorizontal, NcPopover, NcSelect },\n\n\tinject: {\n\t\t/** The look CnAppRoot provides; `board` draws the tabs as pressed chips. */\n\t\tcnLook: { default: 'nextcloud' },\n\t\t/**\n\t\t * The host's label lookup (CnAppRoot provides it); identity without one, so a\n\t\t * label that is not a key renders as written.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\t// NO `model: { prop, event }` OPTION.\n\t//\n\t// The Vue-2 `model` option is REMOVED in Vue 3 — read by nothing, warned\n\t// about by nothing — so it survived the migration as a declaration that\n\t// looked authoritative while doing exactly zero. The component's real\n\t// contract is the explicit `:active-index` / `@update:active-index` pair\n\t// (and `:selected-indices` / `@update:selected-indices` in `multiple`\n\t// mode), which is what `CnIndexPage` binds. Surfaced by\n\t// `vue/no-deprecated-model-definition`, which this repo now arms through\n\t// its own published preset.\n\n\tprops: {\n\t\t/**\n\t\t * Tab definitions — same shape `pages[].config.quickFilters[]` uses.\n\t\t * `filter` is consumed by the parent (CnIndexPage), not this component.\n\t\t */\n\t\ttabs: {\n\t\t\ttype: Array,\n\t\t\trequired: true,\n\t\t\tvalidator: (arr) => Array.isArray(arr) && arr.every((t) => t && typeof t.label === 'string'),\n\t\t},\n\n\t\t/**\n\t\t * Render bare (no padding / bottom border / background) for embedding\n\t\t * inline inside another bar — e.g. the `#filters` slot of `CnActionsBar`,\n\t\t * so the tabs sit beside the view toggle instead of as a separate row.\n\t\t */\n\t\tinline: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Index of the currently active tab, or `null` for none active. Single-select only. */\n\t\tactiveIndex: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Presentation: `'chips'` (pill button strip, default) or\n\t\t * `'dropdown'` (a single `NcSelect`).\n\t\t *\n\t\t * @type {'chips'|'dropdown'}\n\t\t */\n\t\tmode: {\n\t\t\ttype: String,\n\t\t\tdefault: 'chips',\n\t\t\tvalidator: (v) => ['chips', 'dropdown'].includes(v),\n\t\t},\n\n\t\t/**\n\t\t * Allow more than one tab active at once. Selection is exposed via\n\t\t * `selectedIndices` + `update:selected-indices`; the parent ORs the\n\t\t * selected tabs' filters together.\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Active tab indices when `multiple` is set (the array v-model).\n\t\t *\n\t\t * @type {number[]}\n\t\t */\n\t\tselectedIndices: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Accessible label / placeholder for the dropdown control. */\n\t\tselectLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'Filter',\n\t\t},\n\n\t\t/** Placeholder text for the dropdown (falls back to `selectLabel`). */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Chips mode only: how many pills render inline before the rest move\n\t\t * into an overflow menu. `0` (the default) renders every tab, which is\n\t\t * the behaviour this component has always had. The visible set is the\n\t\t * FIRST `maxVisible` tabs in declared order — reorder `tabs` to change\n\t\t * which ones stay out. Ignored in `dropdown` mode.\n\t\t */\n\t\tmaxVisible: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t\tvalidator: (v) => Number.isFinite(v) && v >= 0,\n\t\t},\n\n\t\t/**\n\t\t * How many records each tab matches, keyed by tab index (an array in\n\t\t * tab order works too). A tab with a number here shows it after its\n\t\t * label; a tab without one shows no count. A tab can also carry its\n\t\t * own `count`. `null` (the default) shows no counts at all.\n\t\t *\n\t\t * @type {{[index: number]: number}|Array<number|null>|null}\n\t\t */\n\t\tcounts: {\n\t\t\ttype: [Object, Array],\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['update:active-index', 'update:selected-indices'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow chip's panel is open. */\n\t\t\tmoreOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the tabs draw as board chips (`aria-pressed`, no tablist).\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tisBoardLook() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/**\n\t\t * Every tab paired with its own index, so the overflow split can slice\n\t\t * the list without losing the index the parent's filters are keyed on.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tentries() {\n\t\t\treturn this.tabs.map((tab, index) => ({ tab, index }))\n\t\t},\n\n\t\t/**\n\t\t * The tabs rendered as pills — all of them unless `maxVisible` caps it.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tvisibleEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.slice(0, this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The tabs moved into the overflow menu (empty when `maxVisible` is 0\n\t\t * or there is nothing to hide).\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\toverflowEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.entries.slice(this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The active tabs that live in the overflow menu.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tactiveOverflowEntries() {\n\t\t\treturn this.overflowEntries.filter((e) => this.isChipActive(e.index))\n\t\t},\n\n\t\t/**\n\t\t * Text on the overflow chip — an active hidden tab names itself there,\n\t\t * so the strip never reads \"All\" while the list is narrowed. Nothing\n\t\t * active leaves the chip as the bare `⋯` glyph.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel() {\n\t\t\tconst active = this.activeOverflowEntries\n\t\t\tif (active.length === 1) {\n\t\t\t\treturn this.tl(active[0].tab.label)\n\t\t\t}\n\t\t\tif (active.length > 1) {\n\t\t\t\treturn t('nextcloud-vue', '{count} filters', { count: active.length })\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\t/** @return {string} Accessible name for the overflow chip. */\n\t\toverflowAriaLabel() {\n\t\t\tif (this.overflowLabel) {\n\t\t\t\treturn t('nextcloud-vue', '{label} — show the other filters', { label: this.overflowLabel })\n\t\t\t}\n\t\t\tconst count = this.overflowEntries.length\n\t\t\treturn n('nextcloud-vue', '{count} more filter', '{count} more filters', count, { count })\n\t\t},\n\n\t\t/** @return {string} Heading above the hidden chips in the panel. */\n\t\tmoreHeading() {\n\t\t\treturn t('nextcloud-vue', 'More filters')\n\t\t},\n\n\t\t/**\n\t\t * Dropdown options: every tab that carries a non-empty `filter`,\n\t\t * tagged with its original index. The \"All\" / empty-filter tab is\n\t\t * omitted — an empty selection already means \"all\".\n\t\t *\n\t\t * @return {Array<{label: string, index: number, icon: string}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tdropdownOptions() {\n\t\t\treturn this.tabs\n\t\t\t\t.map((tab, index) => {\n\t\t\t\t\tconst count = this.countOf({ tab, index })\n\t\t\t\t\treturn {\n\t\t\t\t\t\tlabel: count === null ? this.tl(tab.label) : `${this.tl(tab.label)} (${count})`,\n\t\t\t\t\t\ticon: tab.icon,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\t_empty: this.isEmptyFilter(tab),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((o) => !o._empty)\n\t\t},\n\n\t\t/**\n\t\t * Current NcSelect value — an array of option objects when\n\t\t * `multiple`, a single option object (or null) otherwise.\n\t\t *\n\t\t * @return {object|object[]|null}\n\t\t */\n\t\tdropdownValue() {\n\t\t\tif (this.multiple) {\n\t\t\t\treturn this.dropdownOptions.filter((o) => this.selectedIndices.includes(o.index))\n\t\t\t}\n\t\t\treturn this.dropdownOptions.find((o) => o.index === this.activeIndex) || null\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A manifest string through the host's label lookup (`cnTranslate`), so a key\n\t\t * such as \"Mine\" reads in the user's language.\n\t\t *\n\t\t * @param {string} text The text as written in the manifest.\n\t\t * @return {string} The translated text.\n\t\t */\n\t\ttl(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\tt,\n\n\t\t/**\n\t\t * The count to show on a tab, or null for none: `counts[index]`\n\t\t * first, else the tab's own `count`.\n\t\t *\n\t\t * @param {{tab: object, index: number}} entry The tab and its index.\n\t\t * @return {number|null}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tcountOf(entry) {\n\t\t\tconst fromProp = this.counts ? this.counts[entry.index] : undefined\n\t\t\tconst value = (fromProp !== undefined && fromProp !== null) ? fromProp : entry.tab.count\n\t\t\treturn (typeof value === 'number' && Number.isFinite(value)) ? value : null\n\t\t},\n\n\t\t/**\n\t\t * Is tab `i` rendered active in chips mode (handles both single\n\t\t * `activeIndex` and `multiple` `selectedIndices`).\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t * @return {boolean}\n\t\t */\n\t\tisChipActive(i) {\n\t\t\treturn this.multiple ? this.selectedIndices.includes(i) : i === this.activeIndex\n\t\t},\n\n\t\t/**\n\t\t * Whether a tab's `filter` map is absent/empty (the \"All\" tab).\n\t\t *\n\t\t * @param {{label: string, filter?: object}} tab An entry from the `tabs` prop.\n\t\t * @return {boolean} True when the tab applies no filter, so selecting it\n\t\t * clears the multi-selection rather than adding to it.\n\t\t */\n\t\tisEmptyFilter(tab) {\n\t\t\treturn !tab || !tab.filter || Object.keys(tab.filter).length === 0\n\t\t},\n\n\t\t/**\n\t\t * Chip-click handler. In single mode emits the new active index; in\n\t\t * multiple mode toggles the index in/out of the selection. Clicking\n\t\t * an empty-filter (\"All\") chip clears the multi-selection.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonClick(i) {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (this.isEmptyFilter(this.tabs[i])) {\n\t\t\t\t\t/**\n\t\t\t\t\t * @event update:selected-indices Active tab indices changed (multiple mode).\n\t\t\t\t\t * @type {number[]}\n\t\t\t\t\t */\n\t\t\t\t\tthis.$emit('update:selected-indices', [])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst next = this.selectedIndices.includes(i)\n\t\t\t\t\t? this.selectedIndices.filter((x) => x !== i)\n\t\t\t\t\t: [...this.selectedIndices, i]\n\t\t\t\tthis.$emit('update:selected-indices', next)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (i === this.activeIndex) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', i)\n\t\t},\n\n\t\t/**\n\t\t * A chip clicked inside the overflow panel. Single-select closes the\n\t\t * panel on the way out; multi-select keeps it open so several lenses\n\t\t * can be toggled in one visit.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonOverflowClick(i) {\n\t\t\tthis.onClick(i)\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.moreOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler — normalises the option object(s) back to\n\t\t * indices and emits the matching model event.\n\t\t *\n\t\t * @param {object|object[]|null} val Selected option object(s).\n\t\t */\n\t\tonSelectInput(val) {\n\t\t\tif (this.multiple) {\n\t\t\t\tconst arr = Array.isArray(val) ? val : []\n\t\t\t\tthis.$emit('update:selected-indices', arr.map((o) => o.index))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', val ? val.index : null)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-quick-filter-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tbackground: var(--color-main-background);\n}\n\n.cn-quick-filter-bar__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n/* Inline variant — bare strip for embedding inside another bar (e.g. the\n CnActionsBar #filters slot), so it reads as a control beside the view toggle\n rather than a separate bordered row. */\n.cn-quick-filter-bar--inline {\n\tpadding: 0;\n\tborder-bottom: none;\n\tbackground: transparent;\n}\n\n/* Dropdown variant — give the NcSelect a sensible minimum so multi-select\n chips have room without stretching the whole bar. */\n.cn-quick-filter-bar--dropdown {\n\talign-items: center;\n}\n\n.cn-quick-filter-bar__select {\n\tmin-width: 220px;\n}\n\n.cn-quick-filter-bar__tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: background-color 120ms, color 120ms, border-color 120ms;\n}\n\n.cn-quick-filter-bar__tab:hover,\n.cn-quick-filter-bar__tab:focus-visible {\n\tbackground: var(--color-background-hover);\n\toutline: none;\n}\n\n.cn-quick-filter-bar__tab--active {\n\tbackground: var(--color-primary-element, var(--color-primary, #4376fc));\n\tcolor: var(--color-primary-element-text, #fff);\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__icon {\n\tdisplay: inline-flex;\n}\n\n.cn-quick-filter-bar__label {\n\tline-height: 1;\n}\n\n/* Inherits the chip's own text colour, so it stays readable on the active\n (primary) fill as well as on the resting one. The count's text starts with\n a space: the chip is a flex row, so the space is not drawn, but it keeps a\n screen reader from reading label and count as one word. */\n.cn-quick-filter-bar__count {\n\tmin-width: 1.5em;\n\tpadding: 2px 6px;\n\tborder: 1px solid currentColor;\n\tborder-radius: var(--border-radius-pill, 10px);\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tline-height: 1;\n\ttext-align: center;\n}\n\n/* NcPopover wraps its trigger in a plain `<div class=\"v-popper\">`, which as a\n block would drop the chip onto its own line under the strip. */\n.cn-quick-filter-bar > :deep(.v-popper) {\n\tdisplay: inline-flex;\n}\n\n/* The `⋯` glyph is the chip's whole content while no hidden lens is on, so the\n pill tightens to a circle rather than sitting as a wide empty capsule. */\n.cn-quick-filter-bar__more {\n\tgap: 4px;\n}\n\n.cn-quick-filter-bar__more--icon-only {\n\tpadding: 4px 8px;\n}\n\n.cn-quick-filter-bar__more[aria-expanded='true'] {\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__more-panel {\n\tpadding: 10px 12px 12px;\n\tmax-width: 280px;\n}\n\n.cn-quick-filter-bar__more-heading {\n\tmargin: 0 0 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* The hidden lenses stay chips — the panel is more of the strip, not a\n different control that happens to hold the same filters. */\n.cn-quick-filter-bar__more-list {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmax-height: 320px;\n\toverflow-y: auto;\n}\n\n.cn-quick-filter-bar__more-item {\n\tmax-width: 100%;\n}\n\n.cn-quick-filter-bar__more-item .cn-quick-filter-bar__label {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["_normalizeClass","_createVNode","_createElementBlock","_Fragment","_renderList","_createBlock","_createElementVNode","_toDisplayString","_openBlock"],"mappings":"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"}
1
+ {"version":3,"file":"CnQuickFilterBar.vue3.js","sources":["../../../../src/components/CnQuickFilterBar/CnQuickFilterBar.vue?vue&type=template&id=2d5e5fa6&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: AGPL-3.0-or-later\n -->\n\n<template>\n\t<!-- Dropdown mode: a single NcSelect (multi or single) instead of the chip strip. -->\n\t<div\n\t\tv-if=\"mode === 'dropdown'\"\n\t\tclass=\"cn-quick-filter-bar cn-quick-filter-bar--dropdown\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<NcSelect\n\t\t\t:modelValue=\"dropdownValue\"\n\t\t\t:options=\"dropdownOptions\"\n\t\t\t:multiple=\"multiple\"\n\t\t\t:keepOpen=\"multiple\"\n\t\t\t:clearable=\"true\"\n\t\t\tlabel=\"label\"\n\t\t\tclass=\"cn-quick-filter-bar__select\"\n\t\t\t:inputLabel=\"selectLabel\"\n\t\t\t:aria-label-combobox=\"selectLabel\"\n\t\t\t:placeholder=\"placeholder || selectLabel\"\n\t\t\t@update:modelValue=\"onSelectInput\" />\n\t</div>\n\t<!-- Chips mode (default): the clickable tab strip. -->\n\t<div v-else\n\t\tref=\"chipsRoot\"\n\t\tclass=\"cn-quick-filter-bar\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline, 'cn-quick-filter-bar--fit': fit }\">\n\t\t<!-- With `fit`: an invisible copy of every chip and the overflow chip,\n\t\t measured to work out how many chips the bar's width holds. -->\n\t\t<div v-if=\"fit\"\n\t\t\tref=\"measure\"\n\t\t\tclass=\"cn-quick-filter-bar__measure\"\n\t\t\taria-hidden=\"true\">\n\t\t\t<span v-for=\"entry in entries\"\n\t\t\t\t:key=\"'m:' + entry.tab.label + ':' + entry.index\"\n\t\t\t\tclass=\"cn-quick-filter-bar__tab\"\n\t\t\t\t:class=\"{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }\"\n\t\t\t\tdata-measure=\"chip\">\n\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ tl(entry.tab.label) }}</span>\n\t\t\t\t<span v-if=\"countOf(entry) !== null\" class=\"cn-quick-filter-bar__count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t</span>\n\t\t\t<span class=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more\" data-measure=\"more\">\n\t\t\t\t<span v-if=\"overflowLabel\" class=\"cn-quick-filter-bar__label\">{{ overflowLabel }}</span>\n\t\t\t\t<DotsHorizontal :size=\"16\" class=\"cn-quick-filter-bar__icon\" />\n\t\t\t</span>\n\t\t</div>\n\t\t<!-- The tablist holds ONLY tabs: the overflow chip is a sibling, not a\n\t\t child, because a role=\"tablist\" may not contain a menu button. -->\n\t\t<!-- Board look: the tabs are chips, pressed buttons in a group, not a\n\t\t tablist (the chips filter the list, they do not switch a panel). -->\n\t\t<div class=\"cn-quick-filter-bar__tabs\" :role=\"isBoardLook ? 'group' : 'tablist'\" :aria-label=\"isBoardLook ? t('nextcloud-vue', 'Quick filters') : null\">\n\t\t\t<button\n\t\t\t\tv-for=\"entry in visibleEntries\"\n\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\ttype=\"button\"\n\t\t\t\t:role=\"isBoardLook ? null : 'tab'\"\n\t\t\t\t:aria-selected=\"isBoardLook ? null : (isChipActive(entry.index) ? 'true' : 'false')\"\n\t\t\t\t:aria-pressed=\"isBoardLook ? (isChipActive(entry.index) ? 'true' : 'false') : null\"\n\t\t\t\tclass=\"cn-quick-filter-bar__tab\"\n\t\t\t\t:class=\"[{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }]\"\n\t\t\t\t@click=\"onClick(entry.index)\">\n\t\t\t\t<CnIcon\n\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t:size=\"16\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ tl(entry.tab.label) }}</span>\n\t\t\t\t<span\n\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t</button>\n\t\t</div>\n\t\t<!-- The overflow is a CHIP and not a toolbar button: it is one of the\n\t\t lenses, so it carries the same pill, the same active fill and the\n\t\t label of whichever hidden lens is on. -->\n\t\t<NcPopover\n\t\t\tv-if=\"overflowEntries.length > 0\"\n\t\t\tv-model:shown=\"moreOpen\"\n\t\t\t:triggers=\"[]\"\n\t\t\tpopupRole=\"dialog\"\n\t\t\tplacement=\"bottom-end\"\n\t\t\tpopoverBaseClass=\"cn-quick-filter-bar__popper\">\n\t\t\t<template #trigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-more\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more\"\n\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t'cn-quick-filter-bar__tab--active': activeOverflowEntries.length > 0,\n\t\t\t\t\t\t'cn-quick-filter-bar__more--icon-only': !overflowLabel,\n\t\t\t\t\t}\"\n\t\t\t\t\t:aria-expanded=\"moreOpen ? 'true' : 'false'\"\n\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t\t:aria-label=\"overflowAriaLabel\"\n\t\t\t\t\t:title=\"overflowAriaLabel\"\n\t\t\t\t\t@click=\"moreOpen = !moreOpen\">\n\t\t\t\t\t<span v-if=\"overflowLabel\" class=\"cn-quick-filter-bar__label\">{{ overflowLabel }}</span>\n\t\t\t\t\t<DotsHorizontal :size=\"16\" class=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t</button>\n\t\t\t</template>\n\t\t\t<div\n\t\t\t\tclass=\"cn-quick-filter-bar__more-panel\"\n\t\t\t\t@keydown.escape.stop=\"moreOpen = false\">\n\t\t\t\t<p class=\"cn-quick-filter-bar__more-heading\">\n\t\t\t\t\t{{ moreHeading }}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"cn-quick-filter-bar__more-list\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-for=\"entry in overflowEntries\"\n\t\t\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tdata-testid=\"cn-quick-filter-more-item\"\n\t\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more-item\"\n\t\t\t\t\t\t:class=\"{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }\"\n\t\t\t\t\t\t:aria-pressed=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\t\t\t@click=\"onOverflowClick(entry.index)\">\n\t\t\t\t\t\t<CnIcon\n\t\t\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:size=\"16\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ tl(entry.tab.label) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</div>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcPopover, NcSelect } from '@nextcloud/vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport { normalizeLook } from '../../composables/useLook.js'\n\n/**\n * CnQuickFilterBar — quick-filter control rendered above a `type:\"index\"`\n * page's table. Each tab carries a manifest `filter` map that `CnIndexPage`\n * merges into the `useListView` fetch when the tab is active.\n *\n * Two presentations, chosen by `mode`:\n * - `'chips'` (default) — a horizontal row of pill-shaped buttons; the\n * active one is filled, the rest outlined. `maxVisible` caps how many\n * pills render and moves the rest into an overflow menu.\n * - `'dropdown'` — a single `NcSelect`. The \"All\" / empty-filter tab is\n * dropped from the options (an empty selection means \"all\").\n *\n * Two selection cardinalities, chosen by `multiple`:\n * - single (default) — one active tab; uses the `activeIndex` v-model\n * (`update:active-index`).\n * - `multiple` — several tabs at once; uses the `selectedIndices` array\n * prop + `update:selected-indices` event. `CnIndexPage` ORs the selected\n * tabs' filters together.\n *\n * Implementation is deliberately a thin styled `<button>` list (chips) /\n * `NcSelect` (dropdown) rather than `NcAppNavigation*` — this lives INSIDE\n * the index page, not as the app's main nav.\n */\nexport default {\n\tname: 'CnQuickFilterBar',\n\n\tcomponents: { CnIcon, DotsHorizontal, NcPopover, NcSelect },\n\n\tinject: {\n\t\t/** The look CnAppRoot provides; `board` draws the tabs as pressed chips. */\n\t\tcnLook: { default: 'nextcloud' },\n\t\t/**\n\t\t * The host's label lookup (CnAppRoot provides it); identity without one, so a\n\t\t * label that is not a key renders as written.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\t// NO `model: { prop, event }` OPTION.\n\t//\n\t// The Vue-2 `model` option is REMOVED in Vue 3 — read by nothing, warned\n\t// about by nothing — so it survived the migration as a declaration that\n\t// looked authoritative while doing exactly zero. The component's real\n\t// contract is the explicit `:active-index` / `@update:active-index` pair\n\t// (and `:selected-indices` / `@update:selected-indices` in `multiple`\n\t// mode), which is what `CnIndexPage` binds. Surfaced by\n\t// `vue/no-deprecated-model-definition`, which this repo now arms through\n\t// its own published preset.\n\n\tprops: {\n\t\t/**\n\t\t * Tab definitions — same shape `pages[].config.quickFilters[]` uses.\n\t\t * `filter` is consumed by the parent (CnIndexPage), not this component.\n\t\t */\n\t\ttabs: {\n\t\t\ttype: Array,\n\t\t\trequired: true,\n\t\t\tvalidator: (arr) => Array.isArray(arr) && arr.every((t) => t && typeof t.label === 'string'),\n\t\t},\n\n\t\t/**\n\t\t * Render bare (no padding / bottom border / background) for embedding\n\t\t * inline inside another bar — e.g. the `#filters` slot of `CnActionsBar`,\n\t\t * so the tabs sit beside the view toggle instead of as a separate row.\n\t\t */\n\t\tinline: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Index of the currently active tab, or `null` for none active. Single-select only. */\n\t\tactiveIndex: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Presentation: `'chips'` (pill button strip, default) or\n\t\t * `'dropdown'` (a single `NcSelect`).\n\t\t *\n\t\t * @type {'chips'|'dropdown'}\n\t\t */\n\t\tmode: {\n\t\t\ttype: String,\n\t\t\tdefault: 'chips',\n\t\t\tvalidator: (v) => ['chips', 'dropdown'].includes(v),\n\t\t},\n\n\t\t/**\n\t\t * Allow more than one tab active at once. Selection is exposed via\n\t\t * `selectedIndices` + `update:selected-indices`; the parent ORs the\n\t\t * selected tabs' filters together.\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Active tab indices when `multiple` is set (the array v-model).\n\t\t *\n\t\t * @type {number[]}\n\t\t */\n\t\tselectedIndices: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Accessible label / placeholder for the dropdown control. */\n\t\tselectLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'Filter',\n\t\t},\n\n\t\t/** Placeholder text for the dropdown (falls back to `selectLabel`). */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Chips mode only: how many pills render inline before the rest move\n\t\t * into an overflow menu. `0` (the default) renders every tab, which is\n\t\t * the behaviour this component has always had. The visible set is the\n\t\t * FIRST `maxVisible` tabs in declared order — reorder `tabs` to change\n\t\t * which ones stay out. Ignored in `dropdown` mode.\n\t\t */\n\t\tmaxVisible: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t\tvalidator: (v) => Number.isFinite(v) && v >= 0,\n\t\t},\n\n\t\t/**\n\t\t * How many records each tab matches, keyed by tab index (an array in\n\t\t * tab order works too). A tab with a number here shows it after its\n\t\t * label; a tab without one shows no count. A tab can also carry its\n\t\t * own `count`. `null` (the default) shows no counts at all.\n\t\t *\n\t\t * @type {{[index: number]: number}|Array<number|null>|null}\n\t\t */\n\t\tcounts: {\n\t\t\ttype: [Object, Array],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Chips mode only: show as many chips as the bar's own width holds and\n\t\t * move the rest into the overflow chip, measured again whenever the\n\t\t * width, the tabs or the counts change. The bar takes the room it is\n\t\t * given (CnIndexPage's `quickFilterPlacement: \"toolbar\"` gives it what\n\t\t * the Filter button and the view switch leave on their row). With\n\t\t * `maxVisible` too, the smaller of the two wins.\n\t\t */\n\t\tfit: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['update:active-index', 'update:selected-indices'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow chip's panel is open. */\n\t\t\tmoreOpen: false,\n\t\t\t/** With `fit`: how many chips the width holds; null before the first measure. */\n\t\t\tfitCount: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the tabs draw as board chips (`aria-pressed`, no tablist).\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tisBoardLook() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/**\n\t\t * Every tab paired with its own index, so the overflow split can slice\n\t\t * the list without losing the index the parent's filters are keyed on.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tentries() {\n\t\t\treturn this.tabs.map((tab, index) => ({ tab, index }))\n\t\t},\n\n\t\t/**\n\t\t * The tabs rendered as pills — all of them unless `maxVisible` caps it.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tvisibleEntries() {\n\t\t\tconst limit = this.effectiveMax\n\t\t\tif (!limit || this.tabs.length <= limit) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.slice(0, limit)\n\t\t},\n\n\t\t/**\n\t\t * How many chips render: `maxVisible`, and with `fit` no more than the\n\t\t * width holds; 0 for no limit.\n\t\t *\n\t\t * @return {number}\n\t\t */\n\t\teffectiveMax() {\n\t\t\tif (!this.fit || this.fitCount === null) {\n\t\t\t\treturn this.maxVisible\n\t\t\t}\n\t\t\treturn this.maxVisible ? Math.min(this.maxVisible, this.fitCount) : this.fitCount\n\t\t},\n\n\t\t/**\n\t\t * The tabs moved into the overflow menu (empty when `maxVisible` is 0\n\t\t * or there is nothing to hide).\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\toverflowEntries() {\n\t\t\tconst limit = this.effectiveMax\n\t\t\tif (!limit || this.tabs.length <= limit) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.entries.slice(limit)\n\t\t},\n\n\t\t/**\n\t\t * The active tabs that live in the overflow menu.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tactiveOverflowEntries() {\n\t\t\treturn this.overflowEntries.filter((e) => this.isChipActive(e.index))\n\t\t},\n\n\t\t/**\n\t\t * Text on the overflow chip — an active hidden tab names itself there,\n\t\t * so the strip never reads \"All\" while the list is narrowed. Nothing\n\t\t * active leaves the chip as the bare `⋯` glyph.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel() {\n\t\t\tconst active = this.activeOverflowEntries\n\t\t\tif (active.length === 1) {\n\t\t\t\treturn this.tl(active[0].tab.label)\n\t\t\t}\n\t\t\tif (active.length > 1) {\n\t\t\t\treturn t('nextcloud-vue', '{count} filters', { count: active.length })\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\t/** @return {string} Accessible name for the overflow chip. */\n\t\toverflowAriaLabel() {\n\t\t\tif (this.overflowLabel) {\n\t\t\t\treturn t('nextcloud-vue', '{label} — show the other filters', { label: this.overflowLabel })\n\t\t\t}\n\t\t\tconst count = this.overflowEntries.length\n\t\t\treturn n('nextcloud-vue', '{count} more filter', '{count} more filters', count, { count })\n\t\t},\n\n\t\t/** @return {string} Heading above the hidden chips in the panel. */\n\t\tmoreHeading() {\n\t\t\treturn t('nextcloud-vue', 'More filters')\n\t\t},\n\n\t\t/**\n\t\t * Dropdown options: every tab that carries a non-empty `filter`,\n\t\t * tagged with its original index. The \"All\" / empty-filter tab is\n\t\t * omitted — an empty selection already means \"all\".\n\t\t *\n\t\t * @return {Array<{label: string, index: number, icon: string}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tdropdownOptions() {\n\t\t\treturn this.tabs\n\t\t\t\t.map((tab, index) => {\n\t\t\t\t\tconst count = this.countOf({ tab, index })\n\t\t\t\t\treturn {\n\t\t\t\t\t\tlabel: count === null ? this.tl(tab.label) : `${this.tl(tab.label)} (${count})`,\n\t\t\t\t\t\ticon: tab.icon,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\t_empty: this.isEmptyFilter(tab),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((o) => !o._empty)\n\t\t},\n\n\t\t/**\n\t\t * Current NcSelect value — an array of option objects when\n\t\t * `multiple`, a single option object (or null) otherwise.\n\t\t *\n\t\t * @return {object|object[]|null}\n\t\t */\n\t\tdropdownValue() {\n\t\t\tif (this.multiple) {\n\t\t\t\treturn this.dropdownOptions.filter((o) => this.selectedIndices.includes(o.index))\n\t\t\t}\n\t\t\treturn this.dropdownOptions.find((o) => o.index === this.activeIndex) || null\n\t\t},\n\t},\n\n\twatch: {\n\t\ttabs() {\n\t\t\tthis.scheduleFit()\n\t\t},\n\n\t\tcounts: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.scheduleFit()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tif (this.fit && typeof ResizeObserver === 'function' && this.$refs.chipsRoot) {\n\t\t\tthis.fitObserver = new ResizeObserver(() => this.measureFit())\n\t\t\tthis.fitObserver.observe(this.$refs.chipsRoot)\n\t\t}\n\t\tthis.scheduleFit()\n\t},\n\n\tbeforeUnmount() {\n\t\tif (this.fitObserver) {\n\t\t\tthis.fitObserver.disconnect()\n\t\t\tthis.fitObserver = null\n\t\t}\n\t},\n\n\tmethods: {\n\t\t/** Measure the fit after the next render. */\n\t\tscheduleFit() {\n\t\t\tif (this.fit) {\n\t\t\t\tthis.$nextTick(() => this.measureFit())\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Work out how many chips the bar's width holds, from the invisible\n\t\t * copy: every chip that fits, and when not all do, room left for the\n\t\t * overflow chip. At least one chip always shows.\n\t\t */\n\t\tmeasureFit() {\n\t\t\tconst box = this.$refs.measure\n\t\t\tconst root = this.$refs.chipsRoot\n\t\t\tif (!this.fit || !box || !root) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst available = root.clientWidth\n\t\t\tconst chips = [...box.querySelectorAll('[data-measure=\"chip\"]')].map((el) => el.offsetWidth)\n\t\t\tconst more = box.querySelector('[data-measure=\"more\"]')\n\t\t\tconst moreWidth = more ? more.offsetWidth : 0\n\t\t\tconst gap = parseFloat(getComputedStyle(box).columnGap) || 8\n\t\t\tif (available <= 0 || chips.length === 0) {\n\t\t\t\tthis.fitCount = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst total = chips.reduce((sum, width) => sum + width, 0) + gap * (chips.length - 1)\n\t\t\tif (total <= available) {\n\t\t\t\tthis.fitCount = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet used = moreWidth\n\t\t\tlet count = 0\n\t\t\tfor (const width of chips) {\n\t\t\t\tif (used + gap + width > available) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tused += gap + width\n\t\t\t\tcount++\n\t\t\t}\n\t\t\tthis.fitCount = Math.max(1, count)\n\t\t},\n\n\t\t/**\n\t\t * A manifest string through the host's label lookup (`cnTranslate`), so a key\n\t\t * such as \"Mine\" reads in the user's language.\n\t\t *\n\t\t * @param {string} text The text as written in the manifest.\n\t\t * @return {string} The translated text.\n\t\t */\n\t\ttl(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\tt,\n\n\t\t/**\n\t\t * The count to show on a tab, or null for none: `counts[index]`\n\t\t * first, else the tab's own `count`.\n\t\t *\n\t\t * @param {{tab: object, index: number}} entry The tab and its index.\n\t\t * @return {number|null}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tcountOf(entry) {\n\t\t\tconst fromProp = this.counts ? this.counts[entry.index] : undefined\n\t\t\tconst value = (fromProp !== undefined && fromProp !== null) ? fromProp : entry.tab.count\n\t\t\treturn (typeof value === 'number' && Number.isFinite(value)) ? value : null\n\t\t},\n\n\t\t/**\n\t\t * Is tab `i` rendered active in chips mode (handles both single\n\t\t * `activeIndex` and `multiple` `selectedIndices`).\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t * @return {boolean}\n\t\t */\n\t\tisChipActive(i) {\n\t\t\treturn this.multiple ? this.selectedIndices.includes(i) : i === this.activeIndex\n\t\t},\n\n\t\t/**\n\t\t * Whether a tab's `filter` map is absent/empty (the \"All\" tab).\n\t\t *\n\t\t * @param {{label: string, filter?: object}} tab An entry from the `tabs` prop.\n\t\t * @return {boolean} True when the tab applies no filter, so selecting it\n\t\t * clears the multi-selection rather than adding to it.\n\t\t */\n\t\tisEmptyFilter(tab) {\n\t\t\treturn !tab || !tab.filter || Object.keys(tab.filter).length === 0\n\t\t},\n\n\t\t/**\n\t\t * Chip-click handler. In single mode emits the new active index; in\n\t\t * multiple mode toggles the index in/out of the selection. Clicking\n\t\t * an empty-filter (\"All\") chip clears the multi-selection.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonClick(i) {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (this.isEmptyFilter(this.tabs[i])) {\n\t\t\t\t\t/**\n\t\t\t\t\t * @event update:selected-indices Active tab indices changed (multiple mode).\n\t\t\t\t\t * @type {number[]}\n\t\t\t\t\t */\n\t\t\t\t\tthis.$emit('update:selected-indices', [])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst next = this.selectedIndices.includes(i)\n\t\t\t\t\t? this.selectedIndices.filter((x) => x !== i)\n\t\t\t\t\t: [...this.selectedIndices, i]\n\t\t\t\tthis.$emit('update:selected-indices', next)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (i === this.activeIndex) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', i)\n\t\t},\n\n\t\t/**\n\t\t * A chip clicked inside the overflow panel. Single-select closes the\n\t\t * panel on the way out; multi-select keeps it open so several lenses\n\t\t * can be toggled in one visit.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonOverflowClick(i) {\n\t\t\tthis.onClick(i)\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.moreOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler — normalises the option object(s) back to\n\t\t * indices and emits the matching model event.\n\t\t *\n\t\t * @param {object|object[]|null} val Selected option object(s).\n\t\t */\n\t\tonSelectInput(val) {\n\t\t\tif (this.multiple) {\n\t\t\t\tconst arr = Array.isArray(val) ? val : []\n\t\t\t\tthis.$emit('update:selected-indices', arr.map((o) => o.index))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', val ? val.index : null)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-quick-filter-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tbackground: var(--color-main-background);\n}\n\n.cn-quick-filter-bar__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n/* Inline variant — bare strip for embedding inside another bar (e.g. the\n CnActionsBar #filters slot), so it reads as a control beside the view toggle\n rather than a separate bordered row. */\n/* With `fit`: one line, as wide as it is given; the chips it cannot hold\n are in the overflow chip. The measuring copy takes no room and is never\n seen or read. */\n.cn-quick-filter-bar--fit {\n\tposition: relative;\n\tflex-wrap: nowrap;\n\tmin-width: 0;\n}\n\n.cn-quick-filter-bar--fit .cn-quick-filter-bar__tabs {\n\tflex-wrap: nowrap;\n\tmin-width: 0;\n}\n\n.cn-quick-filter-bar__measure {\n\tposition: absolute;\n\tinset-block-start: 0;\n\tinset-inline-start: 0;\n\tdisplay: flex;\n\tgap: 8px;\n\twidth: 0;\n\theight: 0;\n\toverflow: hidden;\n\tvisibility: hidden;\n\tpointer-events: none;\n\twhite-space: nowrap;\n}\n\n.cn-quick-filter-bar__measure > * {\n\tflex: none;\n}\n\n.cn-quick-filter-bar--inline {\n\tpadding: 0;\n\tborder-bottom: none;\n\tbackground: transparent;\n}\n\n/* Dropdown variant — give the NcSelect a sensible minimum so multi-select\n chips have room without stretching the whole bar. */\n.cn-quick-filter-bar--dropdown {\n\talign-items: center;\n}\n\n.cn-quick-filter-bar__select {\n\tmin-width: 220px;\n}\n\n.cn-quick-filter-bar__tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: background-color 120ms, color 120ms, border-color 120ms;\n}\n\n.cn-quick-filter-bar__tab:hover,\n.cn-quick-filter-bar__tab:focus-visible {\n\tbackground: var(--color-background-hover);\n\toutline: none;\n}\n\n.cn-quick-filter-bar__tab--active {\n\tbackground: var(--color-primary-element, var(--color-primary, #4376fc));\n\tcolor: var(--color-primary-element-text, #fff);\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__icon {\n\tdisplay: inline-flex;\n}\n\n.cn-quick-filter-bar__label {\n\tline-height: 1;\n}\n\n/* Inherits the chip's own text colour, so it stays readable on the active\n (primary) fill as well as on the resting one. The count's text starts with\n a space: the chip is a flex row, so the space is not drawn, but it keeps a\n screen reader from reading label and count as one word. */\n.cn-quick-filter-bar__count {\n\tmin-width: 1.5em;\n\tpadding: 2px 6px;\n\tborder: 1px solid currentColor;\n\tborder-radius: var(--border-radius-pill, 10px);\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tline-height: 1;\n\ttext-align: center;\n}\n\n/* NcPopover wraps its trigger in a plain `<div class=\"v-popper\">`, which as a\n block would drop the chip onto its own line under the strip. */\n.cn-quick-filter-bar > :deep(.v-popper) {\n\tdisplay: inline-flex;\n}\n\n/* The `⋯` glyph is the chip's whole content while no hidden lens is on, so the\n pill tightens to a circle rather than sitting as a wide empty capsule. */\n.cn-quick-filter-bar__more {\n\tgap: 4px;\n}\n\n.cn-quick-filter-bar__more--icon-only {\n\tpadding: 4px 8px;\n}\n\n.cn-quick-filter-bar__more[aria-expanded='true'] {\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__more-panel {\n\tpadding: 10px 12px 12px;\n\tmax-width: 280px;\n}\n\n.cn-quick-filter-bar__more-heading {\n\tmargin: 0 0 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* The hidden lenses stay chips — the panel is more of the strip, not a\n different control that happens to hold the same filters. */\n.cn-quick-filter-bar__more-list {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmax-height: 320px;\n\toverflow-y: auto;\n}\n\n.cn-quick-filter-bar__more-item {\n\tmax-width: 100%;\n}\n\n.cn-quick-filter-bar__more-item .cn-quick-filter-bar__label {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["_normalizeClass","_createVNode","_openBlock","_createElementBlock","_Fragment","_renderList","_createElementVNode","_toDisplayString","_createBlock"],"mappings":"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"}