@nextcloud/vue
Version:
Nextcloud vue components
221 lines (220 loc) • 6.76 kB
JavaScript
require('../assets/NcMentionBubble-BL05HUeF.css');
require('../assets/NcHeaderMenu-BYjnMPPl.css');
"use strict";
const components = require("@vueuse/components");
const focusTrap = require("focus-trap");
const GenRandomId = require("./GenRandomId-BQDud3d4.cjs");
const Mixins_clickOutsideOptions = require("../Mixins/clickOutsideOptions.cjs");
require("../Composables/useIsFullscreen.cjs");
require("../Composables/useIsMobile.cjs");
require("@nextcloud/router");
;/* empty css */
const _pluginVue2_normalizer = require("./_plugin-vue2_normalizer-V0q-tHlQ.cjs");
require("escape-html");
require("striptags");
require("vue");
require("@nextcloud/auth");
require("@nextcloud/axios");
require("@nextcloud/capabilities");
const focusTrap$1 = require("./focusTrap-EeXFmjdI.cjs");
const Components_NcButton = require("../Components/NcButton.cjs");
const _sfc_main = {
name: "NcHeaderMenu",
components: {
NcButton: Components_NcButton
},
directives: {
ClickOutside: components.vOnClickOutside
},
mixins: [
Mixins_clickOutsideOptions
],
props: {
/**
* Unique id for this menu
*/
id: {
type: String,
required: true
},
/**
* aria-label attribute of the menu open button
*/
ariaLabel: {
type: String,
default: ""
},
/**
* Current menu open state
*/
open: {
type: Boolean,
default: false
},
/**
* Pass `true` if the header menu is used for website navigation
*
* The wrapper tag will be set to `nav` and its `aria-labelledby`
* will be associated with the menu open button
*/
isNav: {
type: Boolean,
default: false
},
/**
* Additional visually hidden description text for the menu
* open button
*/
description: {
type: String,
default: null
}
},
emits: [
"close",
"closed",
"open",
"opened",
"update:open",
"cancel"
],
data() {
return {
focusTrap: null,
opened: this.open,
shortcutsDisabled: window.OCP?.Accessibility?.disableKeyboardShortcuts?.(),
triggerId: GenRandomId.GenRandomId(),
descriptionId: GenRandomId.GenRandomId()
};
},
computed: {
wrapperTag() {
return this.isNav ? "nav" : "div";
},
clickOutsideConfig() {
return [
this.closeMenu,
this.clickOutsideOptions
];
},
listeners() {
if (this.isNav) {
return {
focusout: this.onFocusOut
};
}
return null;
}
},
watch: {
open(open) {
if (open) {
this.openMenu();
} else {
this.closeMenu();
}
}
},
mounted() {
document.addEventListener("keydown", this.onKeyDown);
},
beforeDestroy() {
document.removeEventListener("keydown", this.onKeyDown);
},
methods: {
/**
* Toggle the current menu open state
*/
toggleMenu() {
if (!this.opened) {
this.openMenu();
} else {
this.closeMenu();
}
},
/**
* Close the current menu
*
* @param {boolean} cancelled emit a cancel event instead of close
*/
closeMenu(cancelled = false) {
this.opened = false;
this.$emit(cancelled ? "cancel" : "close");
this.$emit("update:open", false);
this.clearFocusTrap();
this.$nextTick(() => {
this.$emit("closed");
});
},
/**
* Open the current menu
*/
openMenu() {
this.opened = true;
this.$emit("open");
this.$emit("update:open", true);
this.$nextTick(() => {
this.useFocusTrap();
this.$emit("opened");
});
},
onKeyDown(event) {
if (this.shortcutsDisabled || !this.opened) {
return;
}
if (event.key === "Escape") {
event.preventDefault();
this.closeMenu(true);
}
},
/**
* @param {FocusEvent} event The focus event
*/
onFocusOut(event) {
if (!this.$refs.headerMenu.contains(event.relatedTarget)) {
this.closeMenu();
}
},
/**
* Add focus trap for accessibility.
* Shall only be used when all children are mounted
* and available in the DOM. We use $nextTick for that.
*/
async useFocusTrap() {
if (this.isNav || this.focusTrap) {
return;
}
const contentContainer = this.$refs.content;
this.focusTrap = focusTrap.createFocusTrap(contentContainer, {
allowOutsideClick: true,
trapStack: focusTrap$1.getTrapStack(),
fallbackFocus: this.$refs.trigger
});
this.focusTrap.activate();
},
clearFocusTrap() {
this.focusTrap?.deactivate();
this.focusTrap = null;
}
}
};
var _sfc_render = function render() {
var _vm = this, _c = _vm._self._c;
return _c(_vm.wrapperTag, _vm._g({ directives: [{ name: "click-outside", rawName: "v-click-outside", value: _vm.clickOutsideConfig, expression: "clickOutsideConfig" }], ref: "headerMenu", tag: "component", staticClass: "header-menu", class: { "header-menu--opened": _vm.opened }, attrs: { "id": _vm.id, "aria-labelledby": _vm.isNav ? _vm.triggerId : null } }, _vm.listeners), [_c("NcButton", { ref: "trigger", staticClass: "header-menu__trigger", attrs: { "id": _vm.isNav ? _vm.triggerId : null, "type": "tertiary-no-background", "aria-label": _vm.ariaLabel, "aria-describedby": _vm.description ? _vm.descriptionId : null, "aria-controls": `header-menu-${_vm.id}`, "aria-expanded": _vm.opened.toString(), "size": "large" }, on: { "click": function($event) {
$event.preventDefault();
return _vm.toggleMenu.apply(null, arguments);
} }, scopedSlots: _vm._u([{ key: "icon", fn: function() {
return [_vm._t("trigger")];
}, proxy: true }], null, true) }), _vm.description ? _c("span", { staticClass: "header-menu__description hidden-visually", attrs: { "id": _vm.descriptionId } }, [_vm._v(" " + _vm._s(_vm.description) + " ")]) : _vm._e(), _c("div", { directives: [{ name: "show", rawName: "v-show", value: _vm.opened, expression: "opened" }], staticClass: "header-menu__carret" }), _c("div", { directives: [{ name: "show", rawName: "v-show", value: _vm.opened, expression: "opened" }], staticClass: "header-menu__wrapper", attrs: { "id": `header-menu-${_vm.id}` } }, [_c("div", { ref: "content", staticClass: "header-menu__content" }, [_vm._t("default")], 2)])], 1);
};
var _sfc_staticRenderFns = [];
var __component__ = /* @__PURE__ */ _pluginVue2_normalizer.normalizeComponent(
_sfc_main,
_sfc_render,
_sfc_staticRenderFns,
false,
null,
"ba584e05"
);
const NcHeaderMenu = __component__.exports;
exports.NcHeaderMenu = NcHeaderMenu;