@nextcloud/vue 9.3.2 → 9.3.3

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 (128) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/assets/NcActionCheckbox-DLJQfCUI.css +127 -0
  3. package/dist/assets/NcActionRadio-Bd4RFH-l.css +127 -0
  4. package/dist/chunks/{NcActionButton-BHXE4UKQ.mjs → NcActionButton-DNXoAooH.mjs} +2 -2
  5. package/dist/chunks/{NcActionButton-BHXE4UKQ.mjs.map → NcActionButton-DNXoAooH.mjs.map} +1 -1
  6. package/dist/chunks/NcActionCheckbox-DeHAMd23.mjs +122 -0
  7. package/dist/chunks/NcActionCheckbox-DeHAMd23.mjs.map +1 -0
  8. package/dist/chunks/{NcActionInput-D1uLWx4N.mjs → NcActionInput-BemRG66_.mjs} +3 -3
  9. package/dist/chunks/{NcActionInput-D1uLWx4N.mjs.map → NcActionInput-BemRG66_.mjs.map} +1 -1
  10. package/dist/chunks/NcActionRadio-DILn0DxW.mjs +120 -0
  11. package/dist/chunks/NcActionRadio-DILn0DxW.mjs.map +1 -0
  12. package/dist/chunks/{NcActionTextEditable-DAMWWXnR.mjs → NcActionTextEditable-DL4idmon.mjs} +2 -2
  13. package/dist/chunks/{NcActionTextEditable-DAMWWXnR.mjs.map → NcActionTextEditable-DL4idmon.mjs.map} +1 -1
  14. package/dist/chunks/{NcAppContent-DFbY2ERd.mjs → NcAppContent-BTNf1r8Z.mjs} +2 -2
  15. package/dist/chunks/{NcAppContent-DFbY2ERd.mjs.map → NcAppContent-BTNf1r8Z.mjs.map} +1 -1
  16. package/dist/chunks/{NcAppNavigation-CjnufbC2.mjs → NcAppNavigation-DQB0KqoZ.mjs} +2 -2
  17. package/dist/chunks/{NcAppNavigation-CjnufbC2.mjs.map → NcAppNavigation-DQB0KqoZ.mjs.map} +1 -1
  18. package/dist/chunks/{NcAppNavigationItem-B307vBI9.mjs → NcAppNavigationItem-OrqBniiI.mjs} +2 -2
  19. package/dist/chunks/{NcAppNavigationItem-B307vBI9.mjs.map → NcAppNavigationItem-OrqBniiI.mjs.map} +1 -1
  20. package/dist/chunks/{NcAppNavigationSearch-Bi367hd4.mjs → NcAppNavigationSearch-ByuV3q2c.mjs} +2 -2
  21. package/dist/chunks/{NcAppNavigationSearch-Bi367hd4.mjs.map → NcAppNavigationSearch-ByuV3q2c.mjs.map} +1 -1
  22. package/dist/chunks/{NcAppNavigationSettings-CaTjgcVj.mjs → NcAppNavigationSettings-A0DXzd5B.mjs} +2 -2
  23. package/dist/chunks/{NcAppNavigationSettings-CaTjgcVj.mjs.map → NcAppNavigationSettings-A0DXzd5B.mjs.map} +1 -1
  24. package/dist/chunks/{NcAppSettingsDialog-NlVP7Fo7.mjs → NcAppSettingsDialog-BaN30xl4.mjs} +2 -2
  25. package/dist/chunks/{NcAppSettingsDialog-NlVP7Fo7.mjs.map → NcAppSettingsDialog-BaN30xl4.mjs.map} +1 -1
  26. package/dist/chunks/{NcAssistantButton-DqXCpiMp.mjs → NcAssistantButton-CioiSWRg.mjs} +3 -3
  27. package/dist/chunks/{NcAssistantButton-DqXCpiMp.mjs.map → NcAssistantButton-CioiSWRg.mjs.map} +1 -1
  28. package/dist/chunks/{NcAssistantIcon-PMYKxGuH.mjs → NcAssistantIcon-8pL-4h5f.mjs} +2 -2
  29. package/dist/chunks/{NcAssistantIcon-PMYKxGuH.mjs.map → NcAssistantIcon-8pL-4h5f.mjs.map} +1 -1
  30. package/dist/chunks/{NcAvatar-S8EJR2BK.mjs → NcAvatar-CK_dTsmT.mjs} +2 -2
  31. package/dist/chunks/{NcAvatar-S8EJR2BK.mjs.map → NcAvatar-CK_dTsmT.mjs.map} +1 -1
  32. package/dist/chunks/{NcBreadcrumbs-DHS31Ax7.mjs → NcBreadcrumbs-CbJmdlaF.mjs} +2 -2
  33. package/dist/chunks/{NcBreadcrumbs-DHS31Ax7.mjs.map → NcBreadcrumbs-CbJmdlaF.mjs.map} +1 -1
  34. package/dist/chunks/{NcChip-QHPd3nMF.mjs → NcChip-B8jcrLqG.mjs} +3 -3
  35. package/dist/chunks/{NcChip-QHPd3nMF.mjs.map → NcChip-B8jcrLqG.mjs.map} +1 -1
  36. package/dist/chunks/{NcCollectionList-ByFl0-ca.mjs → NcCollectionList-TB1GbWbo.mjs} +3 -3
  37. package/dist/chunks/{NcCollectionList-ByFl0-ca.mjs.map → NcCollectionList-TB1GbWbo.mjs.map} +1 -1
  38. package/dist/chunks/{NcColorPicker-DpSDaGrh.mjs → NcColorPicker-3wpX7pKD.mjs} +2 -2
  39. package/dist/chunks/{NcColorPicker-DpSDaGrh.mjs.map → NcColorPicker-3wpX7pKD.mjs.map} +1 -1
  40. package/dist/chunks/{NcDashboardWidget-CIUrPOLo.mjs → NcDashboardWidget-1tax78_e.mjs} +3 -3
  41. package/dist/chunks/{NcDashboardWidget-CIUrPOLo.mjs.map → NcDashboardWidget-1tax78_e.mjs.map} +1 -1
  42. package/dist/chunks/{NcDashboardWidgetItem-DdYM1QYk.mjs → NcDashboardWidgetItem-BjsN8uF0.mjs} +3 -3
  43. package/dist/chunks/{NcDashboardWidgetItem-DdYM1QYk.mjs.map → NcDashboardWidgetItem-BjsN8uF0.mjs.map} +1 -1
  44. package/dist/chunks/{NcDateTimePicker-DtQaoKbG.mjs → NcDateTimePicker-DCuHXZjc.mjs} +2 -2
  45. package/dist/chunks/{NcDateTimePicker-DtQaoKbG.mjs.map → NcDateTimePicker-DCuHXZjc.mjs.map} +1 -1
  46. package/dist/chunks/{NcDialog-BTmnYNeo.mjs → NcDialog-BHl_LOs_.mjs} +2 -2
  47. package/dist/chunks/{NcDialog-BTmnYNeo.mjs.map → NcDialog-BHl_LOs_.mjs.map} +1 -1
  48. package/dist/chunks/{NcEmojiPicker-U5k_zceS.mjs → NcEmojiPicker-CReazifM.mjs} +3 -3
  49. package/dist/chunks/{NcEmojiPicker-U5k_zceS.mjs.map → NcEmojiPicker-CReazifM.mjs.map} +1 -1
  50. package/dist/chunks/{NcFormBoxButton-Bptd324P.mjs → NcFormBoxButton-DvMw5yUf.mjs} +2 -2
  51. package/dist/chunks/{NcFormBoxButton-Bptd324P.mjs.map → NcFormBoxButton-DvMw5yUf.mjs.map} +1 -1
  52. package/dist/chunks/{NcFormBoxCopyButton.vue_vue_type_script_setup_true_lang-DhnfC18v.mjs → NcFormBoxCopyButton.vue_vue_type_script_setup_true_lang-DYtyXBqR.mjs} +3 -3
  53. package/dist/chunks/{NcFormBoxCopyButton.vue_vue_type_script_setup_true_lang-DhnfC18v.mjs.map → NcFormBoxCopyButton.vue_vue_type_script_setup_true_lang-DYtyXBqR.mjs.map} +1 -1
  54. package/dist/chunks/{NcInputField-D7Nv5QhT.mjs → NcInputField-Clm9jOGJ.mjs} +2 -2
  55. package/dist/chunks/{NcInputField-D7Nv5QhT.mjs.map → NcInputField-Clm9jOGJ.mjs.map} +1 -1
  56. package/dist/chunks/{NcListItemIcon-IJLXY-te.mjs → NcListItemIcon-DVy6eGJx.mjs} +2 -2
  57. package/dist/chunks/{NcListItemIcon-IJLXY-te.mjs.map → NcListItemIcon-DVy6eGJx.mjs.map} +1 -1
  58. package/dist/chunks/{NcModal-DSCYMxfe.mjs → NcModal-D00OJZV2.mjs} +2 -2
  59. package/dist/chunks/{NcModal-DSCYMxfe.mjs.map → NcModal-D00OJZV2.mjs.map} +1 -1
  60. package/dist/chunks/{NcNoteCard-BUg07N13.mjs → NcNoteCard-Cok_4Fld.mjs} +2 -2
  61. package/dist/chunks/{NcNoteCard-BUg07N13.mjs.map → NcNoteCard-Cok_4Fld.mjs.map} +1 -1
  62. package/dist/chunks/{NcPasswordField-CTuWpUWd.mjs → NcPasswordField-BOZlUwhr.mjs} +3 -3
  63. package/dist/chunks/{NcPasswordField-CTuWpUWd.mjs.map → NcPasswordField-BOZlUwhr.mjs.map} +1 -1
  64. package/dist/chunks/{NcRichContenteditable-Bq1NOBCE.mjs → NcRichContenteditable-B-w64JsT.mjs} +6 -6
  65. package/dist/chunks/{NcRichContenteditable-Bq1NOBCE.mjs.map → NcRichContenteditable-B-w64JsT.mjs.map} +1 -1
  66. package/dist/chunks/{NcRichText-B6VwyPUp.mjs → NcRichText-1U5RXjPL.mjs} +3 -3
  67. package/dist/chunks/{NcRichText-B6VwyPUp.mjs.map → NcRichText-1U5RXjPL.mjs.map} +1 -1
  68. package/dist/chunks/{NcSelectUsers-CiTKYuOb.mjs → NcSelectUsers-DlUM6S6l.mjs} +2 -2
  69. package/dist/chunks/{NcSelectUsers-CiTKYuOb.mjs.map → NcSelectUsers-DlUM6S6l.mjs.map} +1 -1
  70. package/dist/chunks/{NcTextArea-2CifgNom.mjs → NcTextArea-PIs9Kt0A.mjs} +2 -2
  71. package/dist/chunks/{NcTextArea-2CifgNom.mjs.map → NcTextArea-PIs9Kt0A.mjs.map} +1 -1
  72. package/dist/chunks/{NcTextField.vue_vue_type_script_setup_true_lang-BfjSL2EJ.mjs → NcTextField.vue_vue_type_script_setup_true_lang-CCsZqnkM.mjs} +3 -3
  73. package/dist/chunks/{NcTextField.vue_vue_type_script_setup_true_lang-BfjSL2EJ.mjs.map → NcTextField.vue_vue_type_script_setup_true_lang-CCsZqnkM.mjs.map} +1 -1
  74. package/dist/chunks/{NcUserBubble-CiB-Lu5C.mjs → NcUserBubble-Cs84CNHz.mjs} +2 -2
  75. package/dist/chunks/{NcUserBubble-CiB-Lu5C.mjs.map → NcUserBubble-Cs84CNHz.mjs.map} +1 -1
  76. package/dist/chunks/{mdi-DvQxv1t7.mjs → mdi-CpchYUUV.mjs} +33 -25
  77. package/dist/chunks/{mdi-DvQxv1t7.mjs.map → mdi-CpchYUUV.mjs.map} +1 -1
  78. package/dist/chunks/{referencePickerModal-CDHqLZC-.mjs → referencePickerModal-CXAtbcPd.mjs} +3 -3
  79. package/dist/chunks/{referencePickerModal-CDHqLZC-.mjs.map → referencePickerModal-CXAtbcPd.mjs.map} +1 -1
  80. package/dist/chunks/{useCopy-D3yAxBJi.mjs → useCopy-D4CcMqlA.mjs} +2 -2
  81. package/dist/chunks/{useCopy-D3yAxBJi.mjs.map → useCopy-D4CcMqlA.mjs.map} +1 -1
  82. package/dist/components/NcActionButton/index.mjs +1 -1
  83. package/dist/components/NcActionCheckbox/NcActionCheckbox.vue.d.ts +27 -16
  84. package/dist/components/NcActionCheckbox/index.mjs +1 -1
  85. package/dist/components/NcActionInput/index.mjs +1 -1
  86. package/dist/components/NcActionRadio/NcActionRadio.vue.d.ts +26 -17
  87. package/dist/components/NcActionRadio/index.mjs +1 -1
  88. package/dist/components/NcActionTextEditable/index.mjs +1 -1
  89. package/dist/components/NcAppContent/index.mjs +1 -1
  90. package/dist/components/NcAppNavigation/index.mjs +1 -1
  91. package/dist/components/NcAppNavigationItem/index.mjs +1 -1
  92. package/dist/components/NcAppNavigationSearch/index.mjs +1 -1
  93. package/dist/components/NcAppNavigationSettings/index.mjs +1 -1
  94. package/dist/components/NcAppSettingsDialog/index.mjs +1 -1
  95. package/dist/components/NcAssistantButton/index.mjs +1 -1
  96. package/dist/components/NcAssistantIcon/index.mjs +1 -1
  97. package/dist/components/NcAvatar/index.mjs +1 -1
  98. package/dist/components/NcBreadcrumbs/index.mjs +1 -1
  99. package/dist/components/NcChip/index.mjs +1 -1
  100. package/dist/components/NcCollectionList/index.mjs +1 -1
  101. package/dist/components/NcColorPicker/index.mjs +1 -1
  102. package/dist/components/NcDashboardWidget/index.mjs +1 -1
  103. package/dist/components/NcDashboardWidgetItem/index.mjs +1 -1
  104. package/dist/components/NcDateTimePicker/index.mjs +1 -1
  105. package/dist/components/NcDialog/index.mjs +1 -1
  106. package/dist/components/NcEmojiPicker/index.mjs +1 -1
  107. package/dist/components/NcFormBoxButton/index.mjs +1 -1
  108. package/dist/components/NcFormBoxCopyButton/index.mjs +1 -1
  109. package/dist/components/NcInputField/index.mjs +1 -1
  110. package/dist/components/NcListItemIcon/index.mjs +1 -1
  111. package/dist/components/NcModal/index.mjs +1 -1
  112. package/dist/components/NcNoteCard/index.mjs +1 -1
  113. package/dist/components/NcPasswordField/index.mjs +1 -1
  114. package/dist/components/NcRichContenteditable/index.mjs +1 -1
  115. package/dist/components/NcRichText/index.mjs +3 -3
  116. package/dist/components/NcSelectUsers/index.mjs +1 -1
  117. package/dist/components/NcTextArea/index.mjs +1 -1
  118. package/dist/components/NcTextField/index.mjs +1 -1
  119. package/dist/components/NcUserBubble/index.mjs +1 -1
  120. package/dist/functions/reference/index.mjs +1 -1
  121. package/dist/index.mjs +37 -37
  122. package/package.json +2 -2
  123. package/dist/assets/NcActionCheckbox-BeT6fCCy.css +0 -80
  124. package/dist/assets/NcActionRadio-DgdLD238.css +0 -79
  125. package/dist/chunks/NcActionCheckbox-BTHrh-Mu.mjs +0 -127
  126. package/dist/chunks/NcActionCheckbox-BTHrh-Mu.mjs.map +0 -1
  127. package/dist/chunks/NcActionRadio-BM24rDbc.mjs +0 -136
  128. package/dist/chunks/NcActionRadio-BM24rDbc.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"NcDateTimePicker-DtQaoKbG.mjs","sources":["../../src/components/NcDateTimePicker/NcDateTimePicker.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\nIn general it is recommended to use the native date picker (see `NcDateTimePickerNative` which is based on `<input type=\"date\">`).\nBut some use cases are not covered by the native date selector, like selecting ranges or selecting a timezone.\nFor those cases this component can be used.\n\n### General examples\n```vue\n<template>\n\t<div class=\"wrapper\">\n\t\t<fieldset class=\"type-select\">\n\t\t\t<legend>Picker mode</legend>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"date\">Date</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"datetime\">Date and time</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"week\">Week</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"month\">Month</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"year\">Year</NcCheckboxRadioSwitch>\n\t\t</fieldset>\n\t\t<NcDateTimePicker\n\t\t\tv-model=\"time\"\n\t\t\t:type />\n\t\t<span>{{ time }}</span>\n\t</div>\n</template>\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\ttype: 'date',\n\t\t\ttime: new Date('2022-10-10 10:10:10'),\n\t\t}\n\t},\n}\n</script>\n<style scoped>\n.wrapper {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.type-select {\n\tdisplay: flex;\n\tflex-direction: row;\n\tflex-wrap: wrap;\n}\n</style>\n```\n\n### Example with confirm button\n\nBy default the date is applied as soon as you select the day in the calendar.\nSometimes - especially when selecting date and time - it is required to only emit the selected date when the flow is finished.\nFor this the `confirm` prop can be used, this will add a confirmation button to the selector.\n\n```vue\n<template>\n\t<span>\n\t\t<NcDateTimePicker\n\t\t\tv-model=\"time\"\n\t\t\ttype=\"datetime\"\n\t\t\tconfirm />\n\t\t{{ time }}\n\t</span>\n</template>\n<script>\n\texport default {\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\ttime: null,\n\t\t\t}\n\t\t},\n\t}\n</script>\n```\n\n### Range picker\n\nThe most common use case for the `NcDateTimePicker` is picking a range, as this is not supported by the native date picker.\n\nWhen selecting the range picker type, the model value type will change from `Date` to `[Date, Date]`.\nMeaning an array with two dates is used, the first date is the range start and the second date is the range end.\n\n```vue\n<template>\n\t<div>\n\t\t<fieldset class=\"type-select\">\n\t\t\t<legend>Picker mode</legend>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"date-range\">Date</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"time-range\">Time</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"datetime-range\">Date and time</NcCheckboxRadioSwitch>\n\t\t</fieldset>\n\n\t\t<NcDateTimePicker\n\t\t\t:key=\"type\"\n\t\t\tv-model=\"time\"\n\t\t\t:type />\n\t\t<div>\n\t\t\t<div>Start: {{ formatDate(time[0]) }}</div>\n\t\t\t<div>End: {{ formatDate(time[1]) }}</div>\n\t\t</div>\n\t</div>\n</template>\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\ttime: [new Date(2025, 3, 18, 12, 30), new Date(2025, 3, 21, 13, 30)],\n\t\t\ttype: 'date-range',\n\t\t}\n\t},\n\tmethods: {\n\t\tformatDate(date) {\n\t\t\tconst dateString = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`\n\t\t\tconst timeString = `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`\n\t\t\tif (this.type === 'date-range') {\n\t\t\t\treturn dateString\n\t\t\t} else if (this.type === 'time-range') {\n\t\t\t\treturn timeString\n\t\t\t}\n\t\t\treturn `${dateString} ${timeString}`\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.type-select {\n\tdisplay: flex;\n\tflex-direction: row;\n\tflex-wrap: wrap;\n}\n</style>\n```\n\n### Time zone aware date picker\n\nThe datepicker can optionally include a picker for the preferred time zone. The selected time does not factor in the\npicked time zone, but you will have to convert it yourself when necessary.\n\n```vue\n<template>\n\t<span>\n\t\t<NcDateTimePicker\n\t\t\tv-model=\"time\"\n\t\t\ttype=\"datetime\"\n\t\t\tshow-timezone-select\n\t\t\tv-model:timezone-id=\"tz\" /><br>\n\t\t{{ time }} | {{ tz }}\n\t</span>\n</template>\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\ttime: undefined,\n\t\t\ttz: 'Europe/Berlin',\n\t\t}\n\t},\n}\n</script>\n```\n</docs>\n\n<script setup lang=\"ts\">\nimport type {\n\t// The accepted model value\n\tModelValue as LibraryModelValue,\n\t// The emitted object for time picker\n\tTimeObj as LibraryTimeObject,\n\tVueDatePickerProps,\n} from '@vuepic/vue-datepicker'\n\nimport {\n\tmdiCalendarBlank,\n\tmdiChevronDown,\n\tmdiChevronLeft,\n\tmdiChevronRight,\n\tmdiChevronUp,\n\tmdiClock,\n\tmdiClose,\n} from '@mdi/js'\nimport {\n\tgetCanonicalLocale,\n\tgetDayNames,\n\tgetDayNamesMin,\n\tgetFirstDay,\n} from '@nextcloud/l10n'\nimport VueDatePicker from '@vuepic/vue-datepicker'\nimport { computed, useTemplateRef } from 'vue'\nimport NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'\nimport NcTimezonePicker from '../NcTimezonePicker/NcTimezonePicker.vue'\nimport { t } from '../../l10n.ts'\nimport NcButton from '../NcButton/index.ts'\n\ntype LibraryFormatOptions = VueDatePickerProps['format']\n\n/**\n * The preselected IANA time zone ID for the time zone picker,\n * only relevant in combination with `show-timezone-select`.\n * The prop supports two-way binding through v-model directive.\n *\n * @example `Europe/Berlin`\n * @default 'UTC'\n */\nconst timezoneId = defineModel<string>('timezoneId', { default: 'UTC' })\n\nconst props = withDefaults(defineProps<{\n\t/**\n\t * If set to true the menu will be placed on the `<body>`\n\t * instead of default placement on the picker.\n\t */\n\tappendToBody?: boolean\n\n\t/**\n\t * Aria label for the input box.\n\t *\n\t * @default 'Datepicker input'\n\t */\n\tariaLabel?: string\n\n\t/**\n\t * Aria label for the date picker menu.\n\t *\n\t * @default 'Datepicker menu'\n\t */\n\tariaLabelMenu?: string\n\n\t/**\n\t * Allow to clear the input.\n\t *\n\t * @default false\n\t */\n\tclearable?: boolean\n\n\t/**\n\t * Do not auto-apply the date but require clicking the confirmation button.\n\t *\n\t * @default false\n\t */\n\tconfirm?: boolean\n\n\t/**\n\t * Preview format for the picker input field.\n\t * Can either be a string of Unicode tokens or a function that takes a Date object\n\t * or for range picker an array of two dates, and returns the formatted date as string.\n\t *\n\t * @default Intl.DateTimeFormat is used to format dates and times\n\t * @see https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table\n\t */\n\tformat?: string | ((date: Date) => string) | ((dates: [Date, Date]) => string)\n\n\t/**\n\t * The locale to use for formatting the shown dates.\n\t * By default the users current Nextcloud locale is used.\n\t */\n\tlocale?: string\n\n\t/**\n\t * Default increment step for minutes in the time picker.\n\t *\n\t * @default 10\n\t */\n\tminuteStep?: number\n\n\t/**\n\t * The value to initialize, but also two-way bind the selected date. The date is – like the `Date` object in\n\t * JavaScript – tied to UTC. The selected time zone does not have an influence of the selected time and date\n\t * value. You have to translate the time yourself when you want to factor in time zones.\n\t *\n\t * When using the range picker then an array containing the start and end date needs to be passed.\n\t */\n\tmodelValue?: Date | [Date, Date] | null\n\n\t/**\n\t * Optional custom placeholder for the input box.\n\t */\n\tplaceholder?: string\n\n\t/**\n\t * Include a timezone picker within the menu.\n\t * Please note that the dates are still bound to the locale timezone\n\t * and any conversion needs to be done by the app itself.\n\t *\n\t * @default false\n\t */\n\tshowTimezoneSelect?: boolean\n\n\t/**\n\t * Show the ISO week numbers within the calendar.\n\t *\n\t * @default false\n\t */\n\tshowWeekNumber?: boolean\n\n\t/**\n\t * Type of the picker.\n\t * There is some special handling for ranges as those types require a `[Date, Date]` model value.\n\t * - The 'date-range' type will enable a range picker for dates\n\t * - The 'time-range' allows picking a time range.\n\t * - The 'datetime-range' allows picking dates with times assigned.\n\t *\n\t * @default 'date'\n\t */\n\ttype?: 'date' | 'datetime' | 'time' | 'week' | 'month' | 'year' | 'date-range' | 'time-range' | 'datetime-range'\n}>(), {\n\tariaLabel: t('Datepicker input'),\n\tariaLabelMenu: t('Datepicker menu'),\n\tformat: undefined,\n\tlocale: getCanonicalLocale(),\n\tminuteStep: 10,\n\ttimezoneId: 'UTC',\n\tmodelValue: null,\n\t// set by fallbackPlaceholder\n\tplaceholder: undefined,\n\ttype: 'date',\n})\n\nconst emit = defineEmits<{\n\t/**\n\t * If range picker is enabled then an array containing start and end date are emitted.\n\t * Otherwise the selected date is emitted.\n\t * `null` is emitted if `clearable` is set to `true` and the value was cleared.\n\t */\n\t'update:modelValue': [Date | [Date, Date] | null]\n\t'update:timezoneId': [string]\n}>()\n\nconst targetElement = useTemplateRef('target')\nconst pickerInstance = useTemplateRef('picker')\n\n/**\n * Mapping of the model-value prop to the format expected by the library.\n * We do not directly pass the prop and adjust the interface to not transparently wrap the library.\n * This has show as beeing a pain in the past when we need to switch underlying libraries.\n */\nconst value = computed<LibraryModelValue>(() => {\n\tif (props.modelValue === null && props.clearable) {\n\t\treturn null\n\t}\n\n\tif (props.type === 'week') {\n\t\tconst date = props.modelValue instanceof Date ? props.modelValue : new Date()\n\t\tconst end = new Date(date)\n\t\tend.setUTCDate(date.getUTCDate() + 6)\n\t\treturn [date, end]\n\t} else if (props.type === 'year') {\n\t\tconst date = props.modelValue instanceof Date ? props.modelValue : new Date()\n\t\treturn date.getUTCFullYear()\n\t} else if (props.type === 'month') {\n\t\tconst date = props.modelValue instanceof Date ? props.modelValue : new Date()\n\t\treturn { year: date.getUTCFullYear(), month: date.getUTCMonth() }\n\t} else if (props.type === 'time') {\n\t\tconst time = props.modelValue instanceof Date ? props.modelValue : new Date()\n\t\treturn {\n\t\t\thours: time.getHours(),\n\t\t\tminutes: time.getMinutes(),\n\t\t\tseconds: time.getSeconds(),\n\t\t} satisfies LibraryTimeObject\n\t} else if (props.type === 'time-range') {\n\t\tconst time = [props.modelValue].flat()\n\t\tif (time.length !== 2) {\n\t\t\tconst start = new Date()\n\t\t\tconst end = new Date(start)\n\t\t\tend.setHours(end.getHours() + 1)\n\t\t\ttime.splice(0, 2, start, end)\n\t\t}\n\n\t\treturn (time as [Date, Date]).map((date) => ({\n\t\t\thours: date.getHours(),\n\t\t\tminutes: date.getMinutes(),\n\t\t\tseconds: date.getSeconds(),\n\t\t} as LibraryTimeObject))\n\t} else if (props.type.endsWith('-range')) {\n\t\tif (props.modelValue === undefined) {\n\t\t\tconst start = new Date()\n\t\t\tconst end = new Date(start)\n\t\t\tend.setUTCDate(start.getUTCDate() + 7)\n\t\t\treturn [start, end]\n\t\t}\n\t\treturn props.modelValue\n\t}\n\n\t// no special handling for other types needed\n\treturn props.modelValue ?? new Date()\n})\n\nconst placeholderFallback = computed(() => {\n\tif (props.type === 'date') {\n\t\treturn t('Select date')\n\t} else if (props.type === 'time') {\n\t\treturn t('Select time')\n\t} else if (props.type === 'datetime') {\n\t\treturn t('Select date and time')\n\t} else if (props.type === 'week') {\n\t\treturn t('Select week')\n\t} else if (props.type === 'month') {\n\t\treturn t('Select month')\n\t} else if (props.type === 'year') {\n\t\treturn t('Select year')\n\t} else if (props.type.endsWith('-range')) {\n\t\treturn t('Select time range')\n\t}\n\t// should not be reached\n\treturn t('Select date and time')\n})\n\n/**\n * The date (time) formatting to be used by the library.\n * We use the provided format if possible, otherwise we provide a formatting function\n * which uses the browsers Intl API to format the date / time in the current users locale.\n */\nconst realFormat = computed<LibraryFormatOptions>(() => {\n\tif (props.format) {\n\t\t// we can cast the type here as in this case its either string\n\t\t// function `(Date) => string` or `([Date, Date]) => string` where we cast to `(Date[]) => string` here.\n\t\treturn props.format as LibraryFormatOptions\n\t} else if (props.type === 'week') {\n\t\t// cannot format weeks with Intl.\n\t\treturn 'RR-II'\n\t}\n\n\tlet formatter: Intl.DateTimeFormat | undefined\n\tif (props.type === 'date' || props.type === 'date-range') {\n\t\tformatter = new Intl.DateTimeFormat(getCanonicalLocale(), { dateStyle: 'medium' })\n\t} else if (props.type === 'time' || props.type === 'time-range') {\n\t\tformatter = new Intl.DateTimeFormat(getCanonicalLocale(), { timeStyle: 'short' })\n\t} else if (props.type === 'datetime' || props.type === 'datetime-range') {\n\t\tformatter = new Intl.DateTimeFormat(getCanonicalLocale(), { dateStyle: 'medium', timeStyle: 'short' })\n\t} else if (props.type === 'month') {\n\t\tformatter = new Intl.DateTimeFormat(getCanonicalLocale(), { year: 'numeric', month: '2-digit' })\n\t} else if (props.type === 'year') {\n\t\tformatter = new Intl.DateTimeFormat(getCanonicalLocale(), { year: 'numeric' })\n\t}\n\n\tif (formatter) {\n\t\treturn (input: Date | [Date, Date]) => Array.isArray(input)\n\t\t\t? formatter.formatRange(input[0], input[1])\n\t\t\t: formatter.format(input)\n\t}\n\n\t// fallback to default formatting\n\treturn undefined\n})\n\nconst pickerType = computed(() => ({\n\ttimePicker: props.type === 'time' || props.type === 'time-range',\n\tyearPicker: props.type === 'year',\n\tmonthPicker: props.type === 'month',\n\tweekPicker: props.type === 'week',\n\trange: props.type.endsWith('-range') && {\n\t\t// do not use partial ranges (meaning after selecting the start [Date, null] will be emitted)\n\t\t// if this is needed someday we can enable it,\n\t\t// but its not covered by our component interface (props / events) documentation so just disabled for now.\n\t\tpartialRange: false,\n\t},\n\tenableTimePicker: !(props.type === 'date' || props.type === 'date-range'),\n\tflow: props.type === 'datetime'\n\t\t? ['calendar', 'time'] as ['calendar', 'time']\n\t\t: undefined,\n}))\n\n/**\n * Called on model value update of the library.\n *\n * @param value The value emitted from the underlying library\n */\nfunction onUpdateModelValue(value: LibraryModelValue): void {\n\tif (value === null) {\n\t\treturn emit('update:modelValue', null)\n\t}\n\n\tif (props.type === 'time') {\n\t\t// time is provided as an object\n\t\temit('update:modelValue', formatLibraryTime(value as LibraryTimeObject))\n\t} else if (props.type === 'time-range') {\n\t\t// same as time but as an array with two elements\n\t\tconst start = formatLibraryTime(value[0])\n\t\tconst end = formatLibraryTime(value[1])\n\t\t// ensure end is beyond the start\n\t\tif (end.getTime() < start.getTime()) {\n\t\t\tend.setDate(end.getDate() + 1)\n\t\t}\n\t\temit('update:modelValue', [start, end])\n\t} else if (props.type === 'month') {\n\t\t// month is emitted as an object with month and year attribute\n\t\tconst data = value as { month: number, year: number }\n\t\temit('update:modelValue', new Date(data.year, data.month, 1))\n\t} else if (props.type === 'year') {\n\t\t// Years are emitted as the numeric year e.g. 2022\n\t\temit('update:modelValue', new Date(value as number, 0))\n\t} else if (props.type === 'week') {\n\t\t// weeks are emitted as [Date, Date]\n\t\temit('update:modelValue', value[0])\n\t} else {\n\t\t// otherwise it already emits the correct format\n\t\temit('update:modelValue', value as Date | [Date, Date])\n\t}\n}\n\n/**\n * Format a vuepick time object to native JS Date object.\n *\n * @param time - The library time value object\n */\nfunction formatLibraryTime(time: LibraryTimeObject): Date {\n\tconst date = new Date()\n\tdate.setHours(time.hours)\n\tdate.setMinutes(time.minutes)\n\tdate.setSeconds(time.seconds)\n\treturn date\n}\n\n// Localization\n\nconst weekStart = getFirstDay()\n\nconst dayNames = [...getDayNamesMin()]\n// see https://github.com/Vuepic/vue-datepicker/issues/1159\nfor (let i = 0; i < weekStart; i++) {\n\tdayNames.push(dayNames.shift() as string)\n}\n\n// TRANSLATORS: A very short abbrevation used as a heading for \"week number\"\nconst weekNumName = t('W')\n\nconst ariaLabels = computed(() => ({\n\ttoggleOverlay: t('Toggle overlay'),\n\tmenu: props.ariaLabelMenu,\n\tinput: props.ariaLabel,\n\topenTimePicker: t('Open time picker'),\n\tcloseTimePicker: t('Close time Picker'),\n\tincrementValue: (type: 'hours' | 'minutes' | 'seconds') => {\n\t\tif (type === 'hours') {\n\t\t\treturn t('Increment hours')\n\t\t} else if (type === 'minutes') {\n\t\t\treturn t('Increment minutes')\n\t\t}\n\t\treturn t('Increment seconds')\n\t},\n\tdecrementValue: (type: 'hours' | 'minutes' | 'seconds') => {\n\t\tif (type === 'hours') {\n\t\t\treturn t('Decrement hours')\n\t\t} else if (type === 'minutes') {\n\t\t\treturn t('Decrement minutes')\n\t\t}\n\t\treturn t('Decrement seconds')\n\t},\n\topenTpOverlay: (type: 'hours' | 'minutes' | 'seconds') => {\n\t\tif (type === 'hours') {\n\t\t\treturn t('Open hours overlay')\n\t\t} else if (type === 'minutes') {\n\t\t\treturn t('Open minutes overlay')\n\t\t}\n\t\treturn t('Open seconds overlay')\n\t},\n\tamPmButton: t('Switch AM/PM mode'),\n\topenYearsOverlay: t('Open years overlay'),\n\topenMonthsOverlay: t('Open months overlay'),\n\tnextMonth: t('Next month'),\n\tprevMonth: t('Previous month'),\n\tnextYear: t('Next year'),\n\tprevYear: t('Previous year'),\n\tweekDay: (day: number) => getDayNames()[day],\n\tclearInput: t('Clear value'),\n\tcalendarIcon: t('Calendar icon'),\n\ttimePicker: t('Time picker'),\n\tmonthPicker: (overlay: boolean) => overlay ? t('Month picker overlay') : t('Month picker'),\n\tyearPicker: (overlay: boolean) => overlay ? t('Year picker overlay') : t('Year picker'),\n}))\n\n/**\n * Select the current value.\n * This is used by the confirmation button if `confirmation` was set.\n */\nfunction selectDate() {\n\tpickerInstance.value!.selectDate()\n}\n\n/**\n * Cancel the current selection by closing the overlay.\n * This is used by the confirmation button if `confirmation` was set.\n */\nfunction cancelSelection() {\n\tpickerInstance.value!.closeMenu()\n}\n</script>\n\n<template>\n\t<div class=\"vue-date-time-picker__wrapper\">\n\t\t<VueDatePicker\n\t\t\tref=\"picker\"\n\t\t\t:aria-labels\n\t\t\t:auto-apply=\"!confirm\"\n\t\t\tclass=\"vue-date-time-picker\"\n\t\t\t:class=\"{ 'vue-date-time-picker--clearable': clearable }\"\n\t\t\t:cancel-text=\"t('Cancel')\"\n\t\t\t:clearable\n\t\t\t:day-names\n\t\t\t:placeholder=\"placeholder ?? placeholderFallback\"\n\t\t\t:format=\"realFormat\"\n\t\t\t:locale\n\t\t\t:minutes-increment=\"minuteStep\"\n\t\t\t:model-value=\"value\"\n\t\t\t:now-button-label=\"t('Now')\"\n\t\t\t:select-text=\"t('Pick')\"\n\t\t\tsix-weeks=\"fair\"\n\t\t\t:teleport=\"appendToBody ? (targetElement || undefined) : false\"\n\t\t\ttext-input\n\t\t\t:week-num-name\n\t\t\t:week-numbers=\"showWeekNumber ? { type: 'iso' } : undefined\"\n\t\t\t:week-start\n\t\t\tv-bind=\"pickerType\"\n\t\t\t@update:model-value=\"onUpdateModelValue\">\n\t\t\t<template #action-buttons>\n\t\t\t\t<NcButton size=\"small\" variant=\"tertiary\" @click=\"cancelSelection\">\n\t\t\t\t\t{{ t('Cancel') }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton size=\"small\" variant=\"primary\" @click=\"selectDate\">\n\t\t\t\t\t{{ t('Pick') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<template #clear-icon=\"{ clear }\">\n\t\t\t\t<NcButton\n\t\t\t\t\t:aria-label=\"t('Clear value')\"\n\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\t@click=\"clear\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiClose\" :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<template #input-icon>\n\t\t\t\t<NcIconSvgWrapper :path=\"mdiCalendarBlank\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template #clock-icon>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiClock\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template #arrow-left>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiChevronLeft\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template #arrow-right>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiChevronRight\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template #arrow-down>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiChevronDown\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template #arrow-up>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiChevronUp\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"showTimezoneSelect\" #action-extra>\n\t\t\t\t<NcTimezonePicker\n\t\t\t\t\tv-model=\"timezoneId\"\n\t\t\t\t\tclass=\"vue-date-time-picker__timezone\"\n\t\t\t\t\t:append-to-body=\"false\"\n\t\t\t\t\t:input-label=\"t('Time zone')\" />\n\t\t\t</template>\n\t\t</VueDatePicker>\n\t\t<Teleport to=\"body\" :disabled=\"!appendToBody\">\n\t\t\t<div ref=\"target\" class=\"vue-date-time-picker__wrapper vue-date-time-picker__wrapper--teleport\" />\n\t\t</Teleport>\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n@use \"sass:meta\";\n\n.vue-date-time-picker__wrapper {\n\t// This is under :root in @vuepic/vue-datepicker/dist/main.css, so importing it scoped won't work\n\t--dp-common-transition: all var(--animation-quick) ease-in;\n\t--dp-menu-padding: 6px 8px;\n\t--dp-animation-duration: var(--animation-quick);\n\t--dp-menu-appear-transition-timing: cubic-bezier(.4, 0, 1, 1);\n\t--dp-transition-timing: ease-out;\n\t--dp-action-row-transtion: all 0.2s ease-in;\n\t--dp-font-family: var(--font-face);\n\t--dp-border-radius: var(--border-radius-element);\n\t--dp-cell-border-radius: var(--border-radius-small);\n\t--dp-transition-length: 22px;\n\t--dp-transition-timing-general: var(--animation-quick);\n\t--dp-button-height: var(--default-clickable-area);\n\t--dp-month-year-row-height: var(--default-clickable-area);\n\t--dp-month-year-row-button-size: var(--clickable-area-small);\n\t--dp-button-icon-height: 20px;\n\t--dp-calendar-wrap-padding: 0 5px;\n\t--dp-cell-size: var(--default-clickable-area);\n\t--dp-cell-padding: 5px;\n\t--dp-common-padding: 10px;\n\t--dp-input-icon-padding: var(--default-clickable-area);\n\t--dp-input-padding: 6px 12px;\n\t--dp-menu-min-width: 260px;\n\t--dp-action-buttons-padding: 1px 6px;\n\t--dp-row-margin: 5px 0;\n\t--dp-calendar-header-cell-padding: 0.5rem;\n\t--dp-multi-calendars-spacing: 10px;\n\t--dp-overlay-col-padding: 3px;\n\t--dp-time-inc-dec-button-size: var(--default-clickable-area);\n\t--dp-font-size: 1rem;\n\t--dp-preview-font-size: var(--font-size-small);\n\t--dp-time-font-size: 2rem;\n\t--dp-action-button-height: var(--clickable-area-small);\n\t--dp-action-row-padding: 8px;\n\t--dp-direction: ltr;\n\n\t// We need to import the vuepic styles, but at least scoped to our class and scope\n\t// plain @import does not work as this will scope all styles imported.\n\t:deep() {\n\t\t@include meta.load-css('@vuepic/vue-datepicker/dist/main.css');\n\t}\n\n\t// When rendered as part of NcActionInput, should be lifted above the NcPopover (99999 < 100000)\n\t&.vue-date-time-picker__wrapper--teleport :deep(.dp--menu-wrapper) {\n\t\tz-index: 100001;\n\t}\n\n\t.vue-date-time-picker--clearable :deep(.dp__input) {\n\t\tpadding-inline-end: var(--default-clickable-area);\n\t}\n\n\t.vue-date-time-picker__timezone {\n\t\tmin-width: unset;\n\t\twidth: 100%;\n\t}\n\n\t:deep(.icon-vue) {\n\t\t// we enforce full opacity to not create a11y issues with contrast\n\t\topacity: 1 !important;\n\t}\n\n\t// time selector button should have consistent padding\n\t:deep(.dp--tp-wrap),\n\t:deep(.dp__action_extra) {\n\t\tpadding: var(--dp-menu-padding);\n\t\tpadding-top: 0;\n\t}\n\n\t:deep(.dp__overlay.dp--overlay-absolute) {\n\t\tpadding: var(--dp-menu-padding);\n\n\t\t.dp__btn.dp__button.dp__button_bottom {\n\t\t\tinset-block-end: 6px;\n\t\t}\n\t}\n\n\t:deep(.dp__btn.dp__button.dp__button_bottom),\n\t:deep(.dp--tp-wrap .dp__button) {\n\t\twidth: 100%;\n\t}\n\n\t:deep(.dp__btn.dp__button.dp__overlay_action) {\n\t\twidth: calc(100% - 16px);\n\t}\n\n\t// fix issues caused by Nextcloud server styles\n\t:deep(input) {\n\t\tpadding-inline-start: var(--dp-input-icon-padding) !important;\n\t}\n\t:deep(.dp__btn) {\n\t\tmargin: 0;\n\t}\n\t:deep(.dp__inner_nav) {\n\t\theight: fit-content;\n\t\twidth: fit-content;\n\t}\n\n\t// make the bottom page toggle stand out better\n\t:deep(.dp__btn.dp__button.dp__button_bottom) {\n\t\tcolor: var(--color-primary-element-light);\n\t\tbackground-color: var(--color-primary-element-light);\n\t}\n\n\t// Fix server styles causing buttons to be primary colored\n\t:deep(.dp--header-wrap .dp__btn:not(.dp__button_bottom)),\n\t:deep(.dp__time_col .dp__btn) {\n\t\tbackground-color: var(--color-main-background);\n\n\t\t&:hover {\n\t\t\tbackground: var(--dp-hover-color);\n\t\t\tcolor: var(--dp-hover-icon-color);\n\t\t}\n\t}\n\n\t// Server styles cause the month and year to be fit-content -> fixing it to be max size.\n\t:deep(.dp__month_year_select) {\n\t\tflex: 1;\n\t}\n\t:deep(.dp--time-overlay-btn) {\n\t\tfont-size: calc(2 * var(--default-font-size)) !important;\n\t}\n\n\t// Adjust padding to prevent horizontal scrolling in time selection\n\t:deep(.dp__time_input .dp__time_col_reg_block) {\n\t\tpadding: 0 calc(4 * var(--default-grid-baseline));\n\t}\n\n\t.vue-date-time-picker.dp__theme_dark,\n\t.vue-date-time-picker.dp__theme_light,\n\t:deep(.dp__theme_dark),\n\t:deep(.dp__theme_light) {\n\t\t--dp-background-color: var(--color-main-background);\n\t\t--dp-text-color: var(--color-main-text);\n\t\t--dp-hover-color: var(--color-primary-element-light-hover);\n\t\t--dp-hover-text-color: var(--color-primary-element-light-text);\n\t\t--dp-hover-icon-color: var(--color-primary-element-light-text);\n\t\t--dp-primary-color: var(--color-primary-element);\n\t\t--dp-primary-disabled-color: var(--color-primary-element-hover);\n\t\t--dp-primary-text-color: var(--color-primary-element-text);\n\t\t--dp-secondary-color: var(--color-text-maxcontrast); // this is used for \"disabled\" dates\n\t\t--dp-border-color: var(--color-border);\n\t\t--dp-menu-border-color: var(--color-border-dark);\n\t\t--dp-border-color-hover: var(--color-border-maxcontrast);\n\t\t--dp-border-color-focus: var(--color-border-maxcontrast);\n\t\t--dp-disabled-color: var(--color-background-dark);\n\t\t--dp-disabled-color-text: var(--color-text-maxcontrast);\n\t\t--dp-scroll-bar-background: var(--color-scrollbar);\n\t\t--dp-scroll-bar-color: var(--color-scrollbar);\n\t\t--dp-success-color: var(--color-success);\n\t\t--dp-success-color-disabled: var(--color-success-hover);\n\t\t--dp-icon-color: var(--color-main-text);\n\t\t--dp-danger-color: var(--color-error);\n\t\t--dp-marker-color: var(--color-text-error, var(--color-error));\n\t\t--dp-tooltip-color: var(--color-main-text);\n\t\t--dp-highlight-color: var(--color-main-text);\n\t}\n}\n</style>\n"],"names":["_useModel","value","_openBlock","_createElementBlock","_createVNode","_unref","_mergeProps","confirm","clearable","placeholder","locale","minuteStep","appendToBody","showWeekNumber","_createSlots","_withCtx","showTimezoneSelect","NcTimezonePicker","_createBlock","_Teleport","_createElementVNode"],"mappings":"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"}
1
+ {"version":3,"file":"NcDateTimePicker-DCuHXZjc.mjs","sources":["../../src/components/NcDateTimePicker/NcDateTimePicker.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\nIn general it is recommended to use the native date picker (see `NcDateTimePickerNative` which is based on `<input type=\"date\">`).\nBut some use cases are not covered by the native date selector, like selecting ranges or selecting a timezone.\nFor those cases this component can be used.\n\n### General examples\n```vue\n<template>\n\t<div class=\"wrapper\">\n\t\t<fieldset class=\"type-select\">\n\t\t\t<legend>Picker mode</legend>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"date\">Date</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"datetime\">Date and time</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"week\">Week</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"month\">Month</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"year\">Year</NcCheckboxRadioSwitch>\n\t\t</fieldset>\n\t\t<NcDateTimePicker\n\t\t\tv-model=\"time\"\n\t\t\t:type />\n\t\t<span>{{ time }}</span>\n\t</div>\n</template>\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\ttype: 'date',\n\t\t\ttime: new Date('2022-10-10 10:10:10'),\n\t\t}\n\t},\n}\n</script>\n<style scoped>\n.wrapper {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.type-select {\n\tdisplay: flex;\n\tflex-direction: row;\n\tflex-wrap: wrap;\n}\n</style>\n```\n\n### Example with confirm button\n\nBy default the date is applied as soon as you select the day in the calendar.\nSometimes - especially when selecting date and time - it is required to only emit the selected date when the flow is finished.\nFor this the `confirm` prop can be used, this will add a confirmation button to the selector.\n\n```vue\n<template>\n\t<span>\n\t\t<NcDateTimePicker\n\t\t\tv-model=\"time\"\n\t\t\ttype=\"datetime\"\n\t\t\tconfirm />\n\t\t{{ time }}\n\t</span>\n</template>\n<script>\n\texport default {\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\ttime: null,\n\t\t\t}\n\t\t},\n\t}\n</script>\n```\n\n### Range picker\n\nThe most common use case for the `NcDateTimePicker` is picking a range, as this is not supported by the native date picker.\n\nWhen selecting the range picker type, the model value type will change from `Date` to `[Date, Date]`.\nMeaning an array with two dates is used, the first date is the range start and the second date is the range end.\n\n```vue\n<template>\n\t<div>\n\t\t<fieldset class=\"type-select\">\n\t\t\t<legend>Picker mode</legend>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"date-range\">Date</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"time-range\">Time</NcCheckboxRadioSwitch>\n\t\t\t<NcCheckboxRadioSwitch v-model=\"type\" type=\"radio\" value=\"datetime-range\">Date and time</NcCheckboxRadioSwitch>\n\t\t</fieldset>\n\n\t\t<NcDateTimePicker\n\t\t\t:key=\"type\"\n\t\t\tv-model=\"time\"\n\t\t\t:type />\n\t\t<div>\n\t\t\t<div>Start: {{ formatDate(time[0]) }}</div>\n\t\t\t<div>End: {{ formatDate(time[1]) }}</div>\n\t\t</div>\n\t</div>\n</template>\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\ttime: [new Date(2025, 3, 18, 12, 30), new Date(2025, 3, 21, 13, 30)],\n\t\t\ttype: 'date-range',\n\t\t}\n\t},\n\tmethods: {\n\t\tformatDate(date) {\n\t\t\tconst dateString = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`\n\t\t\tconst timeString = `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`\n\t\t\tif (this.type === 'date-range') {\n\t\t\t\treturn dateString\n\t\t\t} else if (this.type === 'time-range') {\n\t\t\t\treturn timeString\n\t\t\t}\n\t\t\treturn `${dateString} ${timeString}`\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.type-select {\n\tdisplay: flex;\n\tflex-direction: row;\n\tflex-wrap: wrap;\n}\n</style>\n```\n\n### Time zone aware date picker\n\nThe datepicker can optionally include a picker for the preferred time zone. The selected time does not factor in the\npicked time zone, but you will have to convert it yourself when necessary.\n\n```vue\n<template>\n\t<span>\n\t\t<NcDateTimePicker\n\t\t\tv-model=\"time\"\n\t\t\ttype=\"datetime\"\n\t\t\tshow-timezone-select\n\t\t\tv-model:timezone-id=\"tz\" /><br>\n\t\t{{ time }} | {{ tz }}\n\t</span>\n</template>\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\ttime: undefined,\n\t\t\ttz: 'Europe/Berlin',\n\t\t}\n\t},\n}\n</script>\n```\n</docs>\n\n<script setup lang=\"ts\">\nimport type {\n\t// The accepted model value\n\tModelValue as LibraryModelValue,\n\t// The emitted object for time picker\n\tTimeObj as LibraryTimeObject,\n\tVueDatePickerProps,\n} from '@vuepic/vue-datepicker'\n\nimport {\n\tmdiCalendarBlank,\n\tmdiChevronDown,\n\tmdiChevronLeft,\n\tmdiChevronRight,\n\tmdiChevronUp,\n\tmdiClock,\n\tmdiClose,\n} from '@mdi/js'\nimport {\n\tgetCanonicalLocale,\n\tgetDayNames,\n\tgetDayNamesMin,\n\tgetFirstDay,\n} from '@nextcloud/l10n'\nimport VueDatePicker from '@vuepic/vue-datepicker'\nimport { computed, useTemplateRef } from 'vue'\nimport NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'\nimport NcTimezonePicker from '../NcTimezonePicker/NcTimezonePicker.vue'\nimport { t } from '../../l10n.ts'\nimport NcButton from '../NcButton/index.ts'\n\ntype LibraryFormatOptions = VueDatePickerProps['format']\n\n/**\n * The preselected IANA time zone ID for the time zone picker,\n * only relevant in combination with `show-timezone-select`.\n * The prop supports two-way binding through v-model directive.\n *\n * @example `Europe/Berlin`\n * @default 'UTC'\n */\nconst timezoneId = defineModel<string>('timezoneId', { default: 'UTC' })\n\nconst props = withDefaults(defineProps<{\n\t/**\n\t * If set to true the menu will be placed on the `<body>`\n\t * instead of default placement on the picker.\n\t */\n\tappendToBody?: boolean\n\n\t/**\n\t * Aria label for the input box.\n\t *\n\t * @default 'Datepicker input'\n\t */\n\tariaLabel?: string\n\n\t/**\n\t * Aria label for the date picker menu.\n\t *\n\t * @default 'Datepicker menu'\n\t */\n\tariaLabelMenu?: string\n\n\t/**\n\t * Allow to clear the input.\n\t *\n\t * @default false\n\t */\n\tclearable?: boolean\n\n\t/**\n\t * Do not auto-apply the date but require clicking the confirmation button.\n\t *\n\t * @default false\n\t */\n\tconfirm?: boolean\n\n\t/**\n\t * Preview format for the picker input field.\n\t * Can either be a string of Unicode tokens or a function that takes a Date object\n\t * or for range picker an array of two dates, and returns the formatted date as string.\n\t *\n\t * @default Intl.DateTimeFormat is used to format dates and times\n\t * @see https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table\n\t */\n\tformat?: string | ((date: Date) => string) | ((dates: [Date, Date]) => string)\n\n\t/**\n\t * The locale to use for formatting the shown dates.\n\t * By default the users current Nextcloud locale is used.\n\t */\n\tlocale?: string\n\n\t/**\n\t * Default increment step for minutes in the time picker.\n\t *\n\t * @default 10\n\t */\n\tminuteStep?: number\n\n\t/**\n\t * The value to initialize, but also two-way bind the selected date. The date is – like the `Date` object in\n\t * JavaScript – tied to UTC. The selected time zone does not have an influence of the selected time and date\n\t * value. You have to translate the time yourself when you want to factor in time zones.\n\t *\n\t * When using the range picker then an array containing the start and end date needs to be passed.\n\t */\n\tmodelValue?: Date | [Date, Date] | null\n\n\t/**\n\t * Optional custom placeholder for the input box.\n\t */\n\tplaceholder?: string\n\n\t/**\n\t * Include a timezone picker within the menu.\n\t * Please note that the dates are still bound to the locale timezone\n\t * and any conversion needs to be done by the app itself.\n\t *\n\t * @default false\n\t */\n\tshowTimezoneSelect?: boolean\n\n\t/**\n\t * Show the ISO week numbers within the calendar.\n\t *\n\t * @default false\n\t */\n\tshowWeekNumber?: boolean\n\n\t/**\n\t * Type of the picker.\n\t * There is some special handling for ranges as those types require a `[Date, Date]` model value.\n\t * - The 'date-range' type will enable a range picker for dates\n\t * - The 'time-range' allows picking a time range.\n\t * - The 'datetime-range' allows picking dates with times assigned.\n\t *\n\t * @default 'date'\n\t */\n\ttype?: 'date' | 'datetime' | 'time' | 'week' | 'month' | 'year' | 'date-range' | 'time-range' | 'datetime-range'\n}>(), {\n\tariaLabel: t('Datepicker input'),\n\tariaLabelMenu: t('Datepicker menu'),\n\tformat: undefined,\n\tlocale: getCanonicalLocale(),\n\tminuteStep: 10,\n\ttimezoneId: 'UTC',\n\tmodelValue: null,\n\t// set by fallbackPlaceholder\n\tplaceholder: undefined,\n\ttype: 'date',\n})\n\nconst emit = defineEmits<{\n\t/**\n\t * If range picker is enabled then an array containing start and end date are emitted.\n\t * Otherwise the selected date is emitted.\n\t * `null` is emitted if `clearable` is set to `true` and the value was cleared.\n\t */\n\t'update:modelValue': [Date | [Date, Date] | null]\n\t'update:timezoneId': [string]\n}>()\n\nconst targetElement = useTemplateRef('target')\nconst pickerInstance = useTemplateRef('picker')\n\n/**\n * Mapping of the model-value prop to the format expected by the library.\n * We do not directly pass the prop and adjust the interface to not transparently wrap the library.\n * This has show as beeing a pain in the past when we need to switch underlying libraries.\n */\nconst value = computed<LibraryModelValue>(() => {\n\tif (props.modelValue === null && props.clearable) {\n\t\treturn null\n\t}\n\n\tif (props.type === 'week') {\n\t\tconst date = props.modelValue instanceof Date ? props.modelValue : new Date()\n\t\tconst end = new Date(date)\n\t\tend.setUTCDate(date.getUTCDate() + 6)\n\t\treturn [date, end]\n\t} else if (props.type === 'year') {\n\t\tconst date = props.modelValue instanceof Date ? props.modelValue : new Date()\n\t\treturn date.getUTCFullYear()\n\t} else if (props.type === 'month') {\n\t\tconst date = props.modelValue instanceof Date ? props.modelValue : new Date()\n\t\treturn { year: date.getUTCFullYear(), month: date.getUTCMonth() }\n\t} else if (props.type === 'time') {\n\t\tconst time = props.modelValue instanceof Date ? props.modelValue : new Date()\n\t\treturn {\n\t\t\thours: time.getHours(),\n\t\t\tminutes: time.getMinutes(),\n\t\t\tseconds: time.getSeconds(),\n\t\t} satisfies LibraryTimeObject\n\t} else if (props.type === 'time-range') {\n\t\tconst time = [props.modelValue].flat()\n\t\tif (time.length !== 2) {\n\t\t\tconst start = new Date()\n\t\t\tconst end = new Date(start)\n\t\t\tend.setHours(end.getHours() + 1)\n\t\t\ttime.splice(0, 2, start, end)\n\t\t}\n\n\t\treturn (time as [Date, Date]).map((date) => ({\n\t\t\thours: date.getHours(),\n\t\t\tminutes: date.getMinutes(),\n\t\t\tseconds: date.getSeconds(),\n\t\t} as LibraryTimeObject))\n\t} else if (props.type.endsWith('-range')) {\n\t\tif (props.modelValue === undefined) {\n\t\t\tconst start = new Date()\n\t\t\tconst end = new Date(start)\n\t\t\tend.setUTCDate(start.getUTCDate() + 7)\n\t\t\treturn [start, end]\n\t\t}\n\t\treturn props.modelValue\n\t}\n\n\t// no special handling for other types needed\n\treturn props.modelValue ?? new Date()\n})\n\nconst placeholderFallback = computed(() => {\n\tif (props.type === 'date') {\n\t\treturn t('Select date')\n\t} else if (props.type === 'time') {\n\t\treturn t('Select time')\n\t} else if (props.type === 'datetime') {\n\t\treturn t('Select date and time')\n\t} else if (props.type === 'week') {\n\t\treturn t('Select week')\n\t} else if (props.type === 'month') {\n\t\treturn t('Select month')\n\t} else if (props.type === 'year') {\n\t\treturn t('Select year')\n\t} else if (props.type.endsWith('-range')) {\n\t\treturn t('Select time range')\n\t}\n\t// should not be reached\n\treturn t('Select date and time')\n})\n\n/**\n * The date (time) formatting to be used by the library.\n * We use the provided format if possible, otherwise we provide a formatting function\n * which uses the browsers Intl API to format the date / time in the current users locale.\n */\nconst realFormat = computed<LibraryFormatOptions>(() => {\n\tif (props.format) {\n\t\t// we can cast the type here as in this case its either string\n\t\t// function `(Date) => string` or `([Date, Date]) => string` where we cast to `(Date[]) => string` here.\n\t\treturn props.format as LibraryFormatOptions\n\t} else if (props.type === 'week') {\n\t\t// cannot format weeks with Intl.\n\t\treturn 'RR-II'\n\t}\n\n\tlet formatter: Intl.DateTimeFormat | undefined\n\tif (props.type === 'date' || props.type === 'date-range') {\n\t\tformatter = new Intl.DateTimeFormat(getCanonicalLocale(), { dateStyle: 'medium' })\n\t} else if (props.type === 'time' || props.type === 'time-range') {\n\t\tformatter = new Intl.DateTimeFormat(getCanonicalLocale(), { timeStyle: 'short' })\n\t} else if (props.type === 'datetime' || props.type === 'datetime-range') {\n\t\tformatter = new Intl.DateTimeFormat(getCanonicalLocale(), { dateStyle: 'medium', timeStyle: 'short' })\n\t} else if (props.type === 'month') {\n\t\tformatter = new Intl.DateTimeFormat(getCanonicalLocale(), { year: 'numeric', month: '2-digit' })\n\t} else if (props.type === 'year') {\n\t\tformatter = new Intl.DateTimeFormat(getCanonicalLocale(), { year: 'numeric' })\n\t}\n\n\tif (formatter) {\n\t\treturn (input: Date | [Date, Date]) => Array.isArray(input)\n\t\t\t? formatter.formatRange(input[0], input[1])\n\t\t\t: formatter.format(input)\n\t}\n\n\t// fallback to default formatting\n\treturn undefined\n})\n\nconst pickerType = computed(() => ({\n\ttimePicker: props.type === 'time' || props.type === 'time-range',\n\tyearPicker: props.type === 'year',\n\tmonthPicker: props.type === 'month',\n\tweekPicker: props.type === 'week',\n\trange: props.type.endsWith('-range') && {\n\t\t// do not use partial ranges (meaning after selecting the start [Date, null] will be emitted)\n\t\t// if this is needed someday we can enable it,\n\t\t// but its not covered by our component interface (props / events) documentation so just disabled for now.\n\t\tpartialRange: false,\n\t},\n\tenableTimePicker: !(props.type === 'date' || props.type === 'date-range'),\n\tflow: props.type === 'datetime'\n\t\t? ['calendar', 'time'] as ['calendar', 'time']\n\t\t: undefined,\n}))\n\n/**\n * Called on model value update of the library.\n *\n * @param value The value emitted from the underlying library\n */\nfunction onUpdateModelValue(value: LibraryModelValue): void {\n\tif (value === null) {\n\t\treturn emit('update:modelValue', null)\n\t}\n\n\tif (props.type === 'time') {\n\t\t// time is provided as an object\n\t\temit('update:modelValue', formatLibraryTime(value as LibraryTimeObject))\n\t} else if (props.type === 'time-range') {\n\t\t// same as time but as an array with two elements\n\t\tconst start = formatLibraryTime(value[0])\n\t\tconst end = formatLibraryTime(value[1])\n\t\t// ensure end is beyond the start\n\t\tif (end.getTime() < start.getTime()) {\n\t\t\tend.setDate(end.getDate() + 1)\n\t\t}\n\t\temit('update:modelValue', [start, end])\n\t} else if (props.type === 'month') {\n\t\t// month is emitted as an object with month and year attribute\n\t\tconst data = value as { month: number, year: number }\n\t\temit('update:modelValue', new Date(data.year, data.month, 1))\n\t} else if (props.type === 'year') {\n\t\t// Years are emitted as the numeric year e.g. 2022\n\t\temit('update:modelValue', new Date(value as number, 0))\n\t} else if (props.type === 'week') {\n\t\t// weeks are emitted as [Date, Date]\n\t\temit('update:modelValue', value[0])\n\t} else {\n\t\t// otherwise it already emits the correct format\n\t\temit('update:modelValue', value as Date | [Date, Date])\n\t}\n}\n\n/**\n * Format a vuepick time object to native JS Date object.\n *\n * @param time - The library time value object\n */\nfunction formatLibraryTime(time: LibraryTimeObject): Date {\n\tconst date = new Date()\n\tdate.setHours(time.hours)\n\tdate.setMinutes(time.minutes)\n\tdate.setSeconds(time.seconds)\n\treturn date\n}\n\n// Localization\n\nconst weekStart = getFirstDay()\n\nconst dayNames = [...getDayNamesMin()]\n// see https://github.com/Vuepic/vue-datepicker/issues/1159\nfor (let i = 0; i < weekStart; i++) {\n\tdayNames.push(dayNames.shift() as string)\n}\n\n// TRANSLATORS: A very short abbrevation used as a heading for \"week number\"\nconst weekNumName = t('W')\n\nconst ariaLabels = computed(() => ({\n\ttoggleOverlay: t('Toggle overlay'),\n\tmenu: props.ariaLabelMenu,\n\tinput: props.ariaLabel,\n\topenTimePicker: t('Open time picker'),\n\tcloseTimePicker: t('Close time Picker'),\n\tincrementValue: (type: 'hours' | 'minutes' | 'seconds') => {\n\t\tif (type === 'hours') {\n\t\t\treturn t('Increment hours')\n\t\t} else if (type === 'minutes') {\n\t\t\treturn t('Increment minutes')\n\t\t}\n\t\treturn t('Increment seconds')\n\t},\n\tdecrementValue: (type: 'hours' | 'minutes' | 'seconds') => {\n\t\tif (type === 'hours') {\n\t\t\treturn t('Decrement hours')\n\t\t} else if (type === 'minutes') {\n\t\t\treturn t('Decrement minutes')\n\t\t}\n\t\treturn t('Decrement seconds')\n\t},\n\topenTpOverlay: (type: 'hours' | 'minutes' | 'seconds') => {\n\t\tif (type === 'hours') {\n\t\t\treturn t('Open hours overlay')\n\t\t} else if (type === 'minutes') {\n\t\t\treturn t('Open minutes overlay')\n\t\t}\n\t\treturn t('Open seconds overlay')\n\t},\n\tamPmButton: t('Switch AM/PM mode'),\n\topenYearsOverlay: t('Open years overlay'),\n\topenMonthsOverlay: t('Open months overlay'),\n\tnextMonth: t('Next month'),\n\tprevMonth: t('Previous month'),\n\tnextYear: t('Next year'),\n\tprevYear: t('Previous year'),\n\tweekDay: (day: number) => getDayNames()[day],\n\tclearInput: t('Clear value'),\n\tcalendarIcon: t('Calendar icon'),\n\ttimePicker: t('Time picker'),\n\tmonthPicker: (overlay: boolean) => overlay ? t('Month picker overlay') : t('Month picker'),\n\tyearPicker: (overlay: boolean) => overlay ? t('Year picker overlay') : t('Year picker'),\n}))\n\n/**\n * Select the current value.\n * This is used by the confirmation button if `confirmation` was set.\n */\nfunction selectDate() {\n\tpickerInstance.value!.selectDate()\n}\n\n/**\n * Cancel the current selection by closing the overlay.\n * This is used by the confirmation button if `confirmation` was set.\n */\nfunction cancelSelection() {\n\tpickerInstance.value!.closeMenu()\n}\n</script>\n\n<template>\n\t<div class=\"vue-date-time-picker__wrapper\">\n\t\t<VueDatePicker\n\t\t\tref=\"picker\"\n\t\t\t:aria-labels\n\t\t\t:auto-apply=\"!confirm\"\n\t\t\tclass=\"vue-date-time-picker\"\n\t\t\t:class=\"{ 'vue-date-time-picker--clearable': clearable }\"\n\t\t\t:cancel-text=\"t('Cancel')\"\n\t\t\t:clearable\n\t\t\t:day-names\n\t\t\t:placeholder=\"placeholder ?? placeholderFallback\"\n\t\t\t:format=\"realFormat\"\n\t\t\t:locale\n\t\t\t:minutes-increment=\"minuteStep\"\n\t\t\t:model-value=\"value\"\n\t\t\t:now-button-label=\"t('Now')\"\n\t\t\t:select-text=\"t('Pick')\"\n\t\t\tsix-weeks=\"fair\"\n\t\t\t:teleport=\"appendToBody ? (targetElement || undefined) : false\"\n\t\t\ttext-input\n\t\t\t:week-num-name\n\t\t\t:week-numbers=\"showWeekNumber ? { type: 'iso' } : undefined\"\n\t\t\t:week-start\n\t\t\tv-bind=\"pickerType\"\n\t\t\t@update:model-value=\"onUpdateModelValue\">\n\t\t\t<template #action-buttons>\n\t\t\t\t<NcButton size=\"small\" variant=\"tertiary\" @click=\"cancelSelection\">\n\t\t\t\t\t{{ t('Cancel') }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton size=\"small\" variant=\"primary\" @click=\"selectDate\">\n\t\t\t\t\t{{ t('Pick') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<template #clear-icon=\"{ clear }\">\n\t\t\t\t<NcButton\n\t\t\t\t\t:aria-label=\"t('Clear value')\"\n\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\t@click=\"clear\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiClose\" :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<template #input-icon>\n\t\t\t\t<NcIconSvgWrapper :path=\"mdiCalendarBlank\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template #clock-icon>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiClock\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template #arrow-left>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiChevronLeft\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template #arrow-right>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiChevronRight\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template #arrow-down>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiChevronDown\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template #arrow-up>\n\t\t\t\t<NcIconSvgWrapper inline :path=\"mdiChevronUp\" :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"showTimezoneSelect\" #action-extra>\n\t\t\t\t<NcTimezonePicker\n\t\t\t\t\tv-model=\"timezoneId\"\n\t\t\t\t\tclass=\"vue-date-time-picker__timezone\"\n\t\t\t\t\t:append-to-body=\"false\"\n\t\t\t\t\t:input-label=\"t('Time zone')\" />\n\t\t\t</template>\n\t\t</VueDatePicker>\n\t\t<Teleport to=\"body\" :disabled=\"!appendToBody\">\n\t\t\t<div ref=\"target\" class=\"vue-date-time-picker__wrapper vue-date-time-picker__wrapper--teleport\" />\n\t\t</Teleport>\n\t</div>\n</template>\n\n<style scoped lang=\"scss\">\n@use \"sass:meta\";\n\n.vue-date-time-picker__wrapper {\n\t// This is under :root in @vuepic/vue-datepicker/dist/main.css, so importing it scoped won't work\n\t--dp-common-transition: all var(--animation-quick) ease-in;\n\t--dp-menu-padding: 6px 8px;\n\t--dp-animation-duration: var(--animation-quick);\n\t--dp-menu-appear-transition-timing: cubic-bezier(.4, 0, 1, 1);\n\t--dp-transition-timing: ease-out;\n\t--dp-action-row-transtion: all 0.2s ease-in;\n\t--dp-font-family: var(--font-face);\n\t--dp-border-radius: var(--border-radius-element);\n\t--dp-cell-border-radius: var(--border-radius-small);\n\t--dp-transition-length: 22px;\n\t--dp-transition-timing-general: var(--animation-quick);\n\t--dp-button-height: var(--default-clickable-area);\n\t--dp-month-year-row-height: var(--default-clickable-area);\n\t--dp-month-year-row-button-size: var(--clickable-area-small);\n\t--dp-button-icon-height: 20px;\n\t--dp-calendar-wrap-padding: 0 5px;\n\t--dp-cell-size: var(--default-clickable-area);\n\t--dp-cell-padding: 5px;\n\t--dp-common-padding: 10px;\n\t--dp-input-icon-padding: var(--default-clickable-area);\n\t--dp-input-padding: 6px 12px;\n\t--dp-menu-min-width: 260px;\n\t--dp-action-buttons-padding: 1px 6px;\n\t--dp-row-margin: 5px 0;\n\t--dp-calendar-header-cell-padding: 0.5rem;\n\t--dp-multi-calendars-spacing: 10px;\n\t--dp-overlay-col-padding: 3px;\n\t--dp-time-inc-dec-button-size: var(--default-clickable-area);\n\t--dp-font-size: 1rem;\n\t--dp-preview-font-size: var(--font-size-small);\n\t--dp-time-font-size: 2rem;\n\t--dp-action-button-height: var(--clickable-area-small);\n\t--dp-action-row-padding: 8px;\n\t--dp-direction: ltr;\n\n\t// We need to import the vuepic styles, but at least scoped to our class and scope\n\t// plain @import does not work as this will scope all styles imported.\n\t:deep() {\n\t\t@include meta.load-css('@vuepic/vue-datepicker/dist/main.css');\n\t}\n\n\t// When rendered as part of NcActionInput, should be lifted above the NcPopover (99999 < 100000)\n\t&.vue-date-time-picker__wrapper--teleport :deep(.dp--menu-wrapper) {\n\t\tz-index: 100001;\n\t}\n\n\t.vue-date-time-picker--clearable :deep(.dp__input) {\n\t\tpadding-inline-end: var(--default-clickable-area);\n\t}\n\n\t.vue-date-time-picker__timezone {\n\t\tmin-width: unset;\n\t\twidth: 100%;\n\t}\n\n\t:deep(.icon-vue) {\n\t\t// we enforce full opacity to not create a11y issues with contrast\n\t\topacity: 1 !important;\n\t}\n\n\t// time selector button should have consistent padding\n\t:deep(.dp--tp-wrap),\n\t:deep(.dp__action_extra) {\n\t\tpadding: var(--dp-menu-padding);\n\t\tpadding-top: 0;\n\t}\n\n\t:deep(.dp__overlay.dp--overlay-absolute) {\n\t\tpadding: var(--dp-menu-padding);\n\n\t\t.dp__btn.dp__button.dp__button_bottom {\n\t\t\tinset-block-end: 6px;\n\t\t}\n\t}\n\n\t:deep(.dp__btn.dp__button.dp__button_bottom),\n\t:deep(.dp--tp-wrap .dp__button) {\n\t\twidth: 100%;\n\t}\n\n\t:deep(.dp__btn.dp__button.dp__overlay_action) {\n\t\twidth: calc(100% - 16px);\n\t}\n\n\t// fix issues caused by Nextcloud server styles\n\t:deep(input) {\n\t\tpadding-inline-start: var(--dp-input-icon-padding) !important;\n\t}\n\t:deep(.dp__btn) {\n\t\tmargin: 0;\n\t}\n\t:deep(.dp__inner_nav) {\n\t\theight: fit-content;\n\t\twidth: fit-content;\n\t}\n\n\t// make the bottom page toggle stand out better\n\t:deep(.dp__btn.dp__button.dp__button_bottom) {\n\t\tcolor: var(--color-primary-element-light);\n\t\tbackground-color: var(--color-primary-element-light);\n\t}\n\n\t// Fix server styles causing buttons to be primary colored\n\t:deep(.dp--header-wrap .dp__btn:not(.dp__button_bottom)),\n\t:deep(.dp__time_col .dp__btn) {\n\t\tbackground-color: var(--color-main-background);\n\n\t\t&:hover {\n\t\t\tbackground: var(--dp-hover-color);\n\t\t\tcolor: var(--dp-hover-icon-color);\n\t\t}\n\t}\n\n\t// Server styles cause the month and year to be fit-content -> fixing it to be max size.\n\t:deep(.dp__month_year_select) {\n\t\tflex: 1;\n\t}\n\t:deep(.dp--time-overlay-btn) {\n\t\tfont-size: calc(2 * var(--default-font-size)) !important;\n\t}\n\n\t// Adjust padding to prevent horizontal scrolling in time selection\n\t:deep(.dp__time_input .dp__time_col_reg_block) {\n\t\tpadding: 0 calc(4 * var(--default-grid-baseline));\n\t}\n\n\t.vue-date-time-picker.dp__theme_dark,\n\t.vue-date-time-picker.dp__theme_light,\n\t:deep(.dp__theme_dark),\n\t:deep(.dp__theme_light) {\n\t\t--dp-background-color: var(--color-main-background);\n\t\t--dp-text-color: var(--color-main-text);\n\t\t--dp-hover-color: var(--color-primary-element-light-hover);\n\t\t--dp-hover-text-color: var(--color-primary-element-light-text);\n\t\t--dp-hover-icon-color: var(--color-primary-element-light-text);\n\t\t--dp-primary-color: var(--color-primary-element);\n\t\t--dp-primary-disabled-color: var(--color-primary-element-hover);\n\t\t--dp-primary-text-color: var(--color-primary-element-text);\n\t\t--dp-secondary-color: var(--color-text-maxcontrast); // this is used for \"disabled\" dates\n\t\t--dp-border-color: var(--color-border);\n\t\t--dp-menu-border-color: var(--color-border-dark);\n\t\t--dp-border-color-hover: var(--color-border-maxcontrast);\n\t\t--dp-border-color-focus: var(--color-border-maxcontrast);\n\t\t--dp-disabled-color: var(--color-background-dark);\n\t\t--dp-disabled-color-text: var(--color-text-maxcontrast);\n\t\t--dp-scroll-bar-background: var(--color-scrollbar);\n\t\t--dp-scroll-bar-color: var(--color-scrollbar);\n\t\t--dp-success-color: var(--color-success);\n\t\t--dp-success-color-disabled: var(--color-success-hover);\n\t\t--dp-icon-color: var(--color-main-text);\n\t\t--dp-danger-color: var(--color-error);\n\t\t--dp-marker-color: var(--color-text-error, var(--color-error));\n\t\t--dp-tooltip-color: var(--color-main-text);\n\t\t--dp-highlight-color: var(--color-main-text);\n\t}\n}\n</style>\n"],"names":["_useModel","value","_openBlock","_createElementBlock","_createVNode","_unref","_mergeProps","confirm","clearable","placeholder","locale","minuteStep","appendToBody","showWeekNumber","_createSlots","_withCtx","showTimezoneSelect","NcTimezonePicker","_createBlock","_Teleport","_createElementVNode"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { defineComponent, mergeModels, useModel, useSlots, useTemplateRef, compu
3
3
  import { useElementSize } from "@vueuse/core";
4
4
  import { c as createElementId } from "./createElementId-DhjFt1I9.mjs";
5
5
  import { _ as _sfc_main$1 } from "./NcDialogButton.vue_vue_type_script_setup_true_lang-CYpktNKA.mjs";
6
- import { N as NcModal } from "./NcModal-DSCYMxfe.mjs";
6
+ import { N as NcModal } from "./NcModal-D00OJZV2.mjs";
7
7
  import { _ as _export_sfc } from "./_plugin-vue_export-helper-1tPrXgE0.mjs";
8
8
  const _hoisted_1 = ["id", "textContent"];
9
9
  const _hoisted_2 = ["aria-label", "aria-labelledby"];
@@ -164,4 +164,4 @@ const NcDialog = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-c
164
164
  export {
165
165
  NcDialog as N
166
166
  };
167
- //# sourceMappingURL=NcDialog-BTmnYNeo.mjs.map
167
+ //# sourceMappingURL=NcDialog-BHl_LOs_.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"NcDialog-BTmnYNeo.mjs","sources":["../../src/components/NcDialog/NcDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\n### General description\n\nThis component uses the `NcModal` under the hood for allowing users to create generic dialogs.\n\n### Basic example\n```vue\n<template>\n\t<div>\n\t\t<NcButton @click=\"showDialog = true\">Show dialog</NcButton>\n\t\t<NcDialog v-model:open=\"showDialog\" name=\"Confirmation\" message=\"Are you sure to proceed?\" :buttons=\"buttons\" />\n\t\t<p>Last response: {{ lastResponse }}</p>\n\t</div>\n</template>\n<script>\nimport IconCancel from '@mdi/svg/svg/cancel.svg?raw'\nimport IconCheck from '@mdi/svg/svg/check.svg?raw'\n\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tshowDialog: false,\n\t\t\tlastResponse: 'None',\n\t\t\tbuttons: [\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Cancel',\n\t\t\t\t\ticon: IconCancel,\n\t\t\t\t\tcallback: () => { this.lastResponse = 'Pressed \"Cancel\"' },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Ok',\n\t\t\t\t\ttype: 'primary',\n\t\t\t\t\ticon: IconCheck,\n\t\t\t\t\tcallback: () => { this.lastResponse = 'Pressed \"Ok\"' },\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t},\n}\n</script>\n```\n\n### Use custom actions and content\nInstead of using the buttons property, you can also inject your custom actions using a named slot.\nYou can also use the default slot to inject custom content.\n\n```vue\n<template>\n\t<div style=\"display: flex; gap: 12px;\">\n\t\t<NcButton @click=\"showDialog = true\">Show dialog</NcButton>\n\t\t<NcButton @click=\"showLongDialog = true\">Show long dialog</NcButton>\n\t\t<NcDialog v-if=\"showDialog\" name=\"Warning\" no-close>\n\t\t\t<template #actions>\n\t\t\t\t<NcButton @click=\"showDialog = false\">Ok</NcButton>\n\t\t\t</template>\n\t\t\t<div style=\"color: red; font-weight: bold;\">This is serious</div>\n\t\t</NcDialog>\n\t\t<NcDialog v-model:open=\"showLongDialog\" name=\"Lorem Ipsum\">\n\t\t\t<p v-for=\"i in new Array(63)\" :key=\"i\">Lorem ipsum dolor sit amet.</p>\n\t\t</NcDialog>\n\t</div>\n</template>\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tshowDialog: false,\n\t\t\tshowLongDialog: false,\n\t\t}\n\t},\n}\n</script>\n```\n\n### Form example\nIt is also possible to use the dialog for small forms.\nThis can be used when asking for a password, a name or similar to have native form validation.\n\nTo make the dialog a form the `is-form` prop needs to be set.\nWhen using the form variant you can also pass buttons with `nativeType` prop to add a native `submit` button.\n\nNote that this is not possible if the dialog contains a navigation!\n\n```vue\n<template>\n\t<div>\n\t\t<NcButton @click=\"showDialog = true\">Show dialog</NcButton>\n\t\t<NcDialog is-form\n\t\t\t:buttons=\"buttons\"\n\t\t\tname=\"Choose a name\"\n\t\t\tv-model:open=\"showDialog\"\n\t\t\t@submit=\"currentName = newName\"\n\t\t\t@reset=\"newName = ''\"\n\t\t\t@closing=\"newName = ''\">\n\t\t\t<NcTextField v-model=\"newName\"\n\t\t\t\tlabel=\"New name\"\n\t\t\t\tminlength=\"6\"\n\t\t\t\tplaceholder=\"Min. 6 characters\"\n\t\t\t\trequired />\n\t\t</NcDialog>\n\t\t<p>New name: {{ currentName }}</p>\n\t</div>\n</template>\n<script>\nimport IconCheck from '@mdi/svg/svg/check.svg?raw'\n\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tshowDialog: false,\n\t\t\tnewName: '',\n\t\t\tcurrentName: 'none yet.',\n\t\t\tbuttons: [\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Reset',\n\t\t\t\t\tnativeType: 'reset',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Submit',\n\t\t\t\t\ttype: 'primary',\n\t\t\t\t\tnativeType: 'submit',\n\t\t\t\t\ticon: IconCheck,\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t},\n}\n</script>\n```\n\n### Loading buttons\nSometimes a dialog ends with a request and this request might fail due to server-side-validation.\nIn this case it is often desired to keep the dialog open, this can be done by returning `false` from the button callback,\nto not block this callback should return a `Promise<false>`.\n\nIt is also possible to get the result of the callback from the dialog, as the result is passed as the payload of the `closing` event.\n\nWhile the promise is awaited the button will have a loading state,\nthis means, as long as no custom `icon`-slot is used, a loading icon will be shown.\nPlease note that the **button will not be disabled or accessibility reasons**,\nbecause disabled elements cannot be focused and so the loading state could not be communicated e.g. via screen readers.\n\n```vue\n<template>\n\t<div>\n\t\t<NcButton @click=\"openDialog\">Show dialog</NcButton>\n\t\t<NcDialog :buttons=\"buttons\"\n\t\t\tname=\"Create user\"\n\t\t\t:message=\"message\"\n\t\t\t:open.sync=\"showDialog\"\n\t\t\t@closing=\"response = $event\"\n\t\t\t@update:open=\"clickClosesDialog = false\" />\n\t\t<div style=\"margin-top: 8px;\">Dialog response: {{ response }}</div>\n\t</div>\n</template>\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tshowDialog: false,\n\t\t\tclickClosesDialog: false,\n\t\t\tresponse: 'none',\n\t\t}\n\t},\n\n\tmethods: {\n\t\tasync callback() {\n\t\t\t// wait 3 seconds\n\t\t\tawait new Promise((resolve) => window.setTimeout(resolve, 3000))\n\t\t\tthis.clickClosesDialog = !this.clickClosesDialog\n\t\t\t// Do not close the dialog on first and then every second button click\n\t\t\tif (this.clickClosesDialog) {\n\t\t\t\t// return false means the dialog stays open\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn '✅'\n\t\t},\n\n\t\topenDialog() {\n\t\t\tthis.response = 'none'\n\t\t\tthis.showDialog = true\n\t\t},\n\t},\n\n\tcomputed: {\n\t\tbuttons() {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Create user',\n\t\t\t\t\ttype: 'primary',\n\t\t\t\t\tcallback: this.callback,\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\tmessage() {\n\t\t\tif (this.clickClosesDialog) {\n\t\t\t\treturn 'Next button click will work and close the dialog.'\n\t\t\t} else {\n\t\t\t\treturn 'Clicking the button will load but not close the dialog.'\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n```\n</docs>\n\n<script setup lang=\"ts\">\nimport type { Slot } from 'vue'\nimport type { ComponentProps, VueClassType } from '../../utils/VueTypes.ts'\n\nimport { useElementSize } from '@vueuse/core'\nimport { computed, ref, useTemplateRef } from 'vue'\nimport { createElementId } from '../../utils/createElementId.ts'\nimport NcDialogButton from '../NcDialogButton/index.ts'\nimport NcModal from '../NcModal/index.js'\n\ntype NcDialogButtonProps = ComponentProps<typeof NcDialogButton>\n\n/**\n * Whether the dialog should be shown\n */\nconst open = defineModel<boolean>('open', { default: true })\n\nconst props = withDefaults(defineProps<{\n\t/** Name of the dialog (the heading) */\n\tname: string\n\n\t/** Text of the dialog */\n\tmessage?: string\n\n\t/** Additional elements to add to the focus trap */\n\tadditionalTrapElements?: Array<string | HTMLElement>\n\n\t/**\n\t * The element where to mount the dialog, if `null` is passed the dialog is mounted in place.\n\t */\n\tcontainer?: string\n\n\t/**\n\t * Size of the underlying NcModal\n\t */\n\tsize?: 'small' | 'normal' | 'large' | 'full'\n\n\t/**\n\t * Buttons to display\n\t */\n\tbuttons?: NcDialogButtonProps[]\n\n\t/**\n\t * Make the dialog wrapper a HTML form element.\n\t * The buttons will be wrapped within the form so they can be used as submit / reset buttons.\n\t * Please note that when using the property the `navigation` should not be used.\n\t */\n\tisForm?: boolean\n\n\t/**\n\t * Do not show the close button for the dialog.\n\t */\n\tnoClose?: boolean\n\n\t/**\n\t * Close the dialog if the user clicked outside of the dialog\n\t * Only relevant if `noClose` is not set.\n\t */\n\tcloseOnClickOutside?: boolean\n\n\t/**\n\t * Declare if hiding the modal should be animated\n\t */\n\toutTransition?: boolean\n\n\t/**\n\t * aria-label for the dialog navigation.\n\t * Use it when you want to provide a more meaningful label than the dialog name.\n\t *\n\t * By default, navigation is labeled by the dialog name.\n\t */\n\tnavigationAriaLabel?: string\n\n\t/**\n\t * aria-labelledby for the dialog navigation.\n\t * Use it when you have an implicit navigation label (e.g. a heading).\n\t *\n\t * By default, navigation is labeled by the dialog name.\n\t */\n\tnavigationAriaLabelledby?: string\n\n\t/**\n\t * Optionally pass additional classes which will be set on the content wrapper for custom styling\n\t */\n\tcontentClasses?: VueClassType\n\n\t/**\n\t * Optionally pass additional classes which will be set on the dialog itself\n\t * (the default `class` attribute will be set on the modal wrapper)\n\t */\n\tdialogClasses?: VueClassType\n\n\t/**\n\t * Optionally pass additional classes which will be set on the navigation for custom styling\n\t *\n\t * @example\n\t * ```html\n\t * <DialogBase :navigation-classes=\"['mydialog-navigation']\"><!-- --></DialogBase>\n\t * <!-- ... -->\n\t * <style lang=\"scss\">\n\t * :deep(.mydialog-navigation) {\n\t * flex-direction: row-reverse;\n\t * }\n\t * </style>\n\t * ```\n\t */\n\tnavigationClasses?: VueClassType\n}>(), {\n\tadditionalTrapElements: () => [],\n\tbuttons: () => [],\n\tcontainer: 'body',\n\tcontentClasses: '',\n\tdialogClasses: '',\n\tmessage: '',\n\tnavigationAriaLabel: '',\n\tnavigationAriaLabelledby: '',\n\tnavigationClasses: '',\n\tsize: 'small',\n})\n\nconst emit = defineEmits<{\n\t/**\n\t * Emitted when the dialog is closing, so the out transition did not finish yet.\n\t *\n\t * @param result - The result of the button callback (`undefined` if closing because of clicking the 'close'-button)\n\t */\n\tclosing: [result?: unknown]\n\t/**\n\t * Forwarded HTMLFormElement reset event (only if `is-form` is set).\n\t *\n\t * @param event - The forwarded form event\n\t */\n\treset: [event: Event]\n\t/**\n\t * Forwarded HTMLFormElement submit event (only if `is-form` is set)\n\t *\n\t * @param event - The submit event\n\t */\n\tsubmit: [event: SubmitEvent]\n}>()\n\nconst slots = defineSlots<{\n\tactions?: Slot\n\tdefault?: Slot\n\tnavigation?: Slot\n}>()\n\n/**\n * The dialog wrapper element\n */\nconst wrapperElement = useTemplateRef('wrapper')\n\n/**\n * We use the dialog width to decide if we collapse the navigation (flex direction row)\n */\nconst { width: dialogWidth } = useElementSize(wrapperElement, { width: 900, height: 0 })\n\n/**\n * Whether the navigation is collapsed due to dialog and window size\n * (collapses when modal is below: 900px modal width - 2x 12px margin)\n */\nconst isNavigationCollapsed = computed(() => dialogWidth.value < 876)\n\n/**\n * Whether a navigation was passed and the element should be displayed\n */\nconst hasNavigation = computed(() => slots?.navigation !== undefined)\n\n/**\n * The unique id of the nav element\n */\nconst navigationId = createElementId()\n\n/**\n * aria-label attribute for the nav element\n */\nconst navigationAriaLabelAttr = computed(() => props.navigationAriaLabel || undefined)\n\n/**\n * aria-labelledby attribute for the nav element\n */\nconst navigationAriaLabelledbyAttr = computed(() => {\n\tif (props.navigationAriaLabel) {\n\t\t// Not needed, already labelled by aria-label\n\t\treturn undefined\n\t}\n\t// Use dialog name as a fallback label for navigation\n\treturn props.navigationAriaLabelledby || navigationId\n})\n\nconst dialogRootElement = useTemplateRef<HTMLDivElement | HTMLFormElement>('dialogElement')\n/**\n * The HTML element to use for the dialog wrapper - either form or plain div\n */\nconst dialogTagName = computed(() => props.isForm && !hasNavigation.value ? 'form' : 'div')\n/**\n * Listener to assign to the dialog element\n * This only sets the `@submit` listener if the dialog element is a form\n */\nconst dialogListeners = computed(() => {\n\tif (dialogTagName.value !== 'form') {\n\t\treturn {}\n\t}\n\n\treturn {\n\t\t/**\n\t\t * @param event - Form submit event\n\t\t */\n\t\tsubmit(event: SubmitEvent) {\n\t\t\tevent.preventDefault()\n\t\t\temit('submit', event)\n\t\t},\n\n\t\t/**\n\t\t * @param event - Form submit event\n\t\t */\n\t\treset(event: Event) {\n\t\t\tevent.preventDefault()\n\t\t\temit('reset', event)\n\t\t},\n\t}\n})\n\n/**\n * If the underlying modal is shown\n */\nconst showModal = ref(true)\n\n// Because NcModal does not emit `close` when show prop is changed\n/**\n * Handle clicking a dialog button -> should close\n *\n * @param button - The button that was clicked\n * @param result - Result of the callback function\n */\nfunction handleButtonClose(button: NcDialogButtonProps, result: unknown) {\n\t// Skip close on submit if invalid dialog\n\tif (button.type === 'submit'\n\t\t&& dialogTagName.value === 'form'\n\t\t&& 'reportValidity' in dialogRootElement.value!\n\t\t&& !dialogRootElement.value.reportValidity()) {\n\t\treturn\n\t}\n\thandleClosing(result)\n\twindow.setTimeout(() => handleClosed(), 300)\n}\n\n/**\n * Handle closing the dialog, optional out transition did not run yet\n *\n * @param result - The result of the callback\n */\nfunction handleClosing(result?: unknown): void {\n\tshowModal.value = false\n\temit('closing', result)\n}\n\n/**\n * Handle dialog closed (out transition finished)\n */\nfunction handleClosed() {\n\tshowModal.value = true\n\topen.value = false\n}\n\n/**\n * Properties to pass to the underlying NcModal\n */\nconst modalProps = computed(() => ({\n\tnoClose: props.noClose,\n\tcontainer: props.container === undefined ? 'body' : props.container,\n\t// we do not pass the name as we already have the name as the headline\n\t// name: props.name,\n\t// But we need to set the correct label id so the dialog is labelled\n\tlabelId: navigationId,\n\tsize: props.size,\n\tshow: open.value && showModal.value,\n\toutTransition: props.outTransition,\n\tcloseOnClickOutside: props.closeOnClickOutside,\n\tadditionalTrapElements: props.additionalTrapElements,\n}))\n</script>\n\n<template>\n\t<NcModal\n\t\tv-if=\"open\"\n\t\tclass=\"dialog__modal\"\n\t\t:enable-slideshow=\"false\"\n\t\tdisable-swipe\n\t\tv-bind=\"modalProps\"\n\t\t@close=\"handleClosed\"\n\t\t@update:show=\"handleClosing()\">\n\t\t<!-- The dialog name / header -->\n\t\t<h2 :id=\"navigationId\" class=\"dialog__name\" v-text=\"name\" />\n\t\t<component\n\t\t\t:is=\"dialogTagName\"\n\t\t\tref=\"dialogElement\"\n\t\t\tclass=\"dialog\"\n\t\t\t:class=\"dialogClasses\"\n\t\t\tv-on=\"dialogListeners\">\n\t\t\t<div ref=\"wrapper\" class=\"dialog__wrapper\" :class=\"[{ 'dialog__wrapper--collapsed': isNavigationCollapsed }]\">\n\t\t\t\t<!-- When the navigation is collapsed (too small dialog) it is displayed above the main content, otherwise on the inline start -->\n\t\t\t\t<nav\n\t\t\t\t\tv-if=\"hasNavigation\"\n\t\t\t\t\tclass=\"dialog__navigation\"\n\t\t\t\t\t:class=\"navigationClasses\"\n\t\t\t\t\t:aria-label=\"navigationAriaLabelAttr\"\n\t\t\t\t\t:aria-labelledby=\"navigationAriaLabelledbyAttr\">\n\t\t\t\t\t<slot name=\"navigation\" :is-collapsed=\"isNavigationCollapsed\" />\n\t\t\t\t</nav>\n\t\t\t\t<!-- Main dialog content -->\n\t\t\t\t<div class=\"dialog__content\" :class=\"contentClasses\">\n\t\t\t\t\t<slot>\n\t\t\t\t\t\t<p class=\"dialog__text\">\n\t\t\t\t\t\t\t{{ message }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</slot>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<!-- The dialog actions aka the buttons -->\n\t\t\t<div class=\"dialog__actions\">\n\t\t\t\t<slot name=\"actions\">\n\t\t\t\t\t<NcDialogButton\n\t\t\t\t\t\tv-for=\"(button, idx) in buttons\"\n\t\t\t\t\t\t:key=\"idx\"\n\t\t\t\t\t\tv-bind=\"button\"\n\t\t\t\t\t\t@click=\"(_, result) => handleButtonClose(button, result)\" />\n\t\t\t\t</slot>\n\t\t\t</div>\n\t\t</component>\n\t</NcModal>\n</template>\n\n<style lang=\"scss\">\n/** When having the small dialog style we override the modal styling so dialogs look more dialog like */\n@media only screen and (max-width: $breakpoint-small-mobile) {\n\t.dialog__modal .modal-wrapper--small .modal-container {\n\t\twidth: fit-content;\n\t\theight: unset;\n\t\tmax-height: 90%;\n\t\tposition: relative;\n\t\ttop: unset;\n\t\tborder-radius: var(--border-radius-element);\n\t}\n}\n</style>\n\n<style lang=\"scss\" scoped>\n.dialog {\n\theight: 100%;\n\twidth: 100%;\n\tdisplay: flex;\n\tflex-direction: column;\n\tjustify-content: space-between;\n\toverflow: hidden;\n\n\t&__modal {\n\t\t:deep(.modal-wrapper .modal-container) {\n\t\t\tdisplay: flex !important;\n\t\t\tpadding-block: 4px 0; // 4px to align with close button, 0 block-end to make overflowing content on scroll look nice\n\t\t\tpadding-inline: 12px 0; // Same as with padding-block, we need the actions to have a margin of 4px for the button outline\n\t\t}\n\t\t:deep(.modal-wrapper .modal-container__content) {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\toverflow: hidden; // Only overflow on the .dialog__content\n\t\t}\n\t}\n\n\t&__wrapper {\n\t\tdisplay: flex;\n\t\tflex-direction: row;\n\t\t// Auto scale to fit\n\t\tflex: 1;\n\t\tmin-height: 0;\n\t\toverflow: hidden;\n\n\t\t&--collapsed {\n\t\t\tflex-direction: column;\n\t\t}\n\t}\n\n\t&__navigation {\n\t\tdisplay: flex;\n\t\tflex-shrink: 0;\n\t}\n\n\t// Navigation styling when side-by-side with content\n\t&__wrapper:not(&__wrapper--collapsed) &__navigation {\n\t\tflex-direction: column;\n\n\t\toverflow: hidden auto;\n\t\theight: 100%;\n\t\tmin-width: 200px;\n\t\tmargin-inline-end: 20px;\n\t}\n\n\t// Navigation styling when on top of content\n\t&__wrapper#{&}__wrapper--collapsed &__navigation {\n\t\tflex-direction: row;\n\t\tjustify-content: space-between;\n\n\t\toverflow: auto hidden;\n\t\twidth: 100%;\n\t\tmin-width: 100%;\n\t}\n\n\t&__name {\n\t\tfont-size: 21px;\n\n\t\ttext-align: center;\n\t\theight: fit-content;\n\t\tmin-height: var(--default-clickable-area);\n\t\tline-height: var(--default-clickable-area);\n\t\toverflow-wrap: break-word;\n\t\tmargin-block: 0 12px;\n\t}\n\n\t&__content {\n\t\t// Auto fit\n\t\tflex: 1;\n\t\tmin-height: 0;\n\t\toverflow: auto;\n\t\t// see .dialog__modal, we can not set the padding there to prevent floating scroll bars\n\t\tpadding-inline-end: 12px;\n\t}\n\n\t// In case only text content is show\n\t&__text {\n\t\t// Also add padding to the bottom to make it more readable\n\t\tpadding-block-end: 6px;\n\t}\n\n\t&__actions {\n\t\tdisplay: flex;\n\t\tgap: 6px;\n\t\talign-content: center;\n\t\tjustify-content: end;\n\n\t\twidth: 100%;\n\t\tmax-width: 100%;\n\t\tpadding-inline: 0 12px; // 12px to align with the overall modal padding\n\t\tmargin-inline: 0;\n\t\tmargin-block: 0;\n\n\t\t&:not(:empty) {\n\t\t\tmargin-block: 6px 12px; // only if there are actions, we add margin so if it is empty scroll content looks nice\n\t\t}\n\t}\n}\n\n@media only screen and (max-width: $breakpoint-small-mobile) {\n\t// Ensure the dialog name does not interfere with the close button\n\t.dialog__name {\n\t\ttext-align: start;\n\t\tmargin-inline-end: var(--default-clickable-area);\n\t}\n}\n</style>\n"],"names":["_useModel","_useSlots","_openBlock","_createBlock","_unref","_mergeProps","_createElementVNode","_toDisplayString","name","_resolveDynamicComponent","dialogClasses","_toHandlers","_normalizeClass","_createElementBlock","navigationClasses","_renderSlot","contentClasses","message","_Fragment","_renderList","buttons"],"mappings":"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"}
1
+ {"version":3,"file":"NcDialog-BHl_LOs_.mjs","sources":["../../src/components/NcDialog/NcDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\n### General description\n\nThis component uses the `NcModal` under the hood for allowing users to create generic dialogs.\n\n### Basic example\n```vue\n<template>\n\t<div>\n\t\t<NcButton @click=\"showDialog = true\">Show dialog</NcButton>\n\t\t<NcDialog v-model:open=\"showDialog\" name=\"Confirmation\" message=\"Are you sure to proceed?\" :buttons=\"buttons\" />\n\t\t<p>Last response: {{ lastResponse }}</p>\n\t</div>\n</template>\n<script>\nimport IconCancel from '@mdi/svg/svg/cancel.svg?raw'\nimport IconCheck from '@mdi/svg/svg/check.svg?raw'\n\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tshowDialog: false,\n\t\t\tlastResponse: 'None',\n\t\t\tbuttons: [\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Cancel',\n\t\t\t\t\ticon: IconCancel,\n\t\t\t\t\tcallback: () => { this.lastResponse = 'Pressed \"Cancel\"' },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Ok',\n\t\t\t\t\ttype: 'primary',\n\t\t\t\t\ticon: IconCheck,\n\t\t\t\t\tcallback: () => { this.lastResponse = 'Pressed \"Ok\"' },\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t},\n}\n</script>\n```\n\n### Use custom actions and content\nInstead of using the buttons property, you can also inject your custom actions using a named slot.\nYou can also use the default slot to inject custom content.\n\n```vue\n<template>\n\t<div style=\"display: flex; gap: 12px;\">\n\t\t<NcButton @click=\"showDialog = true\">Show dialog</NcButton>\n\t\t<NcButton @click=\"showLongDialog = true\">Show long dialog</NcButton>\n\t\t<NcDialog v-if=\"showDialog\" name=\"Warning\" no-close>\n\t\t\t<template #actions>\n\t\t\t\t<NcButton @click=\"showDialog = false\">Ok</NcButton>\n\t\t\t</template>\n\t\t\t<div style=\"color: red; font-weight: bold;\">This is serious</div>\n\t\t</NcDialog>\n\t\t<NcDialog v-model:open=\"showLongDialog\" name=\"Lorem Ipsum\">\n\t\t\t<p v-for=\"i in new Array(63)\" :key=\"i\">Lorem ipsum dolor sit amet.</p>\n\t\t</NcDialog>\n\t</div>\n</template>\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tshowDialog: false,\n\t\t\tshowLongDialog: false,\n\t\t}\n\t},\n}\n</script>\n```\n\n### Form example\nIt is also possible to use the dialog for small forms.\nThis can be used when asking for a password, a name or similar to have native form validation.\n\nTo make the dialog a form the `is-form` prop needs to be set.\nWhen using the form variant you can also pass buttons with `nativeType` prop to add a native `submit` button.\n\nNote that this is not possible if the dialog contains a navigation!\n\n```vue\n<template>\n\t<div>\n\t\t<NcButton @click=\"showDialog = true\">Show dialog</NcButton>\n\t\t<NcDialog is-form\n\t\t\t:buttons=\"buttons\"\n\t\t\tname=\"Choose a name\"\n\t\t\tv-model:open=\"showDialog\"\n\t\t\t@submit=\"currentName = newName\"\n\t\t\t@reset=\"newName = ''\"\n\t\t\t@closing=\"newName = ''\">\n\t\t\t<NcTextField v-model=\"newName\"\n\t\t\t\tlabel=\"New name\"\n\t\t\t\tminlength=\"6\"\n\t\t\t\tplaceholder=\"Min. 6 characters\"\n\t\t\t\trequired />\n\t\t</NcDialog>\n\t\t<p>New name: {{ currentName }}</p>\n\t</div>\n</template>\n<script>\nimport IconCheck from '@mdi/svg/svg/check.svg?raw'\n\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tshowDialog: false,\n\t\t\tnewName: '',\n\t\t\tcurrentName: 'none yet.',\n\t\t\tbuttons: [\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Reset',\n\t\t\t\t\tnativeType: 'reset',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Submit',\n\t\t\t\t\ttype: 'primary',\n\t\t\t\t\tnativeType: 'submit',\n\t\t\t\t\ticon: IconCheck,\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t},\n}\n</script>\n```\n\n### Loading buttons\nSometimes a dialog ends with a request and this request might fail due to server-side-validation.\nIn this case it is often desired to keep the dialog open, this can be done by returning `false` from the button callback,\nto not block this callback should return a `Promise<false>`.\n\nIt is also possible to get the result of the callback from the dialog, as the result is passed as the payload of the `closing` event.\n\nWhile the promise is awaited the button will have a loading state,\nthis means, as long as no custom `icon`-slot is used, a loading icon will be shown.\nPlease note that the **button will not be disabled or accessibility reasons**,\nbecause disabled elements cannot be focused and so the loading state could not be communicated e.g. via screen readers.\n\n```vue\n<template>\n\t<div>\n\t\t<NcButton @click=\"openDialog\">Show dialog</NcButton>\n\t\t<NcDialog :buttons=\"buttons\"\n\t\t\tname=\"Create user\"\n\t\t\t:message=\"message\"\n\t\t\t:open.sync=\"showDialog\"\n\t\t\t@closing=\"response = $event\"\n\t\t\t@update:open=\"clickClosesDialog = false\" />\n\t\t<div style=\"margin-top: 8px;\">Dialog response: {{ response }}</div>\n\t</div>\n</template>\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tshowDialog: false,\n\t\t\tclickClosesDialog: false,\n\t\t\tresponse: 'none',\n\t\t}\n\t},\n\n\tmethods: {\n\t\tasync callback() {\n\t\t\t// wait 3 seconds\n\t\t\tawait new Promise((resolve) => window.setTimeout(resolve, 3000))\n\t\t\tthis.clickClosesDialog = !this.clickClosesDialog\n\t\t\t// Do not close the dialog on first and then every second button click\n\t\t\tif (this.clickClosesDialog) {\n\t\t\t\t// return false means the dialog stays open\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn '✅'\n\t\t},\n\n\t\topenDialog() {\n\t\t\tthis.response = 'none'\n\t\t\tthis.showDialog = true\n\t\t},\n\t},\n\n\tcomputed: {\n\t\tbuttons() {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Create user',\n\t\t\t\t\ttype: 'primary',\n\t\t\t\t\tcallback: this.callback,\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\tmessage() {\n\t\t\tif (this.clickClosesDialog) {\n\t\t\t\treturn 'Next button click will work and close the dialog.'\n\t\t\t} else {\n\t\t\t\treturn 'Clicking the button will load but not close the dialog.'\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n```\n</docs>\n\n<script setup lang=\"ts\">\nimport type { Slot } from 'vue'\nimport type { ComponentProps, VueClassType } from '../../utils/VueTypes.ts'\n\nimport { useElementSize } from '@vueuse/core'\nimport { computed, ref, useTemplateRef } from 'vue'\nimport { createElementId } from '../../utils/createElementId.ts'\nimport NcDialogButton from '../NcDialogButton/index.ts'\nimport NcModal from '../NcModal/index.js'\n\ntype NcDialogButtonProps = ComponentProps<typeof NcDialogButton>\n\n/**\n * Whether the dialog should be shown\n */\nconst open = defineModel<boolean>('open', { default: true })\n\nconst props = withDefaults(defineProps<{\n\t/** Name of the dialog (the heading) */\n\tname: string\n\n\t/** Text of the dialog */\n\tmessage?: string\n\n\t/** Additional elements to add to the focus trap */\n\tadditionalTrapElements?: Array<string | HTMLElement>\n\n\t/**\n\t * The element where to mount the dialog, if `null` is passed the dialog is mounted in place.\n\t */\n\tcontainer?: string\n\n\t/**\n\t * Size of the underlying NcModal\n\t */\n\tsize?: 'small' | 'normal' | 'large' | 'full'\n\n\t/**\n\t * Buttons to display\n\t */\n\tbuttons?: NcDialogButtonProps[]\n\n\t/**\n\t * Make the dialog wrapper a HTML form element.\n\t * The buttons will be wrapped within the form so they can be used as submit / reset buttons.\n\t * Please note that when using the property the `navigation` should not be used.\n\t */\n\tisForm?: boolean\n\n\t/**\n\t * Do not show the close button for the dialog.\n\t */\n\tnoClose?: boolean\n\n\t/**\n\t * Close the dialog if the user clicked outside of the dialog\n\t * Only relevant if `noClose` is not set.\n\t */\n\tcloseOnClickOutside?: boolean\n\n\t/**\n\t * Declare if hiding the modal should be animated\n\t */\n\toutTransition?: boolean\n\n\t/**\n\t * aria-label for the dialog navigation.\n\t * Use it when you want to provide a more meaningful label than the dialog name.\n\t *\n\t * By default, navigation is labeled by the dialog name.\n\t */\n\tnavigationAriaLabel?: string\n\n\t/**\n\t * aria-labelledby for the dialog navigation.\n\t * Use it when you have an implicit navigation label (e.g. a heading).\n\t *\n\t * By default, navigation is labeled by the dialog name.\n\t */\n\tnavigationAriaLabelledby?: string\n\n\t/**\n\t * Optionally pass additional classes which will be set on the content wrapper for custom styling\n\t */\n\tcontentClasses?: VueClassType\n\n\t/**\n\t * Optionally pass additional classes which will be set on the dialog itself\n\t * (the default `class` attribute will be set on the modal wrapper)\n\t */\n\tdialogClasses?: VueClassType\n\n\t/**\n\t * Optionally pass additional classes which will be set on the navigation for custom styling\n\t *\n\t * @example\n\t * ```html\n\t * <DialogBase :navigation-classes=\"['mydialog-navigation']\"><!-- --></DialogBase>\n\t * <!-- ... -->\n\t * <style lang=\"scss\">\n\t * :deep(.mydialog-navigation) {\n\t * flex-direction: row-reverse;\n\t * }\n\t * </style>\n\t * ```\n\t */\n\tnavigationClasses?: VueClassType\n}>(), {\n\tadditionalTrapElements: () => [],\n\tbuttons: () => [],\n\tcontainer: 'body',\n\tcontentClasses: '',\n\tdialogClasses: '',\n\tmessage: '',\n\tnavigationAriaLabel: '',\n\tnavigationAriaLabelledby: '',\n\tnavigationClasses: '',\n\tsize: 'small',\n})\n\nconst emit = defineEmits<{\n\t/**\n\t * Emitted when the dialog is closing, so the out transition did not finish yet.\n\t *\n\t * @param result - The result of the button callback (`undefined` if closing because of clicking the 'close'-button)\n\t */\n\tclosing: [result?: unknown]\n\t/**\n\t * Forwarded HTMLFormElement reset event (only if `is-form` is set).\n\t *\n\t * @param event - The forwarded form event\n\t */\n\treset: [event: Event]\n\t/**\n\t * Forwarded HTMLFormElement submit event (only if `is-form` is set)\n\t *\n\t * @param event - The submit event\n\t */\n\tsubmit: [event: SubmitEvent]\n}>()\n\nconst slots = defineSlots<{\n\tactions?: Slot\n\tdefault?: Slot\n\tnavigation?: Slot\n}>()\n\n/**\n * The dialog wrapper element\n */\nconst wrapperElement = useTemplateRef('wrapper')\n\n/**\n * We use the dialog width to decide if we collapse the navigation (flex direction row)\n */\nconst { width: dialogWidth } = useElementSize(wrapperElement, { width: 900, height: 0 })\n\n/**\n * Whether the navigation is collapsed due to dialog and window size\n * (collapses when modal is below: 900px modal width - 2x 12px margin)\n */\nconst isNavigationCollapsed = computed(() => dialogWidth.value < 876)\n\n/**\n * Whether a navigation was passed and the element should be displayed\n */\nconst hasNavigation = computed(() => slots?.navigation !== undefined)\n\n/**\n * The unique id of the nav element\n */\nconst navigationId = createElementId()\n\n/**\n * aria-label attribute for the nav element\n */\nconst navigationAriaLabelAttr = computed(() => props.navigationAriaLabel || undefined)\n\n/**\n * aria-labelledby attribute for the nav element\n */\nconst navigationAriaLabelledbyAttr = computed(() => {\n\tif (props.navigationAriaLabel) {\n\t\t// Not needed, already labelled by aria-label\n\t\treturn undefined\n\t}\n\t// Use dialog name as a fallback label for navigation\n\treturn props.navigationAriaLabelledby || navigationId\n})\n\nconst dialogRootElement = useTemplateRef<HTMLDivElement | HTMLFormElement>('dialogElement')\n/**\n * The HTML element to use for the dialog wrapper - either form or plain div\n */\nconst dialogTagName = computed(() => props.isForm && !hasNavigation.value ? 'form' : 'div')\n/**\n * Listener to assign to the dialog element\n * This only sets the `@submit` listener if the dialog element is a form\n */\nconst dialogListeners = computed(() => {\n\tif (dialogTagName.value !== 'form') {\n\t\treturn {}\n\t}\n\n\treturn {\n\t\t/**\n\t\t * @param event - Form submit event\n\t\t */\n\t\tsubmit(event: SubmitEvent) {\n\t\t\tevent.preventDefault()\n\t\t\temit('submit', event)\n\t\t},\n\n\t\t/**\n\t\t * @param event - Form submit event\n\t\t */\n\t\treset(event: Event) {\n\t\t\tevent.preventDefault()\n\t\t\temit('reset', event)\n\t\t},\n\t}\n})\n\n/**\n * If the underlying modal is shown\n */\nconst showModal = ref(true)\n\n// Because NcModal does not emit `close` when show prop is changed\n/**\n * Handle clicking a dialog button -> should close\n *\n * @param button - The button that was clicked\n * @param result - Result of the callback function\n */\nfunction handleButtonClose(button: NcDialogButtonProps, result: unknown) {\n\t// Skip close on submit if invalid dialog\n\tif (button.type === 'submit'\n\t\t&& dialogTagName.value === 'form'\n\t\t&& 'reportValidity' in dialogRootElement.value!\n\t\t&& !dialogRootElement.value.reportValidity()) {\n\t\treturn\n\t}\n\thandleClosing(result)\n\twindow.setTimeout(() => handleClosed(), 300)\n}\n\n/**\n * Handle closing the dialog, optional out transition did not run yet\n *\n * @param result - The result of the callback\n */\nfunction handleClosing(result?: unknown): void {\n\tshowModal.value = false\n\temit('closing', result)\n}\n\n/**\n * Handle dialog closed (out transition finished)\n */\nfunction handleClosed() {\n\tshowModal.value = true\n\topen.value = false\n}\n\n/**\n * Properties to pass to the underlying NcModal\n */\nconst modalProps = computed(() => ({\n\tnoClose: props.noClose,\n\tcontainer: props.container === undefined ? 'body' : props.container,\n\t// we do not pass the name as we already have the name as the headline\n\t// name: props.name,\n\t// But we need to set the correct label id so the dialog is labelled\n\tlabelId: navigationId,\n\tsize: props.size,\n\tshow: open.value && showModal.value,\n\toutTransition: props.outTransition,\n\tcloseOnClickOutside: props.closeOnClickOutside,\n\tadditionalTrapElements: props.additionalTrapElements,\n}))\n</script>\n\n<template>\n\t<NcModal\n\t\tv-if=\"open\"\n\t\tclass=\"dialog__modal\"\n\t\t:enable-slideshow=\"false\"\n\t\tdisable-swipe\n\t\tv-bind=\"modalProps\"\n\t\t@close=\"handleClosed\"\n\t\t@update:show=\"handleClosing()\">\n\t\t<!-- The dialog name / header -->\n\t\t<h2 :id=\"navigationId\" class=\"dialog__name\" v-text=\"name\" />\n\t\t<component\n\t\t\t:is=\"dialogTagName\"\n\t\t\tref=\"dialogElement\"\n\t\t\tclass=\"dialog\"\n\t\t\t:class=\"dialogClasses\"\n\t\t\tv-on=\"dialogListeners\">\n\t\t\t<div ref=\"wrapper\" class=\"dialog__wrapper\" :class=\"[{ 'dialog__wrapper--collapsed': isNavigationCollapsed }]\">\n\t\t\t\t<!-- When the navigation is collapsed (too small dialog) it is displayed above the main content, otherwise on the inline start -->\n\t\t\t\t<nav\n\t\t\t\t\tv-if=\"hasNavigation\"\n\t\t\t\t\tclass=\"dialog__navigation\"\n\t\t\t\t\t:class=\"navigationClasses\"\n\t\t\t\t\t:aria-label=\"navigationAriaLabelAttr\"\n\t\t\t\t\t:aria-labelledby=\"navigationAriaLabelledbyAttr\">\n\t\t\t\t\t<slot name=\"navigation\" :is-collapsed=\"isNavigationCollapsed\" />\n\t\t\t\t</nav>\n\t\t\t\t<!-- Main dialog content -->\n\t\t\t\t<div class=\"dialog__content\" :class=\"contentClasses\">\n\t\t\t\t\t<slot>\n\t\t\t\t\t\t<p class=\"dialog__text\">\n\t\t\t\t\t\t\t{{ message }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</slot>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<!-- The dialog actions aka the buttons -->\n\t\t\t<div class=\"dialog__actions\">\n\t\t\t\t<slot name=\"actions\">\n\t\t\t\t\t<NcDialogButton\n\t\t\t\t\t\tv-for=\"(button, idx) in buttons\"\n\t\t\t\t\t\t:key=\"idx\"\n\t\t\t\t\t\tv-bind=\"button\"\n\t\t\t\t\t\t@click=\"(_, result) => handleButtonClose(button, result)\" />\n\t\t\t\t</slot>\n\t\t\t</div>\n\t\t</component>\n\t</NcModal>\n</template>\n\n<style lang=\"scss\">\n/** When having the small dialog style we override the modal styling so dialogs look more dialog like */\n@media only screen and (max-width: $breakpoint-small-mobile) {\n\t.dialog__modal .modal-wrapper--small .modal-container {\n\t\twidth: fit-content;\n\t\theight: unset;\n\t\tmax-height: 90%;\n\t\tposition: relative;\n\t\ttop: unset;\n\t\tborder-radius: var(--border-radius-element);\n\t}\n}\n</style>\n\n<style lang=\"scss\" scoped>\n.dialog {\n\theight: 100%;\n\twidth: 100%;\n\tdisplay: flex;\n\tflex-direction: column;\n\tjustify-content: space-between;\n\toverflow: hidden;\n\n\t&__modal {\n\t\t:deep(.modal-wrapper .modal-container) {\n\t\t\tdisplay: flex !important;\n\t\t\tpadding-block: 4px 0; // 4px to align with close button, 0 block-end to make overflowing content on scroll look nice\n\t\t\tpadding-inline: 12px 0; // Same as with padding-block, we need the actions to have a margin of 4px for the button outline\n\t\t}\n\t\t:deep(.modal-wrapper .modal-container__content) {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\toverflow: hidden; // Only overflow on the .dialog__content\n\t\t}\n\t}\n\n\t&__wrapper {\n\t\tdisplay: flex;\n\t\tflex-direction: row;\n\t\t// Auto scale to fit\n\t\tflex: 1;\n\t\tmin-height: 0;\n\t\toverflow: hidden;\n\n\t\t&--collapsed {\n\t\t\tflex-direction: column;\n\t\t}\n\t}\n\n\t&__navigation {\n\t\tdisplay: flex;\n\t\tflex-shrink: 0;\n\t}\n\n\t// Navigation styling when side-by-side with content\n\t&__wrapper:not(&__wrapper--collapsed) &__navigation {\n\t\tflex-direction: column;\n\n\t\toverflow: hidden auto;\n\t\theight: 100%;\n\t\tmin-width: 200px;\n\t\tmargin-inline-end: 20px;\n\t}\n\n\t// Navigation styling when on top of content\n\t&__wrapper#{&}__wrapper--collapsed &__navigation {\n\t\tflex-direction: row;\n\t\tjustify-content: space-between;\n\n\t\toverflow: auto hidden;\n\t\twidth: 100%;\n\t\tmin-width: 100%;\n\t}\n\n\t&__name {\n\t\tfont-size: 21px;\n\n\t\ttext-align: center;\n\t\theight: fit-content;\n\t\tmin-height: var(--default-clickable-area);\n\t\tline-height: var(--default-clickable-area);\n\t\toverflow-wrap: break-word;\n\t\tmargin-block: 0 12px;\n\t}\n\n\t&__content {\n\t\t// Auto fit\n\t\tflex: 1;\n\t\tmin-height: 0;\n\t\toverflow: auto;\n\t\t// see .dialog__modal, we can not set the padding there to prevent floating scroll bars\n\t\tpadding-inline-end: 12px;\n\t}\n\n\t// In case only text content is show\n\t&__text {\n\t\t// Also add padding to the bottom to make it more readable\n\t\tpadding-block-end: 6px;\n\t}\n\n\t&__actions {\n\t\tdisplay: flex;\n\t\tgap: 6px;\n\t\talign-content: center;\n\t\tjustify-content: end;\n\n\t\twidth: 100%;\n\t\tmax-width: 100%;\n\t\tpadding-inline: 0 12px; // 12px to align with the overall modal padding\n\t\tmargin-inline: 0;\n\t\tmargin-block: 0;\n\n\t\t&:not(:empty) {\n\t\t\tmargin-block: 6px 12px; // only if there are actions, we add margin so if it is empty scroll content looks nice\n\t\t}\n\t}\n}\n\n@media only screen and (max-width: $breakpoint-small-mobile) {\n\t// Ensure the dialog name does not interfere with the close button\n\t.dialog__name {\n\t\ttext-align: start;\n\t\tmargin-inline-end: var(--default-clickable-area);\n\t}\n}\n</style>\n"],"names":["_useModel","_useSlots","_openBlock","_createBlock","_unref","_mergeProps","_createElementVNode","_toDisplayString","name","_resolveDynamicComponent","dialogClasses","_toHandlers","_normalizeClass","_createElementBlock","navigationClasses","_renderSlot","contentClasses","message","_Fragment","_renderList","buttons"],"mappings":"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"}
@@ -4,14 +4,14 @@ import { Picker, Emoji, EmojiIndex } from "emoji-mart-vue-fast/src/index.js";
4
4
  import { isFocusable } from "tabbable";
5
5
  import { createElementBlock, openBlock, mergeProps, createElementVNode, createCommentVNode, toDisplayString, resolveComponent, createBlock, withCtx, createVNode, withKeys, withModifiers, createSlots, normalizeStyle, renderSlot, normalizeProps, guardReactiveProps } from "vue";
6
6
  import { _ as _export_sfc } from "./_plugin-vue_export-helper-1tPrXgE0.mjs";
7
- import { N as NcColorPicker } from "./NcColorPicker-DpSDaGrh.mjs";
7
+ import { N as NcColorPicker } from "./NcColorPicker-3wpX7pKD.mjs";
8
8
  import { u as useTrapStackControl } from "./useTrapStackControl-B6cEicto.mjs";
9
9
  import { s as setCurrentSkinTone, g as getCurrentSkinTone } from "./emoji-BY_D0V5K.mjs";
10
10
  import { r as register, q as t42, s as t37, u as t16, v as t5, a as t } from "./_l10n-CgsPi8nC.mjs";
11
11
  import { C as Color } from "./colors-CL_wvNtd.mjs";
12
12
  import { N as NcButton } from "./NcButton-CzpKEx4V.mjs";
13
13
  import { N as NcPopover } from "./NcPopover-C-MTaPCs.mjs";
14
- import { _ as _sfc_main$2 } from "./NcTextField.vue_vue_type_script_setup_true_lang-BfjSL2EJ.mjs";
14
+ import { _ as _sfc_main$2 } from "./NcTextField.vue_vue_type_script_setup_true_lang-CCsZqnkM.mjs";
15
15
  const _sfc_main$1 = {
16
16
  name: "CircleIcon",
17
17
  emits: ["click"],
@@ -403,4 +403,4 @@ const NcEmojiPicker = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_re
403
403
  export {
404
404
  NcEmojiPicker as N
405
405
  };
406
- //# sourceMappingURL=NcEmojiPicker-U5k_zceS.mjs.map
406
+ //# sourceMappingURL=NcEmojiPicker-CReazifM.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"NcEmojiPicker-U5k_zceS.mjs","sources":["../../node_modules/vue-material-design-icons/Circle.vue","../../src/components/NcEmojiPicker/NcEmojiPicker.vue"],"sourcesContent":["<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon circle-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"CircleIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<!--\n - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\n### General description\n\nThis component allows the user to pick an emoji.\n\n### Usage\n\n* Listen to the select event and pass in an HTML element that will be treated as a trigger:\n\n```vue\n<template>\n\t<div>\n\t\t<NcEmojiPicker @select=\"select\" style=\"display: inline-block\">\n\t\t\t<NcButton> Click Me </NcButton>\n\t\t</NcEmojiPicker>\n\t\t<span>selected emoji: {{ emoji }}</span>\n\t</div>\n</template>\n<script>\n\texport default {\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\temoji: '',\n\t\t\t}\n\t\t},\n\t\tmethods: {\n\t\t\tselect(emoji) {\n\t\t\t\tthis.emoji = emoji\n\t\t\t},\n\t\t},\n\t}\n</script>\n```\n\n* Showing a preview and keeping it open after a user selected an emoji\n\n```vue\n<template>\n\t<div>\n\t\t<NcEmojiPicker\n\t\t\t:close-on-select=\"false\"\n\t\t\t:show-preview=\"true\"\n\t\t\t@select=\"select\"\n\t\t\tstyle=\"display: inline-block\">\n\t\t\t<NcButton> Click Me </NcButton>\n\t\t</NcEmojiPicker>\n\t\t<span>selected emoji: {{ emoji }}</span>\n\t</div>\n</template>\n<script>\n\texport default {\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\temoji: '',\n\t\t\t}\n\t\t},\n\t\tmethods: {\n\t\t\tselect(emoji) {\n\t\t\t\tthis.emoji = emoji\n\t\t\t},\n\t\t},\n\t}\n</script>\n```\n\n* Allow unselecting a previously set emoji.\n\n```vue\n<template>\n\t<div>\n\t\t<NcEmojiPicker\n\t\t\t:show-preview=\"true\"\n\t\t\t:allow-unselect=\"true\"\n\t\t\t:selected-emoji=\"emoji\"\n\t\t\t@select=\"select\"\n\t\t\t@unselect=\"unselect\"\n\t\t\tstyle=\"display: inline-block\">\n\t\t\t<NcButton> Click Me </NcButton>\n\t\t</NcEmojiPicker>\n\t\t<span>selected emoji: {{ emoji }}</span>\n\t</div>\n</template>\n<script>\n\texport default {\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\temoji: '',\n\t\t\t}\n\t\t},\n\t\tmethods: {\n\t\t\tselect(emoji) {\n\t\t\t\tthis.emoji = emoji\n\t\t\t},\n\t\t\tunselect() {\n\t\t\t\tthis.emoji = ''\n\t\t\t},\n\t\t},\n\t}\n</script>\n```\n\n</docs>\n\n<template>\n\t<NcPopover\n\t\tref=\"popover\"\n\t\tv-model:shown=\"open\"\n\t\t:container=\"container\"\n\t\tpopup-role=\"dialog\"\n\t\t:no-focus-trap=\"true /* Handled manually to remove emoji buttons from TAB sequence */\"\n\t\t@after-show=\"afterShow\"\n\t\t@after-hide=\"afterHide\">\n\t\t<template #trigger=\"slotProps\">\n\t\t\t<slot v-bind=\"slotProps\" />\n\t\t</template>\n\t\t<div class=\"nc-emoji-picker-container\">\n\t\t\t<Picker\n\t\t\t\tref=\"picker\"\n\t\t\t\tcolor=\"var(--color-primary-element)\"\n\t\t\t\t:data=\"emojiIndex\"\n\t\t\t\t:emoji=\"previewFallbackEmoji\"\n\t\t\t\t:i18n\n\t\t\t\t:native\n\t\t\t\t:emoji-size=\"20\"\n\t\t\t\t:per-line=\"8\"\n\t\t\t\t:picker-styles=\"{ width: '320px' }\"\n\t\t\t\t:show-preview\n\t\t\t\t:skin=\"currentSkinTone\"\n\t\t\t\t:show-skin-tones=\"false\"\n\t\t\t\t:title=\"previewFallbackName\"\n\t\t\t\trole=\"dialog\"\n\t\t\t\taria-modal=\"true\"\n\t\t\t\t:aria-label=\"t('Emoji picker')\"\n\t\t\t\tv-bind=\"$attrs\"\n\t\t\t\t@keydown.tab.prevent=\"handleTabNavigationSkippingEmojis\"\n\t\t\t\t@select=\"select\">\n\t\t\t\t<template #searchTemplate=\"{ onSearch }\">\n\t\t\t\t\t<div class=\"search__wrapper\">\n\t\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t\tref=\"search\"\n\t\t\t\t\t\t\tv-model=\"search\"\n\t\t\t\t\t\t\tclass=\"search\"\n\t\t\t\t\t\t\t:label=\"t('Search')\"\n\t\t\t\t\t\t\t:label-visible=\"true\"\n\t\t\t\t\t\t\t:placeholder=\"i18n.search\"\n\t\t\t\t\t\t\ttrailing-button-icon=\"close\"\n\t\t\t\t\t\t\t:trailing-button-label=\"t('Clear search')\"\n\t\t\t\t\t\t\t:show-trailing-button=\"search !== ''\"\n\t\t\t\t\t\t\t@keydown.left=\"callPickerArrowHandlerWithScrollFix('onArrowLeft', $event)\"\n\t\t\t\t\t\t\t@keydown.right=\"callPickerArrowHandlerWithScrollFix('onArrowRight', $event)\"\n\t\t\t\t\t\t\t@keydown.down=\"callPickerArrowHandlerWithScrollFix('onArrowDown', $event)\"\n\t\t\t\t\t\t\t@keydown.up=\"callPickerArrowHandlerWithScrollFix('onArrowUp', $event)\"\n\t\t\t\t\t\t\t@keydown.enter=\"$refs.picker.onEnter($event)\"\n\t\t\t\t\t\t\t@trailing-button-click=\"clearSearch(); onSearch('');\"\n\t\t\t\t\t\t\t@update:model-value=\"onSearch(search)\" />\n\t\t\t\t\t\t<NcColorPicker\n\t\t\t\t\t\t\tpalette-only\n\t\t\t\t\t\t\t:container\n\t\t\t\t\t\t\t:palette=\"skinTonePalette\"\n\t\t\t\t\t\t\t:model-value=\"currentColor.color\"\n\t\t\t\t\t\t\t@update:model-value=\"onChangeSkinTone\">\n\t\t\t\t\t\t\t<NcButton :aria-label=\"t('Skin tone')\" variant=\"tertiary-no-background\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<IconCircle :style=\"{ color: currentColor.color }\" :title=\"currentColor.name\" :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</NcColorPicker>\n\t\t\t\t\t</div>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"allowUnselect && selectedEmoji\" #customCategory>\n\t\t\t\t\t<div class=\"emoji-mart-category-label\">\n\t\t\t\t\t\t<h3 class=\"emoji-mart-category-label\">\n\t\t\t\t\t\t\t{{ t('Selected') }}\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t</div>\n\t\t\t\t\t<Emoji\n\t\t\t\t\t\tclass=\"emoji-selected\"\n\t\t\t\t\t\t:data=\"emojiIndex\"\n\t\t\t\t\t\t:emoji=\"selectedEmoji\"\n\t\t\t\t\t\tnative\n\t\t\t\t\t\t:size=\"32\"\n\t\t\t\t\t\t@click=\"unselect\" />\n\t\t\t\t\t<Emoji\n\t\t\t\t\t\tclass=\"emoji-delete\"\n\t\t\t\t\t\t:data=\"emojiIndex\"\n\t\t\t\t\t\temoji=\":x:\"\n\t\t\t\t\t\tnative\n\t\t\t\t\t\t:size=\"10\"\n\t\t\t\t\t\t@click=\"unselect\" />\n\t\t\t\t</template>\n\t\t\t</Picker>\n\t\t</div>\n\t</NcPopover>\n</template>\n\n<script>\nimport data from 'emoji-mart-vue-fast/data/all.json'\nimport { Emoji, EmojiIndex, Picker } from 'emoji-mart-vue-fast/src/index.js'\nimport { isFocusable } from 'tabbable'\nimport IconCircle from 'vue-material-design-icons/Circle.vue'\nimport NcColorPicker from '../NcColorPicker/NcColorPicker.vue'\nimport { useTrapStackControl } from '../../composables/useTrapStackControl.ts'\nimport { getCurrentSkinTone, setCurrentSkinTone } from '../../functions/emoji/emoji.ts'\nimport { t } from '../../l10n.ts'\nimport { Color } from '../../utils/colors.ts'\nimport NcButton from '../NcButton/index.ts'\nimport NcPopover from '../NcPopover/index.js'\nimport NcTextField from '../NcTextField/index.ts'\n\n// Shared emoji index and skinTone for all NcEmojiPicker instances\n// Will be initialized on the first NcEmojiPicker creating\nlet emojiIndex\n\nconst i18n = {\n\tsearch: t('Search emoji'),\n\tnotfound: t('No emoji found'),\n\tcategories: {\n\t\tsearch: t('Search results'),\n\t\trecent: t('Frequently used'),\n\t\tsmileys: t('Smileys & Emotion'),\n\t\tpeople: t('People & Body'),\n\t\tnature: t('Animals & Nature'),\n\t\tfoods: t('Food & Drink'),\n\t\tactivity: t('Activities'),\n\t\tplaces: t('Travel & Places'),\n\t\tobjects: t('Objects'),\n\t\tsymbols: t('Symbols'),\n\t\tflags: t('Flags'),\n\t\tcustom: t('Custom'),\n\t},\n}\n\nconst skinTonePalette = [\n\tnew Color(255, 222, 52, t('Neutral skin color')),\n\tnew Color(228, 205, 166, t('Light skin tone')),\n\tnew Color(250, 221, 192, t('Medium light skin tone')),\n\tnew Color(174, 129, 87, t('Medium skin tone')),\n\tnew Color(158, 113, 88, t('Medium dark skin tone')),\n\tnew Color(96, 79, 69, t('Dark skin tone')),\n]\n\nexport default {\n\tname: 'NcEmojiPicker',\n\n\tcomponents: {\n\t\tIconCircle,\n\t\tNcButton,\n\t\tNcColorPicker,\n\t\tNcPopover,\n\t\tNcTextField,\n\t\tEmoji,\n\t\tPicker,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The emoji-set\n\t\t */\n\t\tactiveSet: {\n\t\t\ttype: String,\n\t\t\tdefault: 'native',\n\t\t},\n\n\t\t/**\n\t\t * Show preview section when hovering emoji\n\t\t */\n\t\tshowPreview: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Allow unselecting the selected emoji\n\t\t */\n\t\tallowUnselect: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Selected emoji to allow unselecting\n\t\t */\n\t\tselectedEmoji: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The fallback emoji in the preview section\n\t\t */\n\t\tpreviewFallbackEmoji: {\n\t\t\ttype: String,\n\t\t\tdefault: 'grinning',\n\t\t},\n\n\t\t/**\n\t\t * The fallback text in the preview section\n\t\t */\n\t\tpreviewFallbackName: {\n\t\t\ttype: String,\n\t\t\tdefault: t('Pick an emoji'),\n\t\t},\n\n\t\t/**\n\t\t * Whether to close the emoji picker after picking one\n\t\t */\n\t\tcloseOnSelect: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Selector for the popover container\n\t\t */\n\t\tcontainer: {\n\t\t\ttype: [Boolean, String, Object, Element],\n\t\t\tdefault: 'body',\n\t\t},\n\t},\n\n\temits: [\n\t\t'select',\n\t\t'selectData',\n\t\t'unselect',\n\t],\n\n\tsetup() {\n\t\t// If this is the first instance of NcEmojiPicker - setup EmojiIndex\n\t\tif (!emojiIndex) {\n\t\t\temojiIndex = new EmojiIndex(data)\n\t\t}\n\n\t\treturn {\n\t\t\t// Non-reactive constants\n\t\t\temojiIndex,\n\t\t\tskinTonePalette,\n\t\t\ti18n,\n\t\t}\n\t},\n\n\tdata() {\n\t\tconst currentSkinTone = getCurrentSkinTone()\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * The current active color from the skin tone palette\n\t\t\t */\n\t\t\tcurrentColor: skinTonePalette[currentSkinTone - 1],\n\t\t\t/**\n\t\t\t * The current active skin tone\n\t\t\t *\n\t\t\t * @type {1|2|3|4|5|6}\n\t\t\t */\n\t\t\tcurrentSkinTone,\n\t\t\tsearch: '',\n\t\t\topen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tnative() {\n\t\t\treturn this.activeSet === 'native'\n\t\t},\n\t},\n\n\tcreated() {\n\t\t// Component has its own custom focus management\n\t\t// The global focus trap stack should be paused\n\t\tuseTrapStackControl(() => this.open)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tclearSearch() {\n\t\t\tthis.search = ''\n\t\t\tthis.$refs.search.focus()\n\t\t},\n\n\t\t/**\n\t\t * Update the current skin tone by the result of the color picker\n\t\t *\n\t\t * @param {string} color Color set\n\t\t */\n\t\tonChangeSkinTone(color) {\n\t\t\tconst index = this.skinTonePalette.findIndex((tone) => tone.color.toLowerCase() === color.toLowerCase())\n\t\t\tif (index > -1) {\n\t\t\t\tthis.currentSkinTone = index + 1\n\t\t\t\tthis.currentColor = this.skinTonePalette[index]\n\t\t\t\tsetCurrentSkinTone(this.currentSkinTone)\n\t\t\t}\n\t\t},\n\n\t\tselect(emojiObject) {\n\t\t\t/**\n\t\t\t * Emits a string containing the emoji e.g. '👩🏿‍💻'\n\t\t\t */\n\t\t\tthis.$emit('select', emojiObject.native)\n\n\t\t\t/**\n\t\t\t * Emits a object with more data about the picked emoji\n\t\t\t */\n\t\t\tthis.$emit('selectData', emojiObject)\n\n\t\t\tif (this.closeOnSelect) {\n\t\t\t\tthis.open = false\n\t\t\t}\n\t\t},\n\n\t\tunselect() {\n\t\t\tthis.$emit('unselect')\n\t\t},\n\n\t\tafterShow() {\n\t\t\tthis.$refs.search.focus()\n\t\t},\n\n\t\tafterHide() {\n\t\t\t// Manually return focus to the trigger button, as we disabled focus-trap\n\t\t\t// But only if there is no focus target outside the picker, for example, input element that received focus by click closing the emoji picker\n\t\t\tif (!document.activeElement || this.$refs.picker.$el.contains(document.activeElement) || !isFocusable(document.activeElement)) {\n\t\t\t\tthis.$refs.popover.$el.querySelector('button, [role=\"button\"]')?.focus()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Manually handle Tab navigation skipping emoji buttons.\n\t\t * Navigation over emojis is handled by Arrow keys.\n\t\t *\n\t\t * @param {KeyboardEvent} event - Keyboard event\n\t\t */\n\t\thandleTabNavigationSkippingEmojis(event) {\n\t\t\tconst current = event.target\n\t\t\tconst focusable = Array.from(this.$refs.picker.$el.querySelectorAll('button:not(.emoji-mart-emoji), input'))\n\t\t\tif (!event.shiftKey) {\n\t\t\t\tconst nextNode = focusable.find((node) => current.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_FOLLOWING) || focusable[0]\n\t\t\t\tnextNode.focus()\n\t\t\t} else {\n\t\t\t\tconst prevNode = focusable.findLast((node) => current.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_PRECEDING) || focusable.at(-1)\n\t\t\t\tprevNode.focus()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Handle arrow navigation via <Picker>'s handlers with scroll bug fix\n\t\t *\n\t\t * @param {'onArrowLeft' | 'onArrowRight' | 'onArrowDown' | 'onArrowUp'} originalHandlerName - Picker's arrow keydown handler name\n\t\t * @param {KeyboardEvent} event - Keyboard event\n\t\t */\n\t\tasync callPickerArrowHandlerWithScrollFix(originalHandlerName, event) {\n\t\t\t// Call the original handler\n\t\t\t// See: https://github.com/serebrov/emoji-mart-vue/blob/a1ea72673a111cce78dc8caad8bc9ea3e02ad5bd/src/components/Picker.vue#L29\n\t\t\t// TODO: expose these methods via slot props in upstream library\n\t\t\tthis.$refs.picker[originalHandlerName](event)\n\n\t\t\t// Wait until emoji-mart-vue-fast scrolls\n\t\t\tawait this.$nextTick()\n\n\t\t\t// Scroll position is incorrect after emoji-mart-vue-fast scrolls...\n\t\t\t// It calculates scroll incorrectly.\n\t\t\t// It doesn't take into account, that emojis are wrapped into categories sections\n\t\t\t// See: https://github.com/serebrov/emoji-mart-vue/blob/a1ea72673a111cce78dc8caad8bc9ea3e02ad5bd/src/utils/picker.js#L244\n\t\t\t// Now scroll to the correct position\n\t\t\t// TODO: fix in upstream\n\t\t\tconst selectedEmoji = this.$refs.picker.$el.querySelector('.emoji-mart-emoji-selected')\n\t\t\tselectedEmoji?.scrollIntoView({\n\t\t\t\tblock: 'center',\n\t\t\t\tinline: 'center',\n\t\t\t})\n\t\t},\n\t},\n}\n</script>\n\n<style scoped lang=\"scss\">\n@use \"sass:meta\";\n\n.nc-emoji-picker-container :deep() {\n\t@include meta.load-css('emoji-mart-vue-fast/css/emoji-mart.css');\n}\n\n.nc-emoji-picker-container :deep(.emoji-mart) {\n\tbackground-color: var(--color-main-background) !important;\n\tborder: 0;\n\tcolor: var(--color-main-text) !important;\n\tdisplay: flex !important;\n\n\t// Reset emoji-mart styles\n\tbutton {\n\t\tborder: none;\n\t\tbackground: transparent;\n\t\tfont-size: inherit;\n\t}\n\n\t.emoji-mart-bar,\n\t.emoji-mart-anchors,\n\t.emoji-mart-search,\n\t.emoji-mart-search input,\n\t.emoji-mart-category,\n\t.emoji-mart-category-label,\n\t.emoji-mart-category-label span,\n\t.emoji-mart-skin-swatches {\n\t\tbackground-color: transparent !important;\n\t\tborder-color: var(--color-border) !important;\n\t\tcolor: inherit !important;\n\t}\n\n\t.emoji-mart-anchors {\n\t\tpadding-block: 0;\n\t\tpadding-inline: calc(2 * var(--default-grid-baseline));\n\t}\n\n\t.emoji-mart-anchor {\n\t\tborder-radius: 0;\n\t\tmargin: 0 !important;\n\t\tpadding: 0 !important;\n\t\theight: var(--clickable-area-small);\n\t\tmin-width: var(--clickable-area-small);\n\n\t\t&:hover {\n\t\t\tbackground-color: var(--color-background-hover);\n\t\t}\n\n\t\t&:focus-visible {\n\t\t\toutline: 2px solid var(--color-primary-element) !important;\n\t\t\toutline-offset: -2px;\n\t\t}\n\n\t\t// Icon\n\t\tdiv {\n\t\t\tdisplay: grid;\n\t\t\tplace-content: center;\n\t\t}\n\t}\n\n\t.emoji-mart-scroll {\n\t\tpadding-inline: calc(2 * var(--default-grid-baseline));\n\t\tpadding-block: 0 calc(2 * var(--default-grid-baseline));\n\t}\n\n\t.emoji-mart-category {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: repeat(8, 1fr);\n\t\tjustify-items: stretch;\n\n\t\t&.emoji-mart-no-results {\n\t\t\tgrid-template-columns: 1fr;\n\t\t\tfont-size: inherit;\n\t\t\tcolor: var(--color-text-maxcontrast) !important;\n\t\t}\n\t}\n\n\t/* Label element in the section grid */\n\tdiv.emoji-mart-category-label {\n\t\tgrid-column: span 8;\n\t\tjustify-self: stretch;\n\t}\n\n\t/* An actual heading inside the element */\n\th3.emoji-mart-category-label {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\t// Inline with buttons\n\t\theight: var(--default-clickable-area);\n\t\tmargin: 0;\n\t\t// Inline with input\n\t\tpadding-inline: calc(2 * var(--default-grid-baseline));\n\t\tpadding-block: 0;\n\t\tuser-select: none;\n\t}\n\n\t.emoji-mart-emoji {\n\t\taspect-ratio: 1 / 1;\n\t\ttext-align: center;\n\t\tmargin: 0 !important;\n\t\tpadding: 0 !important;\n\n\t\t&:hover,\n\t\t&:focus-visible,\n\t\t&.emoji-mart-emoji-selected {\n\t\t\tbackground-color: var(--color-background-hover) !important;\n\t\t\tborder: none;\n\t\t\tborder-radius: var(--border-radius-element);\n\t\t\tbox-shadow: none !important;\n\t\t\toutline: 2px solid var(--color-primary-element) !important;\n\t\t\toutline-offset: -2px;\n\t\t}\n\n\t\t&::before {\n\t\t\tdisplay: none;\n\t\t}\n\n\t\tspan {\n\t\t\tcursor: pointer;\n\t\t}\n\t}\n}\n\n.search__wrapper {\n\tdisplay: flex;\n\tflex-direction: row;\n\tgap: var(--default-grid-baseline);\n\talign-items: end;\n\tpadding-block: var(--default-grid-baseline);\n\tpadding-inline: calc(2 * var(--default-grid-baseline));\n}\n\n.row-selected {\n\tbutton, span {\n\t\tvertical-align: middle;\n\t}\n}\n\n.emoji-delete {\n\tvertical-align: top;\n\tmargin-inline-start: -21px;\n\tmargin-top: -3px;\n}\n</style>\n"],"names":["_sfc_main","_hoisted_3","_createElementBlock","_mergeProps","_createElementVNode","_openBlock","NcTextField","_createBlock","_withCtx","_renderSlot","_createVNode","_withKeys","_normalizeStyle","_toDisplayString"],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"NcEmojiPicker-CReazifM.mjs","sources":["../../node_modules/vue-material-design-icons/Circle.vue","../../src/components/NcEmojiPicker/NcEmojiPicker.vue"],"sourcesContent":["<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon circle-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"CircleIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<!--\n - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\n### General description\n\nThis component allows the user to pick an emoji.\n\n### Usage\n\n* Listen to the select event and pass in an HTML element that will be treated as a trigger:\n\n```vue\n<template>\n\t<div>\n\t\t<NcEmojiPicker @select=\"select\" style=\"display: inline-block\">\n\t\t\t<NcButton> Click Me </NcButton>\n\t\t</NcEmojiPicker>\n\t\t<span>selected emoji: {{ emoji }}</span>\n\t</div>\n</template>\n<script>\n\texport default {\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\temoji: '',\n\t\t\t}\n\t\t},\n\t\tmethods: {\n\t\t\tselect(emoji) {\n\t\t\t\tthis.emoji = emoji\n\t\t\t},\n\t\t},\n\t}\n</script>\n```\n\n* Showing a preview and keeping it open after a user selected an emoji\n\n```vue\n<template>\n\t<div>\n\t\t<NcEmojiPicker\n\t\t\t:close-on-select=\"false\"\n\t\t\t:show-preview=\"true\"\n\t\t\t@select=\"select\"\n\t\t\tstyle=\"display: inline-block\">\n\t\t\t<NcButton> Click Me </NcButton>\n\t\t</NcEmojiPicker>\n\t\t<span>selected emoji: {{ emoji }}</span>\n\t</div>\n</template>\n<script>\n\texport default {\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\temoji: '',\n\t\t\t}\n\t\t},\n\t\tmethods: {\n\t\t\tselect(emoji) {\n\t\t\t\tthis.emoji = emoji\n\t\t\t},\n\t\t},\n\t}\n</script>\n```\n\n* Allow unselecting a previously set emoji.\n\n```vue\n<template>\n\t<div>\n\t\t<NcEmojiPicker\n\t\t\t:show-preview=\"true\"\n\t\t\t:allow-unselect=\"true\"\n\t\t\t:selected-emoji=\"emoji\"\n\t\t\t@select=\"select\"\n\t\t\t@unselect=\"unselect\"\n\t\t\tstyle=\"display: inline-block\">\n\t\t\t<NcButton> Click Me </NcButton>\n\t\t</NcEmojiPicker>\n\t\t<span>selected emoji: {{ emoji }}</span>\n\t</div>\n</template>\n<script>\n\texport default {\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\temoji: '',\n\t\t\t}\n\t\t},\n\t\tmethods: {\n\t\t\tselect(emoji) {\n\t\t\t\tthis.emoji = emoji\n\t\t\t},\n\t\t\tunselect() {\n\t\t\t\tthis.emoji = ''\n\t\t\t},\n\t\t},\n\t}\n</script>\n```\n\n</docs>\n\n<template>\n\t<NcPopover\n\t\tref=\"popover\"\n\t\tv-model:shown=\"open\"\n\t\t:container=\"container\"\n\t\tpopup-role=\"dialog\"\n\t\t:no-focus-trap=\"true /* Handled manually to remove emoji buttons from TAB sequence */\"\n\t\t@after-show=\"afterShow\"\n\t\t@after-hide=\"afterHide\">\n\t\t<template #trigger=\"slotProps\">\n\t\t\t<slot v-bind=\"slotProps\" />\n\t\t</template>\n\t\t<div class=\"nc-emoji-picker-container\">\n\t\t\t<Picker\n\t\t\t\tref=\"picker\"\n\t\t\t\tcolor=\"var(--color-primary-element)\"\n\t\t\t\t:data=\"emojiIndex\"\n\t\t\t\t:emoji=\"previewFallbackEmoji\"\n\t\t\t\t:i18n\n\t\t\t\t:native\n\t\t\t\t:emoji-size=\"20\"\n\t\t\t\t:per-line=\"8\"\n\t\t\t\t:picker-styles=\"{ width: '320px' }\"\n\t\t\t\t:show-preview\n\t\t\t\t:skin=\"currentSkinTone\"\n\t\t\t\t:show-skin-tones=\"false\"\n\t\t\t\t:title=\"previewFallbackName\"\n\t\t\t\trole=\"dialog\"\n\t\t\t\taria-modal=\"true\"\n\t\t\t\t:aria-label=\"t('Emoji picker')\"\n\t\t\t\tv-bind=\"$attrs\"\n\t\t\t\t@keydown.tab.prevent=\"handleTabNavigationSkippingEmojis\"\n\t\t\t\t@select=\"select\">\n\t\t\t\t<template #searchTemplate=\"{ onSearch }\">\n\t\t\t\t\t<div class=\"search__wrapper\">\n\t\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t\tref=\"search\"\n\t\t\t\t\t\t\tv-model=\"search\"\n\t\t\t\t\t\t\tclass=\"search\"\n\t\t\t\t\t\t\t:label=\"t('Search')\"\n\t\t\t\t\t\t\t:label-visible=\"true\"\n\t\t\t\t\t\t\t:placeholder=\"i18n.search\"\n\t\t\t\t\t\t\ttrailing-button-icon=\"close\"\n\t\t\t\t\t\t\t:trailing-button-label=\"t('Clear search')\"\n\t\t\t\t\t\t\t:show-trailing-button=\"search !== ''\"\n\t\t\t\t\t\t\t@keydown.left=\"callPickerArrowHandlerWithScrollFix('onArrowLeft', $event)\"\n\t\t\t\t\t\t\t@keydown.right=\"callPickerArrowHandlerWithScrollFix('onArrowRight', $event)\"\n\t\t\t\t\t\t\t@keydown.down=\"callPickerArrowHandlerWithScrollFix('onArrowDown', $event)\"\n\t\t\t\t\t\t\t@keydown.up=\"callPickerArrowHandlerWithScrollFix('onArrowUp', $event)\"\n\t\t\t\t\t\t\t@keydown.enter=\"$refs.picker.onEnter($event)\"\n\t\t\t\t\t\t\t@trailing-button-click=\"clearSearch(); onSearch('');\"\n\t\t\t\t\t\t\t@update:model-value=\"onSearch(search)\" />\n\t\t\t\t\t\t<NcColorPicker\n\t\t\t\t\t\t\tpalette-only\n\t\t\t\t\t\t\t:container\n\t\t\t\t\t\t\t:palette=\"skinTonePalette\"\n\t\t\t\t\t\t\t:model-value=\"currentColor.color\"\n\t\t\t\t\t\t\t@update:model-value=\"onChangeSkinTone\">\n\t\t\t\t\t\t\t<NcButton :aria-label=\"t('Skin tone')\" variant=\"tertiary-no-background\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<IconCircle :style=\"{ color: currentColor.color }\" :title=\"currentColor.name\" :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</NcColorPicker>\n\t\t\t\t\t</div>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"allowUnselect && selectedEmoji\" #customCategory>\n\t\t\t\t\t<div class=\"emoji-mart-category-label\">\n\t\t\t\t\t\t<h3 class=\"emoji-mart-category-label\">\n\t\t\t\t\t\t\t{{ t('Selected') }}\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t</div>\n\t\t\t\t\t<Emoji\n\t\t\t\t\t\tclass=\"emoji-selected\"\n\t\t\t\t\t\t:data=\"emojiIndex\"\n\t\t\t\t\t\t:emoji=\"selectedEmoji\"\n\t\t\t\t\t\tnative\n\t\t\t\t\t\t:size=\"32\"\n\t\t\t\t\t\t@click=\"unselect\" />\n\t\t\t\t\t<Emoji\n\t\t\t\t\t\tclass=\"emoji-delete\"\n\t\t\t\t\t\t:data=\"emojiIndex\"\n\t\t\t\t\t\temoji=\":x:\"\n\t\t\t\t\t\tnative\n\t\t\t\t\t\t:size=\"10\"\n\t\t\t\t\t\t@click=\"unselect\" />\n\t\t\t\t</template>\n\t\t\t</Picker>\n\t\t</div>\n\t</NcPopover>\n</template>\n\n<script>\nimport data from 'emoji-mart-vue-fast/data/all.json'\nimport { Emoji, EmojiIndex, Picker } from 'emoji-mart-vue-fast/src/index.js'\nimport { isFocusable } from 'tabbable'\nimport IconCircle from 'vue-material-design-icons/Circle.vue'\nimport NcColorPicker from '../NcColorPicker/NcColorPicker.vue'\nimport { useTrapStackControl } from '../../composables/useTrapStackControl.ts'\nimport { getCurrentSkinTone, setCurrentSkinTone } from '../../functions/emoji/emoji.ts'\nimport { t } from '../../l10n.ts'\nimport { Color } from '../../utils/colors.ts'\nimport NcButton from '../NcButton/index.ts'\nimport NcPopover from '../NcPopover/index.js'\nimport NcTextField from '../NcTextField/index.ts'\n\n// Shared emoji index and skinTone for all NcEmojiPicker instances\n// Will be initialized on the first NcEmojiPicker creating\nlet emojiIndex\n\nconst i18n = {\n\tsearch: t('Search emoji'),\n\tnotfound: t('No emoji found'),\n\tcategories: {\n\t\tsearch: t('Search results'),\n\t\trecent: t('Frequently used'),\n\t\tsmileys: t('Smileys & Emotion'),\n\t\tpeople: t('People & Body'),\n\t\tnature: t('Animals & Nature'),\n\t\tfoods: t('Food & Drink'),\n\t\tactivity: t('Activities'),\n\t\tplaces: t('Travel & Places'),\n\t\tobjects: t('Objects'),\n\t\tsymbols: t('Symbols'),\n\t\tflags: t('Flags'),\n\t\tcustom: t('Custom'),\n\t},\n}\n\nconst skinTonePalette = [\n\tnew Color(255, 222, 52, t('Neutral skin color')),\n\tnew Color(228, 205, 166, t('Light skin tone')),\n\tnew Color(250, 221, 192, t('Medium light skin tone')),\n\tnew Color(174, 129, 87, t('Medium skin tone')),\n\tnew Color(158, 113, 88, t('Medium dark skin tone')),\n\tnew Color(96, 79, 69, t('Dark skin tone')),\n]\n\nexport default {\n\tname: 'NcEmojiPicker',\n\n\tcomponents: {\n\t\tIconCircle,\n\t\tNcButton,\n\t\tNcColorPicker,\n\t\tNcPopover,\n\t\tNcTextField,\n\t\tEmoji,\n\t\tPicker,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The emoji-set\n\t\t */\n\t\tactiveSet: {\n\t\t\ttype: String,\n\t\t\tdefault: 'native',\n\t\t},\n\n\t\t/**\n\t\t * Show preview section when hovering emoji\n\t\t */\n\t\tshowPreview: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Allow unselecting the selected emoji\n\t\t */\n\t\tallowUnselect: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Selected emoji to allow unselecting\n\t\t */\n\t\tselectedEmoji: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The fallback emoji in the preview section\n\t\t */\n\t\tpreviewFallbackEmoji: {\n\t\t\ttype: String,\n\t\t\tdefault: 'grinning',\n\t\t},\n\n\t\t/**\n\t\t * The fallback text in the preview section\n\t\t */\n\t\tpreviewFallbackName: {\n\t\t\ttype: String,\n\t\t\tdefault: t('Pick an emoji'),\n\t\t},\n\n\t\t/**\n\t\t * Whether to close the emoji picker after picking one\n\t\t */\n\t\tcloseOnSelect: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Selector for the popover container\n\t\t */\n\t\tcontainer: {\n\t\t\ttype: [Boolean, String, Object, Element],\n\t\t\tdefault: 'body',\n\t\t},\n\t},\n\n\temits: [\n\t\t'select',\n\t\t'selectData',\n\t\t'unselect',\n\t],\n\n\tsetup() {\n\t\t// If this is the first instance of NcEmojiPicker - setup EmojiIndex\n\t\tif (!emojiIndex) {\n\t\t\temojiIndex = new EmojiIndex(data)\n\t\t}\n\n\t\treturn {\n\t\t\t// Non-reactive constants\n\t\t\temojiIndex,\n\t\t\tskinTonePalette,\n\t\t\ti18n,\n\t\t}\n\t},\n\n\tdata() {\n\t\tconst currentSkinTone = getCurrentSkinTone()\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * The current active color from the skin tone palette\n\t\t\t */\n\t\t\tcurrentColor: skinTonePalette[currentSkinTone - 1],\n\t\t\t/**\n\t\t\t * The current active skin tone\n\t\t\t *\n\t\t\t * @type {1|2|3|4|5|6}\n\t\t\t */\n\t\t\tcurrentSkinTone,\n\t\t\tsearch: '',\n\t\t\topen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tnative() {\n\t\t\treturn this.activeSet === 'native'\n\t\t},\n\t},\n\n\tcreated() {\n\t\t// Component has its own custom focus management\n\t\t// The global focus trap stack should be paused\n\t\tuseTrapStackControl(() => this.open)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tclearSearch() {\n\t\t\tthis.search = ''\n\t\t\tthis.$refs.search.focus()\n\t\t},\n\n\t\t/**\n\t\t * Update the current skin tone by the result of the color picker\n\t\t *\n\t\t * @param {string} color Color set\n\t\t */\n\t\tonChangeSkinTone(color) {\n\t\t\tconst index = this.skinTonePalette.findIndex((tone) => tone.color.toLowerCase() === color.toLowerCase())\n\t\t\tif (index > -1) {\n\t\t\t\tthis.currentSkinTone = index + 1\n\t\t\t\tthis.currentColor = this.skinTonePalette[index]\n\t\t\t\tsetCurrentSkinTone(this.currentSkinTone)\n\t\t\t}\n\t\t},\n\n\t\tselect(emojiObject) {\n\t\t\t/**\n\t\t\t * Emits a string containing the emoji e.g. '👩🏿‍💻'\n\t\t\t */\n\t\t\tthis.$emit('select', emojiObject.native)\n\n\t\t\t/**\n\t\t\t * Emits a object with more data about the picked emoji\n\t\t\t */\n\t\t\tthis.$emit('selectData', emojiObject)\n\n\t\t\tif (this.closeOnSelect) {\n\t\t\t\tthis.open = false\n\t\t\t}\n\t\t},\n\n\t\tunselect() {\n\t\t\tthis.$emit('unselect')\n\t\t},\n\n\t\tafterShow() {\n\t\t\tthis.$refs.search.focus()\n\t\t},\n\n\t\tafterHide() {\n\t\t\t// Manually return focus to the trigger button, as we disabled focus-trap\n\t\t\t// But only if there is no focus target outside the picker, for example, input element that received focus by click closing the emoji picker\n\t\t\tif (!document.activeElement || this.$refs.picker.$el.contains(document.activeElement) || !isFocusable(document.activeElement)) {\n\t\t\t\tthis.$refs.popover.$el.querySelector('button, [role=\"button\"]')?.focus()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Manually handle Tab navigation skipping emoji buttons.\n\t\t * Navigation over emojis is handled by Arrow keys.\n\t\t *\n\t\t * @param {KeyboardEvent} event - Keyboard event\n\t\t */\n\t\thandleTabNavigationSkippingEmojis(event) {\n\t\t\tconst current = event.target\n\t\t\tconst focusable = Array.from(this.$refs.picker.$el.querySelectorAll('button:not(.emoji-mart-emoji), input'))\n\t\t\tif (!event.shiftKey) {\n\t\t\t\tconst nextNode = focusable.find((node) => current.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_FOLLOWING) || focusable[0]\n\t\t\t\tnextNode.focus()\n\t\t\t} else {\n\t\t\t\tconst prevNode = focusable.findLast((node) => current.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_PRECEDING) || focusable.at(-1)\n\t\t\t\tprevNode.focus()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Handle arrow navigation via <Picker>'s handlers with scroll bug fix\n\t\t *\n\t\t * @param {'onArrowLeft' | 'onArrowRight' | 'onArrowDown' | 'onArrowUp'} originalHandlerName - Picker's arrow keydown handler name\n\t\t * @param {KeyboardEvent} event - Keyboard event\n\t\t */\n\t\tasync callPickerArrowHandlerWithScrollFix(originalHandlerName, event) {\n\t\t\t// Call the original handler\n\t\t\t// See: https://github.com/serebrov/emoji-mart-vue/blob/a1ea72673a111cce78dc8caad8bc9ea3e02ad5bd/src/components/Picker.vue#L29\n\t\t\t// TODO: expose these methods via slot props in upstream library\n\t\t\tthis.$refs.picker[originalHandlerName](event)\n\n\t\t\t// Wait until emoji-mart-vue-fast scrolls\n\t\t\tawait this.$nextTick()\n\n\t\t\t// Scroll position is incorrect after emoji-mart-vue-fast scrolls...\n\t\t\t// It calculates scroll incorrectly.\n\t\t\t// It doesn't take into account, that emojis are wrapped into categories sections\n\t\t\t// See: https://github.com/serebrov/emoji-mart-vue/blob/a1ea72673a111cce78dc8caad8bc9ea3e02ad5bd/src/utils/picker.js#L244\n\t\t\t// Now scroll to the correct position\n\t\t\t// TODO: fix in upstream\n\t\t\tconst selectedEmoji = this.$refs.picker.$el.querySelector('.emoji-mart-emoji-selected')\n\t\t\tselectedEmoji?.scrollIntoView({\n\t\t\t\tblock: 'center',\n\t\t\t\tinline: 'center',\n\t\t\t})\n\t\t},\n\t},\n}\n</script>\n\n<style scoped lang=\"scss\">\n@use \"sass:meta\";\n\n.nc-emoji-picker-container :deep() {\n\t@include meta.load-css('emoji-mart-vue-fast/css/emoji-mart.css');\n}\n\n.nc-emoji-picker-container :deep(.emoji-mart) {\n\tbackground-color: var(--color-main-background) !important;\n\tborder: 0;\n\tcolor: var(--color-main-text) !important;\n\tdisplay: flex !important;\n\n\t// Reset emoji-mart styles\n\tbutton {\n\t\tborder: none;\n\t\tbackground: transparent;\n\t\tfont-size: inherit;\n\t}\n\n\t.emoji-mart-bar,\n\t.emoji-mart-anchors,\n\t.emoji-mart-search,\n\t.emoji-mart-search input,\n\t.emoji-mart-category,\n\t.emoji-mart-category-label,\n\t.emoji-mart-category-label span,\n\t.emoji-mart-skin-swatches {\n\t\tbackground-color: transparent !important;\n\t\tborder-color: var(--color-border) !important;\n\t\tcolor: inherit !important;\n\t}\n\n\t.emoji-mart-anchors {\n\t\tpadding-block: 0;\n\t\tpadding-inline: calc(2 * var(--default-grid-baseline));\n\t}\n\n\t.emoji-mart-anchor {\n\t\tborder-radius: 0;\n\t\tmargin: 0 !important;\n\t\tpadding: 0 !important;\n\t\theight: var(--clickable-area-small);\n\t\tmin-width: var(--clickable-area-small);\n\n\t\t&:hover {\n\t\t\tbackground-color: var(--color-background-hover);\n\t\t}\n\n\t\t&:focus-visible {\n\t\t\toutline: 2px solid var(--color-primary-element) !important;\n\t\t\toutline-offset: -2px;\n\t\t}\n\n\t\t// Icon\n\t\tdiv {\n\t\t\tdisplay: grid;\n\t\t\tplace-content: center;\n\t\t}\n\t}\n\n\t.emoji-mart-scroll {\n\t\tpadding-inline: calc(2 * var(--default-grid-baseline));\n\t\tpadding-block: 0 calc(2 * var(--default-grid-baseline));\n\t}\n\n\t.emoji-mart-category {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: repeat(8, 1fr);\n\t\tjustify-items: stretch;\n\n\t\t&.emoji-mart-no-results {\n\t\t\tgrid-template-columns: 1fr;\n\t\t\tfont-size: inherit;\n\t\t\tcolor: var(--color-text-maxcontrast) !important;\n\t\t}\n\t}\n\n\t/* Label element in the section grid */\n\tdiv.emoji-mart-category-label {\n\t\tgrid-column: span 8;\n\t\tjustify-self: stretch;\n\t}\n\n\t/* An actual heading inside the element */\n\th3.emoji-mart-category-label {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\t// Inline with buttons\n\t\theight: var(--default-clickable-area);\n\t\tmargin: 0;\n\t\t// Inline with input\n\t\tpadding-inline: calc(2 * var(--default-grid-baseline));\n\t\tpadding-block: 0;\n\t\tuser-select: none;\n\t}\n\n\t.emoji-mart-emoji {\n\t\taspect-ratio: 1 / 1;\n\t\ttext-align: center;\n\t\tmargin: 0 !important;\n\t\tpadding: 0 !important;\n\n\t\t&:hover,\n\t\t&:focus-visible,\n\t\t&.emoji-mart-emoji-selected {\n\t\t\tbackground-color: var(--color-background-hover) !important;\n\t\t\tborder: none;\n\t\t\tborder-radius: var(--border-radius-element);\n\t\t\tbox-shadow: none !important;\n\t\t\toutline: 2px solid var(--color-primary-element) !important;\n\t\t\toutline-offset: -2px;\n\t\t}\n\n\t\t&::before {\n\t\t\tdisplay: none;\n\t\t}\n\n\t\tspan {\n\t\t\tcursor: pointer;\n\t\t}\n\t}\n}\n\n.search__wrapper {\n\tdisplay: flex;\n\tflex-direction: row;\n\tgap: var(--default-grid-baseline);\n\talign-items: end;\n\tpadding-block: var(--default-grid-baseline);\n\tpadding-inline: calc(2 * var(--default-grid-baseline));\n}\n\n.row-selected {\n\tbutton, span {\n\t\tvertical-align: middle;\n\t}\n}\n\n.emoji-delete {\n\tvertical-align: top;\n\tmargin-inline-start: -21px;\n\tmargin-top: -3px;\n}\n</style>\n"],"names":["_sfc_main","_hoisted_3","_createElementBlock","_mergeProps","_createElementVNode","_openBlock","NcTextField","_createBlock","_withCtx","_renderSlot","_createVNode","_withKeys","_normalizeStyle","_toDisplayString"],"mappings":"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","x_google_ignoreList":[0]}
@@ -1,6 +1,6 @@
1
1
  import '../assets/NcFormBoxButton-C6EvdLK4.css';
2
2
  import { reactive, inject, computed, defineComponent, toRef, createBlock, openBlock, mergeProps, unref, createSlots, withCtx, renderSlot, createTextVNode, toDisplayString, createCommentVNode } from "vue";
3
- import { o as mdiOpenInNew, p as mdiArrowTopRight } from "./mdi-DvQxv1t7.mjs";
3
+ import { s as mdiOpenInNew, t as mdiArrowTopRight } from "./mdi-CpchYUUV.mjs";
4
4
  import { N as NcFormBoxItem } from "./NcFormBoxItem-vnU0KmUL.mjs";
5
5
  import { N as NcIconSvgWrapper } from "./NcIconSvgWrapper-BvLanNaW.mjs";
6
6
  import { routerKey } from "vue-router";
@@ -142,4 +142,4 @@ const NcFormBoxButton = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules",
142
142
  export {
143
143
  NcFormBoxButton as N
144
144
  };
145
- //# sourceMappingURL=NcFormBoxButton-Bptd324P.mjs.map
145
+ //# sourceMappingURL=NcFormBoxButton-DvMw5yUf.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"NcFormBoxButton-Bptd324P.mjs","sources":["../../src/composables/useButtonLink.ts","../../src/components/NcFormBoxButton/NcFormBoxButton.vue"],"sourcesContent":["/*!\n * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { AnchorHTMLAttributes, ButtonHTMLAttributes, MaybeRef } from 'vue'\nimport type { RouteLocationRaw } from 'vue-router'\n\nimport { computed, inject, reactive } from 'vue'\nimport { routerKey } from 'vue-router'\n\ntype ButtonLinkProps = {\n\t// Required - general link props\n\n\t/**\n\t * RouterLink's to props and a trigger to use RouterLink.\n\t * Note: This takes precedence over the href attribute.\n\t */\n\tto: MaybeRef<RouteLocationRaw | undefined>\n\t/**\n\t * HyperLink href attribute and a trigger to use <a> hyperlink.\n\t */\n\thref: MaybeRef<string | undefined>\n\t/**\n\t * Define additional attributes, based on the tag\n\t */\n\tadditionalAttrs?: (tag: 'RouterLink' | 'a' | 'button') => object | undefined\n\n\t// RouterLink props\n\n\t/**\n\t * RouterLink's activeClass prop\n\t */\n\tactiveClass?: MaybeRef<string | undefined>\n\n\t// Hyperlink\n\n\t/**\n\t * <a> hyperlink's target attribute\n\t */\n\ttarget?: MaybeRef<AnchorHTMLAttributes['target'] | undefined>\n\t/**\n\t * <a> hyperlink's download attribute\n\t */\n\tdownload?: MaybeRef<string | boolean | undefined>\n\n\t// Button\n\n\t/**\n\t * <button> element's type attribute, but default to \"button\" instead of \"submit\"\n\t */\n\ttype?: MaybeRef<ButtonHTMLAttributes['type'] | undefined>\n\t/**\n\t * <button> element's disabled attribute\n\t */\n\tdisabled?: MaybeRef<boolean | undefined>\n}\n\n/**\n * Reusable implementation of an interactive button-like element that can be a link or a button\n *\n * @param options - Props to determine the button/link behavior. Can be a reactive object, or an object with nested refs, or mixed.\n */\nexport function useButtonLink(options: ButtonLinkProps) {\n\t// Resolve all MaybeRef-s values and maybe reactive object via unwrapping\n\tconst props = reactive(options)\n\n\tconst hasVueRouterContext = inject(routerKey, null) !== null\n\n\t/**\n\t * Tag name to be used\n\t */\n\tconst tag = computed(() => {\n\t\t// TODO: should we warn if props.to is provided but there is no vue-router?\n\t\tif (hasVueRouterContext && props.to) {\n\t\t\t// Note: RouterLink is used as globally registered component (by name) and not imported intentionally\n\t\t\t// to use injected component from the app and not bundle it to the button\n\t\t\treturn 'RouterLink'\n\t\t} else if (props.href) {\n\t\t\treturn 'a'\n\t\t} else {\n\t\t\treturn 'button'\n\t\t}\n\t})\n\n\tconst isLink = computed(() => tag.value === 'RouterLink' || tag.value === 'a')\n\tconst isHyperLink = computed(() => tag.value === 'a')\n\tconst isRouterLink = computed(() => tag.value === 'RouterLink')\n\tconst isButton = computed(() => tag.value === 'button')\n\n\tconst attrs = computed(() => {\n\t\tif (tag.value === 'RouterLink') {\n\t\t\treturn {\n\t\t\t\tto: props.to,\n\t\t\t\tactiveClass: 'active',\n\t\t\t\t...(props.additionalAttrs?.('RouterLink') ?? {}),\n\t\t\t}\n\t\t} else if (tag.value === 'a') {\n\t\t\treturn {\n\t\t\t\thref: props.href,\n\t\t\t\ttarget: props.target,\n\t\t\t\tdownload: props.download || undefined,\n\t\t\t\trel: 'nofollow noreferrer noopener',\n\t\t\t\t...(props.additionalAttrs?.('a') ?? {}),\n\t\t\t}\n\t\t} else if (tag.value === 'button') {\n\t\t\treturn {\n\t\t\t\ttype: props.type || 'button',\n\t\t\t\tdisabled: props.disabled,\n\t\t\t\t...(props.additionalAttrs?.('button') ?? {}),\n\t\t\t}\n\t\t}\n\t})\n\n\treturn {\n\t\ttag,\n\t\tisLink,\n\t\tisHyperLink,\n\t\tisRouterLink,\n\t\tisButton,\n\t\tattrs,\n\t}\n}\n","<!--\n - SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { AnchorHTMLAttributes, Slot } from 'vue'\nimport type { RouteLocationRaw } from 'vue-router'\n\nimport { mdiArrowTopRight, mdiOpenInNew } from '@mdi/js'\nimport { computed, toRef } from 'vue'\nimport NcFormBoxItem from '../NcFormBox/NcFormBoxItem.vue'\nimport NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'\nimport { useButtonLink } from '../../composables/useButtonLink.ts'\n\nconst {\n\tlabel = undefined,\n\tdescription = undefined,\n\tinvertedAccent = false,\n\tto = undefined,\n\thref = undefined,\n\ttarget = undefined, // TODO: should it be _blank by default?\n\tdisabled = false,\n} = defineProps<{\n\t/** Main label */\n\tlabel?: string\n\t/** Optional description below the label, also used for the aria-describedby */\n\tdescription?: string\n\t/** Accent on the description instead of the label (see docs) */\n\tinvertedAccent?: boolean\n\t/** RouterLink's `to` prop; when provided, renders as `<RouterLink>` (takes precedence over the `href` prop) */\n\tto?: RouteLocationRaw\n\t/** Hyperlink `href` attribute; when provided, renders as `<a>` */\n\thref?: string\n\t/** Hyperlink's target attribute */\n\ttarget?: AnchorHTMLAttributes['target']\n\t/** Button's disabled attribute, not applicable to links */\n\tdisabled?: boolean\n}>()\n\ndefineEmits<{\n\t/** Native click event */\n\tclick: [event: MouseEvent]\n}>()\n\ndefineSlots<{\n\t/** Custom label content */\n\tdefault?: Slot\n\t/** Custom description content */\n\tdescription?: Slot\n\t/** Required icon (links have a default icon) */\n\ticon?: Slot // TODO: should the default link icon only be used for _blank links?\n}>()\n\nconst { tag, attrs, isLink } = useButtonLink({\n\tto: toRef(() => to),\n\thref: toRef(() => href),\n\ttarget: toRef(() => target),\n\tdisabled: toRef(() => disabled),\n})\n\nconst icon = computed(() => {\n\tif (isLink.value) {\n\t\treturn target === '_blank' ? mdiOpenInNew : mdiArrowTopRight\n\t}\n\treturn undefined\n})\n</script>\n\n<template>\n\t<NcFormBoxItem\n\t\t:tag\n\t\t:item-classes=\"[\n\t\t\t'button-vue', /* Reset server's global HTML button styles */\n\t\t\t$style.formBoxButton,\n\t\t]\"\n\t\t:inverted-accent\n\t\tv-bind=\"attrs\"\n\t\ttabindex=\"0\"\n\t\t@click=\"$emit('click', $event)\">\n\t\t<template v-if=\"$slots.default || label\" #default>\n\t\t\t<slot>\n\t\t\t\t{{ label }}\n\t\t\t</slot>\n\t\t</template>\n\t\t<template v-if=\"$slots.description || description\" #description>\n\t\t\t<slot name=\"description\">\n\t\t\t\t{{ description }}\n\t\t\t</slot>\n\t\t</template>\n\t\t<template v-if=\"$slots.icon || icon\" #icon>\n\t\t\t<slot name=\"icon\">\n\t\t\t\t<NcIconSvgWrapper v-if=\"icon\" :path=\"icon\" inline />\n\t\t\t</slot>\n\t\t</template>\n\t</NcFormBoxItem>\n</template>\n\n<style lang=\"scss\" module>\n.formBoxButton {\n\t/* Reset default HTML button styles */\n\tbackground: unset;\n\tborder: none;\n\tcolor: inherit;\n\tfont-size: inherit;\n\tfont-weight: inherit;\n\ttext-decoration: none;\n\ttext-align: inherit;\n\tline-height: inherit;\n\tpadding: 0;\n\tmargin: 0;\n\toutline: none;\n}\n</style>\n\n<docs>\n### General\n\nAn interactive button-like item within `<NcFormBox>`. It can be a button or a native link/router link if `to` or `href` props are provided.\n\nLike other form box items, it has a label and an optional description.\n\n```vue\n<script>\nimport { mdiContentCopy, mdiInformationOutline } from '@mdi/js'\n\nexport default {\n\tsetup() {\n\t\treturn {\n\t\t\tmdiContentCopy,\n\t\t\tmdiInformationOutline,\n\t\t}\n\t},\n}\n</script>\n\n<template>\n\t<NcFormBox>\n\t\t<NcFormBoxButton\n\t\t\tlabel=\"Nextcloud\"\n\t\t\thref=\"https://nextcloud.com\"\n\t\t\ttarget=\"_blank\" />\n\n\t\t<NcFormBoxButton\n\t\t\thref=\"https://nextcloud-vue-components.netlify.app\">\n\t\t\t<code>@nextcloud/vue</code> documentation\n\t\t</NcFormBoxButton>\n\n\t\t<NcFormBoxButton\n\t\t\tlabel=\"About\"\n\t\t\tdescription=\"Installation details\"\n\t\t\thref=\"https://nextcloud.com\"\n\t\t\ttarget=\"_blank\">\n\t\t\t<template #icon>\n\t\t\t\t<NcIconSvgWrapper :path=\"mdiInformationOutline\" inline />\n\t\t\t</template>\n\t\t</NcFormBoxButton>\n\n\t\t<NcFormBoxButton\n\t\t\tlabel=\"Public signing key\">\n\t\t\t<template #description>\n\t\t\t\t<code>SSBkb24ndCBrbm93IHdoeSB5b3UgZGVjb2RlZCB0aGlzIHZhbHVlDQrgvLwg44GkIOKXlV/il5Ug4Ly944Gk</code>\n\t\t\t</template>\n\t\t\t<template #icon>\n\t\t\t\t<NcIconSvgWrapper :path=\"mdiContentCopy\" inline />\n\t\t\t</template>\n\t\t</NcFormBoxButton>\n\t</NcFormBox>\n</template>\n```\n\n### Inverted accent\n\nSometimes the description is more important than the label. In such cases use `inverted-accent` prop.\n\nFor example:\n- **Steps:** the description of the step is more important than the step number\n- **Copy button:** the value being copied is more important than the value label\n- **Folder picker:** the selected folder path is more important than the input label\n\n```vue\n<script>\nimport { mdiContentCopy, mdiDomain, mdiFolderOpenOutline } from '@mdi/js'\n\nexport default {\n\tsetup() {\n\t\treturn { mdiContentCopy, mdiDomain, mdiFolderOpenOutline }\n\t},\n}\n</script>\n\n<template>\n\t<div style=\"display: flex; flex-direction: column; gap: calc(4 * var(--default-grid-baseline));\">\n\t\t<NcFormGroup label=\"Mailvelope\" description=\"A browser extension that enables easy OpenPGP encryption and decryption of emails\">\n\t\t\t<NcFormBox>\n\t\t\t\t<NcFormBoxButton\n\t\t\t\t\tlabel=\"Step 1\"\n\t\t\t\t\tdescription=\"Install the browser extension\"\n\t\t\t\t\thref=\"https://www.mailvelope.com/\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\tinverted-accent />\n\t\t\t\t<NcFormBoxButton\n\t\t\t\t\tlabel=\"Step 2\"\n\t\t\t\t\tdescription=\"Enable the current domain\"\n\t\t\t\t\tinverted-accent>\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"mdiDomain\" inline />\n\t\t\t\t\t</template>\n\t\t\t\t</NcFormBoxButton>\n\t\t\t</NcFormBox>\n\t\t</NcFormGroup>\n\n\t\t<NcFormGroup label=\"CalDAV\" description=\"Access Nextcloud calendars from other apps and devices\">\n\t\t\t<NcFormBox>\n\t\t\t\t<NcFormBoxButton\n\t\t\t\t\tlabel=\"CalDAV URL\"\n\t\t\t\t\tdescription=\"https://cloud.example.com/remote.php/dav/\"\n\t\t\t\t\tinverted-accent>\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"mdiContentCopy\" inline />\n\t\t\t\t\t</template>\n\t\t\t\t</NcFormBoxButton>\n\t\t\t\t<NcFormBoxButton\n\t\t\t\t\tlabel=\"Server Address for iOS and macOS\"\n\t\t\t\t\tdescription=\"https://cloud.example.com/remote.php/dav/principals/users/user/\"\n\t\t\t\t\tinverted-accent>\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"mdiContentCopy\" inline />\n\t\t\t\t\t</template>\n\t\t\t\t</NcFormBoxButton>\n\t\t\t</NcFormBox>\n\t\t</NcFormGroup>\n\n\t\t<NcFormGroup label=\"Files\">\n\t\t\t<NcFormBox>\n\t\t\t\t<NcFormBoxButton\n\t\t\t\t\tlabel=\"Attachments folder\"\n\t\t\t\t\tdescription=\"/Talk\"\n\t\t\t\t\tinverted-accent>\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"mdiFolderOpenOutline\" inline />\n\t\t\t\t\t</template>\n\t\t\t\t</NcFormBoxButton>\n\t\t\t</NcFormBox>\n\t\t</NcFormGroup>\n\t</div>\n</template>\n```\n\n### Requirements\n\n- Label is required (`label` prop or the default slot)\n- Icon is required unless there is a default icon (links)\n\n```vue\n<template>\n\t<NcFormBox>\n\t\t<NcFormBoxButton description=\"No label example\">\n\t\t\t<template #icon>\n\t\t\t\t✅\n\t\t\t</template>\n\t\t</NcFormBoxButton>\n\t\t<NcFormBoxButton label=\"No icon example\"/>\n\t\t<NcFormBoxButton\n\t\t\tlabel=\"No icon link example\"\n\t\t\tdescription=\"Links have a default icon\"\n\t\t\thref=\"https://nextcloud.com\"\n\t\t\ttarget=\"_blank\" />\n\t</NcFormBox>\n</template>\n```\n</docs>\n"],"names":["_openBlock","_createBlock","_mergeProps","_unref","$style","invertedAccent","$emit","$slots","label","_renderSlot","description"],"mappings":"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"}
1
+ {"version":3,"file":"NcFormBoxButton-DvMw5yUf.mjs","sources":["../../src/composables/useButtonLink.ts","../../src/components/NcFormBoxButton/NcFormBoxButton.vue"],"sourcesContent":["/*!\n * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { AnchorHTMLAttributes, ButtonHTMLAttributes, MaybeRef } from 'vue'\nimport type { RouteLocationRaw } from 'vue-router'\n\nimport { computed, inject, reactive } from 'vue'\nimport { routerKey } from 'vue-router'\n\ntype ButtonLinkProps = {\n\t// Required - general link props\n\n\t/**\n\t * RouterLink's to props and a trigger to use RouterLink.\n\t * Note: This takes precedence over the href attribute.\n\t */\n\tto: MaybeRef<RouteLocationRaw | undefined>\n\t/**\n\t * HyperLink href attribute and a trigger to use <a> hyperlink.\n\t */\n\thref: MaybeRef<string | undefined>\n\t/**\n\t * Define additional attributes, based on the tag\n\t */\n\tadditionalAttrs?: (tag: 'RouterLink' | 'a' | 'button') => object | undefined\n\n\t// RouterLink props\n\n\t/**\n\t * RouterLink's activeClass prop\n\t */\n\tactiveClass?: MaybeRef<string | undefined>\n\n\t// Hyperlink\n\n\t/**\n\t * <a> hyperlink's target attribute\n\t */\n\ttarget?: MaybeRef<AnchorHTMLAttributes['target'] | undefined>\n\t/**\n\t * <a> hyperlink's download attribute\n\t */\n\tdownload?: MaybeRef<string | boolean | undefined>\n\n\t// Button\n\n\t/**\n\t * <button> element's type attribute, but default to \"button\" instead of \"submit\"\n\t */\n\ttype?: MaybeRef<ButtonHTMLAttributes['type'] | undefined>\n\t/**\n\t * <button> element's disabled attribute\n\t */\n\tdisabled?: MaybeRef<boolean | undefined>\n}\n\n/**\n * Reusable implementation of an interactive button-like element that can be a link or a button\n *\n * @param options - Props to determine the button/link behavior. Can be a reactive object, or an object with nested refs, or mixed.\n */\nexport function useButtonLink(options: ButtonLinkProps) {\n\t// Resolve all MaybeRef-s values and maybe reactive object via unwrapping\n\tconst props = reactive(options)\n\n\tconst hasVueRouterContext = inject(routerKey, null) !== null\n\n\t/**\n\t * Tag name to be used\n\t */\n\tconst tag = computed(() => {\n\t\t// TODO: should we warn if props.to is provided but there is no vue-router?\n\t\tif (hasVueRouterContext && props.to) {\n\t\t\t// Note: RouterLink is used as globally registered component (by name) and not imported intentionally\n\t\t\t// to use injected component from the app and not bundle it to the button\n\t\t\treturn 'RouterLink'\n\t\t} else if (props.href) {\n\t\t\treturn 'a'\n\t\t} else {\n\t\t\treturn 'button'\n\t\t}\n\t})\n\n\tconst isLink = computed(() => tag.value === 'RouterLink' || tag.value === 'a')\n\tconst isHyperLink = computed(() => tag.value === 'a')\n\tconst isRouterLink = computed(() => tag.value === 'RouterLink')\n\tconst isButton = computed(() => tag.value === 'button')\n\n\tconst attrs = computed(() => {\n\t\tif (tag.value === 'RouterLink') {\n\t\t\treturn {\n\t\t\t\tto: props.to,\n\t\t\t\tactiveClass: 'active',\n\t\t\t\t...(props.additionalAttrs?.('RouterLink') ?? {}),\n\t\t\t}\n\t\t} else if (tag.value === 'a') {\n\t\t\treturn {\n\t\t\t\thref: props.href,\n\t\t\t\ttarget: props.target,\n\t\t\t\tdownload: props.download || undefined,\n\t\t\t\trel: 'nofollow noreferrer noopener',\n\t\t\t\t...(props.additionalAttrs?.('a') ?? {}),\n\t\t\t}\n\t\t} else if (tag.value === 'button') {\n\t\t\treturn {\n\t\t\t\ttype: props.type || 'button',\n\t\t\t\tdisabled: props.disabled,\n\t\t\t\t...(props.additionalAttrs?.('button') ?? {}),\n\t\t\t}\n\t\t}\n\t})\n\n\treturn {\n\t\ttag,\n\t\tisLink,\n\t\tisHyperLink,\n\t\tisRouterLink,\n\t\tisButton,\n\t\tattrs,\n\t}\n}\n","<!--\n - SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { AnchorHTMLAttributes, Slot } from 'vue'\nimport type { RouteLocationRaw } from 'vue-router'\n\nimport { mdiArrowTopRight, mdiOpenInNew } from '@mdi/js'\nimport { computed, toRef } from 'vue'\nimport NcFormBoxItem from '../NcFormBox/NcFormBoxItem.vue'\nimport NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'\nimport { useButtonLink } from '../../composables/useButtonLink.ts'\n\nconst {\n\tlabel = undefined,\n\tdescription = undefined,\n\tinvertedAccent = false,\n\tto = undefined,\n\thref = undefined,\n\ttarget = undefined, // TODO: should it be _blank by default?\n\tdisabled = false,\n} = defineProps<{\n\t/** Main label */\n\tlabel?: string\n\t/** Optional description below the label, also used for the aria-describedby */\n\tdescription?: string\n\t/** Accent on the description instead of the label (see docs) */\n\tinvertedAccent?: boolean\n\t/** RouterLink's `to` prop; when provided, renders as `<RouterLink>` (takes precedence over the `href` prop) */\n\tto?: RouteLocationRaw\n\t/** Hyperlink `href` attribute; when provided, renders as `<a>` */\n\thref?: string\n\t/** Hyperlink's target attribute */\n\ttarget?: AnchorHTMLAttributes['target']\n\t/** Button's disabled attribute, not applicable to links */\n\tdisabled?: boolean\n}>()\n\ndefineEmits<{\n\t/** Native click event */\n\tclick: [event: MouseEvent]\n}>()\n\ndefineSlots<{\n\t/** Custom label content */\n\tdefault?: Slot\n\t/** Custom description content */\n\tdescription?: Slot\n\t/** Required icon (links have a default icon) */\n\ticon?: Slot // TODO: should the default link icon only be used for _blank links?\n}>()\n\nconst { tag, attrs, isLink } = useButtonLink({\n\tto: toRef(() => to),\n\thref: toRef(() => href),\n\ttarget: toRef(() => target),\n\tdisabled: toRef(() => disabled),\n})\n\nconst icon = computed(() => {\n\tif (isLink.value) {\n\t\treturn target === '_blank' ? mdiOpenInNew : mdiArrowTopRight\n\t}\n\treturn undefined\n})\n</script>\n\n<template>\n\t<NcFormBoxItem\n\t\t:tag\n\t\t:item-classes=\"[\n\t\t\t'button-vue', /* Reset server's global HTML button styles */\n\t\t\t$style.formBoxButton,\n\t\t]\"\n\t\t:inverted-accent\n\t\tv-bind=\"attrs\"\n\t\ttabindex=\"0\"\n\t\t@click=\"$emit('click', $event)\">\n\t\t<template v-if=\"$slots.default || label\" #default>\n\t\t\t<slot>\n\t\t\t\t{{ label }}\n\t\t\t</slot>\n\t\t</template>\n\t\t<template v-if=\"$slots.description || description\" #description>\n\t\t\t<slot name=\"description\">\n\t\t\t\t{{ description }}\n\t\t\t</slot>\n\t\t</template>\n\t\t<template v-if=\"$slots.icon || icon\" #icon>\n\t\t\t<slot name=\"icon\">\n\t\t\t\t<NcIconSvgWrapper v-if=\"icon\" :path=\"icon\" inline />\n\t\t\t</slot>\n\t\t</template>\n\t</NcFormBoxItem>\n</template>\n\n<style lang=\"scss\" module>\n.formBoxButton {\n\t/* Reset default HTML button styles */\n\tbackground: unset;\n\tborder: none;\n\tcolor: inherit;\n\tfont-size: inherit;\n\tfont-weight: inherit;\n\ttext-decoration: none;\n\ttext-align: inherit;\n\tline-height: inherit;\n\tpadding: 0;\n\tmargin: 0;\n\toutline: none;\n}\n</style>\n\n<docs>\n### General\n\nAn interactive button-like item within `<NcFormBox>`. It can be a button or a native link/router link if `to` or `href` props are provided.\n\nLike other form box items, it has a label and an optional description.\n\n```vue\n<script>\nimport { mdiContentCopy, mdiInformationOutline } from '@mdi/js'\n\nexport default {\n\tsetup() {\n\t\treturn {\n\t\t\tmdiContentCopy,\n\t\t\tmdiInformationOutline,\n\t\t}\n\t},\n}\n</script>\n\n<template>\n\t<NcFormBox>\n\t\t<NcFormBoxButton\n\t\t\tlabel=\"Nextcloud\"\n\t\t\thref=\"https://nextcloud.com\"\n\t\t\ttarget=\"_blank\" />\n\n\t\t<NcFormBoxButton\n\t\t\thref=\"https://nextcloud-vue-components.netlify.app\">\n\t\t\t<code>@nextcloud/vue</code> documentation\n\t\t</NcFormBoxButton>\n\n\t\t<NcFormBoxButton\n\t\t\tlabel=\"About\"\n\t\t\tdescription=\"Installation details\"\n\t\t\thref=\"https://nextcloud.com\"\n\t\t\ttarget=\"_blank\">\n\t\t\t<template #icon>\n\t\t\t\t<NcIconSvgWrapper :path=\"mdiInformationOutline\" inline />\n\t\t\t</template>\n\t\t</NcFormBoxButton>\n\n\t\t<NcFormBoxButton\n\t\t\tlabel=\"Public signing key\">\n\t\t\t<template #description>\n\t\t\t\t<code>SSBkb24ndCBrbm93IHdoeSB5b3UgZGVjb2RlZCB0aGlzIHZhbHVlDQrgvLwg44GkIOKXlV/il5Ug4Ly944Gk</code>\n\t\t\t</template>\n\t\t\t<template #icon>\n\t\t\t\t<NcIconSvgWrapper :path=\"mdiContentCopy\" inline />\n\t\t\t</template>\n\t\t</NcFormBoxButton>\n\t</NcFormBox>\n</template>\n```\n\n### Inverted accent\n\nSometimes the description is more important than the label. In such cases use `inverted-accent` prop.\n\nFor example:\n- **Steps:** the description of the step is more important than the step number\n- **Copy button:** the value being copied is more important than the value label\n- **Folder picker:** the selected folder path is more important than the input label\n\n```vue\n<script>\nimport { mdiContentCopy, mdiDomain, mdiFolderOpenOutline } from '@mdi/js'\n\nexport default {\n\tsetup() {\n\t\treturn { mdiContentCopy, mdiDomain, mdiFolderOpenOutline }\n\t},\n}\n</script>\n\n<template>\n\t<div style=\"display: flex; flex-direction: column; gap: calc(4 * var(--default-grid-baseline));\">\n\t\t<NcFormGroup label=\"Mailvelope\" description=\"A browser extension that enables easy OpenPGP encryption and decryption of emails\">\n\t\t\t<NcFormBox>\n\t\t\t\t<NcFormBoxButton\n\t\t\t\t\tlabel=\"Step 1\"\n\t\t\t\t\tdescription=\"Install the browser extension\"\n\t\t\t\t\thref=\"https://www.mailvelope.com/\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\tinverted-accent />\n\t\t\t\t<NcFormBoxButton\n\t\t\t\t\tlabel=\"Step 2\"\n\t\t\t\t\tdescription=\"Enable the current domain\"\n\t\t\t\t\tinverted-accent>\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"mdiDomain\" inline />\n\t\t\t\t\t</template>\n\t\t\t\t</NcFormBoxButton>\n\t\t\t</NcFormBox>\n\t\t</NcFormGroup>\n\n\t\t<NcFormGroup label=\"CalDAV\" description=\"Access Nextcloud calendars from other apps and devices\">\n\t\t\t<NcFormBox>\n\t\t\t\t<NcFormBoxButton\n\t\t\t\t\tlabel=\"CalDAV URL\"\n\t\t\t\t\tdescription=\"https://cloud.example.com/remote.php/dav/\"\n\t\t\t\t\tinverted-accent>\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"mdiContentCopy\" inline />\n\t\t\t\t\t</template>\n\t\t\t\t</NcFormBoxButton>\n\t\t\t\t<NcFormBoxButton\n\t\t\t\t\tlabel=\"Server Address for iOS and macOS\"\n\t\t\t\t\tdescription=\"https://cloud.example.com/remote.php/dav/principals/users/user/\"\n\t\t\t\t\tinverted-accent>\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"mdiContentCopy\" inline />\n\t\t\t\t\t</template>\n\t\t\t\t</NcFormBoxButton>\n\t\t\t</NcFormBox>\n\t\t</NcFormGroup>\n\n\t\t<NcFormGroup label=\"Files\">\n\t\t\t<NcFormBox>\n\t\t\t\t<NcFormBoxButton\n\t\t\t\t\tlabel=\"Attachments folder\"\n\t\t\t\t\tdescription=\"/Talk\"\n\t\t\t\t\tinverted-accent>\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"mdiFolderOpenOutline\" inline />\n\t\t\t\t\t</template>\n\t\t\t\t</NcFormBoxButton>\n\t\t\t</NcFormBox>\n\t\t</NcFormGroup>\n\t</div>\n</template>\n```\n\n### Requirements\n\n- Label is required (`label` prop or the default slot)\n- Icon is required unless there is a default icon (links)\n\n```vue\n<template>\n\t<NcFormBox>\n\t\t<NcFormBoxButton description=\"No label example\">\n\t\t\t<template #icon>\n\t\t\t\t✅\n\t\t\t</template>\n\t\t</NcFormBoxButton>\n\t\t<NcFormBoxButton label=\"No icon example\"/>\n\t\t<NcFormBoxButton\n\t\t\tlabel=\"No icon link example\"\n\t\t\tdescription=\"Links have a default icon\"\n\t\t\thref=\"https://nextcloud.com\"\n\t\t\ttarget=\"_blank\" />\n\t</NcFormBox>\n</template>\n```\n</docs>\n"],"names":["_openBlock","_createBlock","_mergeProps","_unref","$style","invertedAccent","$emit","$slots","label","_renderSlot","description"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { defineComponent, createBlock, openBlock, unref, createSlots, withCtx, createVNode, createTextVNode, toDisplayString, createElementVNode, renderSlot } from "vue";
2
2
  import { whenever } from "@vueuse/core";
3
- import { N as NcFormBoxButton } from "./NcFormBoxButton-Bptd324P.mjs";
3
+ import { N as NcFormBoxButton } from "./NcFormBoxButton-DvMw5yUf.mjs";
4
4
  import { N as NcIconSvgWrapper } from "./NcIconSvgWrapper-BvLanNaW.mjs";
5
- import { u as useCopy } from "./useCopy-D3yAxBJi.mjs";
5
+ import { u as useCopy } from "./useCopy-D4CcMqlA.mjs";
6
6
  const _hoisted_1 = { class: "hidden-visually" };
7
7
  const _sfc_main = /* @__PURE__ */ defineComponent({
8
8
  __name: "NcFormBoxCopyButton",
@@ -50,4 +50,4 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
50
50
  export {
51
51
  _sfc_main as _
52
52
  };
53
- //# sourceMappingURL=NcFormBoxCopyButton.vue_vue_type_script_setup_true_lang-DhnfC18v.mjs.map
53
+ //# sourceMappingURL=NcFormBoxCopyButton.vue_vue_type_script_setup_true_lang-DYtyXBqR.mjs.map