Skip to content

Commit c358658

Browse files
committed
Fix conditional hook call error
1 parent bd0a99b commit c358658

File tree

9 files changed

+87
-81
lines changed

9 files changed

+87
-81
lines changed

.changeset/wicked-pianos-wait.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 a conditional hook call error when violating accessibility requirements.

packages/circuit-ui/components/Checkbox/CheckboxInput.tsx

+11-11
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,6 @@ export const CheckboxInput = forwardRef<HTMLInputElement, CheckboxInputProps>(
6767
},
6868
ref,
6969
) => {
70-
if (
71-
process.env.NODE_ENV !== 'production' &&
72-
process.env.NODE_ENV !== 'test' &&
73-
!isSufficientlyLabelled(children, props)
74-
) {
75-
throw new AccessibilityError(
76-
'CheckboxInput',
77-
'The input is missing a valid label.',
78-
);
79-
}
80-
8170
const inputRef = useRef<HTMLInputElement>(null);
8271

8372
// biome-ignore lint/correctness/useExhaustiveDependencies: Because it came from the props, we keep the `indeterminate` state even if the `checked` one is changed.
@@ -90,6 +79,17 @@ export const CheckboxInput = forwardRef<HTMLInputElement, CheckboxInputProps>(
9079
const id = useId();
9180
const inputId = customId || id;
9281

82+
if (
83+
process.env.NODE_ENV !== 'production' &&
84+
process.env.NODE_ENV !== 'test' &&
85+
!isSufficientlyLabelled(children, props)
86+
) {
87+
throw new AccessibilityError(
88+
'CheckboxInput',
89+
'The input is missing a valid label.',
90+
);
91+
}
92+
9393
return (
9494
<>
9595
<input

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

+24-24
Original file line numberDiff line numberDiff line change
@@ -124,30 +124,6 @@ export const ImageInput = ({
124124
'aria-describedby': descriptionId,
125125
...props
126126
}: ImageInputProps) => {
127-
if (
128-
process.env.NODE_ENV !== 'production' &&
129-
process.env.NODE_ENV !== 'test'
130-
) {
131-
if (!isSufficientlyLabelled(label)) {
132-
throw new AccessibilityError(
133-
'ImageInput',
134-
'The `label` prop is missing or invalid.',
135-
);
136-
}
137-
if (!isSufficientlyLabelled(clearButtonLabel)) {
138-
throw new AccessibilityError(
139-
'ImageInput',
140-
'The `clearButtonLabel` prop is missing or invalid.',
141-
);
142-
}
143-
if (!isSufficientlyLabelled(loadingLabel)) {
144-
throw new AccessibilityError(
145-
'ImageInput',
146-
'The `loadingLabel` prop is missing or invalid.',
147-
);
148-
}
149-
}
150-
151127
const inputRef = useRef<HTMLInputElement>(null);
152128
const id = useId();
153129
const inputId = customId || id;
@@ -242,6 +218,30 @@ export const ImageInput = ({
242218
}
243219
};
244220

221+
if (
222+
process.env.NODE_ENV !== 'production' &&
223+
process.env.NODE_ENV !== 'test'
224+
) {
225+
if (!isSufficientlyLabelled(label)) {
226+
throw new AccessibilityError(
227+
'ImageInput',
228+
'The `label` prop is missing or invalid.',
229+
);
230+
}
231+
if (!isSufficientlyLabelled(clearButtonLabel)) {
232+
throw new AccessibilityError(
233+
'ImageInput',
234+
'The `clearButtonLabel` prop is missing or invalid.',
235+
);
236+
}
237+
if (!isSufficientlyLabelled(loadingLabel)) {
238+
throw new AccessibilityError(
239+
'ImageInput',
240+
'The `loadingLabel` prop is missing or invalid.',
241+
);
242+
}
243+
}
244+
245245
return (
246246
<FieldWrapper className={className} style={style} disabled={disabled}>
247247
<FieldLabelText

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

+12-12
Original file line numberDiff line numberDiff line change
@@ -146,18 +146,6 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
146146
},
147147
ref,
148148
): ReturnType => {
149-
if (
150-
process.env.NODE_ENV !== 'production' &&
151-
process.env.NODE_ENV !== 'test' &&
152-
props.type !== 'hidden' &&
153-
!isSufficientlyLabelled(label)
154-
) {
155-
throw new AccessibilityError(
156-
'Input',
157-
'The `label` prop is missing or invalid. Pass `hideLabel` if you intend to hide the label visually.',
158-
);
159-
}
160-
161149
const id = useId();
162150
const inputId = customId || id;
163151
const validationHintId = useId();
@@ -171,6 +159,18 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
171159
const hasPrefix = Boolean(prefix);
172160
const hasSuffix = Boolean(suffix);
173161

162+
if (
163+
process.env.NODE_ENV !== 'production' &&
164+
process.env.NODE_ENV !== 'test' &&
165+
props.type !== 'hidden' &&
166+
!isSufficientlyLabelled(label)
167+
) {
168+
throw new AccessibilityError(
169+
'Input',
170+
'The `label` prop is missing or invalid. Pass `hideLabel` if you intend to hide the label visually.',
171+
);
172+
}
173+
174174
return (
175175
<FieldWrapper className={className} style={style} disabled={disabled}>
176176
<FieldLabel htmlFor={inputId}>

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

+7-6
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ export const ListItemGroup = forwardRef<HTMLDivElement, ListItemGroupProps>(
7979
},
8080
ref,
8181
) => {
82+
const [focusedItemKey, setFocusedItemKey] = useState<
83+
ItemProps['key'] | null
84+
>(null);
85+
86+
const isPlain = variant === 'plain';
87+
const isInteractive = items.some((item) => !!item.href || !!item.onClick);
88+
8289
if (
8390
process.env.NODE_ENV !== 'production' &&
8491
process.env.NODE_ENV !== 'test' &&
@@ -89,12 +96,6 @@ export const ListItemGroup = forwardRef<HTMLDivElement, ListItemGroupProps>(
8996
'The `label` prop is missing. This is an accessibility requirement. Pass `hideLabel` if you intend to hide the label visually.',
9097
);
9198
}
92-
const [focusedItemKey, setFocusedItemKey] = useState<
93-
ItemProps['key'] | null
94-
>(null);
95-
96-
const isPlain = variant === 'plain';
97-
const isInteractive = items.some((item) => !!item.href || !!item.onClick);
9899

99100
return (
100101
<div

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

+6-6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ export const RadioButton = forwardRef<HTMLInputElement, RadioButtonProps>(
5757
},
5858
ref,
5959
) => {
60+
const id = useId();
61+
const inputId = customId || id;
62+
const descriptionId = useId();
63+
64+
const descriptionIds = clsx(describedBy, description && descriptionId);
65+
6066
if (process.env.NODE_ENV !== 'production') {
6167
deprecate(
6268
'RadioButton',
@@ -74,12 +80,6 @@ export const RadioButton = forwardRef<HTMLInputElement, RadioButtonProps>(
7480
);
7581
}
7682

77-
const id = useId();
78-
const inputId = customId || id;
79-
const descriptionId = useId();
80-
81-
const descriptionIds = clsx(describedBy, description && descriptionId);
82-
8383
return (
8484
<FieldWrapper className={className} style={style} disabled={disabled}>
8585
<RadioButtonInput

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export const RadioButtonInput = forwardRef<
4343
{ 'id': customId, className, style, children, align = 'center', ...props },
4444
ref,
4545
) => {
46+
const id = useId();
47+
const inputId = customId || id;
48+
4649
if (
4750
process.env.NODE_ENV !== 'production' &&
4851
process.env.NODE_ENV !== 'test' &&
@@ -54,9 +57,6 @@ export const RadioButtonInput = forwardRef<
5457
);
5558
}
5659

57-
const id = useId();
58-
const inputId = customId || id;
59-
6060
return (
6161
<>
6262
<input

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

+11-11
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,6 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
129129
},
130130
ref,
131131
): ReturnType => {
132-
if (
133-
process.env.NODE_ENV !== 'production' &&
134-
process.env.NODE_ENV !== 'test' &&
135-
!isSufficientlyLabelled(label)
136-
) {
137-
throw new AccessibilityError(
138-
'Select',
139-
'The `label` prop is missing or invalid. Pass `hideLabel` if you intend to hide the label visually.',
140-
);
141-
}
142-
143132
const id = useId();
144133
const selectId = customId || id;
145134
const validationHintId = useId();
@@ -152,6 +141,17 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
152141
);
153142
const hasPrefix = Boolean(prefix);
154143

144+
if (
145+
process.env.NODE_ENV !== 'production' &&
146+
process.env.NODE_ENV !== 'test' &&
147+
!isSufficientlyLabelled(label)
148+
) {
149+
throw new AccessibilityError(
150+
'Select',
151+
'The `label` prop is missing or invalid. Pass `hideLabel` if you intend to hide the label visually.',
152+
);
153+
}
154+
155155
return (
156156
<FieldWrapper className={className} style={style} disabled={disabled}>
157157
<FieldLabel htmlFor={selectId}>

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

+8-8
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ export const Toggle = forwardRef<HTMLButtonElement, ToggleProps>(
7070
},
7171
ref,
7272
) => {
73+
const switchId = useId();
74+
const labelId = useId();
75+
const descriptionId = useId();
76+
77+
const descriptionIds = [describedBy, description && descriptionId]
78+
.filter(Boolean)
79+
.join(' ');
80+
7381
if (
7482
process.env.NODE_ENV !== 'production' &&
7583
process.env.NODE_ENV !== 'test' &&
@@ -99,14 +107,6 @@ export const Toggle = forwardRef<HTMLButtonElement, ToggleProps>(
99107
}
100108
}
101109

102-
const switchId = useId();
103-
const labelId = useId();
104-
const descriptionId = useId();
105-
106-
const descriptionIds = [describedBy, description && descriptionId]
107-
.filter(Boolean)
108-
.join(' ');
109-
110110
return (
111111
<FieldWrapper
112112
disabled={props.disabled}

0 commit comments

Comments
 (0)