naive-ui
Version:
A Vue 3 Component Library. Fairly Complete, Theme Customizable, Uses TypeScript, Fast
242 lines (241 loc) • 11.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const seemly_1 = require("seemly");
const vooks_1 = require("vooks");
const vue_1 = require("vue");
const vueuc_1 = require("vueuc");
const icons_1 = require("../../_internal/icons");
const _utils_1 = require("../../_utils");
const icon_1 = require("../../icon");
const interface_1 = require("../../popover/src/interface");
const context_1 = require("./context");
const DropdownMenu_1 = __importDefault(require("./DropdownMenu"));
const utils_1 = require("./utils");
exports.default = (0, vue_1.defineComponent)({
name: 'DropdownOption',
props: {
clsPrefix: {
type: String,
required: true
},
tmNode: {
type: Object,
required: true
},
parentKey: {
type: [String, Number],
default: null
},
placement: {
type: String,
default: 'right-start'
},
props: Object,
scrollable: Boolean
},
setup(props) {
const NDropdown = (0, vue_1.inject)(context_1.dropdownInjectionKey);
const { hoverKeyRef, keyboardKeyRef, lastToggledSubmenuKeyRef, pendingKeyPathRef, activeKeyPathRef, animatedRef, mergedShowRef, renderLabelRef, renderIconRef, labelFieldRef, childrenFieldRef, renderOptionRef, nodePropsRef, menuPropsRef } = NDropdown;
const NDropdownOption = (0, vue_1.inject)(context_1.dropdownOptionInjectionKey, null);
const NDropdownMenu = (0, vue_1.inject)(context_1.dropdownMenuInjectionKey);
const NPopoverBody = (0, vue_1.inject)(interface_1.popoverBodyInjectionKey);
const rawNodeRef = (0, vue_1.computed)(() => props.tmNode.rawNode);
const hasSubmenuRef = (0, vue_1.computed)(() => {
const { value: childrenField } = childrenFieldRef;
return (0, utils_1.isSubmenuNode)(props.tmNode.rawNode, childrenField);
});
const mergedDisabledRef = (0, vue_1.computed)(() => {
const { disabled } = props.tmNode;
return disabled;
});
const showSubmenuRef = (0, vue_1.computed)(() => {
if (!hasSubmenuRef.value)
return false;
const { key, disabled } = props.tmNode;
if (disabled)
return false;
const { value: hoverKey } = hoverKeyRef;
const { value: keyboardKey } = keyboardKeyRef;
const { value: lastToggledSubmenuKey } = lastToggledSubmenuKeyRef;
const { value: pendingKeyPath } = pendingKeyPathRef;
if (hoverKey !== null)
return pendingKeyPath.includes(key);
if (keyboardKey !== null) {
return (pendingKeyPath.includes(key)
&& pendingKeyPath[pendingKeyPath.length - 1] !== key);
}
if (lastToggledSubmenuKey !== null)
return pendingKeyPath.includes(key);
return false;
});
const shouldDelayRef = (0, vue_1.computed)(() => {
return keyboardKeyRef.value === null && !animatedRef.value;
});
const deferredShowSubmenuRef = (0, _utils_1.useDeferredTrue)(showSubmenuRef, 300, shouldDelayRef);
const parentEnteringSubmenuRef = (0, vue_1.computed)(() => {
return !!(NDropdownOption === null || NDropdownOption === void 0 ? void 0 : NDropdownOption.enteringSubmenuRef.value);
});
const enteringSubmenuRef = (0, vue_1.ref)(false);
(0, vue_1.provide)(context_1.dropdownOptionInjectionKey, {
enteringSubmenuRef
});
// methods
function handleSubmenuBeforeEnter() {
enteringSubmenuRef.value = true;
}
function handleSubmenuAfterEnter() {
enteringSubmenuRef.value = false;
}
function handleMouseEnter() {
const { parentKey, tmNode } = props;
if (tmNode.disabled)
return;
if (!mergedShowRef.value)
return;
lastToggledSubmenuKeyRef.value = parentKey;
keyboardKeyRef.value = null;
hoverKeyRef.value = tmNode.key;
}
function handleMouseMove() {
const { tmNode } = props;
if (tmNode.disabled)
return;
if (!mergedShowRef.value)
return;
if (hoverKeyRef.value === tmNode.key)
return;
handleMouseEnter();
}
function handleMouseLeave(e) {
if (props.tmNode.disabled)
return;
if (!mergedShowRef.value)
return;
const { relatedTarget } = e;
if (relatedTarget
&& !(0, seemly_1.happensIn)({ target: relatedTarget }, 'dropdownOption')
&& !(0, seemly_1.happensIn)({ target: relatedTarget }, 'scrollbarRail')) {
hoverKeyRef.value = null;
}
}
function handleClick() {
const { value: hasSubmenu } = hasSubmenuRef;
const { tmNode } = props;
if (!mergedShowRef.value)
return;
if (!hasSubmenu && !tmNode.disabled) {
NDropdown.doSelect(tmNode.key, tmNode.rawNode);
NDropdown.doUpdateShow(false);
}
}
return {
labelField: labelFieldRef,
renderLabel: renderLabelRef,
renderIcon: renderIconRef,
siblingHasIcon: NDropdownMenu.showIconRef,
siblingHasSubmenu: NDropdownMenu.hasSubmenuRef,
menuProps: menuPropsRef,
popoverBody: NPopoverBody,
animated: animatedRef,
mergedShowSubmenu: (0, vue_1.computed)(() => {
return deferredShowSubmenuRef.value && !parentEnteringSubmenuRef.value;
}),
rawNode: rawNodeRef,
hasSubmenu: hasSubmenuRef,
pending: (0, vooks_1.useMemo)(() => {
const { value: pendingKeyPath } = pendingKeyPathRef;
const { key } = props.tmNode;
return pendingKeyPath.includes(key);
}),
childActive: (0, vooks_1.useMemo)(() => {
const { value: activeKeyPath } = activeKeyPathRef;
const { key } = props.tmNode;
const index = activeKeyPath.findIndex(k => key === k);
if (index === -1)
return false;
return index < activeKeyPath.length - 1;
}),
active: (0, vooks_1.useMemo)(() => {
const { value: activeKeyPath } = activeKeyPathRef;
const { key } = props.tmNode;
const index = activeKeyPath.findIndex(k => key === k);
if (index === -1)
return false;
return index === activeKeyPath.length - 1;
}),
mergedDisabled: mergedDisabledRef,
renderOption: renderOptionRef,
nodeProps: nodePropsRef,
handleClick,
handleMouseMove,
handleMouseEnter,
handleMouseLeave,
handleSubmenuBeforeEnter,
handleSubmenuAfterEnter
};
},
render() {
var _a, _b;
const { animated, rawNode, mergedShowSubmenu, clsPrefix, siblingHasIcon, siblingHasSubmenu, renderLabel, renderIcon, renderOption, nodeProps, props, scrollable } = this;
let submenuVNode = null;
if (mergedShowSubmenu) {
const submenuNodeProps = (_a = this.menuProps) === null || _a === void 0 ? void 0 : _a.call(this, rawNode, rawNode.children);
submenuVNode = ((0, vue_1.h)(DropdownMenu_1.default, Object.assign({}, submenuNodeProps, { clsPrefix: clsPrefix, scrollable: this.scrollable, tmNodes: this.tmNode.children, parentKey: this.tmNode.key })));
}
const builtinProps = {
class: [
`${clsPrefix}-dropdown-option-body`,
this.pending && `${clsPrefix}-dropdown-option-body--pending`,
this.active && `${clsPrefix}-dropdown-option-body--active`,
this.childActive && `${clsPrefix}-dropdown-option-body--child-active`,
this.mergedDisabled && `${clsPrefix}-dropdown-option-body--disabled`
],
onMousemove: this.handleMouseMove,
onMouseenter: this.handleMouseEnter,
onMouseleave: this.handleMouseLeave,
onClick: this.handleClick
};
const optionNodeProps = nodeProps === null || nodeProps === void 0 ? void 0 : nodeProps(rawNode);
const node = ((0, vue_1.h)("div", Object.assign({ class: [`${clsPrefix}-dropdown-option`, optionNodeProps === null || optionNodeProps === void 0 ? void 0 : optionNodeProps.class], "data-dropdown-option": true }, optionNodeProps),
(0, vue_1.h)('div', (0, vue_1.mergeProps)(builtinProps, props), [
(0, vue_1.h)("div", { class: [
`${clsPrefix}-dropdown-option-body__prefix`,
siblingHasIcon
&& `${clsPrefix}-dropdown-option-body__prefix--show-icon`
] }, [renderIcon ? renderIcon(rawNode) : (0, _utils_1.render)(rawNode.icon)]),
(0, vue_1.h)("div", { "data-dropdown-option": true, class: `${clsPrefix}-dropdown-option-body__label` }, renderLabel
? renderLabel(rawNode)
: (0, _utils_1.render)((_b = rawNode[this.labelField]) !== null && _b !== void 0 ? _b : rawNode.title)),
(0, vue_1.h)("div", { "data-dropdown-option": true, class: [
`${clsPrefix}-dropdown-option-body__suffix`,
siblingHasSubmenu
&& `${clsPrefix}-dropdown-option-body__suffix--has-submenu`
] }, this.hasSubmenu ? ((0, vue_1.h)(icon_1.NIcon, null, {
default: () => (0, vue_1.h)(icons_1.ChevronRightIcon, null)
})) : null)
]),
this.hasSubmenu ? ((0, vue_1.h)(vueuc_1.VBinder, null, {
default: () => [
(0, vue_1.h)(vueuc_1.VTarget, null, {
default: () => ((0, vue_1.h)("div", { class: `${clsPrefix}-dropdown-offset-container` },
(0, vue_1.h)(vueuc_1.VFollower, { show: this.mergedShowSubmenu, placement: this.placement, to: scrollable
? this.popoverBody || undefined
: undefined, teleportDisabled: !scrollable }, {
default: () => {
return ((0, vue_1.h)("div", { class: `${clsPrefix}-dropdown-menu-wrapper` }, animated ? ((0, vue_1.h)(vue_1.Transition, { onBeforeEnter: this.handleSubmenuBeforeEnter, onAfterEnter: this.handleSubmenuAfterEnter, name: "fade-in-scale-up-transition", appear: true }, {
default: () => submenuVNode
})) : (submenuVNode)));
}
})))
})
]
})) : null));
if (renderOption) {
return renderOption({ node, option: rawNode });
}
return node;
}
});