From c42cfd68930a21533f72de57fd2fbd8c5d8c8b25 Mon Sep 17 00:00:00 2001 From: Eric Bonow Date: Wed, 13 Oct 2021 16:15:23 -0700 Subject: [PATCH 1/5] ValueContainer display remains grid if controlShouldRenderValue is false --- packages/react-select/src/components/containers.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-select/src/components/containers.tsx b/packages/react-select/src/components/containers.tsx index 3d7a6d0f1b..e2135c7ce1 100644 --- a/packages/react-select/src/components/containers.tsx +++ b/packages/react-select/src/components/containers.tsx @@ -86,9 +86,10 @@ export const valueContainerCSS = < theme: { spacing }, isMulti, hasValue, + selectProps: { controlShouldRenderValue }, }: ValueContainerProps): CSSObjectWithLabel => ({ alignItems: 'center', - display: isMulti && hasValue ? 'flex' : 'grid', + display: isMulti && hasValue && controlShouldRenderValue ? 'flex' : 'grid', flex: 1, flexWrap: 'wrap', padding: `${spacing.baseUnit / 2}px ${spacing.baseUnit * 2}px`, From 728f30b73f6d814cab7b4c41a03c1ff9f115ecdf Mon Sep 17 00:00:00 2001 From: Eric Bonow Date: Wed, 13 Oct 2021 16:16:42 -0700 Subject: [PATCH 2/5] Set unique key for Option by concatenating getOptionLabel and getOptionValue --- packages/react-select/src/Select.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-select/src/Select.tsx b/packages/react-select/src/Select.tsx index 6b154649f3..d59d9e8ecf 100644 --- a/packages/react-select/src/Select.tsx +++ b/packages/react-select/src/Select.tsx @@ -1648,6 +1648,7 @@ export default class Select< if (isMulti) { return selectValue.map((opt, index) => { const isOptionFocused = opt === focusedValue; + const key = `${this.getOptionLabel(opt)}-${this.getOptionValue(opt)}`; return ( this.removeValue(opt), From f6cd50ee914d5cde461e97dfb2244dd8d0411a53 Mon Sep 17 00:00:00 2001 From: Eric Bonow Date: Wed, 13 Oct 2021 16:19:25 -0700 Subject: [PATCH 3/5] AnimatedValueContainer display remains flex until last value transition onExited --- .../src/animated/ValueContainer.tsx | 84 ++++++++++++++++++- .../react-select/src/animated/transitions.tsx | 9 +- 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/packages/react-select/src/animated/ValueContainer.tsx b/packages/react-select/src/animated/ValueContainer.tsx index 2e3ab7335b..752899e750 100644 --- a/packages/react-select/src/animated/ValueContainer.tsx +++ b/packages/react-select/src/animated/ValueContainer.tsx @@ -1,4 +1,4 @@ -import React, { ReactElement } from 'react'; +import React, { useEffect, useState, ReactElement, ReactNode } from 'react'; import { TransitionGroup } from 'react-transition-group'; import { ValueContainerProps } from '../components/containers'; import { GroupBase } from '../types'; @@ -11,12 +11,92 @@ export type ValueContainerComponent = < props: ValueContainerProps ) => ReactElement; +interface IsMultiValueContainerProps extends ValueContainerProps { + component: ValueContainerComponent; +} + // make ValueContainer a transition group const AnimatedValueContainer = (WrappedComponent: ValueContainerComponent) => >( props: ValueContainerProps ) => - ; + props.isMulti ? ( + + ) : ( + + ); + +const IsMultiValueContainer = ({ + component, + ...restProps +}: IsMultiValueContainerProps) => { + const multiProps = useIsMultiValueContainer(restProps); + + return ; +}; + +const useIsMultiValueContainer = ({ + children, + ...props +}: ValueContainerProps) => { + const { + isMulti, + hasValue, + innerProps, + selectProps: { components, controlShouldRenderValue }, + } = props; + + const [cssDisplayFlex, setCssDisplayFlex] = useState( + isMulti && controlShouldRenderValue && hasValue + ); + const [removingValue, setRemovingValue] = useState(false); + + useEffect(() => { + if (hasValue && !cssDisplayFlex) { + setCssDisplayFlex(true); + } + }, [hasValue, cssDisplayFlex]); + + useEffect(() => { + if (removingValue && !hasValue && cssDisplayFlex) { + setCssDisplayFlex(false); + } + setRemovingValue(false); + }, [removingValue, hasValue, cssDisplayFlex]); + + const onExited = () => setRemovingValue(true); + + const childMapper = (child: ReactNode) => { + if (isMulti && React.isValidElement(child)) { + // Add onExited callback to MultiValues + if (child.type === components.MultiValue) { + return React.cloneElement(child, { onExited }); + } + // While container flexed, Input cursor is shown after Placeholder text, + // so remove Placeholder until display is set back to grid + if (child.type === components.Placeholder && cssDisplayFlex) { + return null; + } + } + return child; + }; + + const newInnerProps = { + ...innerProps, + style: { + ...innerProps?.style, + display: cssDisplayFlex ? 'flex' : 'grid', + }, + }; + + const newProps = { + ...props, + innerProps: newInnerProps, + children: React.Children.toArray(children).map(childMapper), + }; + + return newProps; +}; export default AnimatedValueContainer; diff --git a/packages/react-select/src/animated/transitions.tsx b/packages/react-select/src/animated/transitions.tsx index f0fca0810e..7c48242ceb 100644 --- a/packages/react-select/src/animated/transitions.tsx +++ b/packages/react-select/src/animated/transitions.tsx @@ -127,7 +127,13 @@ export class Collapse extends Component { getTransition = (state: TransitionStatus) => this.transition[state]; render() { - const { children, in: inProp } = this.props; + const { children, in: inProp, onExited } = this.props; + const exitedProp = () => { + if (this.nodeRef.current && onExited) { + onExited(this.nodeRef.current); + } + }; + const { width } = this.state; return ( @@ -136,6 +142,7 @@ export class Collapse extends Component { mountOnEnter unmountOnExit in={inProp} + onExited={exitedProp} timeout={this.duration} nodeRef={this.nodeRef} > From b522ac658f85701ecf413436f3cf8d8d49117c82 Mon Sep 17 00:00:00 2001 From: Eric Bonow Date: Wed, 13 Oct 2021 16:40:26 -0700 Subject: [PATCH 4/5] Add changeset --- .changeset/silver-zebras-sing.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/silver-zebras-sing.md diff --git a/.changeset/silver-zebras-sing.md b/.changeset/silver-zebras-sing.md new file mode 100644 index 0000000000..f3c22ede96 --- /dev/null +++ b/.changeset/silver-zebras-sing.md @@ -0,0 +1,5 @@ +--- +'react-select': minor +--- + +Fix animated MultiValue transitions when being removed and change method used to generate unqiue keys for Option components. Closes #3648 , closes #4844 , closes #4602 From 8c9d5ca5669d5d21071dcd283164ef85f55f9ed4 Mon Sep 17 00:00:00 2001 From: Eric Bonow Date: Thu, 14 Oct 2021 17:52:59 -0700 Subject: [PATCH 5/5] Update silver-zebras-sing.md Update changeset to remove associated issue --- .changeset/silver-zebras-sing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/silver-zebras-sing.md b/.changeset/silver-zebras-sing.md index f3c22ede96..3a2cf2e17d 100644 --- a/.changeset/silver-zebras-sing.md +++ b/.changeset/silver-zebras-sing.md @@ -2,4 +2,4 @@ 'react-select': minor --- -Fix animated MultiValue transitions when being removed and change method used to generate unqiue keys for Option components. Closes #3648 , closes #4844 , closes #4602 +Fix animated MultiValue transitions when being removed and change method used to generate unqiue keys for Option components. Closes #4844 , closes #4602