From 46149b660bce9565aa5b1f60b3407c8169971971 Mon Sep 17 00:00:00 2001
From: tangjinzhou <415800467@qq.com>
Date: Sat, 17 Oct 2020 22:19:52 +0800
Subject: [PATCH] feat: select auto-complete support virtual list
---
components/auto-complete/index.tsx | 50 +-
components/auto-complete/style/index.less | 82 +-
components/pagination/MiniSelect.jsx | 2 +-
components/select/index.tsx | 162 ++--
components/select/index1.tsx | 2 +-
components/select/style/index.less | 754 ++++++------------
.../select/style/{index.js => index.tsx} | 0
components/select/style/multiple.less | 206 +++++
components/select/style/rtl.less | 188 +++++
components/select/style/single.less | 180 +++++
components/style/themes/default.less | 16 +-
components/tree-select/index.jsx | 2 +-
components/tree-select/interface.jsx | 2 +-
.../vc-select2/Selector/MultipleSelector.tsx | 11 +-
components/vc-select2/generate.tsx | 93 ++-
components/vc-select2/index.ts | 10 +-
tsconfig.json | 1 -
17 files changed, 1005 insertions(+), 756 deletions(-)
rename components/select/style/{index.js => index.tsx} (100%)
create mode 100644 components/select/style/multiple.less
create mode 100644 components/select/style/rtl.less
create mode 100644 components/select/style/single.less
diff --git a/components/auto-complete/index.tsx b/components/auto-complete/index.tsx
index 08c2063b2..8b81626c3 100644
--- a/components/auto-complete/index.tsx
+++ b/components/auto-complete/index.tsx
@@ -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] : ;
- return (
-
- {element}
-
- );
+ return {element};
},
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 ;
+ return (
+
+ );
case 'object':
- return ;
+ return (
+
+ );
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 ;
+ return ;
},
});
diff --git a/components/auto-complete/style/index.less b/components/auto-complete/style/index.less
index 6187de2c7..043091876 100644
--- a/components/auto-complete/style/index.less
+++ b/components/auto-complete/style/index.less
@@ -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;
}
}
diff --git a/components/pagination/MiniSelect.jsx b/components/pagination/MiniSelect.jsx
index 80e63b66e..ec79f8981 100644
--- a/components/pagination/MiniSelect.jsx
+++ b/components/pagination/MiniSelect.jsx
@@ -4,7 +4,7 @@ import { getOptionProps, getSlot } from '../_util/props-util';
export default {
inheritAttrs: false,
props: {
- ...SelectProps,
+ ...SelectProps(),
},
Option: VcSelect.Option,
render() {
diff --git a/components/select/index.tsx b/components/select/index.tsx
index 84592ea11..12f5cbbf9 100644
--- a/components/select/index.tsx
+++ b/components/select/index.tsx
@@ -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 extends Omit, 'mode'>
}
export interface SelectPropsTypes
- extends Omit, 'inputIcon' | 'mode' | 'getInputElement' | 'backfill' | 'class' | 'style'> {
+ extends Omit<
+ InternalSelectProps,
+ 'inputIcon' | 'mode' | 'getInputElement' | 'backfill' | 'class' | 'style'
+ > {
mode?: 'multiple' | 'tags';
}
-export type SelectTypes = SelectPropsTypes
-export const SelectProps = {
- ...omit(props, ['inputIcon' ,'mode' ,'getInputElement' ,'backfill' ,'class' ,'style']),
+export type SelectTypes = SelectPropsTypes;
+export const SelectProps = () => ({
+ ...omit(BaseProps(), ['inputIcon', 'mode', 'getInputElement', 'backfill', 'class', 'style']),
value: {
- type: [Array, Object, String, Number] as PropType
+ type: [Array, Object, String, Number] as PropType,
},
defaultValue: {
- type: [Array, Object, String, Number] as PropType
+ type: [Array, Object, String, Number] as PropType,
},
+ 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',
});
-
- {slots?.default()}
-
- }
-})
+ return (
+
+ {slots?.default()}
+
+ );
+ },
+});
/* istanbul ignore next */
Select.install = function(app: App) {
app.component(Select.name, Select);
diff --git a/components/select/index1.tsx b/components/select/index1.tsx
index b7388283b..f72d52c21 100644
--- a/components/select/index1.tsx
+++ b/components/select/index1.tsx
@@ -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() {
diff --git a/components/select/style/index.less b/components/select/style/index.less
index 182b2a686..5bfef19f4 100644
--- a/components/select/style/index.less
+++ b/components/select/style/index.less
@@ -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';
diff --git a/components/select/style/index.js b/components/select/style/index.tsx
similarity index 100%
rename from components/select/style/index.js
rename to components/select/style/index.tsx
diff --git a/components/select/style/multiple.less b/components/select/style/multiple.less
new file mode 100644
index 000000000..548abdfe0
--- /dev/null
+++ b/components/select/style/multiple.less
@@ -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;
+ }
+}
diff --git a/components/select/style/rtl.less b/components/select/style/rtl.less
new file mode 100644
index 000000000..82e055e66
--- /dev/null
+++ b/components/select/style/rtl.less
@@ -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;
+ }
+ }
+ }
+ }
+}
diff --git a/components/select/style/single.less b/components/select/style/single.less
new file mode 100644
index 000000000..0eed6c96c
--- /dev/null
+++ b/components/select/style/single.less
@@ -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;
+ }
+ }
+ }
+}
diff --git a/components/style/themes/default.less b/components/style/themes/default.less
index ec1c82365..80bca6926 100644
--- a/components/style/themes/default.less
+++ b/components/style/themes/default.less
@@ -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
// ----
diff --git a/components/tree-select/index.jsx b/components/tree-select/index.jsx
index db6f2becd..d14c03010 100644
--- a/components/tree-select/index.jsx
+++ b/components/tree-select/index.jsx
@@ -23,7 +23,7 @@ const TreeSelect = {
name: 'ATreeSelect',
props: initDefaultProps(TreeSelectProps(), {
transitionName: 'slide-up',
- choiceTransitionName: 'zoom',
+ choiceTransitionName: '',
showSearch: false,
}),
setup() {
diff --git a/components/tree-select/interface.jsx b/components/tree-select/interface.jsx
index 2524ae37b..9c5f16bf0 100644
--- a/components/tree-select/interface.jsx
+++ b/components/tree-select/interface.jsx
@@ -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])),
diff --git a/components/vc-select2/Selector/MultipleSelector.tsx b/components/vc-select2/Selector/MultipleSelector.tsx
index 4856c4d4f..b97efcac5 100644
--- a/components/vc-select2/Selector/MultipleSelector.tsx
+++ b/components/vc-select2/Selector/MultipleSelector.tsx
@@ -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({
: maxTagPlaceholder,
});
}
- const transitionProps = getTransitionGroupProps(choiceTransitionName, {
- appear: motionAppear,
- });
+ const transitionProps = choiceTransitionName
+ ? getTransitionGroupProps(choiceTransitionName, {
+ appear: motionAppear,
+ })
+ : { css: false };
selectionNode.value = (
{...displayValues.map(
@@ -237,7 +239,6 @@ const SelectSelector = defineComponent({
onInputMouseDown,
onInputCompositionStart,
onInputCompositionEnd,
- choiceTransitionName,
} = props;
return (
<>
diff --git a/components/vc-select2/generate.tsx b/components/vc-select2/generate.tsx
index 230ec974a..105c8b2d1 100644
--- a/components/vc-select2/generate.tsx
+++ b/components/vc-select2/generate.tsx
@@ -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 {
prefixCls?: string;
@@ -336,7 +338,9 @@ export default function generateSelector<
const Select = defineComponent>({
name: 'Select',
setup(props: SelectProps) {
- 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;
}
diff --git a/components/vc-select2/index.ts b/components/vc-select2/index.ts
index 9652b88e2..3f2b9d890 100644
--- a/components/vc-select2/index.ts
+++ b/components/vc-select2/index.ts
@@ -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;
diff --git a/tsconfig.json b/tsconfig.json
index 52bce7dcf..201741eba 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -13,7 +13,6 @@
"noUnusedParameters": true,
"noUnusedLocals": true,
"noImplicitAny": false,
- "module": "esnext",
"target": "es6",
"lib": ["dom", "es2017"],
"skipLibCheck": true,