@conduction/nextcloud-vue 2.147.0 → 2.148.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 (49) hide show
  1. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +71 -8
  2. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  3. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +2 -2
  4. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  5. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
  6. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +6 -1
  7. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
  8. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
  9. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
  10. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +8 -0
  11. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  12. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  13. package/dist/esm/components/CnStepper/CnStepper.vue.js +1 -1
  14. package/dist/esm/components/CnStepper/CnStepper.vue2.js.map +1 -1
  15. package/dist/esm/components/CnStepper/CnStepper.vue3.js.map +1 -1
  16. package/dist/esm/dialogs/CnAccessPurposeDialog.vue.js +1 -1
  17. package/dist/esm/dialogs/CnAccessPurposeDialog.vue2.js +3 -1
  18. package/dist/esm/dialogs/CnAccessPurposeDialog.vue2.js.map +1 -1
  19. package/dist/esm/dialogs/CnAccessPurposeDialog.vue3.js +26 -15
  20. package/dist/esm/dialogs/CnAccessPurposeDialog.vue3.js.map +1 -1
  21. package/dist/esm/l10n/en.json.js +2 -1
  22. package/dist/esm/l10n/en.json.js.map +1 -1
  23. package/dist/esm/l10n/nl.json.js +2 -1
  24. package/dist/esm/l10n/nl.json.js.map +1 -1
  25. package/dist/esm/library-style.js +1 -1
  26. package/dist/esm/nextcloud-vue.css +160 -126
  27. package/dist/esm/utils/builtInFormatters.js +53 -1
  28. package/dist/esm/utils/builtInFormatters.js.map +1 -1
  29. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  30. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  31. package/dist/nextcloud-vue.cjs.js +1357 -1217
  32. package/dist/nextcloud-vue.cjs.js.map +2 -2
  33. package/dist/nextcloud-vue.css +160 -126
  34. package/l10n/en.json +2 -1
  35. package/l10n/nl.json +2 -1
  36. package/package.json +1 -1
  37. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  38. package/src/components/CnDetailPage/CnDetailPage.vue +73 -10
  39. package/src/components/CnFactsWidget/CnFactsWidget.vue +6 -1
  40. package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
  41. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +8 -0
  42. package/src/components/CnStepper/CnStepper.vue +10 -2
  43. package/src/css/dialog.css +5 -2
  44. package/src/css/look-board-index.css +14 -0
  45. package/src/css/look-board.css +3 -0
  46. package/src/dialogs/CnAccessPurposeDialog.vue +27 -12
  47. package/src/schemas/app-manifest-v2.schema.json +4 -2
  48. package/src/utils/builtInFormatters.js +52 -0
  49. package/src/utils/validateManifestV2.compiled.js +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"CnStepper.vue2.js","sources":["../../../../src/components/CnStepper/CnStepper.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<ol class=\"cn-stepper cn-wizard-dialog__progress\"\n\t\t:class=\"[{ 'cn-stepper--board': isBoard }, lookClass]\"\n\t\t:aria-label=\"ariaLabel\"\n\t\tdata-testid=\"cn-stepper\">\n\t\t<li v-for=\"(step, idx) in steps\"\n\t\t\t:key=\"step.id\"\n\t\t\tclass=\"cn-stepper__item cn-wizard-dialog__progress-item\"\n\t\t\t:class=\"{\n\t\t\t\t'cn-stepper__item--done': idx < currentIndex,\n\t\t\t\t'cn-stepper__item--current': idx === currentIndex,\n\t\t\t\t'cn-stepper__item--upcoming': idx > currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--active': idx === currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--done': idx < currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--clickable': isJumpable(idx),\n\t\t\t}\"\n\t\t\t:aria-current=\"idx === currentIndex ? 'step' : undefined\"\n\t\t\t:data-step-id=\"step.id\">\n\t\t\t<component :is=\"isJumpable(idx) ? 'button' : 'span'\"\n\t\t\t\tclass=\"cn-stepper__step\"\n\t\t\t\t:type=\"isJumpable(idx) ? 'button' : undefined\"\n\t\t\t\t@click=\"isJumpable(idx) ? onJump(step.id) : null\">\n\t\t\t\t<span class=\"cn-stepper__dot cn-wizard-dialog__progress-dot\" aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"idx < currentIndex\">\n\t\t\t\t\t\t<Check v-if=\"isBoard\"\n\t\t\t\t\t\t\tclass=\"cn-stepper__check cn-wizard-dialog__progress-check\"\n\t\t\t\t\t\t\t:size=\"16\" />\n\t\t\t\t\t\t<span v-else class=\"cn-wizard-dialog__progress-check\">✓</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<span v-else>{{ idx + 1 }}</span>\n\t\t\t\t</span>\n\t\t\t\t<span class=\"cn-stepper__label cn-wizard-dialog__progress-label\">{{ step.label }}</span>\n\t\t\t\t<span v-if=\"idx < currentIndex\" class=\"cn-stepper__sr\">{{ ', ' + completedLabel }}</span>\n\t\t\t</component>\n\t\t\t<span v-if=\"idx < steps.length - 1\"\n\t\t\t\tclass=\"cn-stepper__connector cn-wizard-dialog__progress-connector\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'cn-stepper__connector--done': idx < currentIndex,\n\t\t\t\t\t'cn-wizard-dialog__progress-connector--done': idx < currentIndex,\n\t\t\t\t}\"\n\t\t\t\taria-hidden=\"true\" />\n\t\t</li>\n\t</ol>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport { useLook } from '../../composables/useLook.js'\n\n/**\n * CnStepper (internal) - the step indicator of a wizard: an ordered list, the\n * current step marked with `aria-current=\"step\"`, finished steps as real\n * buttons only when `allowJumpBack` is set.\n *\n * In the board look (`look=\"board\"`, else the injected `cnLook`) it draws 28px\n * circles with the label beside them, a green check on a finished step, a\n * filled circle on the current one, an outlined circle on the rest and a 2px\n * connector coloured by state. In the Nextcloud look it draws the stacked\n * stepper CnWizardDialog always had, with the same class names.\n *\n * @spec openspec/changes/screens-wizard-parity/specs/wizard-dialog/spec.md#requirement-the-board-stepper\n * @event jump Emitted with a finished step's id when its button is pressed.\n *\n * @event jump Emitted with the step id when a finished step button is pressed.\n */\nexport default {\n\tname: 'CnStepper',\n\n\tcomponents: { Check },\n\n\tprops: {\n\t\t/** The steps: `{ id, label }`. */\n\t\tsteps: { type: Array, required: true },\n\t\t/** Index of the current step. */\n\t\tcurrentIndex: { type: Number, default: 0 },\n\t\t/** Let a finished step be pressed to go back to it. */\n\t\tallowJumpBack: { type: Boolean, default: false },\n\t\t/** The look; unset follows the injected `cnLook`. */\n\t\tlook: { type: String, default: undefined },\n\t\t/** Accessible name of the list. */\n\t\tariaLabel: { type: String, default: () => t('nextcloud-vue', 'Steps') },\n\t\t/** Visually hidden text after a finished step's label. */\n\t\tcompletedLabel: { type: String, default: () => t('nextcloud-vue', 'completed') },\n\t},\n\n\temits: ['jump'],\n\n\tsetup(props) {\n\t\tconst { isBoard, lookClass } = useLook(props)\n\t\treturn { isBoard, lookClass }\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Forward a press on a finished step.\n\t\t *\n\t\t * @param {string} id The step id.\n\t\t */\n\t\tonJump(id) {\n\t\t\t/**\n\t\t\t * @event jump Emitted with the step id when a finished step button is pressed.\n\t\t\t */\n\t\t\tthis.$emit('jump', id)\n\t\t},\n\n\t\tisJumpable(idx) {\n\t\t\treturn this.allowJumpBack && idx < this.currentIndex\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* The Nextcloud look: the stacked stepper, unchanged. */\n.cn-stepper {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: center;\n\tgap: 0;\n\tpadding: 8px 0 4px;\n\tmargin: 0 0 20px;\n\tlist-style: none;\n}\n\n.cn-stepper__item {\n\tposition: relative;\n\tflex: 1 1 0;\n\tmin-width: 0;\n\tmax-width: 180px;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\ttext-align: center;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.8125rem;\n}\n\n.cn-stepper__step {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 6px;\n\tmax-width: 100%;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n\tbackground: none;\n\tcolor: inherit;\n\tfont: inherit;\n}\n\nbutton.cn-stepper__step {\n\tcursor: pointer;\n}\n\n.cn-stepper__dot {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 34px;\n\theight: 34px;\n\tborder-radius: 50%;\n\tborder: 2px solid var(--color-border-dark);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\ttransition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n\tz-index: 1;\n}\n\n.cn-wizard-dialog__progress-check {\n\tfont-size: 16px;\n\tline-height: 1;\n}\n\n.cn-stepper__label {\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-stepper__connector {\n\tposition: absolute;\n\ttop: 17px;\n\tleft: calc(50% + 21px);\n\tright: calc(-50% + 21px);\n\theight: 2px;\n\tbackground: var(--color-border-dark);\n}\n\n.cn-stepper__connector--done {\n\tbackground: var(--color-primary-element);\n}\n\n.cn-stepper__item--current .cn-stepper__dot,\n.cn-stepper__item--done .cn-stepper__dot {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text, #fff);\n}\n\n.cn-stepper__item--current .cn-stepper__label {\n\tcolor: var(--color-main-text);\n\tfont-weight: 600;\n}\n\n.cn-stepper__item--done .cn-stepper__label {\n\tcolor: var(--color-main-text);\n}\n\n.cn-stepper__item--done button.cn-stepper__step:hover .cn-stepper__label {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-stepper__sr {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\tmargin: -1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n\twhite-space: nowrap;\n}\n\n/* The board look: one row, 28px circles, the label beside the circle. */\n/* The board leaves 20px between the stepper and the step's body (DqInstellen). */\n.cn-stepper--board {\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: flex-start;\n\tgap: 8px;\n\tpadding: 0;\n\tmargin: 0 0 20px;\n}\n\n.cn-stepper--board .cn-stepper__item {\n\tflex: 0 1 auto;\n\tflex-direction: row;\n\talign-items: center;\n\tgap: 8px;\n\tmax-width: none;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__item:not(:last-child) {\n\tflex: 1 1 auto;\n}\n\n.cn-stepper--board .cn-stepper__step {\n\tflex-direction: row;\n\tgap: 8px;\n}\n\n.cn-stepper--board .cn-stepper__dot {\n\tflex: 0 0 auto;\n\twidth: 28px;\n\theight: 28px;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__label {\n\toverflow: visible;\n\ttext-overflow: clip;\n\twhite-space: nowrap;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__connector {\n\tposition: static;\n\tflex: 1 1 24px;\n\tmin-width: 16px;\n\theight: 2px;\n\tbackground: var(--color-border);\n}\n\n.cn-stepper--board .cn-stepper__connector--done {\n\tbackground: var(--color-success);\n}\n\n/* Done: filled success circle, 16px check, secondary label. */\n.cn-stepper--board .cn-stepper__item--done .cn-stepper__dot {\n\tborder-color: var(--color-success);\n\tbackground: var(--color-success);\n\tcolor: var(--color-success-text, #fff);\n}\n\n.cn-stepper--board .cn-stepper__item--done .cn-stepper__label {\n\tcolor: var(--cn-board-text-soft, var(--color-main-text));\n\tfont-weight: 400;\n}\n\n/* Current: filled primary, number 14/700, label 14/700 in the main text colour. */\n.cn-stepper--board .cn-stepper__item--current .cn-stepper__dot {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text, #fff);\n\tfont-weight: 700;\n}\n\n.cn-stepper--board .cn-stepper__item--current .cn-stepper__label {\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n}\n\n/* Upcoming: 2px outline, number 14/600, label in the max-contrast tone. */\n.cn-stepper--board .cn-stepper__item--upcoming .cn-stepper__dot {\n\tborder: 2px solid var(--color-border-dark);\n\tbackground: transparent;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: 600;\n}\n\n.cn-stepper--board .cn-stepper__item--upcoming .cn-stepper__label {\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["t"],"mappings":";;;;AAsDA;AACC;AACA;AACA;AACA;AACA;;;;;AAKA;;;AAGA;AACA;;AAED,aAAe;AACd,CAAA,IAAI,EAAE,WAAW;;AAEjB,CAAA,UAAU,EAAE,EAAE,OAAO;;AAErB,CAAA,KAAK,EAAE;;AAEN,EAAA,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM;;AAEtC,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG;AAC1C;AACA,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;AAChD;AACA,EAAA,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW;;AAE1C,EAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,OAAO,CAAA,EAAG;;AAEvE,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;EAChF;;AAED,CAAA,KAAK,EAAE,CAAC,MAAM,CAAC;;CAEf,KAAK,CAAC,KAAK,EAAE;AACZ,EAAA,MAAM,EAAE,OAAO,EAAE,SAAU,EAAA,GAAI,OAAO,CAAC,KAAK,EAAA;EAC5C,OAAO,EAAE,OAAO,EAAE,SAAU,EAAA;EAC5B;;AAED,CAAA,OAAO,EAAE;AACR;;AAEC;;;EAGD,MAAM,CAAC,EAAE,EAAE;AACV;AACC;;AAED,GAAA,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,EAAA;GACrB;;AAED,EAAA,UAAU,CAAC,GAAG,EAAE;GACf,OAAO,IAAI,CAAC,iBAAiB,GAAE,GAAI,IAAI,CAAC,YAAW;GACnD;EACD;AACF;;;;"}
1
+ {"version":3,"file":"CnStepper.vue2.js","sources":["../../../../src/components/CnStepper/CnStepper.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<ol class=\"cn-stepper cn-wizard-dialog__progress\"\n\t\t:class=\"[{ 'cn-stepper--board': isBoard }, lookClass]\"\n\t\t:aria-label=\"ariaLabel\"\n\t\tdata-testid=\"cn-stepper\">\n\t\t<li v-for=\"(step, idx) in steps\"\n\t\t\t:key=\"step.id\"\n\t\t\tclass=\"cn-stepper__item cn-wizard-dialog__progress-item\"\n\t\t\t:class=\"{\n\t\t\t\t'cn-stepper__item--done': idx < currentIndex,\n\t\t\t\t'cn-stepper__item--current': idx === currentIndex,\n\t\t\t\t'cn-stepper__item--upcoming': idx > currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--active': idx === currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--done': idx < currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--clickable': isJumpable(idx),\n\t\t\t}\"\n\t\t\t:aria-current=\"idx === currentIndex ? 'step' : undefined\"\n\t\t\t:data-step-id=\"step.id\">\n\t\t\t<component :is=\"isJumpable(idx) ? 'button' : 'span'\"\n\t\t\t\tclass=\"cn-stepper__step\"\n\t\t\t\t:type=\"isJumpable(idx) ? 'button' : undefined\"\n\t\t\t\t@click=\"isJumpable(idx) ? onJump(step.id) : null\">\n\t\t\t\t<span class=\"cn-stepper__dot cn-wizard-dialog__progress-dot\" aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"idx < currentIndex\">\n\t\t\t\t\t\t<Check v-if=\"isBoard\"\n\t\t\t\t\t\t\tclass=\"cn-stepper__check cn-wizard-dialog__progress-check\"\n\t\t\t\t\t\t\t:size=\"16\" />\n\t\t\t\t\t\t<span v-else class=\"cn-wizard-dialog__progress-check\">✓</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<span v-else>{{ idx + 1 }}</span>\n\t\t\t\t</span>\n\t\t\t\t<span class=\"cn-stepper__label cn-wizard-dialog__progress-label\">{{ step.label }}</span>\n\t\t\t\t<span v-if=\"idx < currentIndex\" class=\"cn-stepper__sr\">{{ ', ' + completedLabel }}</span>\n\t\t\t</component>\n\t\t\t<span v-if=\"idx < steps.length - 1\"\n\t\t\t\tclass=\"cn-stepper__connector cn-wizard-dialog__progress-connector\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'cn-stepper__connector--done': idx < currentIndex,\n\t\t\t\t\t'cn-wizard-dialog__progress-connector--done': idx < currentIndex,\n\t\t\t\t}\"\n\t\t\t\taria-hidden=\"true\" />\n\t\t</li>\n\t</ol>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport { useLook } from '../../composables/useLook.js'\n\n/**\n * CnStepper (internal) - the step indicator of a wizard: an ordered list, the\n * current step marked with `aria-current=\"step\"`, finished steps as real\n * buttons only when `allowJumpBack` is set.\n *\n * In the board look (`look=\"board\"`, else the injected `cnLook`) it draws 28px\n * circles with the label beside them, a green check on a finished step, a\n * filled circle on the current one, an outlined circle on the rest and a 2px\n * connector coloured by state. In the Nextcloud look it draws the stacked\n * stepper CnWizardDialog always had, with the same class names.\n *\n * @spec openspec/changes/screens-wizard-parity/specs/wizard-dialog/spec.md#requirement-the-board-stepper\n * @event jump Emitted with a finished step's id when its button is pressed.\n *\n * @event jump Emitted with the step id when a finished step button is pressed.\n */\nexport default {\n\tname: 'CnStepper',\n\n\tcomponents: { Check },\n\n\tprops: {\n\t\t/** The steps: `{ id, label }`. */\n\t\tsteps: { type: Array, required: true },\n\t\t/** Index of the current step. */\n\t\tcurrentIndex: { type: Number, default: 0 },\n\t\t/** Let a finished step be pressed to go back to it. */\n\t\tallowJumpBack: { type: Boolean, default: false },\n\t\t/** The look; unset follows the injected `cnLook`. */\n\t\tlook: { type: String, default: undefined },\n\t\t/** Accessible name of the list. */\n\t\tariaLabel: { type: String, default: () => t('nextcloud-vue', 'Steps') },\n\t\t/** Visually hidden text after a finished step's label. */\n\t\tcompletedLabel: { type: String, default: () => t('nextcloud-vue', 'completed') },\n\t},\n\n\temits: ['jump'],\n\n\tsetup(props) {\n\t\tconst { isBoard, lookClass } = useLook(props)\n\t\treturn { isBoard, lookClass }\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Forward a press on a finished step.\n\t\t *\n\t\t * @param {string} id The step id.\n\t\t */\n\t\tonJump(id) {\n\t\t\t/**\n\t\t\t * @event jump Emitted with the step id when a finished step button is pressed.\n\t\t\t */\n\t\t\tthis.$emit('jump', id)\n\t\t},\n\n\t\tisJumpable(idx) {\n\t\t\treturn this.allowJumpBack && idx < this.currentIndex\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* The Nextcloud look: the stacked stepper, unchanged. */\n.cn-stepper {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: center;\n\tgap: 0;\n\tpadding: 8px 0 4px;\n\tmargin: 0 0 20px;\n\tlist-style: none;\n}\n\n.cn-stepper__item {\n\tposition: relative;\n\tflex: 1 1 0;\n\tmin-width: 0;\n\tmax-width: 180px;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\ttext-align: center;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.8125rem;\n}\n\n.cn-stepper__step {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 6px;\n\tmax-width: 100%;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n\tbackground: none;\n\tcolor: inherit;\n\tfont: inherit;\n}\n\n/* Nextcloud's server.css gives every plain button a 3px margin and the\n clickable-area height (`button:not(.button-vue, …):not(…)`, 0,2,1), which\n made a done step 40px tall around its 28px circle. Two classes outrank it. */\n.cn-stepper button.cn-stepper__step {\n\tmargin: 0;\n\tmin-height: 0;\n}\n\nbutton.cn-stepper__step {\n\tcursor: pointer;\n}\n\n.cn-stepper__dot {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 34px;\n\theight: 34px;\n\tborder-radius: 50%;\n\tborder: 2px solid var(--color-border-dark);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\ttransition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n\tz-index: 1;\n}\n\n.cn-wizard-dialog__progress-check {\n\tfont-size: 16px;\n\tline-height: 1;\n}\n\n.cn-stepper__label {\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-stepper__connector {\n\tposition: absolute;\n\ttop: 17px;\n\tleft: calc(50% + 21px);\n\tright: calc(-50% + 21px);\n\theight: 2px;\n\tbackground: var(--color-border-dark);\n}\n\n.cn-stepper__connector--done {\n\tbackground: var(--color-primary-element);\n}\n\n.cn-stepper__item--current .cn-stepper__dot,\n.cn-stepper__item--done .cn-stepper__dot {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text, #fff);\n}\n\n.cn-stepper__item--current .cn-stepper__label {\n\tcolor: var(--color-main-text);\n\tfont-weight: 600;\n}\n\n.cn-stepper__item--done .cn-stepper__label {\n\tcolor: var(--color-main-text);\n}\n\n.cn-stepper__item--done button.cn-stepper__step:hover .cn-stepper__label {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-stepper__sr {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\tmargin: -1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n\twhite-space: nowrap;\n}\n\n/* The board look: one row, 28px circles, the label beside the circle. */\n/* The board leaves 16px between the stepper and the step's body (DqInstellen). */\n.cn-stepper--board {\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: flex-start;\n\tgap: 8px;\n\tpadding: 0;\n\tmargin: 0 0 16px;\n}\n\n.cn-stepper--board .cn-stepper__item {\n\tflex: 0 1 auto;\n\tflex-direction: row;\n\talign-items: center;\n\tgap: 8px;\n\tmax-width: none;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__item:not(:last-child) {\n\tflex: 1 1 auto;\n}\n\n.cn-stepper--board .cn-stepper__step {\n\tflex-direction: row;\n\tgap: 8px;\n}\n\n.cn-stepper--board .cn-stepper__dot {\n\tflex: 0 0 auto;\n\twidth: 28px;\n\theight: 28px;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__label {\n\toverflow: visible;\n\ttext-overflow: clip;\n\twhite-space: nowrap;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__connector {\n\tposition: static;\n\tflex: 1 1 24px;\n\tmin-width: 16px;\n\theight: 2px;\n\tbackground: var(--color-border);\n}\n\n.cn-stepper--board .cn-stepper__connector--done {\n\tbackground: var(--color-success);\n}\n\n/* Done: filled success circle, 16px check, secondary label. */\n.cn-stepper--board .cn-stepper__item--done .cn-stepper__dot {\n\tborder-color: var(--color-success);\n\tbackground: var(--color-success);\n\tcolor: var(--color-success-text, #fff);\n}\n\n.cn-stepper--board .cn-stepper__item--done .cn-stepper__label {\n\tcolor: var(--cn-board-text-soft, var(--color-main-text));\n\tfont-weight: 400;\n}\n\n/* Current: filled primary, number 14/700, label 14/700 in the main text colour. */\n.cn-stepper--board .cn-stepper__item--current .cn-stepper__dot {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text, #fff);\n\tfont-weight: 700;\n}\n\n.cn-stepper--board .cn-stepper__item--current .cn-stepper__label {\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n}\n\n/* Upcoming: 2px outline, number 14/600, label in the max-contrast tone. */\n.cn-stepper--board .cn-stepper__item--upcoming .cn-stepper__dot {\n\tborder: 2px solid var(--color-border-dark);\n\tbackground: transparent;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: 600;\n}\n\n.cn-stepper--board .cn-stepper__item--upcoming .cn-stepper__label {\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["t"],"mappings":";;;;AAsDA;AACC;AACA;AACA;AACA;AACA;;;;;AAKA;;;AAGA;AACA;;AAED,aAAe;AACd,CAAA,IAAI,EAAE,WAAW;;AAEjB,CAAA,UAAU,EAAE,EAAE,OAAO;;AAErB,CAAA,KAAK,EAAE;;AAEN,EAAA,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM;;AAEtC,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG;AAC1C;AACA,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;AAChD;AACA,EAAA,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW;;AAE1C,EAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,OAAO,CAAA,EAAG;;AAEvE,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;EAChF;;AAED,CAAA,KAAK,EAAE,CAAC,MAAM,CAAC;;CAEf,KAAK,CAAC,KAAK,EAAE;AACZ,EAAA,MAAM,EAAE,OAAO,EAAE,SAAU,EAAA,GAAI,OAAO,CAAC,KAAK,EAAA;EAC5C,OAAO,EAAE,OAAO,EAAE,SAAU,EAAA;EAC5B;;AAED,CAAA,OAAO,EAAE;AACR;;AAEC;;;EAGD,MAAM,CAAC,EAAE,EAAE;AACV;AACC;;AAED,GAAA,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,EAAA;GACrB;;AAED,EAAA,UAAU,CAAC,GAAG,EAAE;GACf,OAAO,IAAI,CAAC,iBAAiB,GAAE,GAAI,IAAI,CAAC,YAAW;GACnD;EACD;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnStepper.vue3.js","sources":["../../../../src/components/CnStepper/CnStepper.vue?vue&type=template&id=3cab4d7d&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<ol class=\"cn-stepper cn-wizard-dialog__progress\"\n\t\t:class=\"[{ 'cn-stepper--board': isBoard }, lookClass]\"\n\t\t:aria-label=\"ariaLabel\"\n\t\tdata-testid=\"cn-stepper\">\n\t\t<li v-for=\"(step, idx) in steps\"\n\t\t\t:key=\"step.id\"\n\t\t\tclass=\"cn-stepper__item cn-wizard-dialog__progress-item\"\n\t\t\t:class=\"{\n\t\t\t\t'cn-stepper__item--done': idx < currentIndex,\n\t\t\t\t'cn-stepper__item--current': idx === currentIndex,\n\t\t\t\t'cn-stepper__item--upcoming': idx > currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--active': idx === currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--done': idx < currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--clickable': isJumpable(idx),\n\t\t\t}\"\n\t\t\t:aria-current=\"idx === currentIndex ? 'step' : undefined\"\n\t\t\t:data-step-id=\"step.id\">\n\t\t\t<component :is=\"isJumpable(idx) ? 'button' : 'span'\"\n\t\t\t\tclass=\"cn-stepper__step\"\n\t\t\t\t:type=\"isJumpable(idx) ? 'button' : undefined\"\n\t\t\t\t@click=\"isJumpable(idx) ? onJump(step.id) : null\">\n\t\t\t\t<span class=\"cn-stepper__dot cn-wizard-dialog__progress-dot\" aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"idx < currentIndex\">\n\t\t\t\t\t\t<Check v-if=\"isBoard\"\n\t\t\t\t\t\t\tclass=\"cn-stepper__check cn-wizard-dialog__progress-check\"\n\t\t\t\t\t\t\t:size=\"16\" />\n\t\t\t\t\t\t<span v-else class=\"cn-wizard-dialog__progress-check\">✓</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<span v-else>{{ idx + 1 }}</span>\n\t\t\t\t</span>\n\t\t\t\t<span class=\"cn-stepper__label cn-wizard-dialog__progress-label\">{{ step.label }}</span>\n\t\t\t\t<span v-if=\"idx < currentIndex\" class=\"cn-stepper__sr\">{{ ', ' + completedLabel }}</span>\n\t\t\t</component>\n\t\t\t<span v-if=\"idx < steps.length - 1\"\n\t\t\t\tclass=\"cn-stepper__connector cn-wizard-dialog__progress-connector\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'cn-stepper__connector--done': idx < currentIndex,\n\t\t\t\t\t'cn-wizard-dialog__progress-connector--done': idx < currentIndex,\n\t\t\t\t}\"\n\t\t\t\taria-hidden=\"true\" />\n\t\t</li>\n\t</ol>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport { useLook } from '../../composables/useLook.js'\n\n/**\n * CnStepper (internal) - the step indicator of a wizard: an ordered list, the\n * current step marked with `aria-current=\"step\"`, finished steps as real\n * buttons only when `allowJumpBack` is set.\n *\n * In the board look (`look=\"board\"`, else the injected `cnLook`) it draws 28px\n * circles with the label beside them, a green check on a finished step, a\n * filled circle on the current one, an outlined circle on the rest and a 2px\n * connector coloured by state. In the Nextcloud look it draws the stacked\n * stepper CnWizardDialog always had, with the same class names.\n *\n * @spec openspec/changes/screens-wizard-parity/specs/wizard-dialog/spec.md#requirement-the-board-stepper\n * @event jump Emitted with a finished step's id when its button is pressed.\n *\n * @event jump Emitted with the step id when a finished step button is pressed.\n */\nexport default {\n\tname: 'CnStepper',\n\n\tcomponents: { Check },\n\n\tprops: {\n\t\t/** The steps: `{ id, label }`. */\n\t\tsteps: { type: Array, required: true },\n\t\t/** Index of the current step. */\n\t\tcurrentIndex: { type: Number, default: 0 },\n\t\t/** Let a finished step be pressed to go back to it. */\n\t\tallowJumpBack: { type: Boolean, default: false },\n\t\t/** The look; unset follows the injected `cnLook`. */\n\t\tlook: { type: String, default: undefined },\n\t\t/** Accessible name of the list. */\n\t\tariaLabel: { type: String, default: () => t('nextcloud-vue', 'Steps') },\n\t\t/** Visually hidden text after a finished step's label. */\n\t\tcompletedLabel: { type: String, default: () => t('nextcloud-vue', 'completed') },\n\t},\n\n\temits: ['jump'],\n\n\tsetup(props) {\n\t\tconst { isBoard, lookClass } = useLook(props)\n\t\treturn { isBoard, lookClass }\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Forward a press on a finished step.\n\t\t *\n\t\t * @param {string} id The step id.\n\t\t */\n\t\tonJump(id) {\n\t\t\t/**\n\t\t\t * @event jump Emitted with the step id when a finished step button is pressed.\n\t\t\t */\n\t\t\tthis.$emit('jump', id)\n\t\t},\n\n\t\tisJumpable(idx) {\n\t\t\treturn this.allowJumpBack && idx < this.currentIndex\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* The Nextcloud look: the stacked stepper, unchanged. */\n.cn-stepper {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: center;\n\tgap: 0;\n\tpadding: 8px 0 4px;\n\tmargin: 0 0 20px;\n\tlist-style: none;\n}\n\n.cn-stepper__item {\n\tposition: relative;\n\tflex: 1 1 0;\n\tmin-width: 0;\n\tmax-width: 180px;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\ttext-align: center;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.8125rem;\n}\n\n.cn-stepper__step {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 6px;\n\tmax-width: 100%;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n\tbackground: none;\n\tcolor: inherit;\n\tfont: inherit;\n}\n\nbutton.cn-stepper__step {\n\tcursor: pointer;\n}\n\n.cn-stepper__dot {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 34px;\n\theight: 34px;\n\tborder-radius: 50%;\n\tborder: 2px solid var(--color-border-dark);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\ttransition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n\tz-index: 1;\n}\n\n.cn-wizard-dialog__progress-check {\n\tfont-size: 16px;\n\tline-height: 1;\n}\n\n.cn-stepper__label {\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-stepper__connector {\n\tposition: absolute;\n\ttop: 17px;\n\tleft: calc(50% + 21px);\n\tright: calc(-50% + 21px);\n\theight: 2px;\n\tbackground: var(--color-border-dark);\n}\n\n.cn-stepper__connector--done {\n\tbackground: var(--color-primary-element);\n}\n\n.cn-stepper__item--current .cn-stepper__dot,\n.cn-stepper__item--done .cn-stepper__dot {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text, #fff);\n}\n\n.cn-stepper__item--current .cn-stepper__label {\n\tcolor: var(--color-main-text);\n\tfont-weight: 600;\n}\n\n.cn-stepper__item--done .cn-stepper__label {\n\tcolor: var(--color-main-text);\n}\n\n.cn-stepper__item--done button.cn-stepper__step:hover .cn-stepper__label {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-stepper__sr {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\tmargin: -1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n\twhite-space: nowrap;\n}\n\n/* The board look: one row, 28px circles, the label beside the circle. */\n/* The board leaves 20px between the stepper and the step's body (DqInstellen). */\n.cn-stepper--board {\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: flex-start;\n\tgap: 8px;\n\tpadding: 0;\n\tmargin: 0 0 20px;\n}\n\n.cn-stepper--board .cn-stepper__item {\n\tflex: 0 1 auto;\n\tflex-direction: row;\n\talign-items: center;\n\tgap: 8px;\n\tmax-width: none;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__item:not(:last-child) {\n\tflex: 1 1 auto;\n}\n\n.cn-stepper--board .cn-stepper__step {\n\tflex-direction: row;\n\tgap: 8px;\n}\n\n.cn-stepper--board .cn-stepper__dot {\n\tflex: 0 0 auto;\n\twidth: 28px;\n\theight: 28px;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__label {\n\toverflow: visible;\n\ttext-overflow: clip;\n\twhite-space: nowrap;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__connector {\n\tposition: static;\n\tflex: 1 1 24px;\n\tmin-width: 16px;\n\theight: 2px;\n\tbackground: var(--color-border);\n}\n\n.cn-stepper--board .cn-stepper__connector--done {\n\tbackground: var(--color-success);\n}\n\n/* Done: filled success circle, 16px check, secondary label. */\n.cn-stepper--board .cn-stepper__item--done .cn-stepper__dot {\n\tborder-color: var(--color-success);\n\tbackground: var(--color-success);\n\tcolor: var(--color-success-text, #fff);\n}\n\n.cn-stepper--board .cn-stepper__item--done .cn-stepper__label {\n\tcolor: var(--cn-board-text-soft, var(--color-main-text));\n\tfont-weight: 400;\n}\n\n/* Current: filled primary, number 14/700, label 14/700 in the main text colour. */\n.cn-stepper--board .cn-stepper__item--current .cn-stepper__dot {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text, #fff);\n\tfont-weight: 700;\n}\n\n.cn-stepper--board .cn-stepper__item--current .cn-stepper__label {\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n}\n\n/* Upcoming: 2px outline, number 14/600, label in the max-contrast tone. */\n.cn-stepper--board .cn-stepper__item--upcoming .cn-stepper__dot {\n\tborder: 2px solid var(--color-border-dark);\n\tbackground: transparent;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: 600;\n}\n\n.cn-stepper--board .cn-stepper__item--upcoming .cn-stepper__label {\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_normalizeClass","_openBlock","_createElementBlock","_renderList","_createBlock","_resolveDynamicComponent","_Fragment","_createElementVNode","_toDisplayString"],"mappings":";;;;;AA8BU,EAAA,KAAK,EAAC,gDAAG;AAAA,EAAA,aAAA,EAAA,MAAA;;;;AAKA,EAAA,KAAK,EAAC,kCAAkC;;;AAIjD,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,oDAAoD,GAAA;;;AACxD,EAAA,KAAA,EAAA,gBAAA;;;;;;;AA/BN,IAAA,KAAI,EAACA,cAAA,CAAA,CAAA,uCAAsB,EACjB,CAAA,EAAA,mBAAA,EAAA,MAAA,CAAA,OAAA,IAAA,MAAA,CAAA,SAAA,CAAA,CAAA,CAAA;AACb,IAAA,YAAU,EAAE,MAAS,CAAA,SAAA;AACrB,IAAA,aAAQ,EAAA,YAAA;;AACP,KAAAC,SAAA,CAAA,IAAA,CAAA,EAAAC,kBAAA,SAAwB,EAAA,IAAA,EAAAC,UAAA,CAAA,MAAA,CAAA,KAAI,EAAlB,CAAA,IAAI,EAAE,GAAG,KAAA;2BAAnBD;QACA,GAAG,EAAE,IAAI,CAAC,EAAE;AACZ,QAAA,KAAI,kBAAC,kDAA2C,EAAA;AACT,IAAA,wBAAA,EAAA,GAAI,GAAE,MAAY,CAAA,YAAA;AAAM,IAAA,2BAAA,EAAA,GAAA,KAAA,MAAA,CAAA,YAAA;AAAA,IAAA,4BAAA,EAAA,GAAA,GAAA,MAAA,CAAA,YAAA;AAAA,IAAA,yCAAA,EAAA,GAAA,KAAA,MAAA,CAAA,YAAA;AAAA,IAAA,uCAAA,EAAA,GAAA,GAAA,MAAA,CAAA,YAAA;AAAA,IAAA,4CAAA,EAAA,QAAA,CAAA,UAAA,CAAA,GAAA,CAAA;;AAQ/D,QAAA,cAAY,EAAE,GAAG,KAAI,MAAA,CAAA,YAAa,YAAW,SAAA;QAC7C,cAAY,EAAE,IAAI,CAAC,EAAE;;sBACrBE,WAeW,CAAAC,uBAAA,CAfI,QAAU,CAAA,UAAA,CAAC,GAAG,CAAA,GAAA,QAAA,GAAA,MAAA,CAAA,EAAA;AAC5B,UAAA,KAAI,EAAC,kBAAkB;AACtB,UAAA,IAAG,EAAE,QAAA,CAAA,UAAU,CAAC,GAAG,eAAC,SAAA;iBAChB,EAAA,MAAA,KAAE,mBAAU,CAAC,GAAG,IAAI,QAAM,CAAA,MAAA,CAAC,IAAI,CAAC,EAAE,CAAA,GAAA,IAAA,CAAA;;iCASjC;+BAAA,kBAAA,EAAA;AAPU,cAAA,CAAA,GAAG,GAAG,MAAY,CAAA,YAAA;kDAKvB,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;qBAJD,MAAA,CAAA,OAAA;sCAATF,WAEI,CAAA,gBAAA,EAAA;;AADH,0BAAA,KAAK,EAAC,oDAAwB;AAC7B,0BAAA,IAAE,EAAA,EAAA;;sCACJF,kBAA8D,CAAA,MAAA,EAA9D,UAA8D,EAAR,GAAC,CAAA,CAAA;;AAExD,mBAAAD,SAAA,EAAA,EAAAC,kBAAA,CAAS,oCAAA,GAAA,GAAA,CAAA,CAAA,EAAA,CAAA,YAAA,CAAA;;AAEV,YAAAK,kBAAA,CAAiE,MAAjE,EAAA,UAAiE,EAAAC,eAAA,CAAA,IAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;AACzD,YAAA,CAAA,GAAA,GAAA,MAAA,CAAA,YAAA;8BAARN,kBAAQ,CAAA,MAAA,EAAR,UAAQ,EAAAM,eAAA,CAAA,IAAA,GAAA,MAAA,CAAA,cAAA,CAAA,EAAA,CAAA,YAAA;;;;;SAEG,GAAG,GAAG,MAAK,CAAA,KAAA,CAAC,MAAM,GAAA,CAAA;;;AAC7B,cAAA,KAAC,kBAAA,4DAAA,EAAA;AACmB,KAAA,6BAAA,EAAA,GAAA,GAAA,MAAA,CAAA,YAAA;AAAA,KAAA,4CAAA,EAAA,GAAA,GAAA,MAAA,CAAA,YAAA;;;;;;;;;;;;"}
1
+ {"version":3,"file":"CnStepper.vue3.js","sources":["../../../../src/components/CnStepper/CnStepper.vue?vue&type=template&id=3d784176&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<ol class=\"cn-stepper cn-wizard-dialog__progress\"\n\t\t:class=\"[{ 'cn-stepper--board': isBoard }, lookClass]\"\n\t\t:aria-label=\"ariaLabel\"\n\t\tdata-testid=\"cn-stepper\">\n\t\t<li v-for=\"(step, idx) in steps\"\n\t\t\t:key=\"step.id\"\n\t\t\tclass=\"cn-stepper__item cn-wizard-dialog__progress-item\"\n\t\t\t:class=\"{\n\t\t\t\t'cn-stepper__item--done': idx < currentIndex,\n\t\t\t\t'cn-stepper__item--current': idx === currentIndex,\n\t\t\t\t'cn-stepper__item--upcoming': idx > currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--active': idx === currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--done': idx < currentIndex,\n\t\t\t\t'cn-wizard-dialog__progress-item--clickable': isJumpable(idx),\n\t\t\t}\"\n\t\t\t:aria-current=\"idx === currentIndex ? 'step' : undefined\"\n\t\t\t:data-step-id=\"step.id\">\n\t\t\t<component :is=\"isJumpable(idx) ? 'button' : 'span'\"\n\t\t\t\tclass=\"cn-stepper__step\"\n\t\t\t\t:type=\"isJumpable(idx) ? 'button' : undefined\"\n\t\t\t\t@click=\"isJumpable(idx) ? onJump(step.id) : null\">\n\t\t\t\t<span class=\"cn-stepper__dot cn-wizard-dialog__progress-dot\" aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"idx < currentIndex\">\n\t\t\t\t\t\t<Check v-if=\"isBoard\"\n\t\t\t\t\t\t\tclass=\"cn-stepper__check cn-wizard-dialog__progress-check\"\n\t\t\t\t\t\t\t:size=\"16\" />\n\t\t\t\t\t\t<span v-else class=\"cn-wizard-dialog__progress-check\">✓</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<span v-else>{{ idx + 1 }}</span>\n\t\t\t\t</span>\n\t\t\t\t<span class=\"cn-stepper__label cn-wizard-dialog__progress-label\">{{ step.label }}</span>\n\t\t\t\t<span v-if=\"idx < currentIndex\" class=\"cn-stepper__sr\">{{ ', ' + completedLabel }}</span>\n\t\t\t</component>\n\t\t\t<span v-if=\"idx < steps.length - 1\"\n\t\t\t\tclass=\"cn-stepper__connector cn-wizard-dialog__progress-connector\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'cn-stepper__connector--done': idx < currentIndex,\n\t\t\t\t\t'cn-wizard-dialog__progress-connector--done': idx < currentIndex,\n\t\t\t\t}\"\n\t\t\t\taria-hidden=\"true\" />\n\t\t</li>\n\t</ol>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport { useLook } from '../../composables/useLook.js'\n\n/**\n * CnStepper (internal) - the step indicator of a wizard: an ordered list, the\n * current step marked with `aria-current=\"step\"`, finished steps as real\n * buttons only when `allowJumpBack` is set.\n *\n * In the board look (`look=\"board\"`, else the injected `cnLook`) it draws 28px\n * circles with the label beside them, a green check on a finished step, a\n * filled circle on the current one, an outlined circle on the rest and a 2px\n * connector coloured by state. In the Nextcloud look it draws the stacked\n * stepper CnWizardDialog always had, with the same class names.\n *\n * @spec openspec/changes/screens-wizard-parity/specs/wizard-dialog/spec.md#requirement-the-board-stepper\n * @event jump Emitted with a finished step's id when its button is pressed.\n *\n * @event jump Emitted with the step id when a finished step button is pressed.\n */\nexport default {\n\tname: 'CnStepper',\n\n\tcomponents: { Check },\n\n\tprops: {\n\t\t/** The steps: `{ id, label }`. */\n\t\tsteps: { type: Array, required: true },\n\t\t/** Index of the current step. */\n\t\tcurrentIndex: { type: Number, default: 0 },\n\t\t/** Let a finished step be pressed to go back to it. */\n\t\tallowJumpBack: { type: Boolean, default: false },\n\t\t/** The look; unset follows the injected `cnLook`. */\n\t\tlook: { type: String, default: undefined },\n\t\t/** Accessible name of the list. */\n\t\tariaLabel: { type: String, default: () => t('nextcloud-vue', 'Steps') },\n\t\t/** Visually hidden text after a finished step's label. */\n\t\tcompletedLabel: { type: String, default: () => t('nextcloud-vue', 'completed') },\n\t},\n\n\temits: ['jump'],\n\n\tsetup(props) {\n\t\tconst { isBoard, lookClass } = useLook(props)\n\t\treturn { isBoard, lookClass }\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Forward a press on a finished step.\n\t\t *\n\t\t * @param {string} id The step id.\n\t\t */\n\t\tonJump(id) {\n\t\t\t/**\n\t\t\t * @event jump Emitted with the step id when a finished step button is pressed.\n\t\t\t */\n\t\t\tthis.$emit('jump', id)\n\t\t},\n\n\t\tisJumpable(idx) {\n\t\t\treturn this.allowJumpBack && idx < this.currentIndex\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* The Nextcloud look: the stacked stepper, unchanged. */\n.cn-stepper {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: center;\n\tgap: 0;\n\tpadding: 8px 0 4px;\n\tmargin: 0 0 20px;\n\tlist-style: none;\n}\n\n.cn-stepper__item {\n\tposition: relative;\n\tflex: 1 1 0;\n\tmin-width: 0;\n\tmax-width: 180px;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\ttext-align: center;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.8125rem;\n}\n\n.cn-stepper__step {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 6px;\n\tmax-width: 100%;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n\tbackground: none;\n\tcolor: inherit;\n\tfont: inherit;\n}\n\n/* Nextcloud's server.css gives every plain button a 3px margin and the\n clickable-area height (`button:not(.button-vue, …):not(…)`, 0,2,1), which\n made a done step 40px tall around its 28px circle. Two classes outrank it. */\n.cn-stepper button.cn-stepper__step {\n\tmargin: 0;\n\tmin-height: 0;\n}\n\nbutton.cn-stepper__step {\n\tcursor: pointer;\n}\n\n.cn-stepper__dot {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 34px;\n\theight: 34px;\n\tborder-radius: 50%;\n\tborder: 2px solid var(--color-border-dark);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\ttransition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n\tz-index: 1;\n}\n\n.cn-wizard-dialog__progress-check {\n\tfont-size: 16px;\n\tline-height: 1;\n}\n\n.cn-stepper__label {\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-stepper__connector {\n\tposition: absolute;\n\ttop: 17px;\n\tleft: calc(50% + 21px);\n\tright: calc(-50% + 21px);\n\theight: 2px;\n\tbackground: var(--color-border-dark);\n}\n\n.cn-stepper__connector--done {\n\tbackground: var(--color-primary-element);\n}\n\n.cn-stepper__item--current .cn-stepper__dot,\n.cn-stepper__item--done .cn-stepper__dot {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text, #fff);\n}\n\n.cn-stepper__item--current .cn-stepper__label {\n\tcolor: var(--color-main-text);\n\tfont-weight: 600;\n}\n\n.cn-stepper__item--done .cn-stepper__label {\n\tcolor: var(--color-main-text);\n}\n\n.cn-stepper__item--done button.cn-stepper__step:hover .cn-stepper__label {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-stepper__sr {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\tmargin: -1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n\twhite-space: nowrap;\n}\n\n/* The board look: one row, 28px circles, the label beside the circle. */\n/* The board leaves 16px between the stepper and the step's body (DqInstellen). */\n.cn-stepper--board {\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: flex-start;\n\tgap: 8px;\n\tpadding: 0;\n\tmargin: 0 0 16px;\n}\n\n.cn-stepper--board .cn-stepper__item {\n\tflex: 0 1 auto;\n\tflex-direction: row;\n\talign-items: center;\n\tgap: 8px;\n\tmax-width: none;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__item:not(:last-child) {\n\tflex: 1 1 auto;\n}\n\n.cn-stepper--board .cn-stepper__step {\n\tflex-direction: row;\n\tgap: 8px;\n}\n\n.cn-stepper--board .cn-stepper__dot {\n\tflex: 0 0 auto;\n\twidth: 28px;\n\theight: 28px;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__label {\n\toverflow: visible;\n\ttext-overflow: clip;\n\twhite-space: nowrap;\n\tfont-size: 14px;\n}\n\n.cn-stepper--board .cn-stepper__connector {\n\tposition: static;\n\tflex: 1 1 24px;\n\tmin-width: 16px;\n\theight: 2px;\n\tbackground: var(--color-border);\n}\n\n.cn-stepper--board .cn-stepper__connector--done {\n\tbackground: var(--color-success);\n}\n\n/* Done: filled success circle, 16px check, secondary label. */\n.cn-stepper--board .cn-stepper__item--done .cn-stepper__dot {\n\tborder-color: var(--color-success);\n\tbackground: var(--color-success);\n\tcolor: var(--color-success-text, #fff);\n}\n\n.cn-stepper--board .cn-stepper__item--done .cn-stepper__label {\n\tcolor: var(--cn-board-text-soft, var(--color-main-text));\n\tfont-weight: 400;\n}\n\n/* Current: filled primary, number 14/700, label 14/700 in the main text colour. */\n.cn-stepper--board .cn-stepper__item--current .cn-stepper__dot {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text, #fff);\n\tfont-weight: 700;\n}\n\n.cn-stepper--board .cn-stepper__item--current .cn-stepper__label {\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n}\n\n/* Upcoming: 2px outline, number 14/600, label in the max-contrast tone. */\n.cn-stepper--board .cn-stepper__item--upcoming .cn-stepper__dot {\n\tborder: 2px solid var(--color-border-dark);\n\tbackground: transparent;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: 600;\n}\n\n.cn-stepper--board .cn-stepper__item--upcoming .cn-stepper__label {\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_normalizeClass","_openBlock","_createElementBlock","_renderList","_createBlock","_resolveDynamicComponent","_Fragment","_createElementVNode","_toDisplayString"],"mappings":";;;;;AA8BU,EAAA,KAAK,EAAC,gDAAG;AAAA,EAAA,aAAA,EAAA,MAAA;;;;AAKA,EAAA,KAAK,EAAC,kCAAkC;;;AAIjD,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,oDAAoD,GAAA;;;AACxD,EAAA,KAAA,EAAA,gBAAA;;;;;;;AA/BN,IAAA,KAAI,EAACA,cAAA,CAAA,CAAA,uCAAsB,EACjB,CAAA,EAAA,mBAAA,EAAA,MAAA,CAAA,OAAA,IAAA,MAAA,CAAA,SAAA,CAAA,CAAA,CAAA;AACb,IAAA,YAAU,EAAE,MAAS,CAAA,SAAA;AACrB,IAAA,aAAQ,EAAA,YAAA;;AACP,KAAAC,SAAA,CAAA,IAAA,CAAA,EAAAC,kBAAA,SAAwB,EAAA,IAAA,EAAAC,UAAA,CAAA,MAAA,CAAA,KAAI,EAAlB,CAAA,IAAI,EAAE,GAAG,KAAA;2BAAnBD;QACA,GAAG,EAAE,IAAI,CAAC,EAAE;AACZ,QAAA,KAAI,kBAAC,kDAA2C,EAAA;AACT,IAAA,wBAAA,EAAA,GAAI,GAAE,MAAY,CAAA,YAAA;AAAM,IAAA,2BAAA,EAAA,GAAA,KAAA,MAAA,CAAA,YAAA;AAAA,IAAA,4BAAA,EAAA,GAAA,GAAA,MAAA,CAAA,YAAA;AAAA,IAAA,yCAAA,EAAA,GAAA,KAAA,MAAA,CAAA,YAAA;AAAA,IAAA,uCAAA,EAAA,GAAA,GAAA,MAAA,CAAA,YAAA;AAAA,IAAA,4CAAA,EAAA,QAAA,CAAA,UAAA,CAAA,GAAA,CAAA;;AAQ/D,QAAA,cAAY,EAAE,GAAG,KAAI,MAAA,CAAA,YAAa,YAAW,SAAA;QAC7C,cAAY,EAAE,IAAI,CAAC,EAAE;;sBACrBE,WAeW,CAAAC,uBAAA,CAfI,QAAU,CAAA,UAAA,CAAC,GAAG,CAAA,GAAA,QAAA,GAAA,MAAA,CAAA,EAAA;AAC5B,UAAA,KAAI,EAAC,kBAAkB;AACtB,UAAA,IAAG,EAAE,QAAA,CAAA,UAAU,CAAC,GAAG,eAAC,SAAA;iBAChB,EAAA,MAAA,KAAE,mBAAU,CAAC,GAAG,IAAI,QAAM,CAAA,MAAA,CAAC,IAAI,CAAC,EAAE,CAAA,GAAA,IAAA,CAAA;;iCASjC;+BAAA,kBAAA,EAAA;AAPU,cAAA,CAAA,GAAG,GAAG,MAAY,CAAA,YAAA;kDAKvB,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;qBAJD,MAAA,CAAA,OAAA;sCAATF,WAEI,CAAA,gBAAA,EAAA;;AADH,0BAAA,KAAK,EAAC,oDAAwB;AAC7B,0BAAA,IAAE,EAAA,EAAA;;sCACJF,kBAA8D,CAAA,MAAA,EAA9D,UAA8D,EAAR,GAAC,CAAA,CAAA;;AAExD,mBAAAD,SAAA,EAAA,EAAAC,kBAAA,CAAS,oCAAA,GAAA,GAAA,CAAA,CAAA,EAAA,CAAA,YAAA,CAAA;;AAEV,YAAAK,kBAAA,CAAiE,MAAjE,EAAA,UAAiE,EAAAC,eAAA,CAAA,IAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;AACzD,YAAA,CAAA,GAAA,GAAA,MAAA,CAAA,YAAA;8BAARN,kBAAQ,CAAA,MAAA,EAAR,UAAQ,EAAAM,eAAA,CAAA,IAAA,GAAA,MAAA,CAAA,cAAA,CAAA,EAAA,CAAA,YAAA;;;;;SAEG,GAAG,GAAG,MAAK,CAAA,KAAA,CAAC,MAAM,GAAA,CAAA;;;AAC7B,cAAA,KAAC,kBAAA,4DAAA,EAAA;AACmB,KAAA,6BAAA,EAAA,GAAA,GAAA,MAAA,CAAA,YAAA;AAAA,KAAA,4CAAA,EAAA,GAAA,GAAA,MAAA,CAAA,YAAA;;;;;;;;;;;;"}
@@ -2,7 +2,7 @@ import script from './CnAccessPurposeDialog.vue2.js';
2
2
  import { render } from './CnAccessPurposeDialog.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-7fa35363";
5
+ script.__scopeId = "data-v-64fad2b3";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -33,8 +33,10 @@ var script = {
33
33
 
34
34
  /**
35
35
  * The purposes offered, already translated. "Other" is added at the end.
36
+ * A `hint` is a line under the option that says what choosing it does
37
+ * besides recording it.
36
38
  *
37
- * @type {Array<{value: string, label: string}>}
39
+ * @type {Array<{value: string, label: string, hint?: string}>}
38
40
  */
39
41
  options: {
40
42
  type: Array,
@@ -1 +1 @@
1
- {"version":3,"file":"CnAccessPurposeDialog.vue2.js","sources":["../../../src/dialogs/CnAccessPurposeDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"title || t('nextcloud-vue', 'Why are you opening this?')\"\n\t\tdefaultWidth=\"confirm\"\n\t\tsize=\"small\"\n\t\t:noClose=\"loading\"\n\t\tdata-testid=\"cn-access-purpose-dialog\"\n\t\t@closing=\"$emit('cancel')\">\n\t\t<p class=\"cn-access-purpose__sentence\">\n\t\t\t{{ description || t('nextcloud-vue', 'This record holds special categories of personal data. Your purpose is recorded with your name and the time.') }}\n\t\t</p>\n\t\t<fieldset class=\"cn-access-purpose__choices\">\n\t\t\t<legend class=\"cn-access-purpose__legend\">\n\t\t\t\t{{ t('nextcloud-vue', 'Purpose') }}\n\t\t\t</legend>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\tv-for=\"option in choices\"\n\t\t\t\t:key=\"option.value\"\n\t\t\t\tv-model=\"purpose\"\n\t\t\t\ttype=\"radio\"\n\t\t\t\tname=\"cn-access-purpose\"\n\t\t\t\t:value=\"option.value\"\n\t\t\t\t:disabled=\"loading\"\n\t\t\t\t:data-testid=\"`cn-access-purpose-option-${option.value}`\">\n\t\t\t\t{{ option.label }}\n\t\t\t</NcCheckboxRadioSwitch>\n\t\t</fieldset>\n\t\t<NcTextArea\n\t\t\tv-if=\"purpose === OTHER\"\n\t\t\tv-model=\"note\"\n\t\t\t:label=\"t('nextcloud-vue', 'Describe your purpose')\"\n\t\t\t:maxlength=\"500\"\n\t\t\t:disabled=\"loading\"\n\t\t\tdata-testid=\"cn-access-purpose-note\" />\n\t\t<NcNoteCard v-if=\"error\" type=\"error\" data-testid=\"cn-access-purpose-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"loading\" data-testid=\"cn-access-purpose-cancel\" @click=\"$emit('cancel')\">\n\t\t\t\t{{ t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!complete || loading\"\n\t\t\t\tdata-testid=\"cn-access-purpose-submit\"\n\t\t\t\t@click=\"submit\">\n\t\t\t\t<template v-if=\"loading\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" :name=\"t('nextcloud-vue', 'Loading …')\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Open') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea } from '@nextcloud/vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\n\n/** The value of the \"Other\" choice, which asks for a written purpose. */\nconst OTHER = 'other'\n\n/**\n * CnAccessPurposeDialog — asks why the reader opens a record before the page\n * shows it (detail page `accessPurpose`). A short list of purposes plus\n * \"Other\", which needs a written purpose. Emits the choice; the page records\n * it and decides whether to open.\n *\n * @spec openspec/changes/detail-access-purpose/specs/detail-access-purpose/spec.md#requirement-a-detail-page-can-ask-for-a-purpose-before-it-opens\n */\nexport default {\n\tname: 'CnAccessPurposeDialog',\n\n\tcomponents: { CnDialog, NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea },\n\n\tprops: {\n\t\t/** The dialog's title; a default question when empty. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The sentence under the title; a default when empty. */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The purposes offered, already translated. \"Other\" is added at the end.\n\t\t *\n\t\t * @type {Array<{value: string, label: string}>}\n\t\t */\n\t\toptions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether the purpose is being recorded. */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Why the last attempt was refused, shown in the dialog. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: [\n\t\t/**\n\t\t * The reader chose a purpose.\n\t\t *\n\t\t * @type {{purpose: string, note: string}}\n\t\t */\n\t\t'submit',\n\t\t/** The reader closed the dialog without a purpose. */\n\t\t'cancel',\n\t],\n\n\tdata() {\n\t\treturn { purpose: '', note: '', OTHER }\n\t},\n\n\tcomputed: {\n\t\t/** @return {Array<{value: string, label: string}>} The offered purposes and \"Other\". */\n\t\tchoices() {\n\t\t\tconst own = (Array.isArray(this.options) ? this.options : [])\n\t\t\t\t.filter((option) => option && typeof option.value === 'string' && option.value !== '' && option.value !== OTHER)\n\t\t\treturn [...own, { value: OTHER, label: t('nextcloud-vue', 'Other') }]\n\t\t},\n\n\t\t/** @return {boolean} Whether a purpose is chosen and, for \"Other\", written. */\n\t\tcomplete() {\n\t\t\tif (this.purpose === '') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn this.purpose !== OTHER || this.note.trim() !== ''\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Emit the chosen purpose; the written note only goes with \"Other\".\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tsubmit() {\n\t\t\tif (!this.complete) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('submit', { purpose: this.purpose, note: this.purpose === OTHER ? this.note.trim() : '' })\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-access-purpose__sentence {\n\tmargin: 0 0 12px;\n}\n\n.cn-access-purpose__choices {\n\tmargin: 0 0 12px;\n\tpadding: 0;\n\tborder: 0;\n}\n\n.cn-access-purpose__legend {\n\tmargin-bottom: 4px;\n\tfont-weight: 600;\n}\n</style>\n"],"names":["CnDialog","t"],"mappings":";;;;AAiEA;AACA,MAAM,KAAI,GAAI,QAAM;;AAEpB;AACC;;AAEA;;AAEA;AACA;;AAED,aAAe;CACd,IAAI,EAAE,uBAAuB;;AAE7B,CAAA,UAAU,EAAE,YAAEA,UAAQ,EAAE,QAAQ,EAAE,qBAAqB,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY;;AAEhG,CAAA,KAAK,EAAE;;AAEN,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;;EAGD,WAAW,EAAE;GACZ,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;AAEC;AACA;;AAED,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,KAAK;AACX,GAAA,OAAO,EAAE,MAAM,EAAE;GACjB;;AAED;AACA,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;;AAGD,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;EACD;;AAED,CAAA,KAAK,EAAE;AACN;;AAEC;AACA;;AAED,EAAA,QAAQ;AACR;AACA,EAAA,QAAQ;EACR;;AAED,CAAA,IAAI,GAAG;AACN,EAAA,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAM,EAAA;EACtC;;AAED,CAAA,QAAQ,EAAE;AACT;AACA,EAAA,OAAO,GAAG;GACT,MAAM,GAAE,GAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAE,GAAE,IAAI,CAAC,OAAM,GAAI,EAAE;KAC1D,MAAM,CAAC,CAAC,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,KAAI,KAAM,YAAY,MAAM,CAAC,KAAI,KAAM,EAAG,IAAG,MAAM,CAAC,UAAU,KAAK,EAAA;GAChH,OAAO,CAAC,GAAG,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAEC,SAAC,CAAC,eAAe,EAAE,OAAO,CAAA,EAAG,CAAA;GACpE;;AAED;EACA,QAAQ,GAAG;AACV,GAAA,IAAI,IAAI,CAAC,OAAQ,KAAI,EAAE,EAAE;IACxB,OAAO,KAAI;AACZ,IAAA;GACA,OAAO,IAAI,CAAC,YAAY,KAAM,IAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAG,KAAI,EAAC;GACvD;EACD;;AAED,CAAA,OAAO,EAAE;KACRA,SAAC;;AAED;;AAEC;;;AAGD,EAAA,MAAM,GAAG;AACR,GAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;IACnB,MAAK;AACN,IAAA;AACA,GAAA,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,OAAQ,KAAI,KAAM,GAAE,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,EAAA;GACpG;EACD;AACF;;;;"}
1
+ {"version":3,"file":"CnAccessPurposeDialog.vue2.js","sources":["../../../src/dialogs/CnAccessPurposeDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"title || t('nextcloud-vue', 'Why are you opening this?')\"\n\t\tdefaultWidth=\"confirm\"\n\t\tsize=\"small\"\n\t\t:noClose=\"loading\"\n\t\tdata-testid=\"cn-access-purpose-dialog\"\n\t\t@closing=\"$emit('cancel')\">\n\t\t<p class=\"cn-access-purpose__sentence\">\n\t\t\t{{ description || t('nextcloud-vue', 'This record holds special categories of personal data. Your purpose is recorded with your name and the time.') }}\n\t\t</p>\n\t\t<fieldset class=\"cn-access-purpose__choices\">\n\t\t\t<legend class=\"cn-access-purpose__legend\">\n\t\t\t\t{{ t('nextcloud-vue', 'Purpose') }}\n\t\t\t</legend>\n\t\t\t<template v-for=\"option in choices\" :key=\"option.value\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\tv-model=\"purpose\"\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\tname=\"cn-access-purpose\"\n\t\t\t\t\t:value=\"option.value\"\n\t\t\t\t\t:disabled=\"loading\"\n\t\t\t\t\t:data-testid=\"`cn-access-purpose-option-${option.value}`\">\n\t\t\t\t\t{{ option.label }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<!-- What choosing this purpose does besides recording it (\"you become this case's handler\"). -->\n\t\t\t\t<p v-if=\"option.hint\"\n\t\t\t\t\tclass=\"cn-access-purpose__hint\"\n\t\t\t\t\t:data-testid=\"`cn-access-purpose-hint-${option.value}`\">\n\t\t\t\t\t{{ option.hint }}\n\t\t\t\t</p>\n\t\t\t</template>\n\t\t</fieldset>\n\t\t<NcTextArea\n\t\t\tv-if=\"purpose === OTHER\"\n\t\t\tv-model=\"note\"\n\t\t\t:label=\"t('nextcloud-vue', 'Describe your purpose')\"\n\t\t\t:maxlength=\"500\"\n\t\t\t:disabled=\"loading\"\n\t\t\tdata-testid=\"cn-access-purpose-note\" />\n\t\t<NcNoteCard v-if=\"error\" type=\"error\" data-testid=\"cn-access-purpose-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"loading\" data-testid=\"cn-access-purpose-cancel\" @click=\"$emit('cancel')\">\n\t\t\t\t{{ t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!complete || loading\"\n\t\t\t\tdata-testid=\"cn-access-purpose-submit\"\n\t\t\t\t@click=\"submit\">\n\t\t\t\t<template v-if=\"loading\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" :name=\"t('nextcloud-vue', 'Loading …')\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Open') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea } from '@nextcloud/vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\n\n/** The value of the \"Other\" choice, which asks for a written purpose. */\nconst OTHER = 'other'\n\n/**\n * CnAccessPurposeDialog — asks why the reader opens a record before the page\n * shows it (detail page `accessPurpose`). A short list of purposes plus\n * \"Other\", which needs a written purpose. Emits the choice; the page records\n * it and decides whether to open.\n *\n * @spec openspec/changes/detail-access-purpose/specs/detail-access-purpose/spec.md#requirement-a-detail-page-can-ask-for-a-purpose-before-it-opens\n */\nexport default {\n\tname: 'CnAccessPurposeDialog',\n\n\tcomponents: { CnDialog, NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea },\n\n\tprops: {\n\t\t/** The dialog's title; a default question when empty. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The sentence under the title; a default when empty. */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The purposes offered, already translated. \"Other\" is added at the end.\n\t\t * A `hint` is a line under the option that says what choosing it does\n\t\t * besides recording it.\n\t\t *\n\t\t * @type {Array<{value: string, label: string, hint?: string}>}\n\t\t */\n\t\toptions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether the purpose is being recorded. */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Why the last attempt was refused, shown in the dialog. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: [\n\t\t/**\n\t\t * The reader chose a purpose.\n\t\t *\n\t\t * @type {{purpose: string, note: string}}\n\t\t */\n\t\t'submit',\n\t\t/** The reader closed the dialog without a purpose. */\n\t\t'cancel',\n\t],\n\n\tdata() {\n\t\treturn { purpose: '', note: '', OTHER }\n\t},\n\n\tcomputed: {\n\t\t/** @return {Array<{value: string, label: string}>} The offered purposes and \"Other\". */\n\t\tchoices() {\n\t\t\tconst own = (Array.isArray(this.options) ? this.options : [])\n\t\t\t\t.filter((option) => option && typeof option.value === 'string' && option.value !== '' && option.value !== OTHER)\n\t\t\treturn [...own, { value: OTHER, label: t('nextcloud-vue', 'Other') }]\n\t\t},\n\n\t\t/** @return {boolean} Whether a purpose is chosen and, for \"Other\", written. */\n\t\tcomplete() {\n\t\t\tif (this.purpose === '') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn this.purpose !== OTHER || this.note.trim() !== ''\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Emit the chosen purpose; the written note only goes with \"Other\".\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tsubmit() {\n\t\t\tif (!this.complete) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('submit', { purpose: this.purpose, note: this.purpose === OTHER ? this.note.trim() : '' })\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-access-purpose__sentence {\n\tmargin: 0 0 12px;\n}\n\n.cn-access-purpose__choices {\n\tmargin: 0 0 12px;\n\tpadding: 0;\n\tborder: 0;\n}\n\n.cn-access-purpose__hint {\n\tmargin: 0 0 6px;\n\tpadding-inline-start: 36px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-access-purpose__legend {\n\tmargin-bottom: 4px;\n\tfont-weight: 600;\n}\n</style>\n"],"names":["CnDialog","t"],"mappings":";;;;AAuEA;AACA,MAAM,KAAI,GAAI,QAAM;;AAEpB;AACC;;AAEA;;AAEA;AACA;;AAED,aAAe;CACd,IAAI,EAAE,uBAAuB;;AAE7B,CAAA,UAAU,EAAE,YAAEA,UAAQ,EAAE,QAAQ,EAAE,qBAAqB,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY;;AAEhG,CAAA,KAAK,EAAE;;AAEN,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;;EAGD,WAAW,EAAE;GACZ,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;AAGC;AACA;;;AAGD,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,KAAK;AACX,GAAA,OAAO,EAAE,MAAM,EAAE;GACjB;;AAED;AACA,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;;AAGD,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;EACD;;AAED,CAAA,KAAK,EAAE;AACN;;AAEC;AACA;;AAED,EAAA,QAAQ;AACR;AACA,EAAA,QAAQ;EACR;;AAED,CAAA,IAAI,GAAG;AACN,EAAA,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAM,EAAA;EACtC;;AAED,CAAA,QAAQ,EAAE;AACT;AACA,EAAA,OAAO,GAAG;GACT,MAAM,GAAE,GAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAE,GAAE,IAAI,CAAC,OAAM,GAAI,EAAE;KAC1D,MAAM,CAAC,CAAC,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,KAAI,KAAM,YAAY,MAAM,CAAC,KAAI,KAAM,EAAG,IAAG,MAAM,CAAC,UAAU,KAAK,EAAA;GAChH,OAAO,CAAC,GAAG,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAEC,SAAC,CAAC,eAAe,EAAE,OAAO,CAAA,EAAG,CAAA;GACpE;;AAED;EACA,QAAQ,GAAG;AACV,GAAA,IAAI,IAAI,CAAC,OAAQ,KAAI,EAAE,EAAE;IACxB,OAAO,KAAI;AACZ,IAAA;GACA,OAAO,IAAI,CAAC,YAAY,KAAM,IAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAG,KAAI,EAAC;GACvD;EACD;;AAED,CAAA,OAAO,EAAE;KACRA,SAAC;;AAED;;AAEC;;;AAGD,EAAA,MAAM,GAAG;AACR,GAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;IACnB,MAAK;AACN,IAAA;AACA,GAAA,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,OAAQ,KAAI,KAAM,GAAE,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,EAAA;GACpG;EACD;AACF;;;;"}
@@ -3,6 +3,7 @@ import { resolveComponent, openBlock, createBlock, withCtx, createVNode, createT
3
3
  const _hoisted_1 = { class: "cn-access-purpose__sentence" };
4
4
  const _hoisted_2 = { class: "cn-access-purpose__choices" };
5
5
  const _hoisted_3 = { class: "cn-access-purpose__legend" };
6
+ const _hoisted_4 = ["data-testid"];
6
7
 
7
8
  function render(_ctx, _cache, $props, $setup, $data, $options) {
8
9
  const _component_NcCheckboxRadioSwitch = resolveComponent("NcCheckboxRadioSwitch");
@@ -61,21 +62,31 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
61
62
  createElementVNode("fieldset", _hoisted_2, [
62
63
  createElementVNode("legend", _hoisted_3, toDisplayString($options.t('nextcloud-vue', 'Purpose')), 1 /* TEXT */),
63
64
  (openBlock(true), createElementBlock(Fragment, null, renderList($options.choices, (option) => {
64
- return (openBlock(), createBlock(_component_NcCheckboxRadioSwitch, {
65
- key: option.value,
66
- modelValue: $data.purpose,
67
- "onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (($data.purpose) = $event)),
68
- type: "radio",
69
- name: "cn-access-purpose",
70
- value: option.value,
71
- disabled: $props.loading,
72
- "data-testid": `cn-access-purpose-option-${option.value}`
73
- }, {
74
- default: withCtx(() => [
75
- createTextVNode(toDisplayString(option.label), 1 /* TEXT */)
76
- ]),
77
- _: 2 /* DYNAMIC */
78
- }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "value", "disabled", "data-testid"]))
65
+ return (openBlock(), createElementBlock(Fragment, {
66
+ key: option.value
67
+ }, [
68
+ createVNode(_component_NcCheckboxRadioSwitch, {
69
+ modelValue: $data.purpose,
70
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (($data.purpose) = $event)),
71
+ type: "radio",
72
+ name: "cn-access-purpose",
73
+ value: option.value,
74
+ disabled: $props.loading,
75
+ "data-testid": `cn-access-purpose-option-${option.value}`
76
+ }, {
77
+ default: withCtx(() => [
78
+ createTextVNode(toDisplayString(option.label), 1 /* TEXT */)
79
+ ]),
80
+ _: 2 /* DYNAMIC */
81
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "value", "disabled", "data-testid"]),
82
+ (option.hint)
83
+ ? (openBlock(), createElementBlock("p", {
84
+ key: 0,
85
+ class: "cn-access-purpose__hint",
86
+ "data-testid": `cn-access-purpose-hint-${option.value}`
87
+ }, toDisplayString(option.hint), 9 /* TEXT, PROPS */, _hoisted_4))
88
+ : createCommentVNode("v-if", true)
89
+ ], 64 /* STABLE_FRAGMENT */))
79
90
  }), 128 /* KEYED_FRAGMENT */))
80
91
  ]),
81
92
  ($data.purpose === $data.OTHER)
@@ -1 +1 @@
1
- {"version":3,"file":"CnAccessPurposeDialog.vue3.js","sources":["../../../src/dialogs/CnAccessPurposeDialog.vue?vue&type=template&id=7fa35363&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"title || t('nextcloud-vue', 'Why are you opening this?')\"\n\t\tdefaultWidth=\"confirm\"\n\t\tsize=\"small\"\n\t\t:noClose=\"loading\"\n\t\tdata-testid=\"cn-access-purpose-dialog\"\n\t\t@closing=\"$emit('cancel')\">\n\t\t<p class=\"cn-access-purpose__sentence\">\n\t\t\t{{ description || t('nextcloud-vue', 'This record holds special categories of personal data. Your purpose is recorded with your name and the time.') }}\n\t\t</p>\n\t\t<fieldset class=\"cn-access-purpose__choices\">\n\t\t\t<legend class=\"cn-access-purpose__legend\">\n\t\t\t\t{{ t('nextcloud-vue', 'Purpose') }}\n\t\t\t</legend>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\tv-for=\"option in choices\"\n\t\t\t\t:key=\"option.value\"\n\t\t\t\tv-model=\"purpose\"\n\t\t\t\ttype=\"radio\"\n\t\t\t\tname=\"cn-access-purpose\"\n\t\t\t\t:value=\"option.value\"\n\t\t\t\t:disabled=\"loading\"\n\t\t\t\t:data-testid=\"`cn-access-purpose-option-${option.value}`\">\n\t\t\t\t{{ option.label }}\n\t\t\t</NcCheckboxRadioSwitch>\n\t\t</fieldset>\n\t\t<NcTextArea\n\t\t\tv-if=\"purpose === OTHER\"\n\t\t\tv-model=\"note\"\n\t\t\t:label=\"t('nextcloud-vue', 'Describe your purpose')\"\n\t\t\t:maxlength=\"500\"\n\t\t\t:disabled=\"loading\"\n\t\t\tdata-testid=\"cn-access-purpose-note\" />\n\t\t<NcNoteCard v-if=\"error\" type=\"error\" data-testid=\"cn-access-purpose-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"loading\" data-testid=\"cn-access-purpose-cancel\" @click=\"$emit('cancel')\">\n\t\t\t\t{{ t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!complete || loading\"\n\t\t\t\tdata-testid=\"cn-access-purpose-submit\"\n\t\t\t\t@click=\"submit\">\n\t\t\t\t<template v-if=\"loading\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" :name=\"t('nextcloud-vue', 'Loading …')\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Open') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea } from '@nextcloud/vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\n\n/** The value of the \"Other\" choice, which asks for a written purpose. */\nconst OTHER = 'other'\n\n/**\n * CnAccessPurposeDialog — asks why the reader opens a record before the page\n * shows it (detail page `accessPurpose`). A short list of purposes plus\n * \"Other\", which needs a written purpose. Emits the choice; the page records\n * it and decides whether to open.\n *\n * @spec openspec/changes/detail-access-purpose/specs/detail-access-purpose/spec.md#requirement-a-detail-page-can-ask-for-a-purpose-before-it-opens\n */\nexport default {\n\tname: 'CnAccessPurposeDialog',\n\n\tcomponents: { CnDialog, NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea },\n\n\tprops: {\n\t\t/** The dialog's title; a default question when empty. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The sentence under the title; a default when empty. */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The purposes offered, already translated. \"Other\" is added at the end.\n\t\t *\n\t\t * @type {Array<{value: string, label: string}>}\n\t\t */\n\t\toptions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether the purpose is being recorded. */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Why the last attempt was refused, shown in the dialog. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: [\n\t\t/**\n\t\t * The reader chose a purpose.\n\t\t *\n\t\t * @type {{purpose: string, note: string}}\n\t\t */\n\t\t'submit',\n\t\t/** The reader closed the dialog without a purpose. */\n\t\t'cancel',\n\t],\n\n\tdata() {\n\t\treturn { purpose: '', note: '', OTHER }\n\t},\n\n\tcomputed: {\n\t\t/** @return {Array<{value: string, label: string}>} The offered purposes and \"Other\". */\n\t\tchoices() {\n\t\t\tconst own = (Array.isArray(this.options) ? this.options : [])\n\t\t\t\t.filter((option) => option && typeof option.value === 'string' && option.value !== '' && option.value !== OTHER)\n\t\t\treturn [...own, { value: OTHER, label: t('nextcloud-vue', 'Other') }]\n\t\t},\n\n\t\t/** @return {boolean} Whether a purpose is chosen and, for \"Other\", written. */\n\t\tcomplete() {\n\t\t\tif (this.purpose === '') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn this.purpose !== OTHER || this.note.trim() !== ''\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Emit the chosen purpose; the written note only goes with \"Other\".\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tsubmit() {\n\t\t\tif (!this.complete) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('submit', { purpose: this.purpose, note: this.purpose === OTHER ? this.note.trim() : '' })\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-access-purpose__sentence {\n\tmargin: 0 0 12px;\n}\n\n.cn-access-purpose__choices {\n\tmargin: 0 0 12px;\n\tpadding: 0;\n\tborder: 0;\n}\n\n.cn-access-purpose__legend {\n\tmargin-bottom: 4px;\n\tfont-weight: 600;\n}\n</style>\n"],"names":["_createBlock","_createVNode","_createTextVNode","_createElementVNode","_toDisplayString","_Fragment","_renderList"],"mappings":"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"}
1
+ {"version":3,"file":"CnAccessPurposeDialog.vue3.js","sources":["../../../src/dialogs/CnAccessPurposeDialog.vue?vue&type=template&id=64fad2b3&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"title || t('nextcloud-vue', 'Why are you opening this?')\"\n\t\tdefaultWidth=\"confirm\"\n\t\tsize=\"small\"\n\t\t:noClose=\"loading\"\n\t\tdata-testid=\"cn-access-purpose-dialog\"\n\t\t@closing=\"$emit('cancel')\">\n\t\t<p class=\"cn-access-purpose__sentence\">\n\t\t\t{{ description || t('nextcloud-vue', 'This record holds special categories of personal data. Your purpose is recorded with your name and the time.') }}\n\t\t</p>\n\t\t<fieldset class=\"cn-access-purpose__choices\">\n\t\t\t<legend class=\"cn-access-purpose__legend\">\n\t\t\t\t{{ t('nextcloud-vue', 'Purpose') }}\n\t\t\t</legend>\n\t\t\t<template v-for=\"option in choices\" :key=\"option.value\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\tv-model=\"purpose\"\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\tname=\"cn-access-purpose\"\n\t\t\t\t\t:value=\"option.value\"\n\t\t\t\t\t:disabled=\"loading\"\n\t\t\t\t\t:data-testid=\"`cn-access-purpose-option-${option.value}`\">\n\t\t\t\t\t{{ option.label }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<!-- What choosing this purpose does besides recording it (\"you become this case's handler\"). -->\n\t\t\t\t<p v-if=\"option.hint\"\n\t\t\t\t\tclass=\"cn-access-purpose__hint\"\n\t\t\t\t\t:data-testid=\"`cn-access-purpose-hint-${option.value}`\">\n\t\t\t\t\t{{ option.hint }}\n\t\t\t\t</p>\n\t\t\t</template>\n\t\t</fieldset>\n\t\t<NcTextArea\n\t\t\tv-if=\"purpose === OTHER\"\n\t\t\tv-model=\"note\"\n\t\t\t:label=\"t('nextcloud-vue', 'Describe your purpose')\"\n\t\t\t:maxlength=\"500\"\n\t\t\t:disabled=\"loading\"\n\t\t\tdata-testid=\"cn-access-purpose-note\" />\n\t\t<NcNoteCard v-if=\"error\" type=\"error\" data-testid=\"cn-access-purpose-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"loading\" data-testid=\"cn-access-purpose-cancel\" @click=\"$emit('cancel')\">\n\t\t\t\t{{ t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!complete || loading\"\n\t\t\t\tdata-testid=\"cn-access-purpose-submit\"\n\t\t\t\t@click=\"submit\">\n\t\t\t\t<template v-if=\"loading\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" :name=\"t('nextcloud-vue', 'Loading …')\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Open') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea } from '@nextcloud/vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\n\n/** The value of the \"Other\" choice, which asks for a written purpose. */\nconst OTHER = 'other'\n\n/**\n * CnAccessPurposeDialog — asks why the reader opens a record before the page\n * shows it (detail page `accessPurpose`). A short list of purposes plus\n * \"Other\", which needs a written purpose. Emits the choice; the page records\n * it and decides whether to open.\n *\n * @spec openspec/changes/detail-access-purpose/specs/detail-access-purpose/spec.md#requirement-a-detail-page-can-ask-for-a-purpose-before-it-opens\n */\nexport default {\n\tname: 'CnAccessPurposeDialog',\n\n\tcomponents: { CnDialog, NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea },\n\n\tprops: {\n\t\t/** The dialog's title; a default question when empty. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The sentence under the title; a default when empty. */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The purposes offered, already translated. \"Other\" is added at the end.\n\t\t * A `hint` is a line under the option that says what choosing it does\n\t\t * besides recording it.\n\t\t *\n\t\t * @type {Array<{value: string, label: string, hint?: string}>}\n\t\t */\n\t\toptions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether the purpose is being recorded. */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Why the last attempt was refused, shown in the dialog. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: [\n\t\t/**\n\t\t * The reader chose a purpose.\n\t\t *\n\t\t * @type {{purpose: string, note: string}}\n\t\t */\n\t\t'submit',\n\t\t/** The reader closed the dialog without a purpose. */\n\t\t'cancel',\n\t],\n\n\tdata() {\n\t\treturn { purpose: '', note: '', OTHER }\n\t},\n\n\tcomputed: {\n\t\t/** @return {Array<{value: string, label: string}>} The offered purposes and \"Other\". */\n\t\tchoices() {\n\t\t\tconst own = (Array.isArray(this.options) ? this.options : [])\n\t\t\t\t.filter((option) => option && typeof option.value === 'string' && option.value !== '' && option.value !== OTHER)\n\t\t\treturn [...own, { value: OTHER, label: t('nextcloud-vue', 'Other') }]\n\t\t},\n\n\t\t/** @return {boolean} Whether a purpose is chosen and, for \"Other\", written. */\n\t\tcomplete() {\n\t\t\tif (this.purpose === '') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn this.purpose !== OTHER || this.note.trim() !== ''\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Emit the chosen purpose; the written note only goes with \"Other\".\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tsubmit() {\n\t\t\tif (!this.complete) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('submit', { purpose: this.purpose, note: this.purpose === OTHER ? this.note.trim() : '' })\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-access-purpose__sentence {\n\tmargin: 0 0 12px;\n}\n\n.cn-access-purpose__choices {\n\tmargin: 0 0 12px;\n\tpadding: 0;\n\tborder: 0;\n}\n\n.cn-access-purpose__hint {\n\tmargin: 0 0 6px;\n\tpadding-inline-start: 36px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-access-purpose__legend {\n\tmargin-bottom: 4px;\n\tfont-weight: 600;\n}\n</style>\n"],"names":["_createBlock","_createVNode","_createTextVNode","_createElementVNode","_toDisplayString","_Fragment","_renderList","_createElementBlock"],"mappings":"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"}
@@ -2396,7 +2396,8 @@ var translations = {
2396
2396
  "From {date}": "From {date}",
2397
2397
  "Until {date}": "Until {date}",
2398
2398
  "More actions for {name}": "More actions for {name}",
2399
- "Unlink contact": "Unlink contact"
2399
+ "Unlink contact": "Unlink contact",
2400
+ "{term}, extendable by {extension}": "{term}, extendable by {extension}"
2400
2401
  };
2401
2402
  var plurals = {
2402
2403
  "{count} member": [
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2651,7 +2651,8 @@ var translations = {
2651
2651
  "From {date}": "Vanaf {date}",
2652
2652
  "Until {date}": "Tot {date}",
2653
2653
  "More actions for {name}": "Meer acties voor {name}",
2654
- "Unlink contact": "Contact ontkoppelen"
2654
+ "Unlink contact": "Contact ontkoppelen",
2655
+ "{term}, extendable by {extension}": "{term}, te verdagen met {extension}"
2655
2656
  };
2656
2657
  var plurals = {
2657
2658
  "{count} member": [
@@ -1 +1 @@
1
- {"version":3,"file":"nl.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"nl.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}