@oruga-ui/oruga-next
Version:
UI components for Vue.js and CSS framework agnostic
467 lines (466 loc) • 18.3 kB
JavaScript
/*! 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