@opentiny/vue-renderless
Version:
An enterprise-class UI component library, support both Vue.js 2 and Vue.js 3, as well as PC and mobile.
254 lines (253 loc) • 8.14 kB
JavaScript
import "../chunk-G2ADBYYC.js";
import { KEY_CODE } from "@opentiny/utils";
import { addClass, removeClass, on, off } from "@opentiny/utils";
const watchVisible = ({ broadcast, emit, nextTick }) => (value) => {
broadcast("TinyDropdownMenu", "visible", value);
nextTick(() => emit("visible-change", value));
};
const watchFocusing = (parent) => (value) => {
const selfDefine = parent.$el.querySelector(".tiny-dropdown-selfdefine");
if (selfDefine) {
value ? addClass(selfDefine, "focusing") : removeClass(selfDefine, "focusing");
}
};
const show = ({ props, state, emit }) => () => {
if (props.disabled) {
return;
}
if (state.visibleIsBoolean) {
emit("update:visible", true);
} else {
clearTimeout(Number(state.timeout));
state.timeout = setTimeout(
() => {
state.visible = true;
},
state.trigger === "click" ? 0 : props.showTimeout
);
}
};
const hide = ({ api, props, state, emit }) => () => {
if (props.disabled) {
return;
}
api.removeTabindex();
if (props.tabindex >= 0 && state.triggerElm) {
api.resetTabindex(state.triggerElm);
}
if (state.visibleIsBoolean) {
emit("update:visible", false);
} else {
clearTimeout(Number(state.timeout));
state.timeout = setTimeout(
() => {
state.visible = false;
},
state.trigger === "click" ? 0 : props.hideTimeout
);
}
};
const handleClick = ({ api, props, state, emit }) => () => {
if (props.disabled) {
return;
}
if (state.visibleIsBoolean) {
emit("handle-click", props.visible);
} else {
emit("handle-click", state.visible);
state.visible ? api.hide() : api.show();
}
};
const handleTriggerKeyDown = ({ api, state }) => (event) => {
const keyCode = event.keyCode;
if (~[KEY_CODE.ArrowUp, KEY_CODE.ArrowDown].indexOf(keyCode)) {
api.removeTabindex();
if (state.menuItems) {
api.resetTabindex(state.menuItems[0]);
state.menuItems[0].focus();
}
event.preventDefault();
event.stopPropagation();
} else if (keyCode === KEY_CODE.Enter) {
api.handleClick();
} else if (~[KEY_CODE.Tab, KEY_CODE.Escape].indexOf(keyCode)) {
api.hide();
}
};
const handleItemKeyDown = ({ api, props, state, emit }) => (event) => {
const keyCode = event.keyCode;
const target = event.target;
const currentIndex = state.menuItemsArray.indexOf(target);
const max = state.menuItemsArray.length - 1;
let nextIndex;
if (~[KEY_CODE.ArrowUp, KEY_CODE.ArrowDown].indexOf(keyCode)) {
if (keyCode === KEY_CODE.ArrowUp) {
nextIndex = currentIndex !== 0 ? currentIndex - 1 : 0;
} else {
nextIndex = currentIndex < max ? currentIndex + 1 : max;
}
api.removeTabindex();
if (state.menuItems) {
api.resetTabindex(state.menuItems[nextIndex]);
state.menuItems[nextIndex].focus();
}
event.preventDefault();
event.stopPropagation();
} else if (keyCode === KEY_CODE.Enter) {
api.triggerElmFocus();
target == null ? void 0 : target.click();
if (props.hideOnClick) {
state.visible = false;
}
} else if (~[KEY_CODE.Tab, KEY_CODE.Escape].indexOf(keyCode)) {
api.hide();
api.triggerElmFocus();
}
};
const resetTabindex = (api) => (el) => {
api.removeTabindex();
el.setAttribute("tabindex", "0");
};
const removeTabindex = (state) => () => {
var _a, _b;
(_a = state.triggerElm) == null ? void 0 : _a.setAttribute("tabindex", "-1");
(_b = state.menuItemsArray) == null ? void 0 : _b.forEach((item) => {
item.setAttribute("tabindex", "-1");
});
};
const initAria = ({ state, props }) => () => {
var _a, _b, _c, _d, _e;
(_a = state.dropdownElm) == null ? void 0 : _a.setAttribute("id", state.listId);
(_b = state.triggerElm) == null ? void 0 : _b.setAttribute("aria-haspopup", "list");
(_c = state.triggerElm) == null ? void 0 : _c.setAttribute("aria-controls", state.listId);
if (!props.splitButton || !props.singleButton) {
(_d = state.triggerElm) == null ? void 0 : _d.setAttribute("role", "button");
(_e = state.triggerElm) == null ? void 0 : _e.setAttribute("tabindex", String(props.tabindex));
addClass(state.triggerElm, "tiny-dropdown-selfdefine");
}
};
const toggleFocus = ({ state, value }) => () => {
state.focusing = value;
};
const initEvent = ({ api, props, state, vm, mode }) => () => {
var _a;
let buttonValue = props.splitButton || props.singleButton;
state.triggerElm = buttonValue ? vm.$refs.trigger.$el : props.border ? vm.$refs.trigger.$el : vm.$refs.trigger;
on(state.triggerElm, "keydown", api.handleTriggerKeyDown);
(_a = state.dropdownElm) == null ? void 0 : _a.addEventListener("keydown", api.handleItemKeyDown, true);
if (!props.splitButton || !props.singleButton) {
on(state.triggerElm, "focus", api.toggleFocusOnTrue);
on(state.triggerElm, "blur", api.toggleFocusOnFalse);
on(state.triggerElm, "click", api.toggleFocusOnFalse);
}
if (state.visibleIsBoolean) {
return;
}
if (state.trigger === "hover") {
on(state.triggerElm, "mouseenter", api.show);
on(state.triggerElm, "mouseleave", api.hide);
on(state.dropdownElm, "mouseenter", api.show);
on(state.dropdownElm, "mouseleave", api.hide);
} else if (state.trigger === "click") {
on(state.triggerElm, "click", api.handleClick);
}
if (mode === "mobile-first") {
if (props.splitButton || props.singleButton) {
on(state.triggerElm, "click", api.handleClick);
}
}
};
const handleMenuItemClick = ({ props, state, emit }) => ({ itemData, vm, disabled }) => {
if (props.hideOnClick && !disabled) {
state.visible = false;
}
if (!disabled) {
const data = { itemData, vm };
emit("item-click", data);
}
};
const triggerElmFocus = (state) => () => {
var _a;
((_a = state.triggerElm) == null ? void 0 : _a.focus) && state.triggerElm.focus();
};
const initDomOperation = ({ api, state, vm }) => () => {
var _a;
state.dropdownElm = vm.popperElm;
state.menuItems = (_a = state.dropdownElm) == null ? void 0 : _a.querySelectorAll('[tabindex="-1"]');
state.menuItemsArray = [].slice.call(state.menuItems);
api.initEvent();
api.initAria();
};
const handleMainButtonClick = ({ api, emit }) => (event) => {
emit("button-click", event);
api.hide();
};
const mounted = ({
api,
vm,
state,
broadcast,
props
}) => () => {
if (state.showSelfIcon) {
state.showIcon = false;
}
vm.$on("menu-item-click", api.handleMenuItemClick);
vm.$on("current-item-click", api.handleMenuItemClick);
vm.$on("selected-index", (selectedIndex) => {
broadcast("TinyDropdownMenu", "menu-selected-index", selectedIndex);
});
if (!state.visibleIsBoolean) {
vm.$on("is-disabled", api.clickOutside);
} else if (props.visible) {
broadcast("TinyDropdownMenu", "visible", true);
}
};
const beforeDistory = ({ vm, api, state }) => () => {
if (state.triggerElm) {
off(state.triggerElm, "keydown", api.handleTriggerKeyDown);
off(state.triggerElm, "focus", api.toggleFocusOnTrue);
off(state.triggerElm, "blur", api.toggleFocusOnFalse);
off(state.triggerElm, "click", api.toggleFocusOnFalse);
off(state.triggerElm, "mouseenter", api.show);
off(state.triggerElm, "mouseleave", api.hide);
off(state.triggerElm, "click", api.handleClick);
state.triggerElm = null;
}
if (state.dropdownElm) {
state.dropdownElm.removeEventListener("keydown", api.handleItemKeyDown, true);
off(state.dropdownElm, "mouseenter", api.show);
off(state.dropdownElm, "mouseleave", api.hide);
state.dropdownElm = null;
}
vm.$off("menu-item-click");
vm.$off("current-item-click");
vm.$off("selected-index");
vm.$off("is-disabled");
};
const clickOutside = ({ props, api }) => (disabled) => {
if (props.hideOnClick) {
disabled ? api.show() : api.hide();
}
};
export {
beforeDistory,
clickOutside,
handleClick,
handleItemKeyDown,
handleMainButtonClick,
handleMenuItemClick,
handleTriggerKeyDown,
hide,
initAria,
initDomOperation,
initEvent,
mounted,
removeTabindex,
resetTabindex,
show,
toggleFocus,
triggerElmFocus,
watchFocusing,
watchVisible
};