Skip to content

Commit cecf7a6

Browse files
committed
Fix tests
1 parent 65c6ec7 commit cecf7a6

File tree

6 files changed

+71
-56
lines changed

6 files changed

+71
-56
lines changed

packages/react/src/field/root/FieldRoot.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ export const FieldRoot = React.forwardRef(function FieldRoot(
5656
setDirtyUnwrapped(value);
5757
}, []);
5858

59-
const invalid = Boolean(invalidProp || (name && {}.hasOwnProperty.call(errors, name)));
59+
const invalid = Boolean(
60+
invalidProp || (name && {}.hasOwnProperty.call(errors, name) && errors[name] !== undefined),
61+
);
6062

6163
const [validityData, setValidityData] = React.useState<FieldValidityData>({
6264
state: DEFAULT_VALIDITY_STATE,

packages/react/src/form/Form.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { FormContext } from './FormContext';
55
import { useEventCallback } from '../utils/useEventCallback';
66
import { useRenderElement } from '../utils/useRenderElement';
77

8+
const EMPTY = {};
9+
810
/**
911
* A native form element with consolidated error handling.
1012
* Renders a `<form>` element.
@@ -55,10 +57,8 @@ export const Form = React.forwardRef(function Form(
5557
}
5658
}, [errors, focusControl]);
5759

58-
const state = React.useMemo<Form.State>(() => ({}), []);
59-
6060
const renderElement = useRenderElement('form', componentProps, {
61-
state,
61+
state: EMPTY,
6262
ref: forwardedRef,
6363
props: [
6464
{
@@ -89,7 +89,7 @@ export const Form = React.forwardRef(function Form(
8989
});
9090

9191
const clearErrors = useEventCallback((name: string | undefined) => {
92-
if (name && errors && {}.hasOwnProperty.call(errors, name)) {
92+
if (name && errors && EMPTY.hasOwnProperty.call(errors, name)) {
9393
const nextErrors = { ...errors };
9494
delete nextErrors[name];
9595
onClearErrors(nextErrors);

packages/react/src/slider/control/SliderControl.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export const SliderControl = React.forwardRef(function SliderControl(
105105
onValueCommitted,
106106
orientation,
107107
range,
108+
registerFieldControlRef,
108109
setActive,
109110
setDragging,
110111
setValue,
@@ -352,7 +353,7 @@ export const SliderControl = React.forwardRef(function SliderControl(
352353

353354
const renderElement = useRenderElement('div', componentProps, {
354355
state,
355-
ref: [forwardedRef, controlRef, setStylesRef],
356+
ref: [forwardedRef, registerFieldControlRef, controlRef, setStylesRef],
356357
props: [
357358
{
358359
onPointerDown(event: React.PointerEvent<HTMLDivElement>) {

packages/react/src/slider/root/SliderRoot.test.tsx

+7-8
Original file line numberDiff line numberDiff line change
@@ -1894,18 +1894,17 @@ describe.skipIf(typeof Touch === 'undefined')('<Slider.Root />', () => {
18941894
});
18951895

18961896
it('should receive name prop from Field.Root', async () => {
1897-
const { getByTestId } = await render(
1897+
const { container } = await render(
18981898
<Field.Root name="field-slider">
18991899
<Slider.Root>
19001900
<Slider.Control>
1901-
<Slider.Thumb data-testid="thumb" />
1901+
<Slider.Thumb />
19021902
</Slider.Control>
19031903
</Slider.Root>
19041904
</Field.Root>,
19051905
);
19061906

1907-
const thumb = getByTestId('thumb');
1908-
const input = thumb.querySelector('input');
1907+
const input = container.querySelector('input[type="hidden"]');
19091908
expect(input).to.have.attribute('name', 'field-slider');
19101909
});
19111910

@@ -1976,7 +1975,7 @@ describe.skipIf(typeof Touch === 'undefined')('<Slider.Root />', () => {
19761975
});
19771976

19781977
it('prop: validate', async () => {
1979-
const { container } = await render(
1978+
await render(
19801979
<Field.Root validate={() => 'error'}>
19811980
<Slider.Root>
19821981
<Slider.Control>
@@ -1987,7 +1986,7 @@ describe.skipIf(typeof Touch === 'undefined')('<Slider.Root />', () => {
19871986
</Field.Root>,
19881987
);
19891988

1990-
const input = container.querySelector<HTMLInputElement>('input')!;
1989+
const input = screen.getByRole('slider');
19911990
const thumb = screen.getByTestId('thumb');
19921991

19931992
expect(input).not.to.have.attribute('aria-invalid');
@@ -2024,7 +2023,7 @@ describe.skipIf(typeof Touch === 'undefined')('<Slider.Root />', () => {
20242023
});
20252024

20262025
it('prop: validationMode=onBlur', async () => {
2027-
const { container } = await render(
2026+
await render(
20282027
<Field.Root
20292028
validationMode="onBlur"
20302029
validate={(value) => {
@@ -2040,7 +2039,7 @@ describe.skipIf(typeof Touch === 'undefined')('<Slider.Root />', () => {
20402039
</Field.Root>,
20412040
);
20422041

2043-
const input = container.querySelector<HTMLInputElement>('input')!;
2042+
const input = screen.getByRole('slider');
20442043
const thumb = screen.getByTestId('thumb');
20452044

20462045
expect(input).not.to.have.attribute('aria-invalid');

packages/react/src/slider/root/SliderRoot.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ export const SliderRoot = React.forwardRef(function SliderRoot<
144144
controlRef,
145145
});
146146

147+
const registerFieldControlRef = useEventCallback((element: HTMLElement | null) => {
148+
if (element) {
149+
controlRef.current = element;
150+
}
151+
});
152+
147153
const range = Array.isArray(valueUnwrapped);
148154

149155
const values = React.useMemo(() => {
@@ -271,6 +277,7 @@ export const SliderRoot = React.forwardRef(function SliderRoot<
271277
onValueCommitted,
272278
orientation,
273279
range,
280+
registerFieldControlRef,
274281
setActive,
275282
setDragging,
276283
setValue,
@@ -298,6 +305,7 @@ export const SliderRoot = React.forwardRef(function SliderRoot<
298305
onValueCommitted,
299306
orientation,
300307
range,
308+
registerFieldControlRef,
301309
setActive,
302310
setDragging,
303311
setValue,

packages/react/src/slider/thumb/SliderThumb.tsx

+47-42
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export const SliderThumb = React.forwardRef(function SliderThumb(
137137

138138
const direction = useDirection();
139139
const { setTouched, setFocused, validationMode } = useFieldRootContext();
140-
const { commitValidation } = useFieldControlValidation();
140+
const { commitValidation, getValidationProps } = useFieldControlValidation();
141141

142142
const thumbRef = React.useRef<HTMLElement>(null);
143143

@@ -292,48 +292,53 @@ export const SliderThumb = React.forwardRef(function SliderThumb(
292292
cssWritingMode = isRtl ? 'vertical-rl' : 'vertical-lr';
293293
}
294294

295-
const inputProps = mergeProps<'input'>({
296-
'aria-label':
297-
typeof getAriaLabelProp === 'function' ? getAriaLabelProp(index) : elementProps['aria-label'],
298-
'aria-labelledby': labelId,
299-
'aria-orientation': orientation,
300-
'aria-valuemax': max,
301-
'aria-valuemin': min,
302-
'aria-valuenow': thumbValue,
303-
'aria-valuetext':
304-
typeof getAriaValueTextProp === 'function'
305-
? getAriaValueTextProp(
306-
formatNumber(thumbValue, locale, formatOptionsRef.current ?? undefined),
307-
thumbValue,
308-
index,
309-
)
310-
: elementProps['aria-valuetext'] ||
311-
getDefaultAriaValueText(
312-
sliderValues,
313-
index,
314-
formatOptionsRef.current ?? undefined,
315-
locale,
316-
),
317-
[SliderThumbDataAttributes.index as string]: index,
318-
disabled,
319-
id: inputId,
320-
max,
321-
min,
322-
onChange(event: React.ChangeEvent<HTMLInputElement>) {
323-
handleInputChange(event.target.valueAsNumber, index, event);
324-
},
325-
step,
326-
style: {
327-
...visuallyHidden,
328-
// So that VoiceOver's focus indicator matches the thumb's dimensions
329-
width: '100%',
330-
height: '100%',
331-
writingMode: cssWritingMode,
295+
const inputProps = mergeProps<'input'>(
296+
{
297+
'aria-label':
298+
typeof getAriaLabelProp === 'function'
299+
? getAriaLabelProp(index)
300+
: elementProps['aria-label'],
301+
'aria-labelledby': labelId,
302+
'aria-orientation': orientation,
303+
'aria-valuemax': max,
304+
'aria-valuemin': min,
305+
'aria-valuenow': thumbValue,
306+
'aria-valuetext':
307+
typeof getAriaValueTextProp === 'function'
308+
? getAriaValueTextProp(
309+
formatNumber(thumbValue, locale, formatOptionsRef.current ?? undefined),
310+
thumbValue,
311+
index,
312+
)
313+
: elementProps['aria-valuetext'] ||
314+
getDefaultAriaValueText(
315+
sliderValues,
316+
index,
317+
formatOptionsRef.current ?? undefined,
318+
locale,
319+
),
320+
[SliderThumbDataAttributes.index as string]: index,
321+
disabled,
322+
id: inputId,
323+
max,
324+
min,
325+
onChange(event: React.ChangeEvent<HTMLInputElement>) {
326+
handleInputChange(event.target.valueAsNumber, index, event);
327+
},
328+
step,
329+
style: {
330+
...visuallyHidden,
331+
// So that VoiceOver's focus indicator matches the thumb's dimensions
332+
width: '100%',
333+
height: '100%',
334+
writingMode: cssWritingMode,
335+
},
336+
tabIndex: -1,
337+
type: 'range',
338+
value: thumbValue ?? '',
332339
},
333-
tabIndex: -1,
334-
type: 'range',
335-
value: thumbValue ?? '',
336-
});
340+
getValidationProps,
341+
);
337342

338343
if (typeof render === 'function') {
339344
return render(thumbProps, inputProps, state);

0 commit comments

Comments
 (0)