|
|
|
import Trigger from '../vc-trigger';
|
|
|
|
import PropTypes from '../_util/vue-types';
|
|
|
|
import classNames from '../_util/classNames';
|
|
|
|
import type { CSSProperties, PropType } from 'vue';
|
|
|
|
import { computed, ref, defineComponent } from 'vue';
|
|
|
|
import type { VueNode } from '../_util/type';
|
|
|
|
import type { DropdownRender, Placement, RenderDOMFunc } from './BaseSelect';
|
|
|
|
|
|
|
|
const getBuiltInPlacements = (adjustX: number) => {
|
|
|
|
return {
|
|
|
|
bottomLeft: {
|
|
|
|
points: ['tl', 'bl'],
|
|
|
|
offset: [0, 4],
|
|
|
|
overflow: {
|
|
|
|
adjustX,
|
|
|
|
adjustY: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
bottomRight: {
|
|
|
|
points: ['tr', 'br'],
|
|
|
|
offset: [0, 4],
|
|
|
|
overflow: {
|
|
|
|
adjustX,
|
|
|
|
adjustY: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
topLeft: {
|
|
|
|
points: ['bl', 'tl'],
|
|
|
|
offset: [0, -4],
|
|
|
|
overflow: {
|
|
|
|
adjustX,
|
|
|
|
adjustY: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
topRight: {
|
|
|
|
points: ['br', 'tr'],
|
|
|
|
offset: [0, -4],
|
|
|
|
overflow: {
|
|
|
|
adjustX,
|
|
|
|
adjustY: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const getAdjustX = (
|
|
|
|
adjustXDependencies: Pick<SelectTriggerProps, 'autoAdjustOverflow' | 'dropdownMatchSelectWidth'>,
|
|
|
|
) => {
|
|
|
|
const { autoAdjustOverflow, dropdownMatchSelectWidth } = adjustXDependencies;
|
|
|
|
if (!!autoAdjustOverflow) return 1;
|
|
|
|
// Enable horizontal overflow auto-adjustment when a custom dropdown width is provided
|
|
|
|
return typeof dropdownMatchSelectWidth !== 'number' ? 0 : 1;
|
|
|
|
};
|
|
|
|
export interface RefTriggerProps {
|
|
|
|
getPopupElement: () => HTMLDivElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface SelectTriggerProps {
|
|
|
|
prefixCls: string;
|
|
|
|
disabled: boolean;
|
|
|
|
visible: boolean;
|
|
|
|
popupElement: VueNode;
|
|
|
|
animation?: string;
|
|
|
|
transitionName?: string;
|
|
|
|
containerWidth: number;
|
|
|
|
placement?: Placement;
|
|
|
|
dropdownStyle: CSSProperties;
|
|
|
|
dropdownClassName: string;
|
|
|
|
direction: string;
|
|
|
|
dropdownMatchSelectWidth?: boolean | number;
|
|
|
|
dropdownRender?: DropdownRender;
|
|
|
|
getPopupContainer?: RenderDOMFunc;
|
|
|
|
dropdownAlign: object;
|
|
|
|
empty: boolean;
|
|
|
|
autoAdjustOverflow?: boolean;
|
|
|
|
getTriggerDOMNode: () => any;
|
|
|
|
onPopupVisibleChange?: (visible: boolean) => void;
|
|
|
|
|
|
|
|
onPopupMouseEnter: () => void;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SelectTrigger = defineComponent<SelectTriggerProps, { popupRef: any }>({
|
|
|
|
name: 'SelectTrigger',
|
|
|
|
inheritAttrs: false,
|
|
|
|
props: {
|
|
|
|
dropdownAlign: PropTypes.object,
|
|
|
|
visible: { type: Boolean, default: undefined },
|
|
|
|
disabled: { type: Boolean, default: undefined },
|
|
|
|
dropdownClassName: String,
|
|
|
|
dropdownStyle: PropTypes.object,
|
|
|
|
placement: String,
|
|
|
|
empty: { type: Boolean, default: undefined },
|
|
|
|
autoAdjustOverflow: { type: Boolean, default: undefined },
|
|
|
|
prefixCls: String,
|
|
|
|
popupClassName: String,
|
|
|
|
animation: String,
|
|
|
|
transitionName: String,
|
|
|
|
getPopupContainer: Function,
|
|
|
|
dropdownRender: Function,
|
|
|
|
containerWidth: Number,
|
|
|
|
dropdownMatchSelectWidth: PropTypes.oneOfType([Number, Boolean]).def(true),
|
|
|
|
popupElement: PropTypes.any,
|
|
|
|
direction: String,
|
|
|
|
getTriggerDOMNode: Function,
|
|
|
|
onPopupVisibleChange: Function as PropType<(open: boolean) => void>,
|
|
|
|
onPopupMouseEnter: Function,
|
|
|
|
} as any,
|
|
|
|
setup(props, { slots, attrs, expose }) {
|
|
|
|
const builtInPlacements = computed(() => {
|
|
|
|
const { autoAdjustOverflow, dropdownMatchSelectWidth } = props;
|
|
|
|
return getBuiltInPlacements(
|
|
|
|
getAdjustX({
|
|
|
|
autoAdjustOverflow,
|
|
|
|
dropdownMatchSelectWidth,
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
const popupRef = ref();
|
|
|
|
expose({
|
|
|
|
getPopupElement: () => {
|
|
|
|
return popupRef.value;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
return () => {
|
|
|
|
const { empty = false, ...restProps } = { ...props, ...attrs };
|
|
|
|
const {
|
|
|
|
visible,
|
|
|
|
dropdownAlign,
|
|
|
|
prefixCls,
|
|
|
|
popupElement,
|
|
|
|
dropdownClassName,
|
|
|
|
dropdownStyle,
|
|
|
|
direction = 'ltr',
|
|
|
|
placement,
|
|
|
|
dropdownMatchSelectWidth,
|
|
|
|
containerWidth,
|
|
|
|
dropdownRender,
|
|
|
|
animation,
|
|
|
|
transitionName,
|
|
|
|
getPopupContainer,
|
|
|
|
getTriggerDOMNode,
|
|
|
|
onPopupVisibleChange,
|
|
|
|
onPopupMouseEnter,
|
|
|
|
} = restProps as SelectTriggerProps;
|
|
|
|
const dropdownPrefixCls = `${prefixCls}-dropdown`;
|
|
|
|
|
|
|
|
let popupNode = popupElement;
|
|
|
|
if (dropdownRender) {
|
|
|
|
popupNode = dropdownRender({ menuNode: popupElement, props });
|
|
|
|
}
|
|
|
|
|
|
|
|
const mergedTransitionName = animation ? `${dropdownPrefixCls}-${animation}` : transitionName;
|
|
|
|
|
|
|
|
const popupStyle = { minWidth: `${containerWidth}px`, ...dropdownStyle };
|
|
|
|
|
|
|
|
if (typeof dropdownMatchSelectWidth === 'number') {
|
|
|
|
popupStyle.width = `${dropdownMatchSelectWidth}px`;
|
|
|
|
} else if (dropdownMatchSelectWidth) {
|
|
|
|
popupStyle.width = `${containerWidth}px`;
|
|
|
|
}
|
|
|
|
return (
|
|
|
|
<Trigger
|
|
|
|
{...props}
|
|
|
|
showAction={onPopupVisibleChange ? ['click'] : []}
|
|
|
|
hideAction={onPopupVisibleChange ? ['click'] : []}
|
|
|
|
popupPlacement={placement || (direction === 'rtl' ? 'bottomRight' : 'bottomLeft')}
|
|
|
|
builtinPlacements={builtInPlacements.value}
|
|
|
|
prefixCls={dropdownPrefixCls}
|
|
|
|
popupTransitionName={mergedTransitionName}
|
|
|
|
popupAlign={dropdownAlign}
|
|
|
|
popupVisible={visible}
|
|
|
|
getPopupContainer={getPopupContainer}
|
|
|
|
popupClassName={classNames(dropdownClassName, {
|
|
|
|
[`${dropdownPrefixCls}-empty`]: empty,
|
|
|
|
})}
|
|
|
|
popupStyle={popupStyle}
|
|
|
|
getTriggerDOMNode={getTriggerDOMNode}
|
|
|
|
onPopupVisibleChange={onPopupVisibleChange}
|
|
|
|
v-slots={{
|
|
|
|
default: slots.default,
|
|
|
|
popup: () => (
|
|
|
|
<div ref={popupRef} onMouseenter={onPopupMouseEnter}>
|
|
|
|
{popupNode}
|
|
|
|
</div>
|
|
|
|
),
|
|
|
|
}}
|
|
|
|
></Trigger>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
export default SelectTrigger;
|