Skip to content

Commit c040aab

Browse files
committed
Fix dynamic number of RadioButtonGroup options
1 parent 4c9a39b commit c040aab

File tree

5 files changed

+52
-93
lines changed

5 files changed

+52
-93
lines changed

.changeset/chatty-starfishes-march.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@sumup-oss/circuit-ui": patch
3+
---
4+
5+
Fixed rendering of a dynamic number of RadioButtonGroup options.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.label-text {
2+
display: inline-block;
3+
padding-left: var(--cui-spacings-byte);
4+
}

packages/circuit-ui/components/RadioButton/RadioButton.tsx

+18-18
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
'use client';
1717

18-
import { forwardRef, useId, type InputHTMLAttributes } from 'react';
18+
import { forwardRef, useId } from 'react';
1919

2020
import {
2121
AccessibilityError,
@@ -24,11 +24,14 @@ import {
2424
import { FieldWrapper, FieldDescription } from '../Field/index.js';
2525
import { clsx } from '../../styles/clsx.js';
2626
import { utilClasses } from '../../styles/utility.js';
27-
import { deprecate } from '../../util/logger.js';
28-
import { RadioButtonInput } from '../RadioButtonGroup/RadioButtonInput.js';
27+
import {
28+
RadioButtonInput,
29+
type RadioButtonInputProps,
30+
} from '../RadioButtonGroup/RadioButtonInput.js';
31+
32+
import classes from './RadioButton.module.css';
2933

30-
export interface RadioButtonProps
31-
extends InputHTMLAttributes<HTMLInputElement> {
34+
export interface RadioButtonProps extends Omit<RadioButtonInputProps, 'align'> {
3235
/**
3336
* A clear and concise description of the option's purpose.
3437
*/
@@ -41,7 +44,7 @@ export interface RadioButtonProps
4144
}
4245

4346
/**
44-
* @deprecated Use the {@link RadioButtonGroup} component instead.
47+
* @deprecated Use the {@link RadioButtonGroup} or {@link RadioButtonInput} components instead.
4548
*/
4649
export const RadioButton = forwardRef<HTMLInputElement, RadioButtonProps>(
4750
(
@@ -63,12 +66,6 @@ export const RadioButton = forwardRef<HTMLInputElement, RadioButtonProps>(
6366

6467
const descriptionIds = clsx(describedBy, description && descriptionId);
6568

66-
if (process.env.NODE_ENV !== 'production') {
67-
deprecate(
68-
'RadioButton',
69-
'The RadioButton component has been deprecated. Use the RadioButtonGroup or RadioButtonInput components instead.',
70-
);
71-
}
7269
if (
7370
process.env.NODE_ENV !== 'production' &&
7471
process.env.NODE_ENV !== 'test' &&
@@ -88,13 +85,16 @@ export const RadioButton = forwardRef<HTMLInputElement, RadioButtonProps>(
8885
id={inputId}
8986
disabled={disabled}
9087
aria-describedby={descriptionIds}
88+
align="start"
9189
>
92-
{label}
93-
{description && (
94-
<FieldDescription aria-hidden="true">
95-
{description}
96-
</FieldDescription>
97-
)}
90+
<span className={classes['label-text']}>
91+
{label}
92+
{description && (
93+
<FieldDescription aria-hidden="true">
94+
{description}
95+
</FieldDescription>
96+
)}
97+
</span>
9898
</RadioButtonInput>
9999
{description && (
100100
<p id={descriptionId} className={utilClasses.hideVisually}>

packages/circuit-ui/components/RadioButtonGroup/RadioButtonGroup.module.css

-5
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,3 @@
33
flex-direction: column;
44
gap: var(--cui-spacings-bit);
55
}
6-
7-
.label-text {
8-
display: inline-block;
9-
padding-left: var(--cui-spacings-byte);
10-
}

packages/circuit-ui/components/RadioButtonGroup/RadioButtonGroup.tsx

+25-70
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,22 @@ import {
2828
FieldValidationHint,
2929
FieldLegend,
3030
FieldSet,
31-
FieldWrapper,
32-
FieldDescription,
3331
} from '../Field/index.js';
3432
import {
3533
AccessibilityError,
3634
isSufficientlyLabelled,
3735
} from '../../util/errors.js';
3836
import { isEmpty } from '../../util/helpers.js';
39-
import { utilClasses } from '../../styles/utility.js';
4037
import { clsx } from '../../styles/clsx.js';
41-
4238
import {
43-
RadioButtonInput,
44-
type RadioButtonInputProps,
45-
} from './RadioButtonInput.js';
39+
RadioButton,
40+
type RadioButtonProps,
41+
} from '../RadioButton/RadioButton.js';
42+
4643
import classes from './RadioButtonGroup.module.css';
4744

4845
type Option = Omit<
49-
RadioButtonInputProps,
46+
RadioButtonProps,
5047
'onChange' | 'onBlur' | 'name' | 'children'
5148
> & {
5249
/**
@@ -73,12 +70,12 @@ export interface RadioButtonGroupProps
7370
* A callback that is called when any of the inputs change their values.
7471
* Passed on to the RadioButtons.
7572
*/
76-
onChange?: RadioButtonInputProps['onChange'];
73+
onChange?: RadioButtonProps['onChange'];
7774
/**
7875
* A callback that is called when any of the inputs lose focus.
7976
* Passed on to the RadioButtons.
8077
*/
81-
onBlur?: RadioButtonInputProps['onBlur'];
78+
onBlur?: RadioButtonProps['onBlur'];
8279
/**
8380
* A visually hidden description of the selector group for screen readers.
8481
*/
@@ -91,11 +88,11 @@ export interface RadioButtonGroupProps
9188
/**
9289
* The value of the currently checked RadioButton.
9390
*/
94-
value?: RadioButtonInputProps['value'];
91+
value?: RadioButtonProps['value'];
9592
/**
9693
* The value of the currently checked RadioButton.
9794
*/
98-
defaultValue?: RadioButtonInputProps['value'];
95+
defaultValue?: RadioButtonProps['value'];
9996
/**
10097
* The ref to the HTML DOM element
10198
*/
@@ -194,64 +191,22 @@ export const RadioButtonGroup = forwardRef(
194191
/>
195192
</FieldLegend>
196193
<div className={classes.base}>
197-
{options.map(
198-
({
199-
className,
200-
style,
201-
label: optionLabel,
202-
description,
203-
'aria-describedby': describedBy,
204-
...option
205-
}) => {
206-
const optionDescriptionId = useId();
207-
const optionDescriptionIds = clsx(
208-
description && optionDescriptionId,
209-
describedBy,
210-
);
211-
212-
return (
213-
<FieldWrapper
214-
key={option.value?.toString() || optionLabel}
215-
className={className}
216-
style={style}
217-
disabled={disabled || option.disabled}
218-
>
219-
<RadioButtonInput
220-
{...option}
221-
name={name}
222-
onChange={onChange}
223-
onBlur={onBlur}
224-
disabled={disabled || option.disabled}
225-
checked={value ? option.value === value : option.checked}
226-
aria-describedby={optionDescriptionIds}
227-
defaultChecked={
228-
defaultValue
229-
? option.value === defaultValue
230-
: option.defaultChecked
231-
}
232-
align="start"
233-
>
234-
<span className={classes['label-text']}>
235-
{optionLabel}
236-
{description && (
237-
<FieldDescription aria-hidden="true">
238-
{description}
239-
</FieldDescription>
240-
)}
241-
</span>
242-
</RadioButtonInput>
243-
{description && (
244-
<p
245-
id={optionDescriptionId}
246-
className={utilClasses.hideVisually}
247-
>
248-
{description}
249-
</p>
250-
)}
251-
</FieldWrapper>
252-
);
253-
},
254-
)}
194+
{options.map((option) => (
195+
<RadioButton
196+
{...option}
197+
key={option.value?.toString() || option.label}
198+
disabled={disabled || option.disabled}
199+
name={name}
200+
onChange={onChange}
201+
onBlur={onBlur}
202+
checked={value ? option.value === value : option.checked}
203+
defaultChecked={
204+
defaultValue
205+
? option.value === defaultValue
206+
: option.defaultChecked
207+
}
208+
/>
209+
))}
255210
</div>
256211
<FieldValidationHint
257212
id={validationHintId}

0 commit comments

Comments
 (0)