ant-design-vue/components/dropdown/dropdown.tsx

151 lines
4.7 KiB
Vue
Raw Normal View History

2021-09-01 02:50:18 +00:00
import { ExtractPropTypes, computed } from 'vue';
import { defineComponent } from 'vue';
import RcDropdown from '../vc-dropdown';
2019-01-12 03:33:27 +00:00
import DropdownButton from './dropdown-button';
import { cloneElement } from '../_util/vnode';
2020-08-31 08:53:19 +00:00
import classNames from '../_util/classNames';
2021-09-01 02:50:18 +00:00
import { isValidElement, initDefaultProps } from '../_util/props-util';
import { dropdownProps } from './props';
import RightOutlined from '@ant-design/icons-vue/RightOutlined';
2021-09-01 02:50:18 +00:00
import useConfigInject from '../_util/hooks/useConfigInject';
import devWarning from '../vc-util/devWarning';
import omit from '../_util/omit';
2018-03-19 02:16:27 +00:00
2021-09-01 02:50:18 +00:00
export type DropdownProps = Partial<ExtractPropTypes<ReturnType<typeof dropdownProps>>>;
2021-06-23 13:47:53 +00:00
2020-10-13 10:04:02 +00:00
const Dropdown = defineComponent({
2018-04-08 13:17:20 +00:00
name: 'ADropdown',
2020-07-30 07:41:54 +00:00
inheritAttrs: false,
2021-09-01 02:50:18 +00:00
props: initDefaultProps(dropdownProps(), {
mouseEnterDelay: 0.15,
mouseLeaveDelay: 0.1,
placement: 'bottomLeft',
trigger: 'hover',
}),
2020-11-23 05:46:30 +00:00
emits: ['visibleChange', 'update:visible'],
2021-09-01 02:50:18 +00:00
slots: ['overlay'],
setup(props, { slots, attrs, emit }) {
const { prefixCls, rootPrefixCls, direction, getPopupContainer } = useConfigInject(
'dropdown',
props,
);
const transitionName = computed(() => {
const { placement = '', transitionName } = props;
2018-01-29 10:57:20 +00:00
if (transitionName !== undefined) {
2019-01-12 03:33:27 +00:00
return transitionName;
2018-01-29 10:57:20 +00:00
}
if (placement.indexOf('top') >= 0) {
2021-09-01 02:50:18 +00:00
return `${rootPrefixCls.value}-slide-down`;
2018-01-29 10:57:20 +00:00
}
2021-09-01 02:50:18 +00:00
return `${rootPrefixCls.value}-slide-up`;
});
const renderOverlay = () => {
// rc-dropdown already can process the function of overlay, but we have check logic here.
// So we need render the element to check and pass back to rc-dropdown.
const overlay = props.overlay || slots.overlay?.();
2019-09-10 10:57:08 +00:00
const overlayNode = Array.isArray(overlay) ? overlay[0] : overlay;
2021-09-01 02:50:18 +00:00
if (!overlayNode) return null;
const overlayProps = overlayNode.props || {};
// Warning if use other mode
devWarning(
!overlayProps.mode || overlayProps.mode === 'vertical',
'Dropdown',
`mode="${overlayProps.mode}" is not supported for Dropdown's Menu.`,
2019-04-10 02:09:00 +00:00
);
2021-09-01 02:50:18 +00:00
// menu cannot be selectable in dropdown defaultly
const { selectable = false, expandIcon = (overlayNode.children as any)?.expandIcon?.() } =
overlayProps;
const overlayNodeExpandIcon =
typeof expandIcon !== 'undefined' && isValidElement(expandIcon) ? (
expandIcon
) : (
<span class={`${prefixCls.value}-menu-submenu-arrow`}>
<RightOutlined class={`${prefixCls.value}-menu-submenu-arrow-icon`} />
</span>
);
2020-06-21 14:45:30 +00:00
const fixedModeOverlay = isValidElement(overlayNode)
2021-09-01 02:50:18 +00:00
? cloneElement(overlayNode, {
2020-06-21 14:45:30 +00:00
mode: 'vertical',
selectable,
2021-09-01 02:50:18 +00:00
expandIcon: () => overlayNodeExpandIcon,
2020-06-21 14:45:30 +00:00
})
2021-09-01 02:50:18 +00:00
: overlayNode;
2019-04-10 02:09:00 +00:00
return fixedModeOverlay;
2021-09-01 02:50:18 +00:00
};
const placement = computed(() => {
if (props.placement !== undefined) {
return props.placement;
}
return direction.value === 'rtl' ? 'bottomRight' : 'bottomLeft';
});
const handleVisibleChange = (val: boolean) => {
emit('update:visible', val);
emit('visibleChange', val);
};
2018-01-29 10:57:20 +00:00
2021-09-01 02:50:18 +00:00
return () => {
const { arrow, trigger, disabled, overlayClassName } = props;
const child = slots.default?.()[0];
const dropdownTrigger = cloneElement(
child,
Object.assign(
{
class: classNames(
child?.props?.class,
{
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
},
`${prefixCls.value}-trigger`,
),
},
disabled ? { disabled } : {},
),
);
const overlayClassNameCustomized = classNames(overlayClassName, {
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
});
const triggerActions = disabled ? [] : trigger;
let alignPoint: boolean;
if (triggerActions && triggerActions.indexOf('contextmenu') !== -1) {
alignPoint = true;
}
const dropdownProps = omit(
{
2021-09-01 02:50:18 +00:00
...props,
...attrs,
overlayClassName: overlayClassNameCustomized,
arrow,
alignPoint,
prefixCls: prefixCls.value,
getPopupContainer: getPopupContainer.value,
transitionName: transitionName.value,
trigger: triggerActions,
onVisibleChange: handleVisibleChange,
placement: placement.value,
},
2021-09-01 02:50:18 +00:00
['overlay'],
);
return (
<RcDropdown {...dropdownProps} v-slots={{ overlay: renderOverlay }}>
{dropdownTrigger}
</RcDropdown>
);
2019-01-12 03:33:27 +00:00
};
2018-01-29 10:57:20 +00:00
},
2020-10-13 10:04:02 +00:00
});
2018-01-29 10:57:20 +00:00
2019-01-12 03:33:27 +00:00
Dropdown.Button = DropdownButton;
export default Dropdown;