perf: update select
parent
147f1530ed
commit
3e8e90da5e
|
@ -1,5 +1,5 @@
|
|||
module.exports = {
|
||||
dev: {
|
||||
componentName: 'steps', // dev components
|
||||
componentName: 'select', // dev components
|
||||
},
|
||||
};
|
||||
|
|
|
@ -63,7 +63,7 @@ exports[`renders ./components/select/demo/custom-dropdown-menu.md correctly 1`]
|
|||
<div tabindex="0" class="ant-select ant-select-enabled" style="width: 120px;">
|
||||
<div role="combobox" aria-autocomplete="list" aria-haspopup="true" aria-controls="test-uuid" class="ant-select-selection ant-select-selection--single">
|
||||
<div class="ant-select-selection__rendered">
|
||||
<div title="Lucy" class="ant-select-selection-selected-value" style="display: block; opacity: 1;">Lucy</div>
|
||||
<div title="lucy" class="ant-select-selection-selected-value" style="display: block; opacity: 1;">lucy</div>
|
||||
</div><span unselectable="on" class="ant-select-arrow" style="user-select: none;"><i aria-label="icon: down" class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -125,6 +125,24 @@ exports[`renders ./components/select/demo/optgroup.md correctly 1`] = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/select/demo/option-label-prop.md correctly 1`] = `
|
||||
<div tabindex="0" class="ant-select ant-select-enabled" style="width: 100%;">
|
||||
<div role="combobox" aria-autocomplete="list" aria-haspopup="true" aria-controls="test-uuid" class="ant-select-selection ant-select-selection--multiple">
|
||||
<div class="ant-select-selection__rendered">
|
||||
<div unselectable="on" class="ant-select-selection__placeholder" style="display: none; user-select: none;">select one country</div>
|
||||
<div>
|
||||
<li unselectable="on" role="presentation" title="China" class="ant-select-selection__choice" style="user-select: none;">
|
||||
<div class="ant-select-selection__choice__content">China</div><span class="ant-select-selection__choice__remove"><i aria-label="icon: close" class="ant-select-remove-icon anticon anticon-close"><svg viewBox="64 64 896 896" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></i></span>
|
||||
</li>
|
||||
<li class="ant-select-search ant-select-search--inline">
|
||||
<div class="ant-select-search__field__wrap"><input autocomplete="off" value="" class="ant-select-search__field"><span class="ant-select-search__field__mirror"> </span></div>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/select/demo/options.md correctly 1`] = `
|
||||
<div tabindex="0" class="ant-select ant-select-enabled" style="width: 120px;">
|
||||
<div role="combobox" aria-autocomplete="list" aria-haspopup="true" aria-controls="test-uuid" class="ant-select-selection ant-select-selection--single">
|
||||
|
|
|
@ -3,9 +3,11 @@ import { asyncExpect } from '@/tests/utils';
|
|||
import Select from '..';
|
||||
import Icon from '../../icon';
|
||||
import focusTest from '../../../tests/shared/focusTest';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
|
||||
describe('Select', () => {
|
||||
focusTest(Select);
|
||||
mountTest(Select);
|
||||
|
||||
it('should have default notFoundContent', async () => {
|
||||
const wrapper = mount(Select, {
|
||||
|
|
|
@ -14,21 +14,27 @@ Customize the dropdown menu via `dropdownRender`.
|
|||
<div slot="dropdownRender" slot-scope="menu">
|
||||
<v-nodes :vnodes="menu" />
|
||||
<a-divider style="margin: 4px 0;" />
|
||||
<div style="padding: 8px; cursor: pointer;"><a-icon type="plus" /> Add item</div>
|
||||
<div style="padding: 4px 8px; cursor: pointer;" @mousedown="e => e.preventDefault()" @click="addItem"><a-icon type="plus" /> Add item</div>
|
||||
</div>
|
||||
<a-select-option value="jack">Jack</a-select-option>
|
||||
<a-select-option value="lucy">Lucy</a-select-option>
|
||||
<a-select-option v-for="item in items" :value="item" :key="item">{{item}}</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
<script>
|
||||
let index = 0;
|
||||
export default {
|
||||
data: () => ({ console: console }),
|
||||
data: () => ({ items: ['jack', 'lucy'] }),
|
||||
components: {
|
||||
VNodes: {
|
||||
functional: true,
|
||||
render: (h, ctx) => ctx.props.vnodes,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
addItem() {
|
||||
console.log('addItem');
|
||||
this.items.push(`New item ${index++}`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
|
|
@ -13,6 +13,7 @@ import SelectUsers from './select-users';
|
|||
import Suffix from './suffix';
|
||||
import HideSelected from './hide-selected';
|
||||
import CustomDropdownMenu from './custom-dropdown-menu';
|
||||
import OptionLabelProp from './option-label-prop';
|
||||
|
||||
import CN from '../index.zh-CN.md';
|
||||
import US from '../index.en-US.md';
|
||||
|
@ -54,6 +55,7 @@ export default {
|
|||
<Suffix />
|
||||
<HideSelected />
|
||||
<CustomDropdownMenu />
|
||||
<OptionLabelProp />
|
||||
<api>
|
||||
<CN slot="cn" />
|
||||
<US />
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<cn>
|
||||
#### 定制回填内容
|
||||
使用 `optionLabelProp` 指定回填到选择框的 `Option` 属性。
|
||||
</cn>
|
||||
|
||||
<us>
|
||||
#### Custom selection render
|
||||
Spacified the prop name of Option which will be rendered in select box.
|
||||
</us>
|
||||
|
||||
```tpl
|
||||
<template>
|
||||
<a-select
|
||||
mode="multiple"
|
||||
style="width: 100%"
|
||||
placeholder="select one country"
|
||||
v-model="value"
|
||||
optionLabelProp="label"
|
||||
>
|
||||
<a-select-option value="china" label="China">
|
||||
<span role="img" aria-label="China">
|
||||
🇨🇳
|
||||
</span>
|
||||
China (中国)
|
||||
</a-select-option>
|
||||
<a-select-option value="usa" label="USA">
|
||||
<span role="img" aria-label="USA">
|
||||
🇺🇸
|
||||
</span>
|
||||
USA (美国)
|
||||
</a-select-option>
|
||||
<a-select-option value="japan" label="Japan">
|
||||
<span role="img" aria-label="Japan">
|
||||
🇯🇵
|
||||
</span>
|
||||
Japan (日本)
|
||||
</a-select-option>
|
||||
<a-select-option value="korea" label="Korea">
|
||||
<span role="img" aria-label="Korea">
|
||||
🇰🇷
|
||||
</span>
|
||||
Korea (韩国)
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
value: ['china']
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
console.log(`selected:`, val);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
```
|
|
@ -20,6 +20,7 @@
|
|||
| dropdownMatchSelectWidth | Whether dropdown's width is same with select. | boolean | true |
|
||||
| dropdownRender | Customize dropdown content | (menuNode: VNode, props) => VNode | - |
|
||||
| dropdownStyle | style of dropdown menu | object | - |
|
||||
| dropdownMenuStyle | additional style applied to dropdown menu | object | - |
|
||||
| filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns `true`, the option will be included in the filtered set; Otherwise, it will be excluded. | boolean or function(inputValue, option) | true |
|
||||
| firstActiveValue | Value of action option by default | string\|string\[] | - |
|
||||
| getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative. | function(triggerNode) | () => document.body |
|
||||
|
@ -85,3 +86,9 @@
|
|||
| -------- | ----------- | ------------ | ------- |
|
||||
| key | | string | - |
|
||||
| label | Group label | string\|slot | - |
|
||||
|
||||
## FAQ
|
||||
|
||||
### The dropdown is closed when click `dropdownRender` area?
|
||||
|
||||
See the [dropdownRender example](/components/select/#components-select-demo-custom-dropdown).
|
||||
|
|
|
@ -118,21 +118,13 @@ const Select = {
|
|||
created() {
|
||||
warning(
|
||||
this.$props.mode !== 'combobox',
|
||||
'Select',
|
||||
'The combobox mode of Select is deprecated,' +
|
||||
'it will be removed in next major version,' +
|
||||
'please use AutoComplete instead',
|
||||
);
|
||||
},
|
||||
methods: {
|
||||
savePopupRef(ref) {
|
||||
this.popupRef = ref;
|
||||
},
|
||||
focus() {
|
||||
this.$refs.vcSelect.focus();
|
||||
},
|
||||
blur() {
|
||||
this.$refs.vcSelect.blur();
|
||||
},
|
||||
getNotFoundContent(renderEmpty) {
|
||||
const h = this.$createElement;
|
||||
const notFoundContent = getComponentFromProp(this, 'notFoundContent');
|
||||
|
@ -144,6 +136,16 @@ const Select = {
|
|||
}
|
||||
return renderEmpty(h, 'Select');
|
||||
},
|
||||
savePopupRef(ref) {
|
||||
this.popupRef = ref;
|
||||
},
|
||||
focus() {
|
||||
this.$refs.vcSelect.focus();
|
||||
},
|
||||
blur() {
|
||||
this.$refs.vcSelect.blur();
|
||||
},
|
||||
|
||||
isCombobox() {
|
||||
const { mode } = this;
|
||||
return mode === 'combobox' || mode === SECRET_COMBOBOX_MODE_DO_NOT_USE;
|
||||
|
@ -171,6 +173,7 @@ const Select = {
|
|||
mode,
|
||||
options,
|
||||
getPopupContainer,
|
||||
showArrow,
|
||||
...restProps
|
||||
} = getOptionProps(this);
|
||||
|
||||
|
@ -198,6 +201,7 @@ const Select = {
|
|||
const cls = {
|
||||
[`${prefixCls}-lg`]: size === 'large',
|
||||
[`${prefixCls}-sm`]: size === 'small',
|
||||
[`${prefixCls}-show-arrow`]: showArrow,
|
||||
};
|
||||
|
||||
let { optionLabelProp } = this.$props;
|
||||
|
@ -234,6 +238,7 @@ const Select = {
|
|||
removeIcon: finalRemoveIcon,
|
||||
clearIcon: finalClearIcon,
|
||||
menuItemSelectedIcon: finalMenuItemSelectedIcon,
|
||||
showArrow,
|
||||
...rest,
|
||||
...modeConfig,
|
||||
prefixCls,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
| dropdownMatchSelectWidth | 下拉菜单和选择器同宽 | boolean | true |
|
||||
| dropdownRender | 自定义下拉框内容 | (menuNode: VNode, props) => VNode | - |
|
||||
| dropdownStyle | 下拉菜单的 style 属性 | object | - |
|
||||
| dropdownMenuStyle | dropdown 菜单自定义样式 | object | - |
|
||||
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | boolean or function(inputValue, option) | true |
|
||||
| firstActiveValue | 默认高亮的选项 | string\|string\[] | - |
|
||||
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | Function(triggerNode) | () => document.body |
|
||||
|
@ -86,3 +87,9 @@
|
|||
| ----- | ---- | --------------------------- | ------ |
|
||||
| key | | string | - |
|
||||
| label | 组名 | string\|\|function(h)\|slot | 无 |
|
||||
|
||||
## FAQ
|
||||
|
||||
### 点击 `dropdownRender` 里的内容浮层关闭怎么办?
|
||||
|
||||
看下 [dropdownRender 例子](/components/select-cn/#components-select-demo-custom-dropdown) 里的说明。
|
||||
|
|
|
@ -37,7 +37,7 @@ export default {
|
|||
},
|
||||
|
||||
created() {
|
||||
this.rafInstance = { cancel: () => null };
|
||||
this.rafInstance = null;
|
||||
this.lastInputValue = this.$props.inputValue;
|
||||
this.lastVisible = false;
|
||||
},
|
||||
|
@ -60,8 +60,8 @@ export default {
|
|||
this.prevVisible = this.visible;
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.rafInstance && this.rafInstance.cancel) {
|
||||
this.rafInstance.cancel();
|
||||
if (this.rafInstance) {
|
||||
raf.cancel(this.rafInstance);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -59,6 +59,11 @@ const SELECT_EMPTY_VALUE_KEY = 'RC_SELECT_EMPTY_VALUE_KEY';
|
|||
|
||||
const noop = () => null;
|
||||
|
||||
// Where el is the DOM element you'd like to test for visibility
|
||||
function isHidden(node) {
|
||||
return !node || node.offsetParent === null;
|
||||
}
|
||||
|
||||
function chaining(...fns) {
|
||||
return function(...args) {
|
||||
// eslint-disable-line
|
||||
|
@ -130,6 +135,13 @@ const Select = {
|
|||
this.__propsSymbol__,
|
||||
'Replace slots.default with props.children and pass props.__propsSymbol__',
|
||||
);
|
||||
if (props.tags && typeof props.filterOption !== 'function') {
|
||||
const isDisabledExist = Object.keys(optionsInfo).some(key => optionsInfo[key].disabled);
|
||||
warning(
|
||||
!isDisabledExist,
|
||||
'Please avoid setting option to disabled in tags mode since user can always type text as tag.',
|
||||
);
|
||||
}
|
||||
const state = {
|
||||
_value: this.getValueFromProps(props, true), // true: use default value
|
||||
_inputValue: props.combobox
|
||||
|
@ -191,6 +203,7 @@ const Select = {
|
|||
beforeDestroy() {
|
||||
this.clearFocusTime();
|
||||
this.clearBlurTime();
|
||||
this.clearComboboxTime();
|
||||
if (this.dropdownContainer) {
|
||||
document.body.removeChild(this.dropdownContainer);
|
||||
this.dropdownContainer = null;
|
||||
|
@ -326,7 +339,7 @@ const Select = {
|
|||
if (nextValue !== undefined) {
|
||||
this.fireChange(nextValue);
|
||||
}
|
||||
this.setOpenState(false, true);
|
||||
this.setOpenState(false, { needFocus: true });
|
||||
this.setInputValue('', false);
|
||||
return;
|
||||
}
|
||||
|
@ -378,14 +391,14 @@ const Select = {
|
|||
},
|
||||
|
||||
onInputKeydown(event) {
|
||||
const props = this.$props;
|
||||
if (props.disabled) {
|
||||
const { disabled, combobox, defaultActiveFirstOption } = this.$props;
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
const state = this.$data;
|
||||
const isRealOpen = this.getRealOpenState(state);
|
||||
const keyCode = event.keyCode;
|
||||
if (isMultipleOrTags(props) && !event.target.value && keyCode === KeyCode.BACKSPACE) {
|
||||
if (isMultipleOrTags(this.$props) && !event.target.value && keyCode === KeyCode.BACKSPACE) {
|
||||
event.preventDefault();
|
||||
const { _value: value } = state;
|
||||
if (value.length) {
|
||||
|
@ -407,6 +420,12 @@ const Select = {
|
|||
if (isRealOpen || !props.combobox) {
|
||||
event.preventDefault();
|
||||
}
|
||||
// Hard close popup to avoid lock of non option in combobox mode
|
||||
if (isRealOpen && combobox && defaultActiveFirstOption === false) {
|
||||
this.comboboxTimer = setTimeout(() => {
|
||||
this.setOpenState(false);
|
||||
});
|
||||
}
|
||||
} else if (keyCode === KeyCode.ESC) {
|
||||
if (state._open) {
|
||||
this.setOpenState(false);
|
||||
|
@ -433,12 +452,14 @@ const Select = {
|
|||
const props = this.$props;
|
||||
const selectedValue = getValuePropValue(item);
|
||||
const lastValue = value[value.length - 1];
|
||||
this.fireSelect(selectedValue);
|
||||
let skipTrigger = false;
|
||||
|
||||
if (isMultipleOrTags(props)) {
|
||||
if (findIndexInValueBySingleValue(value, selectedValue) !== -1) {
|
||||
return;
|
||||
skipTrigger = true;
|
||||
} else {
|
||||
value = value.concat([selectedValue]);
|
||||
}
|
||||
value = value.concat([selectedValue]);
|
||||
} else {
|
||||
if (
|
||||
!isCombobox(props) &&
|
||||
|
@ -446,30 +467,40 @@ const Select = {
|
|||
lastValue === selectedValue &&
|
||||
selectedValue !== this.$data._backfillValue
|
||||
) {
|
||||
this.setOpenState(false, true);
|
||||
return;
|
||||
this.setOpenState(false, { needFocus: true, fireSearch: false });
|
||||
skipTrigger = true;
|
||||
} else {
|
||||
value = [selectedValue];
|
||||
this.setOpenState(false, { needFocus: true, fireSearch: false });
|
||||
}
|
||||
value = [selectedValue];
|
||||
this.setOpenState(false, true);
|
||||
}
|
||||
this.fireChange(value);
|
||||
const inputValue = isCombobox(props) ? getPropValue(item, props.optionLabelProp) : '';
|
||||
if (!skipTrigger) {
|
||||
this.fireChange(value);
|
||||
}
|
||||
if (!skipTrigger) {
|
||||
this.fireSelect(selectedValue);
|
||||
const inputValue = isCombobox(props) ? getPropValue(item, props.optionLabelProp) : '';
|
||||
|
||||
if (props.autoClearSearchValue) {
|
||||
this.setInputValue(inputValue, false);
|
||||
if (props.autoClearSearchValue) {
|
||||
this.setInputValue(inputValue, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onMenuDeselect({ item, domEvent }) {
|
||||
if (domEvent.type === 'keydown' && domEvent.keyCode === KeyCode.ENTER) {
|
||||
this.removeSelected(getValuePropValue(item));
|
||||
const menuItemDomNode = item.$el;
|
||||
// https://github.com/ant-design/ant-design/issues/20465#issuecomment-569033796
|
||||
if (!isHidden(menuItemDomNode)) {
|
||||
this.removeSelected(getValuePropValue(item));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (domEvent.type === 'click') {
|
||||
this.removeSelected(getValuePropValue(item));
|
||||
}
|
||||
if (this.autoClearSearchValue) {
|
||||
this.setInputValue('', false);
|
||||
this.setInputValue('');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -478,7 +509,7 @@ const Select = {
|
|||
e.preventDefault();
|
||||
this.clearBlurTime();
|
||||
if (!this.disabled) {
|
||||
this.setOpenState(!this.$data._open, !this.$data._open);
|
||||
this.setOpenState(!this.$data._open, { needFocus: !this.$data._open });
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -505,7 +536,7 @@ const Select = {
|
|||
if (value.length) {
|
||||
this.fireChange([]);
|
||||
}
|
||||
this.setOpenState(false, true);
|
||||
this.setOpenState(false, { needFocus: true });
|
||||
if (inputValue) {
|
||||
this.setInputValue('');
|
||||
}
|
||||
|
@ -527,9 +558,12 @@ const Select = {
|
|||
}
|
||||
let defaultLabel = value;
|
||||
if (this.$props.labelInValue) {
|
||||
const label = getLabelFromPropsValue(this.$props.value, value);
|
||||
if (label !== undefined) {
|
||||
defaultLabel = label;
|
||||
const valueLabel = getLabelFromPropsValue(this.$props.value, value);
|
||||
const defaultValueLabel = getLabelFromPropsValue(this.$props.defaultValue, value);
|
||||
if (valueLabel !== undefined) {
|
||||
defaultLabel = valueLabel;
|
||||
} else if (defaultValueLabel !== undefined) {
|
||||
defaultLabel = defaultValueLabel;
|
||||
}
|
||||
}
|
||||
const defaultInfo = {
|
||||
|
@ -734,7 +768,18 @@ const Select = {
|
|||
return;
|
||||
}
|
||||
this.clearBlurTime();
|
||||
if (!isMultipleOrTagsOrCombobox(this.$props) && e.target === this.getInputDOMNode()) {
|
||||
|
||||
// In IE11, onOuterFocus will be trigger twice when focus input
|
||||
// First one: e.target is div
|
||||
// Second one: e.target is input
|
||||
// other browser only trigger second one
|
||||
// https://github.com/ant-design/ant-design/issues/15942
|
||||
// Here we ignore the first one when e.target is div
|
||||
const inputNode = this.getInputDOMNode();
|
||||
if (inputNode && e.target === this.rootRef) {
|
||||
return;
|
||||
}
|
||||
if (!isMultipleOrTagsOrCombobox(this.$props) && e.target === inputNode) {
|
||||
return;
|
||||
}
|
||||
if (this._focused) {
|
||||
|
@ -837,8 +882,9 @@ const Select = {
|
|||
}
|
||||
},
|
||||
|
||||
setOpenState(open, needFocus) {
|
||||
setOpenState(open, config = {}) {
|
||||
const { $props: props, $data: state } = this;
|
||||
const { needFocus, fireSearch } = config;
|
||||
if (state._open === open) {
|
||||
this.maybeFocus(open, !!needFocus);
|
||||
return;
|
||||
|
@ -850,7 +896,7 @@ const Select = {
|
|||
};
|
||||
// clear search input value when open is false in singleMode.
|
||||
if (!open && isSingleMode(props) && props.showSearch) {
|
||||
this.setInputValue('', false);
|
||||
this.setInputValue('', fireSearch);
|
||||
}
|
||||
if (!open) {
|
||||
this.maybeFocus(open, !!needFocus);
|
||||
|
@ -1002,6 +1048,13 @@ const Select = {
|
|||
}
|
||||
},
|
||||
|
||||
clearComboboxTime() {
|
||||
if (this.comboboxTimer) {
|
||||
clearTimeout(this.comboboxTimer);
|
||||
this.comboboxTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
updateFocusClassName() {
|
||||
const { rootRef, prefixCls } = this;
|
||||
// avoid setState and its side effect
|
||||
|
@ -1130,30 +1183,18 @@ const Select = {
|
|||
options.push(menuItem);
|
||||
menuItems.push(menuItem);
|
||||
});
|
||||
if (inputValue) {
|
||||
const notFindInputItem = menuItems.every(option => {
|
||||
// this.filterOption return true has two meaning,
|
||||
// 1, some one exists after filtering
|
||||
// 2, filterOption is set to false
|
||||
// condition 2 does not mean the option has same value with inputValue
|
||||
const filterFn = () => getValuePropValue(option) === inputValue;
|
||||
if (filterOption !== false) {
|
||||
return !this._filterOption(inputValue, option, filterFn);
|
||||
}
|
||||
return !filterFn();
|
||||
});
|
||||
if (notFindInputItem) {
|
||||
const p = {
|
||||
attrs: UNSELECTABLE_ATTRIBUTE,
|
||||
key: inputValue,
|
||||
props: {
|
||||
value: inputValue,
|
||||
role: 'option',
|
||||
},
|
||||
style: UNSELECTABLE_STYLE,
|
||||
};
|
||||
options.unshift(<MenuItem {...p}>{inputValue}</MenuItem>);
|
||||
}
|
||||
// ref: https://github.com/ant-design/ant-design/issues/14090
|
||||
if (inputValue && menuItems.every(option => getValuePropValue(option) !== inputValue)) {
|
||||
const p = {
|
||||
attrs: UNSELECTABLE_ATTRIBUTE,
|
||||
key: inputValue,
|
||||
props: {
|
||||
value: inputValue,
|
||||
role: 'option',
|
||||
},
|
||||
style: UNSELECTABLE_STYLE,
|
||||
};
|
||||
options.unshift(<MenuItem {...p}>{inputValue}</MenuItem>);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import classnames from 'classnames';
|
||||
import raf from 'raf';
|
||||
import Trigger from '../vc-trigger';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import DropdownMenu from './DropdownMenu';
|
||||
|
@ -65,6 +66,7 @@ export default {
|
|||
};
|
||||
},
|
||||
created() {
|
||||
this.rafInstance = null;
|
||||
this.saveDropdownMenuRef = saveRef(this, 'dropdownMenuRef');
|
||||
this.saveTriggerRef = saveRef(this, 'triggerRef');
|
||||
},
|
||||
|
@ -80,14 +82,24 @@ export default {
|
|||
this.setDropdownWidth();
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.cancelRafInstance();
|
||||
},
|
||||
methods: {
|
||||
setDropdownWidth() {
|
||||
const width = this.$el.offsetWidth;
|
||||
if (width !== this.dropdownWidth) {
|
||||
this.setState({ dropdownWidth: width });
|
||||
this.cancelRafInstance();
|
||||
this.rafInstance = raf(() => {
|
||||
const width = this.$el.offsetWidth;
|
||||
if (width !== this.dropdownWidth) {
|
||||
this.setState({ dropdownWidth: width });
|
||||
}
|
||||
});
|
||||
},
|
||||
cancelRafInstance() {
|
||||
if (this.rafInstance) {
|
||||
raf.cancel(this.rafInstance);
|
||||
}
|
||||
},
|
||||
|
||||
getInnerMenu() {
|
||||
return this.dropdownMenuRef && this.dropdownMenuRef.$refs.menuRef;
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// based on vc-select 8.9.0
|
||||
// based on vc-select 9.2.2
|
||||
import ProxySelect, { Select } from './Select';
|
||||
import Option from './Option';
|
||||
import { SelectPropTypes } from './PropTypes';
|
||||
|
|
Loading…
Reference in New Issue