Skip to content

Commit e629d68

Browse files
authored
fix(RadioButtonGroup): set default width to 100% and add margin between content and input (#1044)
1 parent cf3ccc2 commit e629d68

File tree

2 files changed

+49
-13
lines changed

2 files changed

+49
-13
lines changed

packages/react/src/components/radio-button-group/radio-button-group.test.tsx.snap

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ exports[`Radio button Matches the snapshot 1`] = `
123123
border: none;
124124
margin: 0;
125125
padding: 0;
126+
width: 100%;
126127
}
127128
128129
.c1 {

packages/react/src/components/radio-button-group/radio-button-group.tsx

+48-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { ChangeEvent, useCallback, useRef, useState, VoidFunctionComponent } from 'react';
2-
import styled from 'styled-components';
1+
import { ChangeEvent, Fragment, TransitionEvent, useCallback, useRef, useState, VoidFunctionComponent } from 'react';
2+
import styled, { css } from 'styled-components';
33
import { useDataAttributes } from '../../hooks/use-data-attributes';
44
import { Tooltip, TooltipProps } from '../tooltip/tooltip';
55
import { RadioButton } from '../radio-button/radio-button';
@@ -9,6 +9,7 @@ const StyledFieldset = styled.fieldset`
99
border: none;
1010
margin: 0;
1111
padding: 0;
12+
width: 100%;
1213
`;
1314

1415
const StyledLegend = styled.legend<{ isMobile: boolean }>`
@@ -30,13 +31,40 @@ const StyledTooltip = styled(Tooltip)`
3031
margin-left: calc(var(--spacing-1x) * 1.5);
3132
`;
3233

33-
const ContentWrapper = styled.div<{ $isExpanded: boolean, $maxHeight?: number, $transitionDuration: number }>(({ $isExpanded, $maxHeight = 500, $transitionDuration }) => `
34-
overflow: hidden;
34+
interface ContentWrapperProps {
35+
$isCollapsing: boolean;
36+
$isExpanded: boolean;
37+
$maxHeight?: number;
38+
$transitionDuration: number;
39+
}
40+
41+
function getTransition({ $isCollapsing, $transitionDuration }: ContentWrapperProps): string {
42+
const maxHeightTransition = `max-height ${$transitionDuration}ms ease-in-out`;
43+
if ($isCollapsing) {
44+
const marginTransition = `margin-bottom ${$transitionDuration / 2}ms ${$transitionDuration / 2}ms ease-in-out`;
45+
return `${maxHeightTransition}, ${marginTransition}`;
46+
}
47+
48+
return maxHeightTransition;
49+
}
50+
51+
const ContentWrapper = styled.div<ContentWrapperProps>(({
52+
$isExpanded,
53+
$maxHeight = 500,
54+
}) => css`
3555
max-height: ${$isExpanded ? `${$maxHeight}px` : '0'};
36-
transition: max-height ${$transitionDuration}ms ease-in-out;
56+
overflow: hidden;
57+
transition: ${getTransition};
58+
59+
:not(:last-child) {
60+
margin-bottom: ${$isExpanded ? 'var(--spacing-1x)' : '0'};
61+
}
3762
`);
3863

39-
const InnerContent = styled.div<{ $isExpanded: boolean, $transitionStarted: boolean }>(({ $isExpanded, $transitionStarted }) => `
64+
const InnerContent = styled.div<{ $isExpanded: boolean, $transitionStarted: boolean }>(({
65+
$isExpanded,
66+
$transitionStarted,
67+
}) => `
4068
display: ${$isExpanded || $transitionStarted ? 'block' : 'none'};
4169
`);
4270

@@ -90,6 +118,7 @@ export const RadioButtonGroup: VoidFunctionComponent<RadioButtonGroupProps> = ({
90118
);
91119
const prevChecked = useRef(currentChecked);
92120
const [transitionStarted, setTransitionStarted] = useState(false);
121+
const [collapsingElement, setCollapsingElement] = useState<string>();
93122
const dataAttributes = useDataAttributes(otherProps);
94123
const dataTestId = dataAttributes['data-testid'] ? dataAttributes['data-testid'] : 'radio-button-group';
95124

@@ -109,23 +138,27 @@ export const RadioButtonGroup: VoidFunctionComponent<RadioButtonGroupProps> = ({
109138
|| buttons.find((b) => b.value === currentChecked)?.content;
110139

111140
if (willHaveTransition) {
141+
setCollapsingElement(prevChecked.current);
112142
setTransitionStarted(true);
113143
}
114144
newRefValue = currentChecked;
115145
}
116146

117-
if (newRefValue !== null) {
147+
if (newRefValue !== undefined) {
118148
prevChecked.current = newRefValue;
119149
}
120150

121-
const handleTransitionEnd = useCallback(() => {
122-
setTransitionStarted(false);
151+
const handleTransitionEnd = useCallback((event: TransitionEvent) => {
152+
if (event.propertyName === 'max-height') {
153+
setCollapsingElement(undefined);
154+
setTransitionStarted(false);
155+
}
123156
}, []);
124157

125158
return (
126-
<StyledFieldset className={className}>
159+
<StyledFieldset key={label} className={className}>
127160
{label && (
128-
<StyledLegend isMobile={isMobile}>
161+
<StyledLegend key="legend" isMobile={isMobile}>
129162
{label}
130163
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
131164
{tooltip && <StyledTooltip {...tooltip} />}
@@ -135,7 +168,7 @@ export const RadioButtonGroup: VoidFunctionComponent<RadioButtonGroupProps> = ({
135168
const isExpanded = currentChecked === button.value;
136169

137170
return (
138-
<>
171+
<Fragment key={`${groupName}-${button.value}-fragment`}>
139172
<StyledRadioButton
140173
key={`${groupName}-${button.value}`}
141174
aria-label={ariaLabel}
@@ -153,9 +186,11 @@ export const RadioButtonGroup: VoidFunctionComponent<RadioButtonGroupProps> = ({
153186
/>
154187
{button.content && (
155188
<ContentWrapper
189+
key={`${groupName}-${button.value}-content`}
156190
data-testid="content-wrapper"
157191
$maxHeight={button.content.maxHeight}
158192
$isExpanded={isExpanded}
193+
$isCollapsing={transitionStarted && collapsingElement === button.value}
159194
$transitionDuration={transitionDuration}
160195
onTransitionEnd={handleTransitionEnd}
161196
>
@@ -167,7 +202,7 @@ export const RadioButtonGroup: VoidFunctionComponent<RadioButtonGroupProps> = ({
167202
</InnerContent>
168203
</ContentWrapper>
169204
)}
170-
</>
205+
</Fragment>
171206
);
172207
})}
173208
</StyledFieldset>

0 commit comments

Comments
 (0)