From bd138a8711cf1714f626137727f3d12ae9632e2e Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Thu, 8 Oct 2020 22:51:09 +0800 Subject: [PATCH] fix: select2 bug --- antdv-demo | 2 +- components/vc-select2/OptionList.tsx | 11 +- components/vc-select2/SelectTrigger.tsx | 21 ++- components/vc-select2/Selector/Input.tsx | 134 ++++++++--------- .../vc-select2/Selector/MultipleSelector.tsx | 27 ++-- .../vc-select2/Selector/SingleSelector.tsx | 11 +- components/vc-select2/Selector/index.tsx | 12 +- components/vc-select2/examples/combobox.tsx | 136 ++++++++++++++++++ components/vc-select2/examples/controlled.tsx | 105 ++++++++++++++ components/vc-select2/examples/multiple.tsx | 119 +++++++++++++++ components/vc-select2/generate.tsx | 130 +++++++++++------ components/vc-select2/interface/index.ts | 2 +- 12 files changed, 562 insertions(+), 148 deletions(-) create mode 100644 components/vc-select2/examples/combobox.tsx create mode 100644 components/vc-select2/examples/controlled.tsx create mode 100644 components/vc-select2/examples/multiple.tsx diff --git a/antdv-demo b/antdv-demo index 79d49c0ff..ac51177e8 160000 --- a/antdv-demo +++ b/antdv-demo @@ -1 +1 @@ -Subproject commit 79d49c0ff31a4f505ccd5bc3ad238c08f9925212 +Subproject commit ac51177e860801a773d0e4241931d03be0efce65 diff --git a/components/vc-select2/OptionList.tsx b/components/vc-select2/OptionList.tsx index 54fa9a558..6984b68f6 100644 --- a/components/vc-select2/OptionList.tsx +++ b/components/vc-select2/OptionList.tsx @@ -49,14 +49,14 @@ const OptionListProps = { height: PropTypes.number, itemHeight: PropTypes.number, values: PropTypes.any, - multiple: PropTypes.bool, - open: PropTypes.bool, - defaultActiveFirstOption: PropTypes.bool, + multiple: { type: Boolean, default: undefined }, + open: { type: Boolean, default: undefined }, + defaultActiveFirstOption: { type: Boolean, default: undefined }, notFoundContent: PropTypes.any, menuItemSelectedIcon: PropTypes.any, - childrenAsData: PropTypes.bool, + childrenAsData: { type: Boolean, default: undefined }, searchValue: PropTypes.string, - virtual: PropTypes.bool, + virtual: { type: Boolean, default: undefined }, onSelect: PropTypes.func, onToggleOpen: PropTypes.func, @@ -131,6 +131,7 @@ const OptionList = defineComponent({ () => { setActive(props.defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1); }, + { immediate: true }, ); // Auto scroll to item position in single mode diff --git a/components/vc-select2/SelectTrigger.tsx b/components/vc-select2/SelectTrigger.tsx index c736b16f2..29acbb37c 100644 --- a/components/vc-select2/SelectTrigger.tsx +++ b/components/vc-select2/SelectTrigger.tsx @@ -71,14 +71,6 @@ const SelectTrigger = defineComponent({ }, methods: { - getDropdownTransitionName() { - const props = this.$props; - let transitionName = props.transitionName; - if (!transitionName && props.animation) { - transitionName = `${this.getDropdownPrefixCls()}-${props.animation}`; - } - return transitionName; - }, getPopupElement() { return this.popupRef.current; }, @@ -96,6 +88,8 @@ const SelectTrigger = defineComponent({ dropdownMatchSelectWidth, containerWidth, dropdownRender, + animation, + transitionName, } = props; const dropdownPrefixCls = `${prefixCls}-dropdown`; @@ -105,6 +99,9 @@ const SelectTrigger = defineComponent({ } const builtInPlacements = getBuiltInPlacements(dropdownMatchSelectWidth); + + const mergedTransitionName = animation ? `${dropdownPrefixCls}-${animation}` : transitionName; + const popupStyle = { minWidth: containerWidth, ...dropdownStyle }; if (typeof dropdownMatchSelectWidth === 'number') { @@ -120,7 +117,7 @@ const SelectTrigger = defineComponent({ popupPlacement={this.direction === 'rtl' ? 'bottomRight' : 'bottomLeft'} builtinPlacements={builtInPlacements} prefixCls={dropdownPrefixCls} - popupTransitionName={this.getDropdownTransitionName()} + popupTransitionName={mergedTransitionName} onPopupVisibleChange={props.onDropdownVisibleChange} popup={
{popupNode}
} popupAlign={dropdownAlign} @@ -139,11 +136,11 @@ const SelectTrigger = defineComponent({ }); SelectTrigger.props = { dropdownAlign: PropTypes.object, - visible: PropTypes.bool, - disabled: PropTypes.bool, + visible: { type: Boolean, default: undefined }, + disabled: { type: Boolean, default: undefined }, dropdownClassName: PropTypes.string, dropdownStyle: PropTypes.object, - empty: PropTypes.bool, + empty: { type: Boolean, default: undefined }, prefixCls: PropTypes.string, popupClassName: PropTypes.string, animation: PropTypes.string, diff --git a/components/vc-select2/Selector/Input.tsx b/components/vc-select2/Selector/Input.tsx index 4278cd789..91d195246 100644 --- a/components/vc-select2/Selector/Input.tsx +++ b/components/vc-select2/Selector/Input.tsx @@ -68,66 +68,72 @@ const Input = defineComponent({ onCompositionend: onOriginCompositionEnd, style, } = inputProps; - - inputNode = cloneElement(inputNode, { - id, - ref: inputRef, - disabled, - tabindex, - autocomplete: autocomplete || 'off', - type: 'search', - autofocus, - class: `${prefixCls}-selection-search-input`, - style: { ...style, opacity: editable ? null : 0 }, - role: 'combobox', - 'aria-expanded': open, - 'aria-haspopup': 'listbox', - 'aria-owns': `${id}_list`, - 'aria-autocomplete': 'list', - 'aria-controls': `${id}_list`, - 'aria-activedescendant': `${id}_list_${accessibilityIndex}`, - ...attrs, - value: editable ? value : '', - readonly: !editable, - unselectable: !editable ? 'on' : null, - onKeydown: (event: KeyboardEvent) => { - onKeydown(event); - if (onOriginKeyDown) { - onOriginKeyDown(event); - } - }, - onMousedown: (event: MouseEvent) => { - onMousedown(event); - if (onOriginMouseDown) { - onOriginMouseDown(event); - } - }, - onInput: (event: Event) => { - onChange(event); - if (onOriginInput) { - onOriginInput(event); - } - }, - onCompositionstart(event: CompositionEvent) { - onCompositionstart(event); - if (onOriginCompositionStart) { - onOriginCompositionStart(event); - } - }, - onCompositionend(event: CompositionEvent) { - onCompositionend(event); - if (onOriginCompositionEnd) { - onOriginCompositionEnd(event); - } - }, - onPaste, - onFocus: (...args: any[]) => { - this.VCSelectContainerEvent?.focus(args[0]); - }, - onBlur: (...args: any[]) => { - this.VCSelectContainerEvent?.blur(args[0]); - }, - }) as VNode; + inputNode = cloneElement( + inputNode, + Object.assign( + { + id, + ref: inputRef, + disabled, + tabindex, + autocomplete: autocomplete || 'off', + autofocus, + class: `${prefixCls}-selection-search-input`, + style: { ...style, opacity: editable ? null : 0 }, + role: 'combobox', + 'aria-expanded': open, + 'aria-haspopup': 'listbox', + 'aria-owns': `${id}_list`, + 'aria-autocomplete': 'list', + 'aria-controls': `${id}_list`, + 'aria-activedescendant': `${id}_list_${accessibilityIndex}`, + ...attrs, + value: editable ? value : '', + readonly: !editable, + unselectable: !editable ? 'on' : null, + onKeydown: (event: KeyboardEvent) => { + onKeydown(event); + if (onOriginKeyDown) { + onOriginKeyDown(event); + } + }, + onMousedown: (event: MouseEvent) => { + onMousedown(event); + if (onOriginMouseDown) { + onOriginMouseDown(event); + } + }, + onInput: (event: Event) => { + onChange(event); + if (onOriginInput) { + onOriginInput(event); + } + }, + onCompositionstart(event: CompositionEvent) { + onCompositionstart(event); + if (onOriginCompositionStart) { + onOriginCompositionStart(event); + } + }, + onCompositionend(event: CompositionEvent) { + onCompositionend(event); + if (onOriginCompositionEnd) { + onOriginCompositionEnd(event); + } + }, + onPaste, + onFocus: (...args: any[]) => { + this.VCSelectContainerEvent?.focus(args[0]); + }, + onBlur: (...args: any[]) => { + this.VCSelectContainerEvent?.blur(args[0]); + }, + }, + inputNode.type === 'textarea' ? {} : { type: 'search' }, + ), + true, + true, + ) as VNode; return inputNode; }, }); @@ -137,13 +143,13 @@ Input.props = { prefixCls: PropTypes.string, id: PropTypes.string, inputElement: PropTypes.any, - disabled: PropTypes.bool, - autofocus: PropTypes.bool, + disabled: { type: Boolean, default: undefined }, + autofocus: { type: Boolean, default: undefined }, autocomplete: PropTypes.string, - editable: PropTypes.bool, + editable: { type: Boolean, default: undefined }, accessibilityIndex: PropTypes.number, value: PropTypes.string, - open: PropTypes.bool, + open: { type: Boolean, default: undefined }, tabindex: PropTypes.number, /** Pass accessibility props to input */ attrs: PropTypes.object, diff --git a/components/vc-select2/Selector/MultipleSelector.tsx b/components/vc-select2/Selector/MultipleSelector.tsx index 4bf350451..c29bd4464 100644 --- a/components/vc-select2/Selector/MultipleSelector.tsx +++ b/components/vc-select2/Selector/MultipleSelector.tsx @@ -43,19 +43,19 @@ const props = { id: PropTypes.string, prefixCls: PropTypes.string, values: PropTypes.array, - open: PropTypes.bool, + open: { type: Boolean, default: undefined }, searchValue: PropTypes.string, inputRef: PropTypes.any, placeholder: PropTypes.any, - disabled: PropTypes.bool, + disabled: { type: Boolean, default: undefined }, mode: PropTypes.string, - showSearch: PropTypes.bool, - autofocus: PropTypes.bool, + showSearch: { type: Boolean, default: undefined }, + autofocus: { type: Boolean, default: undefined }, autocomplete: PropTypes.string, accessibilityIndex: PropTypes.number, tabindex: PropTypes.number, - removeIcon: PropTypes.bool, + removeIcon: { type: Boolean, default: undefined }, choiceTransitionName: PropTypes.string, maxTagCount: PropTypes.number, @@ -95,13 +95,16 @@ const SelectSelector = defineComponent({ ); // We measure width and set to the input immediately - watch( - inputValue, - () => { - inputWidth.value = measureRef.value.scrollWidth; - }, - { flush: 'pre' }, - ); + onMounted(() => { + watch( + inputValue, + () => { + inputWidth.value = measureRef.value.scrollWidth; + }, + { flush: 'post' }, + ); + }); + const selectionNode = ref(); watchEffect(() => { const { diff --git a/components/vc-select2/Selector/SingleSelector.tsx b/components/vc-select2/Selector/SingleSelector.tsx index d519c291a..938d8d9cb 100644 --- a/components/vc-select2/Selector/SingleSelector.tsx +++ b/components/vc-select2/Selector/SingleSelector.tsx @@ -14,19 +14,19 @@ const props = { id: PropTypes.string, prefixCls: PropTypes.string, values: PropTypes.array, - open: PropTypes.bool, + open: { type: Boolean, default: undefined }, searchValue: PropTypes.string, inputRef: PropTypes.any, placeholder: PropTypes.any, - disabled: PropTypes.bool, + disabled: { type: Boolean, default: undefined }, mode: PropTypes.string, - showSearch: PropTypes.bool, - autofocus: PropTypes.bool, + showSearch: { type: Boolean, default: undefined }, + autofocus: { type: Boolean, default: undefined }, autocomplete: PropTypes.string, accessibilityIndex: PropTypes.number, tabindex: PropTypes.number, activeValue: PropTypes.string, - backfill: PropTypes.bool, + backfill: { type: Boolean, default: undefined }, onInputChange: PropTypes.func, onInputPaste: PropTypes.func, onInputKeyDown: PropTypes.func, @@ -56,6 +56,7 @@ const SingleSelector = defineComponent({ inputChanged.value = false; } }, + { immediate: true }, ); // Not show text when closed expect combobox mode diff --git a/components/vc-select2/Selector/index.tsx b/components/vc-select2/Selector/index.tsx index 90e88e52d..40ef31fcb 100644 --- a/components/vc-select2/Selector/index.tsx +++ b/components/vc-select2/Selector/index.tsx @@ -252,20 +252,20 @@ Selector.inheritAttrs = false; Selector.props = { id: PropTypes.string, prefixCls: PropTypes.string, - showSearch: PropTypes.bool, - open: PropTypes.bool, + showSearch: { type: Boolean, default: undefined }, + open: { type: Boolean, default: undefined }, /** Display in the Selector value, it's not same as `value` prop */ values: PropTypes.array, - multiple: PropTypes.bool, + multiple: { type: Boolean, default: undefined }, mode: PropTypes.string, searchValue: PropTypes.string, activeValue: PropTypes.string, inputElement: PropTypes.any, - autofocus: PropTypes.bool, + autofocus: { type: Boolean, default: undefined }, accessibilityIndex: PropTypes.number, tabindex: PropTypes.number, - disabled: PropTypes.bool, + disabled: { type: Boolean, default: undefined }, placeholder: PropTypes.any, removeIcon: PropTypes.any, @@ -276,7 +276,7 @@ Selector.props = { tagRender: PropTypes.func, /** Check if `tokenSeparators` contains `\n` or `\r\n` */ - tokenWithEnter: PropTypes.bool, + tokenWithEnter: { type: Boolean, default: undefined }, // Motion choiceTransitionName: PropTypes.string, diff --git a/components/vc-select2/examples/combobox.tsx b/components/vc-select2/examples/combobox.tsx new file mode 100644 index 000000000..df27af3e5 --- /dev/null +++ b/components/vc-select2/examples/combobox.tsx @@ -0,0 +1,136 @@ +import createRef from '../../_util/createRef'; +/* eslint-disable no-console */ +import Select, { Option } from '..'; +import '../assets/index.less'; +import { nextTick } from 'vue'; + +const Combobox = { + data() { + this.textareaRef = createRef(); + + this.timeoutId; + return { + disabled: false, + value: '', + options: [], + }; + }, + + mounted() { + nextTick(() => { + console.log('Ref:', this.textareaRef.current); + }); + }, + methods: { + onChange(value, option) { + console.log('onChange', value, option); + + this.value = value; + }, + + onKeyDown(e) { + const { value } = this; + if (e.keyCode === 13) { + console.log('onEnter', value); + } + }, + + onSelect(v, option) { + console.log('onSelect', v, option); + }, + + onSearch(text: string) { + console.log('onSearch:', text); + }, + + onAsyncChange(value) { + window.clearTimeout(this.timeoutId); + console.log(value); + this.options = []; + //const value = String(Math.random()); + this.timeoutId = window.setTimeout(() => { + this.options = [{ value }, { value: `${value}-${value}` }]; + }, 1000); + }, + + toggleDisabled() { + const { disabled } = this; + + this.disabled = !disabled; + }, + }, + + render() { + const { value, disabled } = this; + return ( +
+

combobox

+

+ + +

+
+ + +

Customize Input Element

+