UNPKG

@oruga-ui/oruga-next

Version:

UI components for Vue.js and CSS framework agnostic

467 lines (466 loc) 18.3 kB
/*! Oruga v0.11.0 | MIT License | github.com/oruga-ui/oruga */ import { defineComponent, mergeModels, useId, computed, ref, useModel, resolveComponent, withDirectives, createElementBlock, openBlock, normalizeClass, unref, createBlock, createCommentVNode, resolveDynamicComponent, mergeProps, withKeys, withCtx, renderSlot, createElementVNode, toDisplayString, Transition, Fragment, renderList, vShow, useTemplateRef, withModifiers } from "vue"; import { _ as _sfc_main$2 } from "./Icon.vue_vue_type_script_setup_true_lang-C6IfOTXx.mjs"; import { P as PlainButton } from "./PlainButton-Dro80nqF.mjs"; import { g as getDefault, b as registerComponent } from "./config-Dl7tu_Ly.mjs"; import { d as defineClasses } from "./defineClasses-CWB9NuS-.mjs"; import { u as useProviderParent, a as useProviderChild } from "./useParentProvider-26MPTCZ6.mjs"; import { n as normalizeOptions, i as isGroupOption } from "./useOptions-eabMIWNM.mjs"; import { mod } from "./helpers.mjs"; import { u as useSequentialId } from "./useSequentialId-BpzOPIdj.mjs"; const _hoisted_1$1 = ["id", "data-id"]; const _hoisted_2$1 = ["id"]; const _sfc_main$1 = /* @__PURE__ */ defineComponent({ ...{ isOruga: true, name: "OMenuItem", configField: "menu", inheritAttrs: false }, __name: "MenuItem", props: /* @__PURE__ */ mergeModels({ override: { type: Boolean, default: void 0 }, value: {}, active: { type: Boolean, default: false }, options: { default: void 0 }, label: { default: void 0 }, expanded: { type: Boolean, default: false }, disabled: { type: Boolean, default: false }, hidden: { type: Boolean, default: false }, submenuId: { default: () => useId() }, icon: { default: void 0 }, iconPack: { default: () => getDefault("menu.iconPack") }, iconSize: { default: () => getDefault("menu.iconSize") }, animation: { default: () => getDefault("menu.animation", "slide") }, tag: { default: () => getDefault("menu.itemTag", PlainButton) }, itemClass: {}, itemActiveClass: {}, itemFocusedClass: {}, itemDisabledClass: {}, itemButtonClass: {}, itemButtonActiveClass: {}, itemButtonFocusedClass: {}, itemButtonDisabledClass: {}, itemButtonIconClass: {}, itemSubmenuClass: {} }, { "active": { type: Boolean, ...{ default: false } }, "activeModifiers": {} }), emits: /* @__PURE__ */ mergeModels(["update:active", "click"], ["update:active"]), setup(__props, { emit: __emit }) { const props = __props; const emits = __emit; const itemValue = props.value ?? useId(); const provideData = computed(() => ({ expanded: isExpanded.value, setExpand, triggerReset })); const { childItems } = useProviderParent({ key: "menu-item", data: provideData }); const menuItem = useProviderChild({ key: "menu-item", needParent: false }); const providedData = computed(() => ({ ...props, value: itemValue, parent: menuItem.parent.value, hasChildren: hasChildren.value, expanded: isExpanded.value, setExpand, reset, selectItem })); const { parent, item } = useProviderChild({ data: providedData }); const nextSequence = parent.value.nextSequence; const normalizedOptions = computed( () => normalizeOptions(props.options, nextSequence) ); const isActive = useModel(__props, "active"); const hasChildren = computed(() => !!childItems.value.length); const isFocused = computed( () => item.value.identifier === parent.value.focsuedIdentifier ); function selectItem(event) { if (props.disabled || parent.value.disabled) return; triggerReset(); isActive.value = !isActive.value; if (parent.value.accordion) isExpanded.value = isActive.value; parent.value.selectItem(isActive.value ? item.value : void 0); emits("click", itemValue, event); } function triggerReset(childs) { var _a; if (typeof ((_a = menuItem.parent.value) == null ? void 0 : _a.triggerReset) === "function") { menuItem.parent.value.triggerReset( childs ? [item.value, ...childs] : [item.value] ); } else if (typeof parent.value.resetMenu === "function") { parent.value.resetMenu(childs ? [item.value, ...childs] : [item.value]); } } const isExpanded = ref(props.expanded); if (!parent.value.accordion) isExpanded.value = true; function setExpand(state) { var _a; if (!parent.value.accordion) return; isExpanded.value = state; if (typeof ((_a = menuItem.parent.value) == null ? void 0 : _a.setExpand) === "function") menuItem.parent.value.setExpand(state); } function reset() { if (parent.value.accordion) isExpanded.value = false; isActive.value = false; } const itemClasses = defineClasses( ["itemClass", "o-menu__item"], ["itemActiveClass", "o-menu__item--active", null, isActive], ["itemFocusedClass", "o-menu__item--focused", null, isFocused], [ "itemDisabledClass", "o-menu__item--disabled", null, computed(() => props.disabled || parent.value.disabled) ] ); const buttonClasses = defineClasses( ["itemButtonClass", "o-menu__item__button"], ["itemButtonActiveClass", "o-menu__item__button--active", null, isActive], [ "itemButtonFocusedClass", "o-menu__item__button--focused", null, isFocused ], [ "itemButtonDisabledClass", "o-menu__item__button--disabled", null, computed(() => props.disabled || parent.value.disabled) ], [ "itemButtonIconClass", "o-menu__item__button--icon", null, computed(() => !!props.icon) ] ); const submenuClasses = defineClasses([ "itemSubmenuClass", "o-menu__item__submenu" ]); return (_ctx, _cache) => { const _component_OMenuItem = resolveComponent("OMenuItem"); return withDirectives((openBlock(), createElementBlock("li", { id: `${unref(parent).menuId}-${unref(item).identifier}`, "data-oruga": "menu-item", "data-id": `menu-${unref(item).identifier}`, class: normalizeClass(unref(itemClasses)), role: "none" }, [ (openBlock(), createBlock(resolveDynamicComponent(_ctx.tag), mergeProps(_ctx.$attrs, { class: unref(buttonClasses), role: unref(parent).role + "item", disabled: _ctx.disabled || unref(parent).disabled, tabindex: "-1", "aria-selected": unref(parent).role == "tree" ? isActive.value : void 0, "aria-disabled": _ctx.disabled || unref(parent).disabled, "aria-expanded": hasChildren.value ? isExpanded.value : void 0, "aria-owns": hasChildren.value ? _ctx.submenuId : void 0, onClick: selectItem, onKeydown: [ withKeys(selectItem, ["enter"]), withKeys(selectItem, ["space"]) ] }), { default: withCtx(() => [ _ctx.icon ? (openBlock(), createBlock(_sfc_main$2, { key: 0, icon: _ctx.icon, pack: _ctx.iconPack, size: _ctx.iconSize }, null, 8, ["icon", "pack", "size"])) : createCommentVNode("", true), renderSlot(_ctx.$slots, "label", { expanded: isExpanded.value, active: isActive.value }, () => [ createElementVNode("span", null, toDisplayString(_ctx.label), 1) ]) ]), _: 3 }, 16, ["class", "role", "disabled", "aria-selected", "aria-disabled", "aria-expanded", "aria-owns"])), _ctx.$slots.default || _ctx.options ? (openBlock(), createBlock(Transition, { key: 0, name: _ctx.animation }, { default: withCtx(() => [ withDirectives(createElementVNode("ul", { id: _ctx.submenuId, class: normalizeClass(unref(submenuClasses)), tabindex: "-1", role: "group" }, [ renderSlot(_ctx.$slots, "default", {}, () => [ (openBlock(true), createElementBlock(Fragment, null, renderList(normalizedOptions.value, (option) => { return openBlock(), createBlock(_component_OMenuItem, mergeProps({ key: option.key, ref_for: true }, option.attrs, { value: option.value, label: option.label, hidden: option.hidden }), null, 16, ["value", "label", "hidden"]); }), 128)) ]) ], 10, _hoisted_2$1), [ [vShow, isExpanded.value] ]) ]), _: 3 }, 8, ["name"])) : createCommentVNode("", true) ], 10, _hoisted_1$1)), [ [vShow, !_ctx.hidden] ]); }; } }); const _hoisted_1 = ["id"]; const _hoisted_2 = ["id", "role", "aria-labelledby", "onKeydown"]; const _sfc_main = /* @__PURE__ */ defineComponent({ ...{ isOruga: true, name: "OMenu", configField: "menu" }, __name: "Menu", props: /* @__PURE__ */ mergeModels({ override: { type: Boolean, default: void 0 }, modelValue: { default: void 0 }, options: { default: void 0 }, label: { default: void 0 }, accordion: { type: Boolean, default: true }, disabled: { type: Boolean, default: false }, menuId: { default: () => useId() }, labelId: { default: () => useId() }, role: { default: () => getDefault("menu.role", "tree") }, icon: { default: void 0 }, iconPack: { default: () => getDefault("menu.iconPack") }, iconSize: { default: () => getDefault("menu.iconSize") }, rootClass: {}, listClass: {}, labelClass: {} }, { "modelValue": { default: void 0 }, "modelModifiers": {} }), emits: /* @__PURE__ */ mergeModels(["update:model-value"], ["update:modelValue"]), setup(__props) { const props = __props; const rootRef = useTemplateRef("rootElement"); const provideData = computed(() => { var _a; return { focsuedIdentifier: (_a = focusedItem.value) == null ? void 0 : _a.identifier, menuId: props.menuId, accordion: props.accordion, disabled: props.disabled, role: props.role, nextSequence, resetMenu, selectItem }; }); const { childItems } = useProviderParent({ rootRef, data: provideData }); const { nextSequence } = useSequentialId(); const normalizedOptions = computed( () => normalizeOptions(props.options, nextSequence) ); function resetMenu(excludedItems = []) { childItems.value.forEach((item) => { var _a; if (!excludedItems.map((i) => i == null ? void 0 : i.identifier).includes(item.identifier)) (_a = item.data) == null ? void 0 : _a.reset(); }); } const vmodel = useModel(__props, "modelValue"); const selectedItem = ref(); function selectItem(item) { var _a; const value = (_a = item == null ? void 0 : item.data) == null ? void 0 : _a.value; if (vmodel.value == value) return; vmodel.value = value; selectedItem.value = item; } const focusedItem = ref(); const isNotEmpty = computed(() => childItems.value.some(isItemViable)); function onCollapse() { var _a, _b; if (!focusedItem.value) return; if ((_a = focusedItem.value.data) == null ? void 0 : _a.expanded) (_b = focusedItem.value.data) == null ? void 0 : _b.setExpand(false); else moveFocus(-1); } function onExpend() { var _a, _b, _c; if (!focusedItem.value) return; if (((_a = focusedItem.value.data) == null ? void 0 : _a.hasChildren) && !((_b = focusedItem.value.data) == null ? void 0 : _b.expanded)) (_c = focusedItem.value.data) == null ? void 0 : _c.setExpand(true); else moveFocus(1); } function setFocus(item) { focusedItem.value = item; } function moveFocus(delta) { var _a; if (!isNotEmpty.value) return; const item = getFirstViableItem(((_a = focusedItem.value) == null ? void 0 : _a.index) || 0, delta); setFocus(item); } function onUpPressed() { moveFocus(-1); } function onDownPressed() { moveFocus(1); } function onEnter(event) { var _a; if (!focusedItem.value) return; setFocus(focusedItem.value); (_a = focusedItem.value.data) == null ? void 0 : _a.selectItem(event); } function onHomePressed() { if (!isNotEmpty.value) return; const item = getFirstViableItem(0, 1); setFocus(item); } function onEndPressed() { if (!isNotEmpty.value) return; const item = getFirstViableItem(childItems.value.length - 1, -1); setFocus(item); } function getFirstViableItem(startingIndex, delta) { var _a, _b; let newIndex = mod( ((_a = focusedItem.value) == null ? void 0 : _a.index) == startingIndex ? startingIndex + delta : startingIndex, childItems.value.length ); for (; newIndex !== ((_b = focusedItem.value) == null ? void 0 : _b.index); newIndex = mod(newIndex + delta, childItems.value.length)) { if (isItemViable(childItems.value[newIndex])) break; } return childItems.value[newIndex]; } function isItemViable(item) { var _a, _b, _c, _d; return !((_a = item.data) == null ? void 0 : _a.disabled) && !((_b = item.data) == null ? void 0 : _b.hidden) && (((_d = (_c = item.data) == null ? void 0 : _c.parent) == null ? void 0 : _d.expanded) ?? true); } function onFocusLeave() { focusedItem.value = void 0; } const rootClasses = defineClasses(["rootClass", "o-menu"]); const listClasses = defineClasses(["listClass", "o-menu__list"]); const labelClasses = defineClasses(["labelClass", "o-menu__label"]); return (_ctx, _cache) => { var _a, _b, _c, _d, _e, _f, _g, _h; return openBlock(), createElementBlock("nav", { ref: "rootElement", "data-oruga": "menu", class: normalizeClass(unref(rootClasses)), onFocusout: onFocusLeave }, [ _ctx.label || _ctx.$slots.label ? (openBlock(), createElementBlock("div", { key: 0, id: _ctx.labelId, class: normalizeClass(unref(labelClasses)) }, [ renderSlot(_ctx.$slots, "label", { focused: (_a = focusedItem.value) == null ? void 0 : _a.data, focusedIndex: (_b = focusedItem.value) == null ? void 0 : _b.index, selected: (_c = selectedItem.value) == null ? void 0 : _c.data, selectedIndex: (_d = selectedItem.value) == null ? void 0 : _d.index }, () => [ _ctx.icon ? (openBlock(), createBlock(_sfc_main$2, { key: 0, icon: _ctx.icon, pack: _ctx.iconPack, size: _ctx.iconSize }, null, 8, ["icon", "pack", "size"])) : createCommentVNode("", true), createElementVNode("span", null, toDisplayString(_ctx.label), 1) ]) ], 10, _hoisted_1)) : createCommentVNode("", true), createElementVNode("ul", { id: _ctx.menuId, class: normalizeClass(unref(listClasses)), role: _ctx.role, tabindex: 0, "aria-labelledby": _ctx.labelId, onKeydown: [ withKeys(onCollapse, ["left"]), withKeys(onExpend, ["right"]), withKeys(withModifiers(onEnter, ["prevent"]), ["enter"]), withKeys(withModifiers(onEnter, ["prevent"]), ["space"]), withKeys(withModifiers(onUpPressed, ["prevent"]), ["up"]), withKeys(withModifiers(onDownPressed, ["prevent"]), ["down"]), withKeys(withModifiers(onHomePressed, ["prevent"]), ["home"]), withKeys(withModifiers(onEndPressed, ["prevent"]), ["end"]) ] }, [ renderSlot(_ctx.$slots, "default", { focused: (_e = focusedItem.value) == null ? void 0 : _e.data, focusedIndex: (_f = focusedItem.value) == null ? void 0 : _f.index, selected: (_g = selectedItem.value) == null ? void 0 : _g.data, selectedIndex: (_h = selectedItem.value) == null ? void 0 : _h.index }, () => [ (openBlock(true), createElementBlock(Fragment, null, renderList(normalizedOptions.value, (option) => { return openBlock(), createElementBlock(Fragment, { key: option.key }, [ unref(isGroupOption)(option) ? (openBlock(), createBlock(_sfc_main$1, mergeProps({ key: 0, ref_for: true }, option.attrs, { label: option.label, hidden: option.hidden }), { default: withCtx(() => [ (openBlock(true), createElementBlock(Fragment, null, renderList(option.options, (_option) => { return openBlock(), createBlock(_sfc_main$1, mergeProps({ ref_for: true }, _option.attrs, { key: _option.key, value: _option.value, label: _option.label, hidden: _option.hidden }), null, 16, ["value", "label", "hidden"]); }), 128)) ]), _: 2 }, 1040, ["label", "hidden"])) : (openBlock(), createBlock(_sfc_main$1, mergeProps({ key: 1, ref_for: true }, option.attrs, { value: option.value, label: option.label, hidden: option.hidden }), null, 16, ["value", "label", "hidden"])) ], 64); }), 128)) ]) ], 42, _hoisted_2) ], 34); }; } }); const index = { install(app) { registerComponent(app, _sfc_main); registerComponent(app, _sfc_main$1); } }; export { _sfc_main as OMenu, _sfc_main$1 as OMenuItem, index as default }; //# sourceMappingURL=menu.mjs.map