UNPKG

primevue

Version:

PrimeVue is an open source UI library for Vue featuring a rich set of 80+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBloc

1 lines 113 kB
{"version":3,"file":"index.mjs","sources":["../../src/menubar/BaseMenubar.vue","../../src/menubar/MenubarSub.vue","../../src/menubar/MenubarSub.vue?vue&type=template&id=3775ff40&lang.js","../../src/menubar/Menubar.vue","../../src/menubar/Menubar.vue?vue&type=template&id=3e375c2c&lang.js"],"sourcesContent":["<script>\nimport BaseComponent from '@primevue/core/basecomponent';\nimport MenubarStyle from 'primevue/menubar/style';\n\nexport default {\n name: 'BaseMenubar',\n extends: BaseComponent,\n props: {\n model: {\n type: Array,\n default: null\n },\n buttonProps: {\n type: null,\n default: null\n },\n breakpoint: {\n type: String,\n default: '960px'\n },\n ariaLabelledby: {\n type: String,\n default: null\n },\n ariaLabel: {\n type: String,\n default: null\n }\n },\n style: MenubarStyle,\n provide() {\n return {\n $pcMenubar: this,\n $parentInstance: this\n };\n }\n};\n</script>\n","<template>\n <ul :class=\"level === 0 ? cx('rootList') : cx('submenu')\" v-bind=\"level === 0 ? ptm('rootList') : ptm('submenu')\">\n <template v-for=\"(processedItem, index) of items\" :key=\"getItemKey(processedItem)\">\n <li\n v-if=\"isItemVisible(processedItem) && !getItemProp(processedItem, 'separator')\"\n :id=\"getItemId(processedItem)\"\n :style=\"getItemProp(processedItem, 'style')\"\n :class=\"[cx('item', { processedItem }), getItemProp(processedItem, 'class')]\"\n role=\"menuitem\"\n :aria-label=\"getItemLabel(processedItem)\"\n :aria-disabled=\"isItemDisabled(processedItem) || undefined\"\n :aria-expanded=\"isItemGroup(processedItem) ? isItemActive(processedItem) : undefined\"\n :aria-haspopup=\"isItemGroup(processedItem) && !getItemProp(processedItem, 'to') ? 'menu' : undefined\"\n :aria-level=\"level + 1\"\n :aria-setsize=\"getAriaSetSize\"\n :aria-posinset=\"getAriaPosInset(index)\"\n v-bind=\"getPTOptions(processedItem, index, 'item')\"\n :data-p-active=\"isItemActive(processedItem)\"\n :data-p-focused=\"isItemFocused(processedItem)\"\n :data-p-disabled=\"isItemDisabled(processedItem)\"\n >\n <div\n :class=\"cx('itemContent')\"\n @click=\"onItemClick($event, processedItem)\"\n @mouseenter=\"onItemMouseEnter($event, processedItem)\"\n @mousemove=\"onItemMouseMove($event, processedItem)\"\n v-bind=\"getPTOptions(processedItem, index, 'itemContent')\"\n >\n <template v-if=\"!templates.item\">\n <a v-ripple :href=\"getItemProp(processedItem, 'url')\" :class=\"cx('itemLink')\" :target=\"getItemProp(processedItem, 'target')\" tabindex=\"-1\" v-bind=\"getPTOptions(processedItem, index, 'itemLink')\">\n <component v-if=\"templates.itemicon\" :is=\"templates.itemicon\" :item=\"processedItem.item\" :class=\"cx('itemIcon')\" />\n <span v-else-if=\"getItemProp(processedItem, 'icon')\" :class=\"[cx('itemIcon'), getItemProp(processedItem, 'icon')]\" v-bind=\"getPTOptions(processedItem, index, 'itemIcon')\" />\n <span :id=\"getItemLabelId(processedItem)\" :class=\"cx('itemLabel')\" v-bind=\"getPTOptions(processedItem, index, 'itemLabel')\">{{ getItemLabel(processedItem) }}</span>\n <template v-if=\"getItemProp(processedItem, 'items')\">\n <component v-if=\"templates.submenuicon\" :is=\"templates.submenuicon\" :root=\"root\" :active=\"isItemActive(processedItem)\" :class=\"cx('submenuIcon')\" />\n <component v-else :is=\"root ? 'AngleDownIcon' : 'AngleRightIcon'\" :class=\"cx('submenuIcon')\" v-bind=\"getPTOptions(processedItem, index, 'submenuIcon')\" />\n </template>\n </a>\n </template>\n <component v-else :is=\"templates.item\" :item=\"processedItem.item\" :root=\"root\" :hasSubmenu=\"getItemProp(processedItem, 'items')\" :label=\"getItemLabel(processedItem)\" :props=\"getMenuItemProps(processedItem, index)\"></component>\n </div>\n <MenubarSub\n v-if=\"isItemVisible(processedItem) && isItemGroup(processedItem)\"\n :id=\"getItemId(processedItem) + '_list'\"\n :menuId=\"menuId\"\n role=\"menu\"\n :style=\"sx('submenu', true, { processedItem })\"\n :focusedItemId=\"focusedItemId\"\n :items=\"processedItem.items\"\n :mobileActive=\"mobileActive\"\n :activeItemPath=\"activeItemPath\"\n :templates=\"templates\"\n :level=\"level + 1\"\n :aria-labelledby=\"getItemLabelId(processedItem)\"\n :pt=\"pt\"\n :unstyled=\"unstyled\"\n @item-click=\"$emit('item-click', $event)\"\n @item-mouseenter=\"$emit('item-mouseenter', $event)\"\n @item-mousemove=\"$emit('item-mousemove', $event)\"\n />\n </li>\n <li\n v-if=\"isItemVisible(processedItem) && getItemProp(processedItem, 'separator')\"\n :id=\"getItemId(processedItem)\"\n :class=\"[cx('separator'), getItemProp(processedItem, 'class')]\"\n :style=\"getItemProp(processedItem, 'style')\"\n role=\"separator\"\n v-bind=\"ptm('separator')\"\n ></li>\n </template>\n </ul>\n</template>\n\n<script>\nimport { isNotEmpty, resolve } from '@primeuix/utils/object';\nimport BaseComponent from '@primevue/core/basecomponent';\nimport AngleDownIcon from '@primevue/icons/angledown';\nimport AngleRightIcon from '@primevue/icons/angleright';\nimport Ripple from 'primevue/ripple';\nimport { mergeProps } from 'vue';\n\nexport default {\n name: 'MenubarSub',\n hostName: 'Menubar',\n extends: BaseComponent,\n emits: ['item-mouseenter', 'item-click', 'item-mousemove'],\n props: {\n items: {\n type: Array,\n default: null\n },\n root: {\n type: Boolean,\n default: false\n },\n popup: {\n type: Boolean,\n default: false\n },\n mobileActive: {\n type: Boolean,\n default: false\n },\n templates: {\n type: Object,\n default: null\n },\n level: {\n type: Number,\n default: 0\n },\n menuId: {\n type: String,\n default: null\n },\n focusedItemId: {\n type: String,\n default: null\n },\n activeItemPath: {\n type: Object,\n default: null\n }\n },\n list: null,\n\n methods: {\n getItemId(processedItem) {\n return `${this.menuId}_${processedItem.key}`;\n },\n getItemKey(processedItem) {\n return this.getItemId(processedItem);\n },\n getItemProp(processedItem, name, params) {\n return processedItem && processedItem.item ? resolve(processedItem.item[name], params) : undefined;\n },\n getItemLabel(processedItem) {\n return this.getItemProp(processedItem, 'label');\n },\n getItemLabelId(processedItem) {\n return `${this.menuId}_${processedItem.key}_label`;\n },\n getPTOptions(processedItem, index, key) {\n return this.ptm(key, {\n context: {\n item: processedItem.item,\n index,\n active: this.isItemActive(processedItem),\n focused: this.isItemFocused(processedItem),\n disabled: this.isItemDisabled(processedItem),\n level: this.level\n }\n });\n },\n isItemActive(processedItem) {\n return this.activeItemPath.some((path) => path.key === processedItem.key);\n },\n isItemVisible(processedItem) {\n return this.getItemProp(processedItem, 'visible') !== false;\n },\n isItemDisabled(processedItem) {\n return this.getItemProp(processedItem, 'disabled');\n },\n isItemFocused(processedItem) {\n return this.focusedItemId === this.getItemId(processedItem);\n },\n isItemGroup(processedItem) {\n return isNotEmpty(processedItem.items);\n },\n onItemClick(event, processedItem) {\n this.getItemProp(processedItem, 'command', { originalEvent: event, item: processedItem.item });\n this.$emit('item-click', { originalEvent: event, processedItem, isFocus: true });\n },\n onItemMouseEnter(event, processedItem) {\n this.$emit('item-mouseenter', { originalEvent: event, processedItem });\n },\n onItemMouseMove(event, processedItem) {\n this.$emit('item-mousemove', { originalEvent: event, processedItem });\n },\n getAriaPosInset(index) {\n return index - this.calculateAriaSetSize.slice(0, index).length + 1;\n },\n getMenuItemProps(processedItem, index) {\n return {\n action: mergeProps(\n {\n class: this.cx('itemLink'),\n tabindex: -1\n },\n this.getPTOptions(processedItem, index, 'itemLink')\n ),\n icon: mergeProps(\n {\n class: [this.cx('itemIcon'), this.getItemProp(processedItem, 'icon')]\n },\n this.getPTOptions(processedItem, index, 'itemIcon')\n ),\n label: mergeProps(\n {\n class: this.cx('itemLabel')\n },\n this.getPTOptions(processedItem, index, 'itemLabel')\n ),\n submenuicon: mergeProps(\n {\n class: this.cx('submenuIcon')\n },\n this.getPTOptions(processedItem, index, 'submenuIcon')\n )\n };\n }\n },\n computed: {\n calculateAriaSetSize() {\n return this.items.filter((processedItem) => this.isItemVisible(processedItem) && this.getItemProp(processedItem, 'separator'));\n },\n getAriaSetSize() {\n return this.items.filter((processedItem) => this.isItemVisible(processedItem) && !this.getItemProp(processedItem, 'separator')).length;\n }\n },\n components: {\n AngleRightIcon: AngleRightIcon,\n AngleDownIcon: AngleDownIcon\n },\n directives: {\n ripple: Ripple\n }\n};\n</script>\n","<template>\n <ul :class=\"level === 0 ? cx('rootList') : cx('submenu')\" v-bind=\"level === 0 ? ptm('rootList') : ptm('submenu')\">\n <template v-for=\"(processedItem, index) of items\" :key=\"getItemKey(processedItem)\">\n <li\n v-if=\"isItemVisible(processedItem) && !getItemProp(processedItem, 'separator')\"\n :id=\"getItemId(processedItem)\"\n :style=\"getItemProp(processedItem, 'style')\"\n :class=\"[cx('item', { processedItem }), getItemProp(processedItem, 'class')]\"\n role=\"menuitem\"\n :aria-label=\"getItemLabel(processedItem)\"\n :aria-disabled=\"isItemDisabled(processedItem) || undefined\"\n :aria-expanded=\"isItemGroup(processedItem) ? isItemActive(processedItem) : undefined\"\n :aria-haspopup=\"isItemGroup(processedItem) && !getItemProp(processedItem, 'to') ? 'menu' : undefined\"\n :aria-level=\"level + 1\"\n :aria-setsize=\"getAriaSetSize\"\n :aria-posinset=\"getAriaPosInset(index)\"\n v-bind=\"getPTOptions(processedItem, index, 'item')\"\n :data-p-active=\"isItemActive(processedItem)\"\n :data-p-focused=\"isItemFocused(processedItem)\"\n :data-p-disabled=\"isItemDisabled(processedItem)\"\n >\n <div\n :class=\"cx('itemContent')\"\n @click=\"onItemClick($event, processedItem)\"\n @mouseenter=\"onItemMouseEnter($event, processedItem)\"\n @mousemove=\"onItemMouseMove($event, processedItem)\"\n v-bind=\"getPTOptions(processedItem, index, 'itemContent')\"\n >\n <template v-if=\"!templates.item\">\n <a v-ripple :href=\"getItemProp(processedItem, 'url')\" :class=\"cx('itemLink')\" :target=\"getItemProp(processedItem, 'target')\" tabindex=\"-1\" v-bind=\"getPTOptions(processedItem, index, 'itemLink')\">\n <component v-if=\"templates.itemicon\" :is=\"templates.itemicon\" :item=\"processedItem.item\" :class=\"cx('itemIcon')\" />\n <span v-else-if=\"getItemProp(processedItem, 'icon')\" :class=\"[cx('itemIcon'), getItemProp(processedItem, 'icon')]\" v-bind=\"getPTOptions(processedItem, index, 'itemIcon')\" />\n <span :id=\"getItemLabelId(processedItem)\" :class=\"cx('itemLabel')\" v-bind=\"getPTOptions(processedItem, index, 'itemLabel')\">{{ getItemLabel(processedItem) }}</span>\n <template v-if=\"getItemProp(processedItem, 'items')\">\n <component v-if=\"templates.submenuicon\" :is=\"templates.submenuicon\" :root=\"root\" :active=\"isItemActive(processedItem)\" :class=\"cx('submenuIcon')\" />\n <component v-else :is=\"root ? 'AngleDownIcon' : 'AngleRightIcon'\" :class=\"cx('submenuIcon')\" v-bind=\"getPTOptions(processedItem, index, 'submenuIcon')\" />\n </template>\n </a>\n </template>\n <component v-else :is=\"templates.item\" :item=\"processedItem.item\" :root=\"root\" :hasSubmenu=\"getItemProp(processedItem, 'items')\" :label=\"getItemLabel(processedItem)\" :props=\"getMenuItemProps(processedItem, index)\"></component>\n </div>\n <MenubarSub\n v-if=\"isItemVisible(processedItem) && isItemGroup(processedItem)\"\n :id=\"getItemId(processedItem) + '_list'\"\n :menuId=\"menuId\"\n role=\"menu\"\n :style=\"sx('submenu', true, { processedItem })\"\n :focusedItemId=\"focusedItemId\"\n :items=\"processedItem.items\"\n :mobileActive=\"mobileActive\"\n :activeItemPath=\"activeItemPath\"\n :templates=\"templates\"\n :level=\"level + 1\"\n :aria-labelledby=\"getItemLabelId(processedItem)\"\n :pt=\"pt\"\n :unstyled=\"unstyled\"\n @item-click=\"$emit('item-click', $event)\"\n @item-mouseenter=\"$emit('item-mouseenter', $event)\"\n @item-mousemove=\"$emit('item-mousemove', $event)\"\n />\n </li>\n <li\n v-if=\"isItemVisible(processedItem) && getItemProp(processedItem, 'separator')\"\n :id=\"getItemId(processedItem)\"\n :class=\"[cx('separator'), getItemProp(processedItem, 'class')]\"\n :style=\"getItemProp(processedItem, 'style')\"\n role=\"separator\"\n v-bind=\"ptm('separator')\"\n ></li>\n </template>\n </ul>\n</template>\n\n<script>\nimport { isNotEmpty, resolve } from '@primeuix/utils/object';\nimport BaseComponent from '@primevue/core/basecomponent';\nimport AngleDownIcon from '@primevue/icons/angledown';\nimport AngleRightIcon from '@primevue/icons/angleright';\nimport Ripple from 'primevue/ripple';\nimport { mergeProps } from 'vue';\n\nexport default {\n name: 'MenubarSub',\n hostName: 'Menubar',\n extends: BaseComponent,\n emits: ['item-mouseenter', 'item-click', 'item-mousemove'],\n props: {\n items: {\n type: Array,\n default: null\n },\n root: {\n type: Boolean,\n default: false\n },\n popup: {\n type: Boolean,\n default: false\n },\n mobileActive: {\n type: Boolean,\n default: false\n },\n templates: {\n type: Object,\n default: null\n },\n level: {\n type: Number,\n default: 0\n },\n menuId: {\n type: String,\n default: null\n },\n focusedItemId: {\n type: String,\n default: null\n },\n activeItemPath: {\n type: Object,\n default: null\n }\n },\n list: null,\n\n methods: {\n getItemId(processedItem) {\n return `${this.menuId}_${processedItem.key}`;\n },\n getItemKey(processedItem) {\n return this.getItemId(processedItem);\n },\n getItemProp(processedItem, name, params) {\n return processedItem && processedItem.item ? resolve(processedItem.item[name], params) : undefined;\n },\n getItemLabel(processedItem) {\n return this.getItemProp(processedItem, 'label');\n },\n getItemLabelId(processedItem) {\n return `${this.menuId}_${processedItem.key}_label`;\n },\n getPTOptions(processedItem, index, key) {\n return this.ptm(key, {\n context: {\n item: processedItem.item,\n index,\n active: this.isItemActive(processedItem),\n focused: this.isItemFocused(processedItem),\n disabled: this.isItemDisabled(processedItem),\n level: this.level\n }\n });\n },\n isItemActive(processedItem) {\n return this.activeItemPath.some((path) => path.key === processedItem.key);\n },\n isItemVisible(processedItem) {\n return this.getItemProp(processedItem, 'visible') !== false;\n },\n isItemDisabled(processedItem) {\n return this.getItemProp(processedItem, 'disabled');\n },\n isItemFocused(processedItem) {\n return this.focusedItemId === this.getItemId(processedItem);\n },\n isItemGroup(processedItem) {\n return isNotEmpty(processedItem.items);\n },\n onItemClick(event, processedItem) {\n this.getItemProp(processedItem, 'command', { originalEvent: event, item: processedItem.item });\n this.$emit('item-click', { originalEvent: event, processedItem, isFocus: true });\n },\n onItemMouseEnter(event, processedItem) {\n this.$emit('item-mouseenter', { originalEvent: event, processedItem });\n },\n onItemMouseMove(event, processedItem) {\n this.$emit('item-mousemove', { originalEvent: event, processedItem });\n },\n getAriaPosInset(index) {\n return index - this.calculateAriaSetSize.slice(0, index).length + 1;\n },\n getMenuItemProps(processedItem, index) {\n return {\n action: mergeProps(\n {\n class: this.cx('itemLink'),\n tabindex: -1\n },\n this.getPTOptions(processedItem, index, 'itemLink')\n ),\n icon: mergeProps(\n {\n class: [this.cx('itemIcon'), this.getItemProp(processedItem, 'icon')]\n },\n this.getPTOptions(processedItem, index, 'itemIcon')\n ),\n label: mergeProps(\n {\n class: this.cx('itemLabel')\n },\n this.getPTOptions(processedItem, index, 'itemLabel')\n ),\n submenuicon: mergeProps(\n {\n class: this.cx('submenuIcon')\n },\n this.getPTOptions(processedItem, index, 'submenuIcon')\n )\n };\n }\n },\n computed: {\n calculateAriaSetSize() {\n return this.items.filter((processedItem) => this.isItemVisible(processedItem) && this.getItemProp(processedItem, 'separator'));\n },\n getAriaSetSize() {\n return this.items.filter((processedItem) => this.isItemVisible(processedItem) && !this.getItemProp(processedItem, 'separator')).length;\n }\n },\n components: {\n AngleRightIcon: AngleRightIcon,\n AngleDownIcon: AngleDownIcon\n },\n directives: {\n ripple: Ripple\n }\n};\n</script>\n","<template>\n <div :ref=\"containerRef\" :class=\"cx('root')\" v-bind=\"ptmi('root')\">\n <div v-if=\"$slots.start\" :class=\"cx('start')\" v-bind=\"ptm('start')\">\n <slot name=\"start\"></slot>\n </div>\n <slot :id=\"$id\" :name=\"$slots.button ? 'button' : 'menubutton'\" :class=\"cx('button')\" :toggleCallback=\"(event) => menuButtonClick(event)\">\n <!-- TODO: menubutton deprecated since v4.0-->\n <a\n v-if=\"model && model.length > 0\"\n ref=\"menubutton\"\n role=\"button\"\n tabindex=\"0\"\n :class=\"cx('button')\"\n :aria-haspopup=\"model.length && model.length > 0 ? true : false\"\n :aria-expanded=\"mobileActive\"\n :aria-controls=\"$id\"\n :aria-label=\"$primevue.config.locale.aria?.navigation\"\n @click=\"menuButtonClick($event)\"\n @keydown=\"menuButtonKeydown($event)\"\n v-bind=\"{ ...buttonProps, ...ptm('button') }\"\n >\n <!-- TODO: menubuttonicon deprecated since v4.0-->\n <slot :name=\"$slots.buttonicon ? 'buttonicon' : 'menubuttonicon'\">\n <BarsIcon v-bind=\"ptm('buttonicon')\" />\n </slot>\n </a>\n </slot>\n <MenubarSub\n :ref=\"menubarRef\"\n :id=\"$id + '_list'\"\n role=\"menubar\"\n :items=\"processedItems\"\n :templates=\"$slots\"\n :root=\"true\"\n :mobileActive=\"mobileActive\"\n tabindex=\"0\"\n :aria-activedescendant=\"focused ? focusedItemId : undefined\"\n :menuId=\"$id\"\n :focusedItemId=\"focused ? focusedItemId : undefined\"\n :activeItemPath=\"activeItemPath\"\n :level=\"0\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-label=\"ariaLabel\"\n :pt=\"pt\"\n :unstyled=\"unstyled\"\n @focus=\"onFocus\"\n @blur=\"onBlur\"\n @keydown=\"onKeyDown\"\n @item-click=\"onItemClick\"\n @item-mouseenter=\"onItemMouseEnter\"\n @item-mousemove=\"onItemMouseMove\"\n />\n <div v-if=\"$slots.end\" :class=\"cx('end')\" v-bind=\"ptm('end')\">\n <slot name=\"end\"></slot>\n </div>\n </div>\n</template>\n\n<script>\nimport { findSingle, focus, isTouchDevice } from '@primeuix/utils/dom';\nimport { findLastIndex, isEmpty, isNotEmpty, isPrintableCharacter, resolve } from '@primeuix/utils/object';\nimport { ZIndex } from '@primeuix/utils/zindex';\nimport BarsIcon from '@primevue/icons/bars';\nimport BaseMenubar from './BaseMenubar.vue';\nimport MenubarSub from './MenubarSub.vue';\n\nexport default {\n name: 'Menubar',\n extends: BaseMenubar,\n inheritAttrs: false,\n emits: ['focus', 'blur'],\n matchMediaListener: null,\n data() {\n return {\n mobileActive: false,\n focused: false,\n focusedItemInfo: { index: -1, level: 0, parentKey: '' },\n activeItemPath: [],\n dirty: false,\n query: null,\n queryMatches: false\n };\n },\n watch: {\n activeItemPath(newPath) {\n if (isNotEmpty(newPath)) {\n this.bindOutsideClickListener();\n this.bindResizeListener();\n } else {\n this.unbindOutsideClickListener();\n this.unbindResizeListener();\n }\n }\n },\n outsideClickListener: null,\n container: null,\n menubar: null,\n mounted() {\n this.bindMatchMediaListener();\n },\n beforeUnmount() {\n this.mobileActive = false;\n this.unbindOutsideClickListener();\n this.unbindResizeListener();\n this.unbindMatchMediaListener();\n\n if (this.container) {\n ZIndex.clear(this.container);\n }\n\n this.container = null;\n },\n methods: {\n getItemProp(item, name) {\n return item ? resolve(item[name]) : undefined;\n },\n getItemLabel(item) {\n return this.getItemProp(item, 'label');\n },\n isItemDisabled(item) {\n return this.getItemProp(item, 'disabled');\n },\n isItemVisible(item) {\n return this.getItemProp(item, 'visible') !== false;\n },\n isItemGroup(item) {\n return isNotEmpty(this.getItemProp(item, 'items'));\n },\n isItemSeparator(item) {\n return this.getItemProp(item, 'separator');\n },\n getProccessedItemLabel(processedItem) {\n return processedItem ? this.getItemLabel(processedItem.item) : undefined;\n },\n isProccessedItemGroup(processedItem) {\n return processedItem && isNotEmpty(processedItem.items);\n },\n toggle(event) {\n if (this.mobileActive) {\n this.mobileActive = false;\n ZIndex.clear(this.menubar);\n this.hide();\n } else {\n this.mobileActive = true;\n ZIndex.set('menu', this.menubar, this.$primevue.config.zIndex.menu);\n setTimeout(() => {\n this.show();\n }, 1);\n }\n\n this.bindOutsideClickListener();\n event.preventDefault();\n },\n show() {\n focus(this.menubar);\n },\n hide(event, isFocus) {\n if (this.mobileActive) {\n this.mobileActive = false;\n setTimeout(() => {\n focus(this.$refs.menubutton);\n }, 0);\n }\n\n this.activeItemPath = [];\n this.focusedItemInfo = { index: -1, level: 0, parentKey: '' };\n\n isFocus && focus(this.menubar);\n this.dirty = false;\n },\n onFocus(event) {\n this.focused = true;\n this.focusedItemInfo = this.focusedItemInfo.index !== -1 ? this.focusedItemInfo : { index: this.findFirstFocusedItemIndex(), level: 0, parentKey: '' };\n\n this.$emit('focus', event);\n },\n onBlur(event) {\n this.focused = false;\n this.focusedItemInfo = { index: -1, level: 0, parentKey: '' };\n this.searchValue = '';\n this.dirty = false;\n this.$emit('blur', event);\n },\n onKeyDown(event) {\n const metaKey = event.metaKey || event.ctrlKey;\n\n switch (event.code) {\n case 'ArrowDown':\n this.onArrowDownKey(event);\n break;\n\n case 'ArrowUp':\n this.onArrowUpKey(event);\n break;\n\n case 'ArrowLeft':\n this.onArrowLeftKey(event);\n break;\n\n case 'ArrowRight':\n this.onArrowRightKey(event);\n break;\n\n case 'Home':\n this.onHomeKey(event);\n break;\n\n case 'End':\n this.onEndKey(event);\n break;\n\n case 'Space':\n this.onSpaceKey(event);\n break;\n\n case 'Enter':\n case 'NumpadEnter':\n this.onEnterKey(event);\n break;\n\n case 'Escape':\n this.onEscapeKey(event);\n break;\n\n case 'Tab':\n this.onTabKey(event);\n break;\n\n case 'PageDown':\n case 'PageUp':\n case 'Backspace':\n case 'ShiftLeft':\n case 'ShiftRight':\n //NOOP\n break;\n\n default:\n if (!metaKey && isPrintableCharacter(event.key)) {\n this.searchItems(event, event.key);\n }\n\n break;\n }\n },\n onItemChange(event, type) {\n const { processedItem, isFocus } = event;\n\n if (isEmpty(processedItem)) return;\n\n const { index, key, level, parentKey, items } = processedItem;\n const grouped = isNotEmpty(items);\n const activeItemPath = this.activeItemPath.filter((p) => p.parentKey !== parentKey && p.parentKey !== key);\n\n grouped && activeItemPath.push(processedItem);\n\n this.focusedItemInfo = { index, level, parentKey };\n\n grouped && (this.dirty = true);\n isFocus && focus(this.menubar);\n\n if (type === 'hover' && this.queryMatches) {\n return;\n }\n\n this.activeItemPath = activeItemPath;\n },\n onItemClick(event) {\n const { originalEvent, processedItem } = event;\n const grouped = this.isProccessedItemGroup(processedItem);\n const root = isEmpty(processedItem.parent);\n const selected = this.isSelected(processedItem);\n\n if (selected) {\n const { index, key, level, parentKey } = processedItem;\n\n this.activeItemPath = this.activeItemPath.filter((p) => key !== p.key && key.startsWith(p.key));\n this.focusedItemInfo = { index, level, parentKey };\n\n this.dirty = !root;\n focus(this.menubar);\n } else {\n if (grouped) {\n this.onItemChange(event);\n } else {\n const rootProcessedItem = root ? processedItem : this.activeItemPath.find((p) => p.parentKey === '');\n\n this.hide(originalEvent);\n this.changeFocusedItemIndex(originalEvent, rootProcessedItem ? rootProcessedItem.index : -1);\n\n this.mobileActive = false;\n focus(this.menubar);\n }\n }\n },\n onItemMouseEnter(event) {\n if (this.dirty) {\n this.onItemChange(event, 'hover');\n }\n },\n onItemMouseMove(event) {\n if (this.focused) {\n this.changeFocusedItemIndex(event, event.processedItem.index);\n }\n },\n menuButtonClick(event) {\n this.toggle(event);\n },\n menuButtonKeydown(event) {\n (event.code === 'Enter' || event.code === 'NumpadEnter' || event.code === 'Space') && this.menuButtonClick(event);\n },\n onArrowDownKey(event) {\n const processedItem = this.visibleItems[this.focusedItemInfo.index];\n const root = processedItem ? isEmpty(processedItem.parent) : null;\n\n if (root) {\n const grouped = this.isProccessedItemGroup(processedItem);\n\n if (grouped) {\n this.onItemChange({ originalEvent: event, processedItem });\n this.focusedItemInfo = { index: -1, parentKey: processedItem.key };\n this.onArrowRightKey(event);\n }\n } else {\n const itemIndex = this.focusedItemInfo.index !== -1 ? this.findNextItemIndex(this.focusedItemInfo.index) : this.findFirstFocusedItemIndex();\n\n this.changeFocusedItemIndex(event, itemIndex);\n }\n\n event.preventDefault();\n },\n onArrowUpKey(event) {\n const processedItem = this.visibleItems[this.focusedItemInfo.index];\n const root = isEmpty(processedItem.parent);\n\n if (root) {\n const grouped = this.isProccessedItemGroup(processedItem);\n\n if (grouped) {\n this.onItemChange({ originalEvent: event, processedItem });\n this.focusedItemInfo = { index: -1, parentKey: processedItem.key };\n const itemIndex = this.findLastItemIndex();\n\n this.changeFocusedItemIndex(event, itemIndex);\n }\n } else {\n const parentItem = this.activeItemPath.find((p) => p.key === processedItem.parentKey);\n\n if (this.focusedItemInfo.index === 0) {\n this.focusedItemInfo = { index: -1, parentKey: parentItem ? parentItem.parentKey : '' };\n this.searchValue = '';\n this.onArrowLeftKey(event);\n this.activeItemPath = this.activeItemPath.filter((p) => p.parentKey !== this.focusedItemInfo.parentKey);\n } else {\n const itemIndex = this.focusedItemInfo.index !== -1 ? this.findPrevItemIndex(this.focusedItemInfo.index) : this.findLastFocusedItemIndex();\n\n this.changeFocusedItemIndex(event, itemIndex);\n }\n }\n\n event.preventDefault();\n },\n onArrowLeftKey(event) {\n const processedItem = this.visibleItems[this.focusedItemInfo.index];\n const parentItem = processedItem ? this.activeItemPath.find((p) => p.key === processedItem.parentKey) : null;\n\n if (parentItem) {\n this.onItemChange({ originalEvent: event, processedItem: parentItem });\n this.activeItemPath = this.activeItemPath.filter((p) => p.parentKey !== this.focusedItemInfo.parentKey);\n\n event.preventDefault();\n } else {\n const itemIndex = this.focusedItemInfo.index !== -1 ? this.findPrevItemIndex(this.focusedItemInfo.index) : this.findLastFocusedItemIndex();\n\n this.changeFocusedItemIndex(event, itemIndex);\n event.preventDefault();\n }\n },\n onArrowRightKey(event) {\n const processedItem = this.visibleItems[this.focusedItemInfo.index];\n const parentItem = processedItem ? this.activeItemPath.find((p) => p.key === processedItem.parentKey) : null;\n\n if (parentItem) {\n const grouped = this.isProccessedItemGroup(processedItem);\n\n if (grouped) {\n this.onItemChange({ originalEvent: event, processedItem });\n this.focusedItemInfo = { index: -1, parentKey: processedItem.key };\n this.onArrowDownKey(event);\n }\n } else {\n const itemIndex = this.focusedItemInfo.index !== -1 ? this.findNextItemIndex(this.focusedItemInfo.index) : this.findFirstFocusedItemIndex();\n\n this.changeFocusedItemIndex(event, itemIndex);\n event.preventDefault();\n }\n },\n onHomeKey(event) {\n this.changeFocusedItemIndex(event, this.findFirstItemIndex());\n event.preventDefault();\n },\n onEndKey(event) {\n this.changeFocusedItemIndex(event, this.findLastItemIndex());\n event.preventDefault();\n },\n onEnterKey(event) {\n if (this.focusedItemInfo.index !== -1) {\n const element = findSingle(this.menubar, `li[id=\"${`${this.focusedItemId}`}\"]`);\n const anchorElement = element && findSingle(element, 'a[data-pc-section=\"itemlink\"]');\n\n anchorElement ? anchorElement.click() : element && element.click();\n\n const processedItem = this.visibleItems[this.focusedItemInfo.index];\n const grouped = this.isProccessedItemGroup(processedItem);\n\n !grouped && (this.focusedItemInfo.index = this.findFirstFocusedItemIndex());\n }\n\n event.preventDefault();\n },\n onSpaceKey(event) {\n this.onEnterKey(event);\n },\n onEscapeKey(event) {\n if (this.focusedItemInfo.level !== 0) {\n const _focusedItemInfo = this.focusedItemInfo;\n\n this.hide(event, false);\n this.focusedItemInfo = { index: Number(_focusedItemInfo.parentKey.split('_')[0]), level: 0, parentKey: '' };\n }\n\n event.preventDefault();\n },\n onTabKey(event) {\n if (this.focusedItemInfo.index !== -1) {\n const processedItem = this.visibleItems[this.focusedItemInfo.index];\n const grouped = this.isProccessedItemGroup(processedItem);\n\n !grouped && this.onItemChange({ originalEvent: event, processedItem });\n }\n\n this.hide();\n },\n bindOutsideClickListener() {\n if (!this.outsideClickListener) {\n this.outsideClickListener = (event) => {\n const isOutsideContainer = this.container && !this.container.contains(event.target);\n const isOutsideTarget = !(this.target && (this.target === event.target || this.target.contains(event.target)));\n\n if (isOutsideContainer && isOutsideTarget) {\n this.hide();\n }\n };\n\n document.addEventListener('click', this.outsideClickListener, true);\n }\n },\n unbindOutsideClickListener() {\n if (this.outsideClickListener) {\n document.removeEventListener('click', this.outsideClickListener, true);\n this.outsideClickListener = null;\n }\n },\n bindResizeListener() {\n if (!this.resizeListener) {\n this.resizeListener = (event) => {\n if (!isTouchDevice()) {\n this.hide(event, true);\n }\n\n this.mobileActive = false;\n };\n\n window.addEventListener('resize', this.resizeListener);\n }\n },\n unbindResizeListener() {\n if (this.resizeListener) {\n window.removeEventListener('resize', this.resizeListener);\n this.resizeListener = null;\n }\n },\n bindMatchMediaListener() {\n if (!this.matchMediaListener) {\n const query = matchMedia(`(max-width: ${this.breakpoint})`);\n\n this.query = query;\n this.queryMatches = query.matches;\n\n this.matchMediaListener = () => {\n this.queryMatches = query.matches;\n this.mobileActive = false;\n };\n\n this.query.addEventListener('change', this.matchMediaListener);\n }\n },\n unbindMatchMediaListener() {\n if (this.matchMediaListener) {\n this.query.removeEventListener('change', this.matchMediaListener);\n this.matchMediaListener = null;\n }\n },\n isItemMatched(processedItem) {\n return this.isValidItem(processedItem) && this.getProccessedItemLabel(processedItem)?.toLocaleLowerCase().startsWith(this.searchValue.toLocaleLowerCase());\n },\n isValidItem(processedItem) {\n return !!processedItem && !this.isItemDisabled(processedItem.item) && !this.isItemSeparator(processedItem.item) && this.isItemVisible(processedItem.item);\n },\n isValidSelectedItem(processedItem) {\n return this.isValidItem(processedItem) && this.isSelected(processedItem);\n },\n isSelected(processedItem) {\n return this.activeItemPath.some((p) => p.key === processedItem.key);\n },\n findFirstItemIndex() {\n return this.visibleItems.findIndex((processedItem) => this.isValidItem(processedItem));\n },\n findLastItemIndex() {\n return findLastIndex(this.visibleItems, (processedItem) => this.isValidItem(processedItem));\n },\n findNextItemIndex(index) {\n const matchedItemIndex = index < this.visibleItems.length - 1 ? this.visibleItems.slice(index + 1).findIndex((processedItem) => this.isValidItem(processedItem)) : -1;\n\n return matchedItemIndex > -1 ? matchedItemIndex + index + 1 : index;\n },\n findPrevItemIndex(index) {\n const matchedItemIndex = index > 0 ? findLastIndex(this.visibleItems.slice(0, index), (processedItem) => this.isValidItem(processedItem)) : -1;\n\n return matchedItemIndex > -1 ? matchedItemIndex : index;\n },\n findSelectedItemIndex() {\n return this.visibleItems.findIndex((processedItem) => this.isValidSelectedItem(processedItem));\n },\n findFirstFocusedItemIndex() {\n const selectedIndex = this.findSelectedItemIndex();\n\n return selectedIndex < 0 ? this.findFirstItemIndex() : selectedIndex;\n },\n findLastFocusedItemIndex() {\n const selectedIndex = this.findSelectedItemIndex();\n\n return selectedIndex < 0 ? this.findLastItemIndex() : selectedIndex;\n },\n searchItems(event, char) {\n this.searchValue = (this.searchValue || '') + char;\n\n let itemIndex = -1;\n let matched = false;\n\n if (this.focusedItemInfo.index !== -1) {\n itemIndex = this.visibleItems.slice(this.focusedItemInfo.index).findIndex((processedItem) => this.isItemMatched(processedItem));\n itemIndex = itemIndex === -1 ? this.visibleItems.slice(0, this.focusedItemInfo.index).findIndex((processedItem) => this.isItemMatched(processedItem)) : itemIndex + this.focusedItemInfo.index;\n } else {\n itemIndex = this.visibleItems.findIndex((processedItem) => this.isItemMatched(processedItem));\n }\n\n if (itemIndex !== -1) {\n matched = true;\n }\n\n if (itemIndex === -1 && this.focusedItemInfo.index === -1) {\n itemIndex = this.findFirstFocusedItemIndex();\n }\n\n if (itemIndex !== -1) {\n this.changeFocusedItemIndex(event, itemIndex);\n }\n\n if (this.searchTimeout) {\n clearTimeout(this.searchTimeout);\n }\n\n this.searchTimeout = setTimeout(() => {\n this.searchValue = '';\n this.searchTimeout = null;\n }, 500);\n\n return matched;\n },\n changeFocusedItemIndex(event, index) {\n if (this.focusedItemInfo.index !== index) {\n this.focusedItemInfo.index = index;\n this.scrollInView();\n }\n },\n scrollInView(index = -1) {\n const id = index !== -1 ? `${this.$id}_${index}` : this.focusedItemId;\n const element = findSingle(this.menubar, `li[id=\"${id}\"]`);\n\n if (element) {\n element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'start' });\n }\n },\n createProcessedItems(items, level = 0, parent = {}, parentKey = '') {\n const processedItems = [];\n\n items &&\n items.forEach((item, index) => {\n const key = (parentKey !== '' ? parentKey + '_' : '') + index;\n const newItem = {\n item,\n index,\n level,\n key,\n parent,\n parentKey\n };\n\n newItem['items'] = this.createProcessedItems(item.items, level + 1, newItem, key);\n processedItems.push(newItem);\n });\n\n return processedItems;\n },\n containerRef(el) {\n this.container = el;\n },\n menubarRef(el) {\n this.menubar = el ? el.$el : undefined;\n }\n },\n computed: {\n processedItems() {\n return this.createProcessedItems(this.model || []);\n },\n visibleItems() {\n const processedItem = this.activeItemPath.find((p) => p.key === this.focusedItemInfo.parentKey);\n\n return processedItem ? processedItem.items : this.processedItems;\n },\n focusedItemId() {\n return this.focusedItemInfo.index !== -1 ? `${this.$id}${isNotEmpty(this.focusedItemInfo.parentKey) ? '_' + this.focusedItemInfo.parentKey : ''}_${this.focusedItemInfo.index}` : null;\n }\n },\n components: {\n MenubarSub: MenubarSub,\n BarsIcon: BarsIcon\n }\n};\n</script>\n","<template>\n <div :ref=\"containerRef\" :class=\"cx('root')\" v-bind=\"ptmi('root')\">\n <div v-if=\"$slots.start\" :class=\"cx('start')\" v-bind=\"ptm('start')\">\n <slot name=\"start\"></slot>\n </div>\n <slot :id=\"$id\" :name=\"$slots.button ? 'button' : 'menubutton'\" :class=\"cx('button')\" :toggleCallback=\"(event) => menuButtonClick(event)\">\n <!-- TODO: menubutton deprecated since v4.0-->\n <a\n v-if=\"model && model.length > 0\"\n ref=\"menubutton\"\n role=\"button\"\n tabindex=\"0\"\n :class=\"cx('button')\"\n :aria-haspopup=\"model.length && model.length > 0 ? true : false\"\n :aria-expanded=\"mobileActive\"\n :aria-controls=\"$id\"\n :aria-label=\"$primevue.config.locale.aria?.navigation\"\n @click=\"menuButtonClick($event)\"\n @keydown=\"menuButtonKeydown($event)\"\n v-bind=\"{ ...buttonProps, ...ptm('button') }\"\n >\n <!-- TODO: menubuttonicon deprecated since v4.0-->\n <slot :name=\"$slots.buttonicon ? 'buttonicon' : 'menubuttonicon'\">\n <BarsIcon v-bind=\"ptm('buttonicon')\" />\n </slot>\n </a>\n </slot>\n <MenubarSub\n :ref=\"menubarRef\"\n :id=\"$id + '_list'\"\n role=\"menubar\"\n :items=\"processedItems\"\n :templates=\"$slots\"\n :root=\"true\"\n :mobileActive=\"mobileActive\"\n tabindex=\"0\"\n :aria-activedescendant=\"focused ? focusedItemId : undefined\"\n :menuId=\"$id\"\n :focusedItemId=\"focused ? focusedItemId : undefined\"\n :activeItemPath=\"activeItemPath\"\n :level=\"0\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-label=\"ariaLabel\"\n :pt=\"pt\"\n :unstyled=\"unstyled\"\n @focus=\"onFocus\"\n @blur=\"onBlur\"\n @keydown=\"onKeyDown\"\n @item-click=\"onItemClick\"\n @item-mouseenter=\"onItemMouseEnter\"\n @item-mousemove=\"onItemMouseMove\"\n />\n <div v-if=\"$slots.end\" :class=\"cx('end')\" v-bind=\"ptm('end')\">\n <slot name=\"end\"></slot>\n </div>\n </div>\n</template>\n\n<script>\nimport { findSingle, focus, isTouchDevice } from '@primeuix/utils/dom';\nimport { findLastIndex, isEmpty, isNotEmpty, isPrintableCharacter, resolve } from '@primeuix/utils/object';\nimport { ZIndex } from '@primeuix/utils/zindex';\nimport BarsIcon from '@primevue/icons/bars';\nimport BaseMenubar from './BaseMenubar.vue';\nimport MenubarSub from './MenubarSub.vue';\n\nexport default {\n name: 'Menubar',\n extends: BaseMenubar,\n inheritAttrs: false,\n emits: ['focus', 'blur'],\n matchMediaListener: null,\n data() {\n return {\n mobileActive: false,\n focused: false,\n focusedItemInfo: { index: -1, level: 0, pare