parent
f71a72208b
commit
38258d33ba
@ -1,117 +1,92 @@
|
||||
import type { VNode, ExtractPropTypes } from 'vue';
|
||||
import { provide, inject, defineComponent } from 'vue';
|
||||
import { ExtractPropTypes } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import Button from '../button';
|
||||
import classNames from '../_util/classNames';
|
||||
import buttonTypes from '../button/buttonTypes';
|
||||
import Dropdown from './dropdown';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { hasProp, getComponent, getSlot } from '../_util/props-util';
|
||||
import getDropdownProps from './getDropdownProps';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import { initDefaultProps } from '../_util/props-util';
|
||||
import { dropdownButtonProps } from './props';
|
||||
import EllipsisOutlined from '@ant-design/icons-vue/EllipsisOutlined';
|
||||
import { tuple } from '../_util/type';
|
||||
|
||||
const ButtonTypesProps = buttonTypes();
|
||||
const DropdownProps = getDropdownProps();
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
const ButtonGroup = Button.Group;
|
||||
const dropdownButtonProps = {
|
||||
...DropdownProps,
|
||||
type: PropTypes.oneOf(tuple('primary', 'ghost', 'dashed', 'danger', 'default')).def('default'),
|
||||
size: PropTypes.oneOf(tuple('small', 'large', 'default')).def('default'),
|
||||
htmlType: ButtonTypesProps.htmlType,
|
||||
href: PropTypes.string,
|
||||
disabled: PropTypes.looseBool,
|
||||
prefixCls: PropTypes.string,
|
||||
placement: DropdownProps.placement.def('bottomRight'),
|
||||
icon: PropTypes.any,
|
||||
title: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
onVisibleChange: PropTypes.func,
|
||||
'onUpdate:visible': PropTypes.func,
|
||||
};
|
||||
export type DropdownButtonProps = Partial<ExtractPropTypes<typeof dropdownButtonProps>>;
|
||||
|
||||
export type DropdownButtonProps = Partial<ExtractPropTypes<ReturnType<typeof dropdownButtonProps>>>;
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ADropdownButton',
|
||||
inheritAttrs: false,
|
||||
props: dropdownButtonProps,
|
||||
__ANT_BUTTON: true,
|
||||
props: initDefaultProps(dropdownButtonProps(), {
|
||||
trigger: 'hover',
|
||||
placement: 'bottomRight',
|
||||
type: 'default',
|
||||
}),
|
||||
emits: ['click', 'visibleChange', 'update:visible'],
|
||||
setup() {
|
||||
return {
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
popupRef: null,
|
||||
slots: ['icon', 'leftButton', 'rightButton', 'overlay'],
|
||||
setup(props, { slots, attrs, emit }) {
|
||||
const handleClick = (e: MouseEvent) => {
|
||||
emit('click', e);
|
||||
};
|
||||
},
|
||||
created() {
|
||||
provide('savePopupRef', this.savePopupRef);
|
||||
},
|
||||
methods: {
|
||||
savePopupRef(ref: VNode) {
|
||||
this.popupRef = ref;
|
||||
},
|
||||
handleClick(e: Event) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
handleVisibleChange(val: boolean) {
|
||||
this.$emit('update:visible', val);
|
||||
this.$emit('visibleChange', val);
|
||||
},
|
||||
},
|
||||
render() {
|
||||
const {
|
||||
type,
|
||||
disabled,
|
||||
onClick,
|
||||
htmlType,
|
||||
class: className,
|
||||
prefixCls: customizePrefixCls,
|
||||
overlay,
|
||||
trigger,
|
||||
align,
|
||||
visible,
|
||||
onVisibleChange,
|
||||
placement,
|
||||
getPopupContainer,
|
||||
href,
|
||||
title,
|
||||
...restProps
|
||||
} = { ...this.$props, ...this.$attrs } as any;
|
||||
const icon = getComponent(this, 'icon') || <EllipsisOutlined />;
|
||||
const { getPopupContainer: getContextPopupContainer } = this.configProvider;
|
||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('dropdown-button', customizePrefixCls);
|
||||
const dropdownProps: any = {
|
||||
align,
|
||||
disabled,
|
||||
trigger: disabled ? [] : trigger,
|
||||
placement,
|
||||
getPopupContainer: getPopupContainer || getContextPopupContainer,
|
||||
onVisibleChange: this.handleVisibleChange,
|
||||
const handleVisibleChange = (val: boolean) => {
|
||||
emit('update:visible', val);
|
||||
emit('visibleChange', val);
|
||||
};
|
||||
if (hasProp(this, 'visible')) {
|
||||
dropdownProps.visible = visible;
|
||||
}
|
||||
|
||||
const buttonGroupProps = {
|
||||
...restProps,
|
||||
class: classNames(prefixCls, className),
|
||||
};
|
||||
const { prefixCls, direction, getPopupContainer } = useConfigInject('dropdown-button', props);
|
||||
|
||||
return () => {
|
||||
const {
|
||||
type,
|
||||
disabled,
|
||||
htmlType,
|
||||
class: className = '',
|
||||
overlay = slots.overlay?.(),
|
||||
trigger,
|
||||
align,
|
||||
visible,
|
||||
onVisibleChange,
|
||||
placement = direction.value === 'rtl' ? 'bottomLeft' : 'bottomRight',
|
||||
href,
|
||||
title,
|
||||
icon = slots.icon?.() || <EllipsisOutlined />,
|
||||
mouseEnterDelay,
|
||||
mouseLeaveDelay,
|
||||
...restProps
|
||||
} = { ...props, ...attrs };
|
||||
|
||||
const dropdownProps = {
|
||||
align,
|
||||
disabled,
|
||||
trigger: disabled ? [] : trigger,
|
||||
placement,
|
||||
getPopupContainer: getPopupContainer.value,
|
||||
onVisibleChange: handleVisibleChange,
|
||||
mouseEnterDelay,
|
||||
mouseLeaveDelay,
|
||||
visible,
|
||||
};
|
||||
|
||||
return (
|
||||
<ButtonGroup {...buttonGroupProps}>
|
||||
const leftButton = (
|
||||
<Button
|
||||
type={type}
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
onClick={handleClick}
|
||||
htmlType={htmlType}
|
||||
href={href}
|
||||
title={title}
|
||||
>
|
||||
{getSlot(this)}
|
||||
</Button>
|
||||
<Dropdown {...dropdownProps} overlay={getComponent(this, 'overlay')}>
|
||||
<Button type={type}>{icon}</Button>
|
||||
</Dropdown>
|
||||
</ButtonGroup>
|
||||
);
|
||||
v-slots={{ default: slots.default }}
|
||||
></Button>
|
||||
);
|
||||
|
||||
const rightButton = <Button type={type} icon={icon} />;
|
||||
|
||||
return (
|
||||
<ButtonGroup {...restProps} class={classNames(prefixCls.value, className)}>
|
||||
{slots.leftButton ? slots.leftButton({ button: leftButton }) : leftButton}
|
||||
<Dropdown {...dropdownProps} v-slots={{ overlay: slots.overlay }}>
|
||||
{slots.rightButton ? slots.rightButton({ button: rightButton }) : rightButton}
|
||||
</Dropdown>
|
||||
</ButtonGroup>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@ -1,28 +0,0 @@
|
||||
import { tuple } from '../_util/type';
|
||||
import type { PropType } from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
export default () => ({
|
||||
trigger: {
|
||||
type: [Array, String] as PropType<
|
||||
('click' | 'hover' | 'contextmenu')[] | 'click' | 'hover' | 'contextmenu'
|
||||
>,
|
||||
default: 'hover',
|
||||
},
|
||||
overlay: PropTypes.any,
|
||||
visible: PropTypes.looseBool,
|
||||
disabled: PropTypes.looseBool,
|
||||
align: PropTypes.object,
|
||||
getPopupContainer: PropTypes.func,
|
||||
prefixCls: PropTypes.string,
|
||||
transitionName: PropTypes.string,
|
||||
placement: PropTypes.oneOf(
|
||||
tuple('topLeft', 'topCenter', 'topRight', 'bottomLeft', 'bottomCenter', 'bottomRight'),
|
||||
),
|
||||
overlayClassName: PropTypes.string,
|
||||
overlayStyle: PropTypes.style,
|
||||
forceRender: PropTypes.looseBool,
|
||||
mouseEnterDelay: PropTypes.number,
|
||||
mouseLeaveDelay: PropTypes.number,
|
||||
openClassName: PropTypes.string,
|
||||
minOverlayWidthMatchTrigger: PropTypes.looseBool,
|
||||
});
|
@ -0,0 +1,60 @@
|
||||
import { tuple } from '../_util/type';
|
||||
import type { PropType } from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
|
||||
import buttonTypes from '../button/buttonTypes';
|
||||
|
||||
type Align = {
|
||||
points?: [string, string];
|
||||
offset?: [number, number];
|
||||
targetOffset?: [number, number];
|
||||
overflow?: {
|
||||
adjustX?: boolean;
|
||||
adjustY?: boolean;
|
||||
};
|
||||
useCssRight?: boolean;
|
||||
useCssBottom?: boolean;
|
||||
useCssTransform?: boolean;
|
||||
};
|
||||
const dropdownProps = () => ({
|
||||
arrow: PropTypes.looseBool,
|
||||
trigger: {
|
||||
type: [Array, String] as PropType<
|
||||
('click' | 'hover' | 'contextmenu')[] | 'click' | 'hover' | 'contextmenu'
|
||||
>,
|
||||
},
|
||||
overlay: PropTypes.any,
|
||||
visible: PropTypes.looseBool,
|
||||
disabled: PropTypes.looseBool,
|
||||
align: { type: Object as PropType<Align> },
|
||||
getPopupContainer: PropTypes.func,
|
||||
prefixCls: PropTypes.string,
|
||||
transitionName: PropTypes.string,
|
||||
placement: PropTypes.oneOf(
|
||||
tuple('topLeft', 'topCenter', 'topRight', 'bottomLeft', 'bottomCenter', 'bottomRight'),
|
||||
),
|
||||
overlayClassName: PropTypes.string,
|
||||
overlayStyle: PropTypes.style,
|
||||
forceRender: PropTypes.looseBool,
|
||||
mouseEnterDelay: PropTypes.number,
|
||||
mouseLeaveDelay: PropTypes.number,
|
||||
openClassName: PropTypes.string,
|
||||
minOverlayWidthMatchTrigger: PropTypes.looseBool,
|
||||
});
|
||||
|
||||
const ButtonTypesProps = buttonTypes();
|
||||
const dropdownButtonProps = () => ({
|
||||
...dropdownProps(),
|
||||
type: PropTypes.oneOf(tuple('primary', 'ghost', 'dashed', 'default')),
|
||||
size: PropTypes.oneOf(tuple('small', 'large')),
|
||||
htmlType: ButtonTypesProps.htmlType,
|
||||
href: PropTypes.string,
|
||||
disabled: PropTypes.looseBool,
|
||||
prefixCls: PropTypes.string,
|
||||
icon: PropTypes.any,
|
||||
title: PropTypes.string,
|
||||
});
|
||||
|
||||
export { dropdownProps, dropdownButtonProps };
|
||||
|
||||
export default dropdownProps;
|
@ -0,0 +1,89 @@
|
||||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';
|
||||
|
||||
.@{dropdown-prefix-cls} {
|
||||
&-rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
&::before {
|
||||
.@{dropdown-prefix-cls}-rtl& {
|
||||
right: -7px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-menu {
|
||||
&&-rtl {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&-item-group-title {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
&-submenu-popup {
|
||||
&.@{dropdown-prefix-cls}-menu-submenu-rtl {
|
||||
transform-origin: 100% 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
li {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-item,
|
||||
&-submenu-title {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
> .@{iconfont-css-prefix}:first-child,
|
||||
> span > .@{iconfont-css-prefix}:first-child {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
margin-right: 0;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.@{dropdown-prefix-cls}-menu-submenu-arrow {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
right: auto;
|
||||
left: @padding-xs;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
margin-left: 0 !important;
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-submenu-title {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
padding-right: @control-padding-horizontal;
|
||||
padding-left: @control-padding-horizontal + @font-size-sm;
|
||||
}
|
||||
}
|
||||
|
||||
&-submenu-vertical > & {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
right: 100%;
|
||||
left: 0;
|
||||
margin-right: 4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
@import './index';
|
||||
|
||||
.@{dropdown-prefix-cls}-menu-item {
|
||||
&&-danger {
|
||||
color: @error-color;
|
||||
|
||||
&:hover {
|
||||
color: @text-color-inverse;
|
||||
background-color: @error-color;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
import { computed, defineComponent, ref, watch } from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import Trigger from '../vc-trigger';
|
||||
import placements from './placements';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
import classNames from '../_util/classNames';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
minOverlayWidthMatchTrigger: PropTypes.looseBool,
|
||||
arrow: PropTypes.looseBool.def(false),
|
||||
prefixCls: PropTypes.string.def('rc-dropdown'),
|
||||
transitionName: PropTypes.string,
|
||||
overlayClassName: PropTypes.string.def(''),
|
||||
openClassName: PropTypes.string,
|
||||
animation: PropTypes.any,
|
||||
align: PropTypes.object,
|
||||
overlayStyle: PropTypes.style,
|
||||
placement: PropTypes.string.def('bottomLeft'),
|
||||
overlay: PropTypes.any,
|
||||
trigger: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]).def(
|
||||
'hover',
|
||||
),
|
||||
alignPoint: PropTypes.looseBool,
|
||||
showAction: PropTypes.array,
|
||||
hideAction: PropTypes.array,
|
||||
getPopupContainer: PropTypes.func,
|
||||
visible: PropTypes.looseBool,
|
||||
defaultVisible: PropTypes.looseBool.def(false),
|
||||
mouseEnterDelay: PropTypes.number.def(0.15),
|
||||
mouseLeaveDelay: PropTypes.number.def(0.1),
|
||||
},
|
||||
emits: ['visibleChange', 'overlayClick'],
|
||||
slots: ['overlay'],
|
||||
setup(props, { slots, emit, expose }) {
|
||||
const triggerVisible = ref(!!props.visible);
|
||||
watch(
|
||||
() => props.visible,
|
||||
val => {
|
||||
if (val !== undefined) {
|
||||
triggerVisible.value = val;
|
||||
}
|
||||
},
|
||||
);
|
||||
const triggerRef = ref();
|
||||
|
||||
expose({
|
||||
triggerRef,
|
||||
});
|
||||
|
||||
const onClick = (e: MouseEvent) => {
|
||||
if (props.visible === undefined) {
|
||||
triggerVisible.value = false;
|
||||
}
|
||||
|
||||
emit('overlayClick', e);
|
||||
};
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
if (props.visible === undefined) {
|
||||
triggerVisible.value = visible;
|
||||
}
|
||||
emit('visibleChange', visible);
|
||||
};
|
||||
|
||||
const getMenuElement = () => {
|
||||
const overlayElement = slots.overlay?.();
|
||||
const extraOverlayProps = {
|
||||
prefixCls: `${props.prefixCls}-menu`,
|
||||
onClick,
|
||||
getPopupContainer: () => triggerRef.value.getPopupDomNode(),
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{props.arrow && <div class={`${props.prefixCls}-arrow`} />}
|
||||
{cloneElement(overlayElement, extraOverlayProps, false)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const minOverlayWidthMatchTrigger = computed(() => {
|
||||
const { minOverlayWidthMatchTrigger: matchTrigger = !props.alignPoint } = props;
|
||||
return matchTrigger;
|
||||
});
|
||||
|
||||
const renderChildren = () => {
|
||||
const children = slots.default?.();
|
||||
return triggerVisible.value && children
|
||||
? cloneElement(
|
||||
children[0],
|
||||
{ class: props.openClassName || `${props.prefixCls}-open` },
|
||||
false,
|
||||
)
|
||||
: children;
|
||||
};
|
||||
|
||||
const triggerHideAction = computed(() => {
|
||||
if (!props.hideAction && props.trigger.indexOf('contextmenu') !== -1) {
|
||||
return ['click'];
|
||||
}
|
||||
return props.hideAction;
|
||||
});
|
||||
return () => {
|
||||
const {
|
||||
prefixCls,
|
||||
arrow,
|
||||
showAction,
|
||||
overlayStyle,
|
||||
trigger,
|
||||
placement,
|
||||
align,
|
||||
getPopupContainer,
|
||||
transitionName,
|
||||
animation,
|
||||
overlayClassName,
|
||||
...otherProps
|
||||
} = props;
|
||||
return (
|
||||
<Trigger
|
||||
{...otherProps}
|
||||
prefixCls={prefixCls}
|
||||
ref={triggerRef}
|
||||
popupClassName={classNames(overlayClassName, {
|
||||
[`${prefixCls}-show-arrow`]: arrow,
|
||||
})}
|
||||
popupStyle={overlayStyle}
|
||||
builtinPlacements={placements}
|
||||
action={trigger}
|
||||
showAction={showAction}
|
||||
hideAction={triggerHideAction.value || []}
|
||||
popupPlacement={placement}
|
||||
popupAlign={align}
|
||||
popupTransitionName={transitionName}
|
||||
popupAnimation={animation}
|
||||
popupVisible={triggerVisible.value}
|
||||
stretch={minOverlayWidthMatchTrigger.value ? 'minWidth' : ''}
|
||||
onPopupVisibleChange={onVisibleChange}
|
||||
getPopupContainer={getPopupContainer}
|
||||
v-slots={{ popup: getMenuElement, default: renderChildren }}
|
||||
></Trigger>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
@ -1,225 +0,0 @@
|
||||
@dropdownPrefixCls: rc-dropdown;
|
||||
|
||||
@font-face {
|
||||
font-family: 'anticon';
|
||||
src: url('//at.alicdn.com/t/font_1434092639_4910953.eot');
|
||||
/* IE9*/
|
||||
src: url('//at.alicdn.com/t/font_1434092639_4910953.eot?#iefix') format('embedded-opentype'),
|
||||
/* IE6-IE8 */ url('//at.alicdn.com/t/font_1434092639_4910953.woff') format('woff'),
|
||||
/* chrome、firefox */ url('//at.alicdn.com/t/font_1434092639_4910953.ttf') format('truetype'),
|
||||
/* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
|
||||
url('//at.alicdn.com/t/font_1434092639_4910953.svg#iconfont') format('svg');
|
||||
/* iOS 4.1- */
|
||||
}
|
||||
|
||||
.@{dropdownPrefixCls} {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
top: -9999px;
|
||||
z-index: 1070;
|
||||
display: block;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
&-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-menu {
|
||||
outline: none;
|
||||
position: relative;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 2px 0 0 0;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 5px #ccc;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #ccc;
|
||||
|
||||
> li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background: rgb(255, 255, 255);
|
||||
background: rgba(255, 255, 255, 0.01);
|
||||
}
|
||||
|
||||
& > &-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 7px 10px;
|
||||
clear: both;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
color: #666666;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover,
|
||||
&-active,
|
||||
&-selected {
|
||||
background-color: #ebfaff;
|
||||
}
|
||||
|
||||
&-selected {
|
||||
position: relative;
|
||||
&:after {
|
||||
content: '\e613';
|
||||
font-family: 'anticon';
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 16px;
|
||||
color: #3cb8f0;
|
||||
}
|
||||
}
|
||||
|
||||
&-disabled {
|
||||
color: #ccc;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
|
||||
&:hover {
|
||||
color: #ccc;
|
||||
background-color: #fff;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
|
||||
&-divider {
|
||||
height: 1px;
|
||||
margin: 1px 0;
|
||||
overflow: hidden;
|
||||
background-color: #e5e5e5;
|
||||
line-height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.effect() {
|
||||
animation-duration: 0.3s;
|
||||
animation-fill-mode: both;
|
||||
transform-origin: 0 0;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
&-slide-up-enter,
|
||||
&-slide-up-appear {
|
||||
.effect();
|
||||
opacity: 0;
|
||||
animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
|
||||
animation-play-state: paused;
|
||||
}
|
||||
|
||||
&-slide-up-leave {
|
||||
.effect();
|
||||
opacity: 1;
|
||||
animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
|
||||
animation-play-state: paused;
|
||||
}
|
||||
|
||||
&-slide-up-enter&-slide-up-enter-active&-placement-bottomLeft,
|
||||
&-slide-up-appear&-slide-up-appear-active&-placement-bottomLeft,
|
||||
&-slide-up-enter&-slide-up-enter-active&-placement-bottomCenter,
|
||||
&-slide-up-appear&-slide-up-appear-active&-placement-bottomCenter,
|
||||
&-slide-up-enter&-slide-up-enter-active&-placement-bottomRight,
|
||||
&-slide-up-appear&-slide-up-appear-active&-placement-bottomRight {
|
||||
animation-name: rcDropdownSlideUpIn;
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
&-slide-up-enter&-slide-up-enter-active&-placement-topLeft,
|
||||
&-slide-up-appear&-slide-up-appear-active&-placement-topLeft,
|
||||
&-slide-up-enter&-slide-up-enter-active&-placement-topCenter,
|
||||
&-slide-up-appear&-slide-up-appear-active&-placement-topCenter,
|
||||
&-slide-up-enter&-slide-up-enter-active&-placement-topRight,
|
||||
&-slide-up-appear&-slide-up-appear-active&-placement-topRight {
|
||||
animation-name: rcDropdownSlideDownIn;
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
&-slide-up-leave&-slide-up-leave-active&-placement-bottomLeft,
|
||||
&-slide-up-leave&-slide-up-leave-active&-placement-bottomCenter,
|
||||
&-slide-up-leave&-slide-up-leave-active&-placement-bottomRight {
|
||||
animation-name: rcDropdownSlideUpOut;
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
&-slide-up-leave&-slide-up-leave-active&-placement-topLeft,
|
||||
&-slide-up-leave&-slide-up-leave-active&-placement-topCenter,
|
||||
&-slide-up-leave&-slide-up-leave-active&-placement-topRight {
|
||||
animation-name: rcDropdownSlideDownOut;
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
@keyframes rcDropdownSlideUpIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform-origin: 0% 0%;
|
||||
transform: scaleY(0);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform-origin: 0% 0%;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
@keyframes rcDropdownSlideUpOut {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform-origin: 0% 0%;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform-origin: 0% 0%;
|
||||
transform: scaleY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rcDropdownSlideDownIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform-origin: 0% 100%;
|
||||
transform: scaleY(0);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform-origin: 0% 100%;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
@keyframes rcDropdownSlideDownOut {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform-origin: 0% 100%;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform-origin: 0% 100%;
|
||||
transform: scaleY(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
// base in 2.4.1
|
||||
// base in 3.2.0
|
||||
import Dropdown from './Dropdown';
|
||||
export default Dropdown;
|
@ -1,202 +0,0 @@
|
||||
import { defineComponent, Text } from 'vue';
|
||||
import PropTypes from '../../_util/vue-types';
|
||||
import Trigger from '../../vc-trigger';
|
||||
import placements from './placements';
|
||||
import {
|
||||
hasProp,
|
||||
getComponent,
|
||||
getOptionProps,
|
||||
getSlot,
|
||||
findDOMNode,
|
||||
} from '../../_util/props-util';
|
||||
import BaseMixin from '../../_util/BaseMixin';
|
||||
import { cloneElement } from '../../_util/vnode';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [BaseMixin],
|
||||
props: {
|
||||
minOverlayWidthMatchTrigger: PropTypes.looseBool,
|
||||
prefixCls: PropTypes.string.def('rc-dropdown'),
|
||||
transitionName: PropTypes.string,
|
||||
overlayClassName: PropTypes.string.def(''),
|
||||
openClassName: PropTypes.string,
|
||||
animation: PropTypes.any,
|
||||
align: PropTypes.object,
|
||||
overlayStyle: PropTypes.style,
|
||||
placement: PropTypes.string.def('bottomLeft'),
|
||||
overlay: PropTypes.any,
|
||||
trigger: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]).def(
|
||||
'hover',
|
||||
),
|
||||
alignPoint: PropTypes.looseBool,
|
||||
showAction: PropTypes.array,
|
||||
hideAction: PropTypes.array,
|
||||
getPopupContainer: PropTypes.func,
|
||||
visible: PropTypes.looseBool,
|
||||
defaultVisible: PropTypes.looseBool.def(false),
|
||||
mouseEnterDelay: PropTypes.number.def(0.15),
|
||||
mouseLeaveDelay: PropTypes.number.def(0.1),
|
||||
},
|
||||
data() {
|
||||
let sVisible = this.defaultVisible;
|
||||
if (hasProp(this, 'visible')) {
|
||||
sVisible = this.visible;
|
||||
}
|
||||
return {
|
||||
sVisible,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (val !== undefined) {
|
||||
this.setState({
|
||||
sVisible: val,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onClick(e) {
|
||||
const overlayProps = this.getOverlayElement().props;
|
||||
// do no call onVisibleChange, if you need click to hide, use onClick and control visible
|
||||
if (!hasProp(this, 'visible')) {
|
||||
this.setState({
|
||||
sVisible: false,
|
||||
});
|
||||
}
|
||||
this.__emit('overlayClick', e);
|
||||
if (overlayProps.onClick) {
|
||||
overlayProps.onClick(e);
|
||||
}
|
||||
},
|
||||
|
||||
onVisibleChange(visible) {
|
||||
if (!hasProp(this, 'visible')) {
|
||||
this.setState({
|
||||
sVisible: visible,
|
||||
});
|
||||
}
|
||||
this.__emit('update:visible', visible);
|
||||
this.__emit('visibleChange', visible);
|
||||
},
|
||||
|
||||
getMinOverlayWidthMatchTrigger() {
|
||||
const props = getOptionProps(this);
|
||||
const { minOverlayWidthMatchTrigger, alignPoint } = props;
|
||||
if ('minOverlayWidthMatchTrigger' in props) {
|
||||
return minOverlayWidthMatchTrigger;
|
||||
}
|
||||
|
||||
return !alignPoint;
|
||||
},
|
||||
|
||||
getOverlayElement() {
|
||||
const overlay = getComponent(this, 'overlay');
|
||||
return Array.isArray(overlay) ? overlay[0] : overlay;
|
||||
},
|
||||
|
||||
getMenuElement() {
|
||||
const { onClick, prefixCls } = this;
|
||||
const overlayElement = this.getOverlayElement();
|
||||
const extraOverlayProps = {
|
||||
prefixCls: `${prefixCls}-menu`,
|
||||
getPopupContainer: () => this.getPopupDomNode(),
|
||||
onClick,
|
||||
};
|
||||
if (overlayElement && overlayElement.type === Text) {
|
||||
delete extraOverlayProps.prefixCls;
|
||||
}
|
||||
return cloneElement(overlayElement, extraOverlayProps);
|
||||
},
|
||||
|
||||
getMenuElementOrLambda() {
|
||||
const overlay = this.overlay || this.$slots.overlay;
|
||||
if (typeof overlay === 'function') {
|
||||
return this.getMenuElement;
|
||||
}
|
||||
return this.getMenuElement();
|
||||
},
|
||||
|
||||
getPopupDomNode() {
|
||||
return this.triggerRef.getPopupDomNode();
|
||||
},
|
||||
|
||||
getOpenClassName() {
|
||||
const { openClassName, prefixCls } = this.$props;
|
||||
if (openClassName !== undefined) {
|
||||
return openClassName;
|
||||
}
|
||||
return `${prefixCls}-open`;
|
||||
},
|
||||
|
||||
afterVisibleChange(visible) {
|
||||
if (visible && this.getMinOverlayWidthMatchTrigger()) {
|
||||
const overlayNode = this.getPopupDomNode();
|
||||
const rootNode = findDOMNode(this);
|
||||
if (rootNode && overlayNode && rootNode.offsetWidth > overlayNode.offsetWidth) {
|
||||
overlayNode.style.minWidth = `${rootNode.offsetWidth}px`;
|
||||
if (
|
||||
this.triggerRef &&
|
||||
this.triggerRef._component &&
|
||||
this.triggerRef._component.alignInstance
|
||||
) {
|
||||
this.triggerRef._component.alignInstance.forceAlign();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
renderChildren() {
|
||||
const children = getSlot(this);
|
||||
const { sVisible } = this;
|
||||
return sVisible && children
|
||||
? cloneElement(children[0], { class: this.getOpenClassName() }, false)
|
||||
: children;
|
||||
},
|
||||
saveTrigger(node) {
|
||||
this.triggerRef = node;
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
prefixCls,
|
||||
transitionName,
|
||||
animation,
|
||||
align,
|
||||
placement,
|
||||
getPopupContainer,
|
||||
showAction,
|
||||
hideAction,
|
||||
overlayClassName,
|
||||
overlayStyle,
|
||||
trigger,
|
||||
...otherProps
|
||||
} = this.$props;
|
||||
let triggerHideAction = hideAction;
|
||||
if (!triggerHideAction && trigger.indexOf('contextmenu') !== -1) {
|
||||
triggerHideAction = ['click'];
|
||||
}
|
||||
const triggerProps = {
|
||||
...otherProps,
|
||||
prefixCls,
|
||||
popupClassName: overlayClassName,
|
||||
popupStyle: overlayStyle,
|
||||
builtinPlacements: placements,
|
||||
action: trigger,
|
||||
showAction,
|
||||
hideAction: triggerHideAction || [],
|
||||
popupPlacement: placement,
|
||||
popupAlign: align,
|
||||
popupTransitionName: transitionName,
|
||||
popupAnimation: animation,
|
||||
popupVisible: this.sVisible,
|
||||
afterPopupVisibleChange: this.afterVisibleChange,
|
||||
getPopupContainer,
|
||||
onPopupVisibleChange: this.onVisibleChange,
|
||||
popup: this.getMenuElementOrLambda(),
|
||||
ref: this.saveTrigger,
|
||||
};
|
||||
return <Trigger {...triggerProps}>{this.renderChildren()}</Trigger>;
|
||||
},
|
||||
});
|
Loading…
Reference in new issue