feat: select auto-complete support virtual list

This commit is contained in:
tangjinzhou 2020-10-17 22:19:52 +08:00
parent 4d63b7cab6
commit 46149b660b
17 changed files with 1005 additions and 756 deletions

View File

@ -1,18 +1,21 @@
import { App, defineComponent, inject, provide } from 'vue';
import { Option, OptGroup } from '../vc-select';
import Select, { SelectProps } from '../select';
import Input from '../input';
import InputElement from './InputElement';
import PropTypes from '../_util/vue-types';
import { defaultConfigProvider } from '../config-provider';
import { getComponent, getOptionProps, isValidElement, getSlot } from '../_util/props-util';
import Omit from 'omit.js';
import warning from '../_util/warning';
const { Option, OptGroup } = Select;
function isSelectOptionOrSelectOptGroup(child: any): Boolean {
return child && child.type && (child.type.isSelectOption || child.type.isSelectOptGroup);
}
const AutoCompleteProps = {
...SelectProps,
...SelectProps(),
dataSource: PropTypes.array,
dropdownMenuStyle: PropTypes.style,
optionLabelProp: PropTypes.string,
@ -39,7 +42,12 @@ const AutoComplete = defineComponent({
},
Option: { ...Option, name: 'AAutoCompleteOption' },
OptGroup: { ...OptGroup, name: 'AAutoCompleteOptGroup' },
setup() {
setup(props, { slots }) {
warning(
!('dataSource' in props || 'dataSource' in slots),
'AutoComplete',
'`dataSource` is deprecated, please use `options` instead.',
);
return {
configProvider: inject('configProvider', defaultConfigProvider),
popupRef: null,
@ -59,11 +67,7 @@ const AutoComplete = defineComponent({
getInputElement() {
const children = getSlot(this);
const element = children.length ? children[0] : <Input lazy={false} />;
return (
<InputElement placeholder={this.placeholder} {...element.props}>
{element}
</InputElement>
);
return <InputElement {...element.props}>{element}</InputElement>;
},
focus() {
@ -80,8 +84,8 @@ const AutoComplete = defineComponent({
},
render() {
const { size, prefixCls: customizePrefixCls, optionLabelProp, dataSource } = this;
const { size, prefixCls: customizePrefixCls, dataSource } = this;
let optionChildren: any;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('select', customizePrefixCls);
const { class: className } = this.$attrs as any;
@ -92,22 +96,28 @@ const AutoComplete = defineComponent({
[`${prefixCls}-show-search`]: true,
[`${prefixCls}-auto-complete`]: true,
};
let options;
const childArray = getSlot(this, 'dataSource');
if (childArray.length && isSelectOptionOrSelectOptGroup(childArray[0])) {
options = childArray;
optionChildren = childArray;
} else {
options = dataSource
optionChildren = dataSource
? dataSource.map((item: any) => {
if (isValidElement(item)) {
return item;
}
switch (typeof item) {
case 'string':
return <Option key={item}>{item}</Option>;
return (
<Option key={item} value={item}>
{item}
</Option>
);
case 'object':
return <Option key={item.value}>{item.text}</Option>;
return (
<Option key={item.value} value={item.value}>
{item.text}
</Option>
);
default:
throw new Error(
'AutoComplete[dataSource] only supports type `string[] | Object[]`.',
@ -117,17 +127,17 @@ const AutoComplete = defineComponent({
: [];
}
const selectProps = {
...getOptionProps(this),
...Omit(getOptionProps(this), ['dataSource', 'optionLabelProp'] as any),
...this.$attrs,
mode: Select.SECRET_COMBOBOX_MODE_DO_NOT_USE,
optionLabelProp,
// optionLabelProp,
getInputElement: this.getInputElement,
notFoundContent: getComponent(this, 'notFoundContent'),
placeholder: '',
// placeholder: '',
class: cls,
ref: this.saveSelect,
};
return <Select {...selectProps}>{options}</Select>;
return <Select {...selectProps}>{optionChildren}</Select>;
},
});

View File

@ -9,84 +9,8 @@
.@{autocomplete-prefix-cls} {
.reset-component;
&.@{select-prefix-cls} {
.@{select-prefix-cls} {
&-selection {
border: 0;
box-shadow: none;
&__rendered {
height: 100%;
margin-right: 0;
margin-left: 0;
line-height: @input-height-base;
}
&__placeholder {
margin-right: (@input-padding-horizontal-base + 1px);
margin-left: (@input-padding-horizontal-base + 1px);
}
&--single {
height: auto;
}
}
}
// Fix https://github.com/ant-design/ant-design/issues/7800
.@{select-prefix-cls}-search--inline {
position: static;
float: left;
}
&-allow-clear {
.@{select-prefix-cls}-selection:hover .@{select-prefix-cls}-selection__rendered {
margin-right: 0 !important;
}
}
.@{input-prefix-cls} {
height: @input-height-base;
line-height: @line-height-base;
background: transparent;
border-width: @border-width-base;
&:focus,
&:hover {
.hover;
}
&[disabled] {
.disabled;
background-color: transparent;
}
}
&-lg {
.@{select-prefix-cls}-selection__rendered {
line-height: @input-height-lg;
}
.@{input-prefix-cls} {
height: @input-height-lg;
padding-top: @input-padding-vertical-lg;
padding-bottom: @input-padding-vertical-lg;
}
}
&-sm {
.@{select-prefix-cls}-selection__rendered {
line-height: @input-height-sm;
}
.@{input-prefix-cls} {
height: @input-height-sm;
padding-top: @input-padding-vertical-sm;
padding-bottom: @input-padding-vertical-sm;
}
}
}
}
// https://github.com/ant-design/ant-design/issues/14156
.@{input-prefix-cls}-group > .@{autocomplete-prefix-cls} {
.@{select-prefix-cls}-search__field.@{input-prefix-cls}-affix-wrapper {
display: inline;
float: none;
// https://github.com/ant-design/ant-design/issues/22302
.@{select-prefix-cls}-clear {
right: 13px;
}
}

View File

@ -4,7 +4,7 @@ import { getOptionProps, getSlot } from '../_util/props-util';
export default {
inheritAttrs: false,
props: {
...SelectProps,
...SelectProps(),
},
Option: VcSelect.Option,
render() {

View File

@ -1,7 +1,7 @@
import omit from 'omit.js';
import classNames from '../_util/classNames';
import RcSelect, { Option, OptGroup, SelectProps as RcSelectProps, props } from '../vc-select2';
import { OptionProps } from '../vc-select2/Option';
import RcSelect, { Option, OptGroup, SelectProps as RcSelectProps, BaseProps } from '../vc-select2';
import { OptionProps as OptionPropsType } from '../vc-select2/Option';
import { defaultConfigProvider } from '../config-provider';
import getIcons from './utils/iconUtil';
import { computed, defineComponent, inject, ref, VNodeChild, App, PropType } from 'vue';
@ -10,7 +10,7 @@ import { tuple } from '../_util/type';
type RawValue = string | number;
export { OptionProps };
export type OptionProps = OptionPropsType;
export type OptionType = typeof Option;
@ -31,36 +31,40 @@ export interface InternalSelectProps<VT> extends Omit<RcSelectProps<VT>, 'mode'>
}
export interface SelectPropsTypes<VT>
extends Omit<InternalSelectProps<VT>, 'inputIcon' | 'mode' | 'getInputElement' | 'backfill' | 'class' | 'style'> {
extends Omit<
InternalSelectProps<VT>,
'inputIcon' | 'mode' | 'getInputElement' | 'backfill' | 'class' | 'style'
> {
mode?: 'multiple' | 'tags';
}
export type SelectTypes = SelectPropsTypes<SelectValue>
export const SelectProps = {
...omit(props, ['inputIcon' ,'mode' ,'getInputElement' ,'backfill' ,'class' ,'style']),
export type SelectTypes = SelectPropsTypes<SelectValue>;
export const SelectProps = () => ({
...omit(BaseProps(), ['inputIcon', 'mode', 'getInputElement', 'backfill', 'class', 'style']),
value: {
type: [Array, Object, String, Number] as PropType<SelectValue>
type: [Array, Object, String, Number] as PropType<SelectValue>,
},
defaultValue: {
type: [Array, Object, String, Number] as PropType<SelectValue>
type: [Array, Object, String, Number] as PropType<SelectValue>,
},
notFoundContent: PropTypes.VNodeChild,
suffixIcon: PropTypes.VNodeChild,
itemIcon: PropTypes.VNodeChild,
size: PropTypes.oneOf(tuple('small', 'middle', 'large', undefined, 'default')),
mode: PropTypes.oneOf(tuple('multiple', 'tags')),
size: PropTypes.oneOf(tuple('small', 'middle', 'large', 'default')),
mode: PropTypes.oneOf(tuple('multiple', 'tags', 'SECRET_COMBOBOX_MODE_DO_NOT_USE')),
bordered: PropTypes.looseBool.def(true),
transitionName: PropTypes.string.def('slide-up'),
choiceTransitionName: PropTypes.string.def(''),
}
});
const Select = defineComponent({
name: 'ASelect',
Option,
OptGroup,
inheritAttrs: false,
props: SelectProps,
props: SelectProps(),
SECRET_COMBOBOX_MODE_DO_NOT_USE: 'SECRET_COMBOBOX_MODE_DO_NOT_USE',
emits: ['change', 'update:value'],
setup(props: any, {attrs, emit}) {
setup(props: any, { attrs, emit }) {
const selectRef = ref(null);
const configProvider = inject('configProvider', defaultConfigProvider);
@ -77,8 +81,8 @@ const Select = defineComponent({
}
};
const mode = computed(()=>{
const { mode } = props
const mode = computed(() => {
const { mode } = props;
if ((mode as any) === 'combobox') {
return undefined;
@ -90,35 +94,47 @@ const Select = defineComponent({
return mode;
});
const mergedClassName = computed(()=> classNames(
{
[`${props.prefixCls}-lg`]: props.size === 'large',
[`${props.prefixCls}-sm`]: props.size === 'small',
[`${props.prefixCls}-rtl`]: props.direction === 'rtl',
[`${props.prefixCls}-borderless`]: !props.bordered,
},
attrs.class,
));
const triggerChange=(...args: any[])=>{
console.log(args)
emit('update:value', ...args)
emit('change', ...args)
}
const prefixCls = computed(() => {
return configProvider.getPrefixCls('select', props.prefixCls);
});
const mergedClassName = computed(() =>
classNames(
{
[`${prefixCls.value}-lg`]: props.size === 'large',
[`${prefixCls.value}-sm`]: props.size === 'small',
[`${prefixCls.value}-rtl`]: props.direction === 'rtl',
[`${prefixCls.value}-borderless`]: !props.bordered,
},
attrs.class,
),
);
const triggerChange = (...args: any[]) => {
console.log(args);
emit('update:value', ...args);
emit('change', ...args);
};
return {
mergedClassName,
mode,
focus,
blur,
configProvider,
triggerChange
}
triggerChange,
prefixCls,
};
},
render() {
const {configProvider, mode, mergedClassName,triggerChange, $slots: slots, $props} = this as any;
const props: SelectTypes = $props
const {
prefixCls: customizePrefixCls,
configProvider,
mode,
mergedClassName,
triggerChange,
prefixCls,
$slots: slots,
$props,
} = this as any;
const props: SelectTypes = $props;
const {
notFoundContent,
listHeight = 256,
listItemHeight = 24,
@ -126,11 +142,10 @@ const Select = defineComponent({
dropdownClassName,
direction,
virtual,
dropdownMatchSelectWidth
dropdownMatchSelectWidth,
} = props;
const { getPrefixCls, renderEmpty, getPopupContainer: getContextPopupContainer } = configProvider
const prefixCls = getPrefixCls('select', customizePrefixCls);
const { renderEmpty, getPopupContainer: getContextPopupContainer } = configProvider;
const isMultiple = mode === 'multiple' || mode === 'tags';
@ -138,20 +153,24 @@ const Select = defineComponent({
let mergedNotFound: VNodeChild;
if (notFoundContent !== undefined) {
mergedNotFound = notFoundContent;
} else if(slots.notFoundContent){
mergedNotFound = slots.notFoundContent()
} else if (slots.notFoundContent) {
mergedNotFound = slots.notFoundContent();
} else if (mode === 'combobox') {
mergedNotFound = null;
} else {
console.log(111);
mergedNotFound = renderEmpty('Select') as any;
}
// ===================== Icons =====================
const { suffixIcon, itemIcon, removeIcon, clearIcon } = getIcons({
...this.$props,
multiple: isMultiple,
prefixCls,
}, slots);
const { suffixIcon, itemIcon, removeIcon, clearIcon } = getIcons(
{
...this.$props,
multiple: isMultiple,
prefixCls,
},
slots,
);
const selectProps = omit(props, [
'prefixCls',
@ -166,30 +185,33 @@ const Select = defineComponent({
const rcSelectRtlDropDownClassName = classNames(dropdownClassName, {
[`${prefixCls}-dropdown-${direction}`]: direction === 'rtl',
});
<RcSelect
ref="selectRef"
virtual={virtual}
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
{...selectProps}
listHeight={listHeight}
listItemHeight={listItemHeight}
mode={mode}
prefixCls={prefixCls}
direction={direction}
inputIcon={suffixIcon}
menuItemSelectedIcon={itemIcon}
removeIcon={removeIcon}
clearIcon={clearIcon}
notFoundContent={mergedNotFound}
class={mergedClassName}
getPopupContainer={getPopupContainer || getContextPopupContainer}
dropdownClassName={rcSelectRtlDropDownClassName}
onChange={triggerChange}
>
{slots?.default()}
</RcSelect>
}
})
return (
<RcSelect
ref="selectRef"
virtual={virtual}
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
{...selectProps}
{...this.$attrs}
listHeight={listHeight}
listItemHeight={listItemHeight}
mode={mode}
prefixCls={prefixCls}
direction={direction}
inputIcon={suffixIcon}
menuItemSelectedIcon={itemIcon}
removeIcon={removeIcon}
clearIcon={clearIcon}
notFoundContent={mergedNotFound}
class={mergedClassName}
getPopupContainer={getPopupContainer || getContextPopupContainer}
dropdownClassName={rcSelectRtlDropDownClassName}
onChange={triggerChange}
>
{slots?.default()}
</RcSelect>
);
},
});
/* istanbul ignore next */
Select.install = function(app: App) {
app.component(Select.name, Select);

View File

@ -99,7 +99,7 @@ const Select = defineComponent({
...SelectProps,
showSearch: PropTypes.looseBool.def(false),
transitionName: PropTypes.string.def('slide-up'),
choiceTransitionName: PropTypes.string.def('zoom'),
choiceTransitionName: PropTypes.string.def(''),
},
propTypes: SelectPropTypes,
setup() {

View File

@ -2,603 +2,303 @@
@import '../../style/mixins/index';
@import '../../input/style/mixin';
@select-prefix-cls: ~'@{ant-prefix}-select';
@import './single';
@import './multiple';
.selection__clear() {
position: absolute;
top: 50%;
right: @control-padding-horizontal - 1px;
z-index: 1;
display: inline-block;
width: 12px;
height: 12px;
margin-top: -6px;
color: @disabled-color;
font-size: @font-size-sm;
font-style: normal;
line-height: 12px;
text-align: center;
text-transform: none;
background: @component-background;
cursor: pointer;
opacity: 0;
transition: color 0.3s ease, opacity 0.15s ease;
text-rendering: auto;
&::before {
display: block;
@select-prefix-cls: ~'@{ant-prefix}-select';
@select-height-without-border: @input-height-base - 2 * @border-width-base;
@select-dropdown-edge-child-vertical-padding: @dropdown-edge-child-vertical-padding;
.select-selector() {
position: relative;
background-color: @select-background;
border: @border-width-base @border-style-base @select-border-color;
border-radius: @border-radius-base;
transition: all 0.3s @ease-in-out;
input {
cursor: pointer;
}
&:hover {
color: @text-color-secondary;
.@{select-prefix-cls}-show-search& {
cursor: text;
input {
cursor: auto;
}
}
.@{select-prefix-cls}-focused:not(.@{select-prefix-cls}-disabled)& {
.active();
}
.@{select-prefix-cls}-disabled& {
color: @disabled-color;
background: @input-disabled-bg;
cursor: not-allowed;
input {
cursor: not-allowed;
}
}
}
/* Reset search input style */
.select-search-input-without-border() {
.@{select-prefix-cls}-selection-search-input {
margin: 0;
padding: 0;
background: transparent;
border: none;
outline: none;
appearance: none;
&::-webkit-search-cancel-button {
display: none;
-webkit-appearance: none;
}
}
}
.@{select-prefix-cls} {
.reset-component;
position: relative;
display: inline-block;
outline: 0;
cursor: pointer;
ul,
ol {
margin: 0;
padding: 0;
list-style: none;
&:not(.@{select-prefix-cls}-disabled):hover &-selector {
.hover();
}
> ul > li > a {
padding: 0;
background-color: @component-background;
// ======================== Selection ========================
&-selection-item {
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
// IE11 css hack. `*::-ms-backdrop,` is a must have
@media all and (-ms-high-contrast: none) {
*::-ms-backdrop,
& {
flex: auto;
}
}
}
// arrow
// ======================= Placeholder =======================
&-selection-placeholder {
flex: 1;
overflow: hidden;
color: @input-placeholder-color;
white-space: nowrap;
text-overflow: ellipsis;
// IE11 css hack. `*::-ms-backdrop,` is a must have
@media all and (-ms-high-contrast: none) {
*::-ms-backdrop,
& {
flex: auto;
}
}
}
// ========================== Arrow ==========================
&-arrow {
.iconfont-mixin();
position: absolute;
top: 50%;
top: 53%;
right: @control-padding-horizontal - 1px;
width: @font-size-sm;
height: @font-size-sm;
margin-top: -@font-size-sm / 2;
color: @disabled-color;
font-size: @font-size-sm;
line-height: 1;
transform-origin: 50% 50%;
text-align: center;
pointer-events: none;
& &-icon svg {
.@{iconfont-css-prefix} {
vertical-align: top;
transition: transform 0.3s;
> svg {
vertical-align: top;
}
&:not(.@{select-prefix-cls}-suffix) {
pointer-events: auto;
}
}
.@{select-prefix-cls}-disabled & {
cursor: not-allowed;
}
}
&-selection {
display: block;
box-sizing: border-box;
background-color: @select-background;
border: @border-width-base @border-style-base @select-border-color;
// strange align fix for chrome but works
// https://gw.alipayobjects.com/zos/rmsportal/VFTfKXJuogBAXcvfAUWJ.gif
border-top-width: @border-width-base + 0.02px;
border-radius: @border-radius-base;
outline: none;
transition: all 0.3s @ease-in-out;
user-select: none;
// ========================== Clear ==========================
&-clear {
position: absolute;
top: 50%;
right: @control-padding-horizontal - 1px;
z-index: 1;
display: inline-block;
width: @font-size-sm;
height: @font-size-sm;
margin-top: -@font-size-sm / 2;
color: @disabled-color;
font-size: @font-size-sm;
font-style: normal;
line-height: 1;
text-align: center;
text-transform: none;
background: @select-clear-background;
cursor: pointer;
opacity: 0;
transition: color 0.3s ease, opacity 0.15s ease;
text-rendering: auto;
&::before {
display: block;
}
&:hover {
.hover;
color: @text-color-secondary;
}
.@{select-prefix-cls}-focused &,
&:focus,
&:active {
.active;
}
&__clear {
.selection__clear();
}
&:hover &__clear {
.@{select-prefix-cls}:hover & {
opacity: 1;
}
&-selected-value {
float: left;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
&-no-arrow &-selection-selected-value {
padding-right: 0;
}
// ========================== Popup ==========================
&-dropdown {
.reset-component;
position: absolute;
top: -9999px;
left: -9999px;
z-index: @zindex-dropdown;
box-sizing: border-box;
padding: @select-dropdown-edge-child-vertical-padding 0;
overflow: hidden;
font-size: @font-size-base;
// Fix select render lag of long text in chrome
// https://github.com/ant-design/ant-design/issues/11456
// https://github.com/ant-design/ant-design/issues/11843
font-variant: initial;
background-color: @select-dropdown-bg;
border-radius: @border-radius-base;
outline: none;
box-shadow: @box-shadow-base;
&-disabled {
color: @disabled-color;
}
&-disabled &-selection {
background: @input-disabled-bg;
cursor: not-allowed;
&:hover,
&:focus,
&:active {
border-color: @select-border-color;
box-shadow: none;
&.slide-up-enter.slide-up-enter-active&-placement-bottomLeft,
&.slide-up-appear.slide-up-appear-active&-placement-bottomLeft {
animation-name: antSlideUpIn;
}
&__clear {
display: none;
visibility: hidden;
pointer-events: none;
&.slide-up-enter.slide-up-enter-active&-placement-topLeft,
&.slide-up-appear.slide-up-appear-active&-placement-topLeft {
animation-name: antSlideDownIn;
}
}
&-disabled &-selection--multiple &-selection__choice {
padding-right: 10px;
color: fade(@black, 33%);
background: @background-color-base;
&__remove {
&.slide-up-leave.slide-up-leave-active&-placement-bottomLeft {
animation-name: antSlideUpOut;
}
&.slide-up-leave.slide-up-leave-active&-placement-topLeft {
animation-name: antSlideDownOut;
}
&-hidden {
display: none;
}
}
&-selection--single {
position: relative;
height: @input-height-base;
cursor: pointer;
.@{select-prefix-cls}-selection__rendered {
margin-right: 24px;
}
}
&-no-arrow {
.@{select-prefix-cls}-selection__rendered {
margin-right: @control-padding-horizontal - 1px;
}
}
&-selection__rendered {
position: relative;
display: block;
margin-right: @control-padding-horizontal - 1px;
margin-left: @control-padding-horizontal - 1px;
line-height: @input-height-base - 2px;
// https://github.com/ant-design/ant-design/issues/3481#issuecomment-254721026
&::after {
display: inline-block;
width: 0;
visibility: hidden;
content: '.';
pointer-events: none;
}
}
&-lg {
font-size: @font-size-lg;
.@{select-prefix-cls}-selection--single {
height: @input-height-lg;
}
.@{select-prefix-cls}-selection__rendered {
line-height: @input-height-lg - 2px;
}
.@{select-prefix-cls}-selection--multiple {
min-height: @input-height-lg;
.@{select-prefix-cls}-selection__rendered {
li {
height: @input-height-lg - 8px;
line-height: @input-height-lg - 8px;
}
}
.@{select-prefix-cls}-selection__clear,
.@{select-prefix-cls}-arrow {
top: @input-height-lg / 2;
}
}
}
&-sm {
.@{select-prefix-cls}-selection--single {
height: @input-height-sm;
}
.@{select-prefix-cls}-selection__rendered {
margin-left: @control-padding-horizontal-sm - 1px;
line-height: @input-height-sm - 2px;
}
.@{select-prefix-cls}-selection--multiple {
min-height: @input-height-sm;
.@{select-prefix-cls}-selection__rendered {
li {
height: @input-height-sm - 8px;
line-height: @input-height-sm - 10px;
}
}
.@{select-prefix-cls}-selection__clear,
.@{select-prefix-cls}-arrow {
top: @input-height-sm / 2;
}
}
.@{select-prefix-cls}-selection__clear,
.@{select-prefix-cls}-arrow {
right: @control-padding-horizontal-sm;
}
}
&-disabled &-selection__choice__remove {
color: @disabled-color;
cursor: default;
&:hover {
&-empty {
color: @disabled-color;
}
}
&-search__field__wrap {
// ========================= Options =========================
.item() {
position: relative;
display: inline-block;
display: block;
min-height: @select-dropdown-height;
padding: @select-dropdown-vertical-padding @control-padding-horizontal;
color: @text-color;
font-weight: normal;
font-size: @select-dropdown-font-size;
line-height: @select-dropdown-line-height;
}
&-selection__placeholder,
&-search__field__placeholder {
// for TreeSelect compatibility
position: absolute;
top: 50%;
right: 9px;
left: 0;
max-width: 100%;
height: 20px;
margin-top: -10px;
overflow: hidden;
color: @input-placeholder-color;
line-height: 20px;
white-space: nowrap;
text-align: left;
text-overflow: ellipsis;
&-item-empty {
.item();
color: @disabled-color;
}
&-search__field__placeholder {
left: @control-padding-horizontal;
}
&-item {
.item();
&-search__field__mirror {
position: absolute;
top: 0;
left: 0;
white-space: pre;
opacity: 0;
pointer-events: none;
}
cursor: pointer;
transition: background 0.3s ease;
&-search--inline {
position: absolute;
width: 100%;
height: 100%;
.@{select-prefix-cls}-search__field__wrap {
width: 100%;
height: 100%;
}
.@{select-prefix-cls}-search__field {
width: 100%;
height: 100%;
font-size: 100%;
line-height: 1;
background: transparent;
border-width: 0;
border-radius: @border-radius-base;
outline: 0;
}
> i {
float: right;
}
}
&-selection--multiple {
min-height: @input-height-base;
padding-bottom: 3px;
cursor: text;
.clearfix;
.@{select-prefix-cls}-search--inline {
position: static;
float: left;
width: auto;
max-width: 100%;
padding: 0;
.@{select-prefix-cls}-search__field {
width: 0.75em;
max-width: 100%;
padding: 1px;
}
}
.@{select-prefix-cls}-selection__rendered {
height: auto;
margin-bottom: -3px;
margin-left: 5px;
}
.@{select-prefix-cls}-selection__placeholder {
margin-left: 6px;
}
> ul > li,
.@{select-prefix-cls}-selection__rendered > ul > li {
height: @input-height-base - 8px;
// for tree-select
margin-top: 3px;
line-height: @input-height-base - 8px - 2px;
}
.@{select-prefix-cls}-selection__choice {
position: relative;
float: left;
max-width: 99%;
margin-right: 4px;
padding: 0 20px 0 10px;
overflow: hidden;
color: @tag-default-color;
background-color: @tag-default-bg;
border: 1px solid @border-color-split;
border-radius: @border-radius-sm;
// =========== Group ============
&-group {
color: @text-color-secondary;
font-size: @font-size-sm;
cursor: default;
transition: padding 0.3s @ease-in-out;
&__disabled {
padding: 0 10px;
}
}
.@{select-prefix-cls}-selection__choice__content {
display: inline-block;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
transition: margin 0.3s @ease-in-out;
}
// =========== Option ===========
&-option {
display: flex;
.@{select-prefix-cls}-selection__choice__remove {
.iconfont-mixin();
position: absolute;
right: 4px;
display: inline-block;
color: @text-color-secondary;
font-weight: bold;
font-size: @font-size-sm;
line-height: inherit;
cursor: pointer;
transition: all 0.3s;
.iconfont-size-under-12px(10px);
&:hover {
color: @icon-color-hover;
}
}
.@{select-prefix-cls}-selection__clear,
.@{select-prefix-cls}-arrow {
top: @input-height-base / 2;
}
}
&-allow-clear &-selection--multiple &-selection__rendered,
&-show-arrow &-selection--multiple &-selection__rendered {
margin-right: 20px; // In case that clear button will overlap content
}
&-open {
.@{select-prefix-cls}-arrow {
&-icon svg {
transform: rotate(180deg);
}
}
.@{select-prefix-cls}-selection {
.active();
}
}
&-combobox {
.@{select-prefix-cls}-arrow {
display: none;
}
.@{select-prefix-cls}-search--inline {
float: none;
width: 100%;
height: 100%;
}
.@{select-prefix-cls}-search__field__wrap {
width: 100%;
height: 100%;
}
.@{select-prefix-cls}-search__field {
position: relative;
z-index: 1;
width: 100%;
height: 100%;
box-shadow: none;
transition: all 0.3s @ease-in-out, height 0s;
}
}
&-combobox&-allow-clear &-selection:hover &-selection__rendered,
&-combobox&-show-arrow &-selection:hover &-selection__rendered {
margin-right: 20px; // In case that clear button will overlap content
}
}
.@{select-prefix-cls}-dropdown {
.reset-component;
position: absolute;
top: -9999px;
left: -9999px;
z-index: @zindex-dropdown;
box-sizing: border-box;
font-size: @font-size-base;
// Fix select render lag of long text in chrome
// https://github.com/ant-design/ant-design/issues/11456
// https://github.com/ant-design/ant-design/issues/11843
font-variant: initial;
background-color: @select-dropdown-bg;
border-radius: @border-radius-base;
outline: none;
box-shadow: @box-shadow-base;
&.slide-up-enter.slide-up-enter-active&-placement-bottomLeft,
&.slide-up-appear.slide-up-appear-active&-placement-bottomLeft {
animation-name: antSlideUpIn;
}
&.slide-up-enter.slide-up-enter-active&-placement-topLeft,
&.slide-up-appear.slide-up-appear-active&-placement-topLeft {
animation-name: antSlideDownIn;
}
&.slide-up-leave.slide-up-leave-active&-placement-bottomLeft {
animation-name: antSlideUpOut;
}
&.slide-up-leave.slide-up-leave-active&-placement-topLeft {
animation-name: antSlideDownOut;
}
&-hidden {
display: none;
}
&-menu {
max-height: 250px;
margin-bottom: 0;
padding: @select-dropdown-edge-child-vertical-padding 0; //Change
padding-left: 0; // Override default ul/ol
overflow: auto;
list-style: none;
outline: none;
&-item-group-list {
margin: 0;
padding: 0;
> .@{select-prefix-cls}-dropdown-menu-item {
padding-left: 20px;
}
}
&-item-group-title {
height: 32px;
padding: 0 @control-padding-horizontal;
color: @text-color-secondary;
font-size: @font-size-sm;
line-height: 32px;
}
&-item-group-list &-item:first-child:not(:last-child),
&-item-group:not(:last-child) &-item-group-list &-item:last-child {
border-radius: 0;
}
&-item {
position: relative;
display: block;
padding: @select-dropdown-vertical-padding @control-padding-horizontal;
overflow: hidden;
color: @text-color;
font-weight: normal;
font-size: @select-dropdown-font-size;
line-height: @select-dropdown-line-height;
white-space: nowrap;
text-overflow: ellipsis;
cursor: pointer;
transition: background 0.3s ease;
&:hover:not(&-disabled) {
background-color: @item-hover-bg;
&-content {
flex: auto;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&:first-child {
& when (@select-dropdown-edge-child-vertical-padding = 0) {
border-radius: @border-radius-base @border-radius-base 0 0;
}
}
&:last-child {
& when (@select-dropdown-edge-child-vertical-padding = 0) {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
}
&-selected {
color: @select-item-selected-color;
font-weight: @select-item-selected-font-weight;
background-color: @select-item-selected-bg;
}
&-disabled {
color: @disabled-color;
cursor: not-allowed;
&:hover {
color: @disabled-color;
cursor: not-allowed;
}
&-state {
flex: none;
}
&-active:not(&-disabled) {
background-color: @select-item-active-bg;
}
&-divider {
height: 1px;
margin: 1px 0;
overflow: hidden;
line-height: 0;
background-color: @border-color-split;
&-selected:not(&-disabled) {
color: @select-item-selected-color;
font-weight: @select-item-selected-font-weight;
background-color: @select-item-selected-bg;
.@{select-prefix-cls}-item-option-state {
color: @primary-color;
}
}
&-disabled {
color: @disabled-color;
cursor: not-allowed;
}
&-grouped {
padding-left: @control-padding-horizontal * 2;
}
}
}
&&--multiple {
.@{select-prefix-cls}-dropdown-menu-item {
padding-right: @control-padding-horizontal + 20;
& .@{select-prefix-cls}-selected-icon {
position: absolute;
top: 50%;
right: @control-padding-horizontal;
color: transparent;
font-weight: bold;
font-size: 12px;
text-shadow: 0 0.1px 0, 0.1px 0 0, 0 -0.1px 0, -0.1px 0;
transform: translateY(-50%);
transition: all 0.2s;
}
&:hover .@{select-prefix-cls}-selected-icon {
color: fade(@black, 87%);
}
&-disabled .@{select-prefix-cls}-selected-icon {
display: none;
}
&-selected .@{select-prefix-cls}-selected-icon,
&-selected:hover .@{select-prefix-cls}-selected-icon {
display: inline-block;
color: @primary-color;
}
}
// ============================================================
// == Size ==
// ============================================================
&-lg {
font-size: @font-size-lg;
}
// Patch for popup adjust
// https://github.com/ant-design/ant-design/issues/14422
&--empty&--multiple &-menu-item {
padding-right: @control-padding-horizontal;
}
&-container-open,
&-open {
.@{select-prefix-cls}-dropdown {
display: block;
}
// no border style
&-borderless &-selector {
background-color: transparent !important;
border-color: transparent !important;
box-shadow: none !important;
}
}
@import './rtl';

View File

@ -0,0 +1,206 @@
@import './index';
@select-multiple-item-border-width: 1px;
@select-multiple-padding: max(
@input-padding-vertical-base - @select-multiple-item-border-width -
@select-multiple-item-spacing-half,
0
);
/**
* Do not merge `height` & `line-height` under style with `selection` & `search`,
* since chrome may update to redesign with its align logic.
*/
.@{select-prefix-cls} {
&-multiple {
// ========================= Selector =========================
.@{select-prefix-cls}-selector {
.select-selector();
.select-search-input-without-border();
display: flex;
flex-wrap: wrap;
align-items: center;
// Multiple is little different that horizontal is follow the vertical
padding: @select-multiple-padding @input-padding-vertical-base;
.@{select-prefix-cls}-show-search& {
cursor: text;
}
.@{select-prefix-cls}-disabled& {
background: @select-multiple-disabled-background;
cursor: not-allowed;
}
&::after {
display: inline-block;
width: 0;
margin: @select-multiple-item-spacing-half 0;
line-height: @select-multiple-item-height;
content: '\a0';
}
}
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selector,
&.@{select-prefix-cls}-allow-clear .@{select-prefix-cls}-selector {
padding-right: @font-size-sm + @control-padding-horizontal;
}
// ======================== Selections ========================
.@{select-prefix-cls}-selection-item {
position: relative;
display: flex;
flex: none;
box-sizing: border-box;
max-width: 100%;
height: @select-multiple-item-height;
margin-top: @select-multiple-item-spacing-half;
margin-right: @input-padding-vertical-base;
margin-bottom: @select-multiple-item-spacing-half;
padding: 0 (@padding-xs / 2) 0 @padding-xs;
line-height: @select-multiple-item-height - @select-multiple-item-border-width * 2;
background: @select-selection-item-bg;
border: 1px solid @select-selection-item-border-color;
border-radius: @border-radius-base;
cursor: default;
transition: font-size 0.3s, line-height 0.3s, height 0.3s;
user-select: none;
.@{select-prefix-cls}-disabled& {
color: @select-multiple-item-disabled-color;
border-color: @select-multiple-item-disabled-border-color;
cursor: not-allowed;
}
// It's ok not to do this, but 24px makes bottom narrow in view should adjust
&-content {
display: inline-block;
margin-right: @padding-xs / 2;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&-remove {
.iconfont-mixin();
display: inline-block;
color: @text-color-secondary;
font-weight: bold;
font-size: @font-size-sm;
line-height: inherit;
cursor: pointer;
.iconfont-size-under-12px(10px);
> .@{iconfont-css-prefix} {
vertical-align: -0.2em;
}
&:hover {
color: @icon-color-hover;
}
}
}
// ========================== Input ==========================
.@{select-prefix-cls}-selection-search {
position: relative;
margin-left: @select-multiple-padding / 2;
&-input,
&-mirror {
font-family: @font-family;
line-height: @line-height-base;
transition: all 0.3s;
}
&-input {
width: 100%;
min-width: 4.1px; // fix search cursor missing
}
&-mirror {
position: absolute;
top: 0;
left: 0;
z-index: 999;
white-space: nowrap;
visibility: hidden;
}
// https://github.com/ant-design/ant-design/issues/22906
&:first-child .@{select-prefix-cls}-selection-search-input {
margin-left: 6.5px;
}
}
// ======================= Placeholder =======================
.@{select-prefix-cls}-selection-placeholder {
position: absolute;
top: 50%;
right: @input-padding-horizontal;
left: @input-padding-horizontal;
transform: translateY(-50%);
transition: all 0.3s;
}
// ============================================================
// == Size ==
// ============================================================
.select-size(@suffix, @input-height) {
@merged-cls: ~'@{select-prefix-cls}-@{suffix}';
&.@{merged-cls} {
@select-selection-height: @input-height - @input-padding-vertical-base * 2;
@select-height-without-border: @input-height - @border-width-base * 2;
.@{select-prefix-cls}-selector::after {
line-height: @select-selection-height;
}
.@{select-prefix-cls}-selection-item {
height: @select-selection-height;
line-height: @select-selection-height - @border-width-base * 2;
}
.@{select-prefix-cls}-selection-search {
height: @select-selection-height + @select-multiple-padding;
line-height: @select-selection-height + @select-multiple-padding;
&-input,
&-mirror {
height: @select-selection-height;
line-height: @select-selection-height - @border-width-base * 2;
}
}
}
}
.select-size('lg', @input-height-lg);
.select-size('sm', @input-height-sm);
// Size small need additional set padding
&.@{select-prefix-cls}-sm {
.@{select-prefix-cls}-selection-placeholder {
left: @input-padding-horizontal-sm;
}
// https://github.com/ant-design/ant-design/issues/22906
.@{select-prefix-cls}-selection-search:first-child
.@{select-prefix-cls}-selection-search-input {
margin-left: 3px;
}
}
&.@{select-prefix-cls}-lg {
.@{select-prefix-cls}-selection-item {
height: @select-multiple-item-height-lg;
line-height: @select-multiple-item-height-lg;
}
}
}
&-disabled .@{select-prefix-cls}-selection-item-remove {
display: none;
}
}

View File

@ -0,0 +1,188 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
@select-prefix-cls: ~'@{ant-prefix}-select';
.@{select-prefix-cls} {
&-rtl {
direction: rtl;
}
// ========================== Arrow ==========================
&-arrow {
.@{select-prefix-cls}-rtl & {
right: initial;
left: @control-padding-horizontal - 1px;
}
}
// ========================== Clear ==========================
&-clear {
.@{select-prefix-cls}-rtl & {
right: initial;
left: @control-padding-horizontal - 1px;
}
}
// ========================== Popup ==========================
&-dropdown {
&-rtl {
direction: rtl;
}
}
// ========================= Options =========================
&-item {
&-option {
&-grouped {
.@{select-prefix-cls}-dropdown-rtl & {
padding-right: @control-padding-horizontal * 2;
padding-left: @control-padding-horizontal;
}
}
}
}
}
// multiple
@select-multiple-item-border-width: 1px;
@select-multiple-item-spacing-half: ceil(@input-padding-vertical-base / 2);
@select-multiple-padding: max(
@input-padding-vertical-base - @select-multiple-item-border-width -
@select-multiple-item-spacing-half,
0
);
.@{select-prefix-cls}-multiple {
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selector,
&.@{select-prefix-cls}-allow-clear .@{select-prefix-cls}-selector {
.@{select-prefix-cls}-rtl& {
padding-right: @input-padding-vertical-base;
padding-left: @font-size-sm + @control-padding-horizontal;
}
}
// ======================== Selections ========================
.@{select-prefix-cls}-selection-item {
.@{select-prefix-cls}-rtl& {
margin-right: 0;
margin-left: @input-padding-vertical-base;
padding: 0 @padding-xs 0 (@padding-xs / 2);
text-align: right;
}
// It's ok not to do this, but 24px makes bottom narrow in view should adjust
&-content {
.@{select-prefix-cls}-rtl& {
margin-right: 0;
margin-left: @padding-xs / 2;
text-align: right;
}
}
}
// ========================== Input ==========================
.@{select-prefix-cls}-selection-search {
.@{select-prefix-cls}-rtl& {
margin-right: @select-multiple-padding / 2;
margin-left: @input-padding-vertical-base;
}
&-mirror {
.@{select-prefix-cls}-rtl& {
right: 0;
left: auto;
}
}
}
// ======================= Placeholder =======================
.@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
right: @input-padding-horizontal;
left: auto;
}
}
// ============================================================
// == Size ==
// ============================================================
// Size small need additional set padding
&.@{select-prefix-cls}-sm {
.@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
right: @input-padding-horizontal-sm;
}
}
}
}
// single
@selection-item-padding: ceil(@font-size-base * 1.25);
.@{select-prefix-cls}-single {
// ========================= Selector =========================
.@{select-prefix-cls}-selector {
.@{select-prefix-cls}-selection-item,
.@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
right: 0;
left: 9px;
text-align: right;
}
}
}
// With arrow should provides `padding-right` to show the arrow
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-search {
.@{select-prefix-cls}-rtl& {
right: @input-padding-horizontal-base;
left: @input-padding-horizontal-base + @font-size-base;
}
}
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-item,
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
padding-right: 0;
padding-left: @selection-item-padding;
}
}
// ========================== Input ==========================
// We only change the style of non-customize input which is only support by `combobox` mode.
// Not customize
&:not(.@{select-prefix-cls}-customize-input) {
.@{select-prefix-cls}-selector {
.@{select-prefix-cls}-rtl& {
padding: 0 @input-padding-horizontal-base;
}
}
}
// ============================================================
// == Size ==
// ============================================================
// Size small need additional set padding
&.@{select-prefix-cls}-sm {
&:not(.@{select-prefix-cls}-customize-input) {
// With arrow should provides `padding-right` to show the arrow
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-search {
.@{select-prefix-cls}-rtl& {
right: 0;
}
}
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-item,
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
padding-right: 0;
padding-left: @font-size-base * 1.5;
}
}
}
}
}

View File

@ -0,0 +1,180 @@
@import './index';
@selection-item-padding: ceil(@font-size-base * 1.25);
.@{select-prefix-cls}-single {
// ========================= Selector =========================
.@{select-prefix-cls}-selector {
display: flex;
.@{select-prefix-cls}-selection-search {
position: absolute;
top: 0;
right: @input-padding-horizontal-base;
bottom: 0;
left: @input-padding-horizontal-base;
&-input {
width: 100%;
}
}
.@{select-prefix-cls}-selection-item,
.@{select-prefix-cls}-selection-placeholder {
padding: 0;
line-height: @select-height-without-border;
transition: all 0.3s;
// Firefox inline-block position calculation is not same as Chrome & Safari. Patch this:
@supports (-moz-appearance: meterbar) {
& {
line-height: @select-height-without-border;
}
}
}
.@{select-prefix-cls}-selection-item {
position: relative;
user-select: none;
}
.@{select-prefix-cls}-selection-placeholder {
pointer-events: none;
}
// For common baseline align
&::after,
// For '' value baseline align
.@{select-prefix-cls}-selection-item::after,
// For undefined value baseline align
.@{select-prefix-cls}-selection-placeholder::after {
display: inline-block;
width: 0;
visibility: hidden;
content: '\a0';
}
}
// With arrow should provides `padding-right` to show the arrow
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-search {
right: @input-padding-horizontal-base + @font-size-base;
}
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-item,
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-placeholder {
padding-right: @selection-item-padding;
}
// Opacity selection if open
&.@{select-prefix-cls}-open .@{select-prefix-cls}-selection-item {
color: @input-placeholder-color;
}
// ========================== Input ==========================
// We only change the style of non-customize input which is only support by `combobox` mode.
// Not customize
&:not(.@{select-prefix-cls}-customize-input) {
.@{select-prefix-cls}-selector {
.select-selector();
.select-search-input-without-border();
width: 100%;
height: @input-height-base;
padding: 0 @input-padding-horizontal-base;
.@{select-prefix-cls}-selection-search-input {
height: @select-height-without-border;
}
&::after {
line-height: @select-height-without-border;
}
}
}
&.@{select-prefix-cls}-customize-input {
.@{select-prefix-cls}-selector {
&::after {
display: none;
}
.@{select-prefix-cls}-selection-search {
position: static;
width: 100%;
}
.@{select-prefix-cls}-selection-placeholder {
position: absolute;
right: 0;
left: 0;
padding: 0 @input-padding-horizontal-base;
&::after {
display: none;
}
}
}
}
// ============================================================
// == Size ==
// ============================================================
.select-size(@suffix, @input-height) {
@merged-cls: ~'@{select-prefix-cls}-@{suffix}';
&.@{merged-cls}:not(.@{select-prefix-cls}-customize-input) {
.@{select-prefix-cls}-selector {
height: @input-height;
&::after,
.@{select-prefix-cls}-selection-item,
.@{select-prefix-cls}-selection-placeholder {
line-height: @input-height - 2 * @border-width-base;
}
}
// Not customize
&:not(.@{select-prefix-cls}-customize-input) {
.@{select-prefix-cls}-selection-search-input {
height: @input-height - 2 * @border-width-base;
}
}
}
}
.select-size('lg', @select-single-item-height-lg);
.select-size('sm', @input-height-sm);
// Size small need additional set padding
&.@{select-prefix-cls}-sm {
&:not(.@{select-prefix-cls}-customize-input) {
.@{select-prefix-cls}-selection-search {
right: @input-padding-horizontal-sm;
left: @input-padding-horizontal-sm;
}
.@{select-prefix-cls}-selector {
padding: 0 @input-padding-horizontal-sm;
}
// With arrow should provides `padding-right` to show the arrow
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-search {
right: @input-padding-horizontal-sm + @font-size-base * 1.5;
}
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-item,
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-placeholder {
padding-right: @font-size-base * 1.5;
}
}
}
&.@{select-prefix-cls}-lg {
&:not(.@{select-prefix-cls}-customize-input) {
.@{select-prefix-cls}-selector {
padding: 0 @input-padding-horizontal-lg;
}
}
}
}

View File

@ -339,13 +339,23 @@
@select-item-selected-color: @text-color;
@select-item-selected-font-weight: 600;
@select-dropdown-bg: @component-background;
@select-item-selected-bg: @primary-1;
@select-item-active-bg: @item-hover-bg;
@select-dropdown-vertical-padding: @dropdown-vertical-padding;
@select-dropdown-edge-child-vertical-padding: @dropdown-edge-child-vertical-padding;
@select-dropdown-font-size: @dropdown-font-size;
@select-dropdown-line-height: @dropdown-line-height;
@select-item-selected-bg: @background-color-light;
@select-item-active-bg: @item-active-bg;
@select-dropdown-height: 32px;
@select-background: @component-background;
@select-clear-background: @select-background;
@select-selection-item-bg: @background-color-base;
@select-selection-item-border-color: @border-color-split;
@select-single-item-height-lg: 40px;
@select-multiple-item-height: @input-height-base - @input-padding-vertical-base * 2; // Normal 24px
@select-multiple-item-height-lg: 32px;
@select-multiple-item-spacing-half: ceil(@input-padding-vertical-base / 2);
@select-multiple-disabled-background: @input-disabled-bg;
@select-multiple-item-disabled-color: #bfbfbf;
@select-multiple-item-disabled-border-color: @select-border-color;
// Cascader
// ----

View File

@ -23,7 +23,7 @@ const TreeSelect = {
name: 'ATreeSelect',
props: initDefaultProps(TreeSelectProps(), {
transitionName: 'slide-up',
choiceTransitionName: 'zoom',
choiceTransitionName: '',
showSearch: false,
}),
setup() {

View File

@ -10,7 +10,7 @@ export const TreeData = PropTypes.shape({
}).loose;
export const TreeSelectProps = () => ({
...SelectProps,
...SelectProps(),
autofocus: PropTypes.looseBool,
dropdownStyle: PropTypes.object,
filterTreeNode: withUndefined(PropTypes.oneOfType([Function, Boolean])),

View File

@ -55,7 +55,7 @@ const props = {
accessibilityIndex: PropTypes.number,
tabindex: PropTypes.number,
removeIcon: PropTypes.looseBool,
removeIcon: PropTypes.VNodeChild,
choiceTransitionName: PropTypes.string,
maxTagCount: PropTypes.number,
@ -158,9 +158,11 @@ const SelectSelector = defineComponent<SelectorProps>({
: maxTagPlaceholder,
});
}
const transitionProps = getTransitionGroupProps(choiceTransitionName, {
appear: motionAppear,
});
const transitionProps = choiceTransitionName
? getTransitionGroupProps(choiceTransitionName, {
appear: motionAppear,
})
: { css: false };
selectionNode.value = (
<TransitionGroup {...transitionProps}>
{...displayValues.map(
@ -237,7 +239,6 @@ const SelectSelector = defineComponent<SelectorProps>({
onInputMouseDown,
onInputCompositionStart,
onInputCompositionEnd,
choiceTransitionName,
} = props;
return (
<>

View File

@ -49,9 +49,11 @@ import {
VNode,
VNodeChild,
watch,
watchEffect,
} from 'vue';
import createRef from '../_util/createRef';
import PropTypes from '../_util/vue-types';
import PropTypes, { withUndefined } from '../_util/vue-types';
import initDefaultProps from '../_util/props-util/initDefaultProps';
const DEFAULT_OMIT_PROPS = [
'children',
@ -65,7 +67,7 @@ const DEFAULT_OMIT_PROPS = [
'onInputKeyDown',
];
export const props = {
export const BaseProps = () => ({
prefixCls: PropTypes.string,
id: PropTypes.string,
class: PropTypes.string,
@ -84,7 +86,7 @@ export const props = {
// Search
inputValue: PropTypes.string,
searchValue: PropTypes.string,
optionFilterProp: PropTypes.string.def('value'),
optionFilterProp: PropTypes.string,
/**
* In Select, `false` means do nothing.
* In TreeSelect, `false` will highlight match item.
@ -98,20 +100,20 @@ export const props = {
// Icons
allowClear: PropTypes.looseBool,
clearIcon: PropTypes.any,
clearIcon: PropTypes.VNodeChild,
showArrow: PropTypes.looseBool,
inputIcon: PropTypes.any,
removeIcon: PropTypes.any,
menuItemSelectedIcon: PropTypes.func,
inputIcon: PropTypes.VNodeChild,
removeIcon: PropTypes.VNodeChild,
menuItemSelectedIcon: PropTypes.VNodeChild,
// Dropdown
open: PropTypes.looseBool,
defaultOpen: PropTypes.looseBool,
listHeight: PropTypes.number.def(200),
listItemHeight: PropTypes.number.def(20),
listHeight: PropTypes.number,
listItemHeight: PropTypes.number,
dropdownStyle: PropTypes.object,
dropdownClassName: PropTypes.string,
dropdownMatchSelectWidth: PropTypes.oneOfType([Boolean, Number]).def(true),
dropdownMatchSelectWidth: withUndefined(PropTypes.oneOfType([Boolean, Number])),
virtual: PropTypes.looseBool,
dropdownRender: PropTypes.func,
dropdownAlign: PropTypes.any,
@ -125,8 +127,8 @@ export const props = {
loading: PropTypes.looseBool,
autofocus: PropTypes.looseBool,
defaultActiveFirstOption: PropTypes.looseBool,
notFoundContent: PropTypes.any.def('Not Found'),
placeholder: PropTypes.any,
notFoundContent: PropTypes.VNodeChild,
placeholder: PropTypes.VNodeChild,
backfill: PropTypes.looseBool,
getInputElement: PropTypes.func,
optionLabelProp: PropTypes.string,
@ -135,7 +137,7 @@ export const props = {
maxTagPlaceholder: PropTypes.any,
tokenSeparators: PropTypes.array,
tagRender: PropTypes.func,
showAction: PropTypes.array.def([]),
showAction: PropTypes.array,
tabindex: PropTypes.number,
// Events
@ -162,8 +164,8 @@ export const props = {
* Only used in current version for internal event process.
* Do not use in production environment.
*/
internalProps: PropTypes.object.def({}),
}
internalProps: PropTypes.object,
});
export interface SelectProps<OptionsType extends object[], ValueType> {
prefixCls?: string;
@ -336,7 +338,9 @@ export default function generateSelector<
const Select = defineComponent<SelectProps<OptionsType, ValueType>>({
name: 'Select',
setup(props: SelectProps<OptionsType, ValueType>) {
const useInternalProps = computed(() => props.internalProps.mark === INTERNAL_PROPS_MARK);
const useInternalProps = computed(
() => props.internalProps && props.internalProps.mark === INTERNAL_PROPS_MARK,
);
const containerRef = ref(null);
const triggerRef = ref(null);
@ -526,8 +530,8 @@ export default function generateSelector<
const triggerSelect = (newValue: RawValueType, isSelect: boolean, source: SelectSource) => {
const newValueOption = getValueOption([newValue]);
const outOption = findValueOption([newValue], newValueOption)[0];
if (!props.internalProps.skipTriggerSelect) {
const { internalProps = {} } = props;
if (!internalProps.skipTriggerSelect) {
// Skip trigger `onSelect` or `onDeselect` if configured
const selectValue = (mergedLabelInValue.value
? getLabeledValue(newValue, {
@ -547,10 +551,10 @@ export default function generateSelector<
// Trigger internal event
if (useInternalProps.value) {
if (isSelect && props.internalProps.onRawSelect) {
props.internalProps.onRawSelect(newValue, outOption, source);
} else if (!isSelect && props.internalProps.onRawDeselect) {
props.internalProps.onRawDeselect(newValue, outOption, source);
if (isSelect && internalProps.onRawSelect) {
internalProps.onRawSelect(newValue, outOption, source);
} else if (!isSelect && internalProps.onRawDeselect) {
internalProps.onRawDeselect(newValue, outOption, source);
}
}
};
@ -561,7 +565,11 @@ export default function generateSelector<
prevValueOptions.value = val;
};
const triggerChange = (newRawValues: RawValueType[]) => {
if (useInternalProps.value && props.internalProps.skipTriggerChange) {
if (
useInternalProps.value &&
props.internalProps &&
props.internalProps.skipTriggerChange
) {
return;
}
const newRawValuesOptions = getValueOption(newRawValues);
@ -656,8 +664,10 @@ export default function generateSelector<
const innerOpen = ref(undefined);
const mergedOpen = ref(undefined);
const setInnerOpen = (val: boolean) => {
innerOpen.value = val;
mergedOpen.value = innerOpen.value;
setTimeout(() => {
innerOpen.value = val;
mergedOpen.value = innerOpen.value;
});
};
watch(
computed(() => [props.defaultOpen, props.open]),
@ -671,21 +681,16 @@ export default function generateSelector<
const emptyListContent = computed(
() => !props.notFoundContent && !displayOptions.value.length,
);
watch(
computed(
() =>
props.disabled ||
(emptyListContent.value && innerOpen.value && props.mode === 'combobox'),
),
val => {
if (val) {
mergedOpen.value = false;
} else {
mergedOpen.value = innerOpen.value;
}
},
{ immediate: true },
);
watchEffect(() => {
mergedOpen.value = innerOpen.value;
if (
props.disabled ||
(emptyListContent.value && mergedOpen.value && props.mode === 'combobox')
) {
mergedOpen.value = false;
}
});
const triggerOpen = computed(() => (emptyListContent.value ? false : mergedOpen.value));
@ -706,6 +711,7 @@ export default function generateSelector<
const triggerSearch = (searchText: string, fromTyping: boolean, isCompositing: boolean) => {
let ret = true;
let newSearchText = searchText;
const preSearchValue = mergedSearchValue.value;
setActiveValue(null);
// Check if match the `tokenSeparators`
@ -750,7 +756,7 @@ export default function generateSelector<
setInnerSearchValue(newSearchText);
if (props.onSearch && mergedSearchValue.value !== newSearchText) {
if (props.onSearch && preSearchValue !== newSearchText) {
props.onSearch(newSearchText);
}
@ -806,7 +812,6 @@ export default function generateSelector<
const onInternalKeyDown = (event: KeyboardEvent) => {
const clearLock = getClearLock();
const { which } = event;
// We only manage open state here, close logic should handle by list component
if (!mergedOpen.value && which === KeyCode.ENTER) {
onToggleOpen(true);
@ -863,7 +868,7 @@ export default function generateSelector<
}
// `showAction` should handle `focus` if set
if (props.showAction.includes('focus')) {
if (props.showAction && props.showAction.includes('focus')) {
onToggleOpen(true);
}
}
@ -1321,6 +1326,6 @@ export default function generateSelector<
},
});
Select.inheritAttrs = false;
Select.props = props;
Select.props = initDefaultProps(BaseProps(), {});
return Select;
}

View File

@ -1,7 +1,11 @@
import Select, { ExportedSelectProps as SelectProps } from './Select';
import Select from './Select';
import Option from './Option';
import OptGroup from './OptGroup';
import { props } from './generate';
export { Option, OptGroup, SelectProps, props };
import { BaseProps } from './generate';
// eslint-disable-next-line prettier/prettier
export type { ExportedSelectProps as SelectProps } from './Select';
export { Option, OptGroup, BaseProps };
export default Select;

View File

@ -13,7 +13,6 @@
"noUnusedParameters": true,
"noUnusedLocals": true,
"noImplicitAny": false,
"module": "esnext",
"target": "es6",
"lib": ["dom", "es2017"],
"skipLibCheck": true,