Skip to content

Commit 63d8156

Browse files
committed
Revert "Change all uses of RHF <Controller> to useController (#2102)"
e2a7bcd Will put back later today
1 parent 44c646f commit 63d8156

File tree

7 files changed

+195
-165
lines changed

7 files changed

+195
-165
lines changed

.eslintrc.cjs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,7 @@ module.exports = {
4141
'@typescript-eslint/no-empty-interface': 'off',
4242
'@typescript-eslint/ban-ts-comment': 'off',
4343
'@typescript-eslint/no-non-null-assertion': 'off',
44-
'@typescript-eslint/no-unused-vars': [
45-
'error',
46-
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
47-
],
44+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
4845
eqeqeq: ['error', 'always', { null: 'ignore' }],
4946
'import/no-default-export': 'error',
5047
'import/no-unresolved': 'off', // plugin doesn't know anything

app/components/form/fields/CheckboxField.tsx

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@
55
*
66
* Copyright Oxide Computer Company
77
*/
8-
import {
9-
useController,
10-
type Control,
11-
type FieldPath,
12-
type FieldValues,
13-
} from 'react-hook-form'
8+
import { Controller, type Control, type FieldPath, type FieldValues } from 'react-hook-form'
149

1510
import { Checkbox, type CheckboxProps } from '~/ui/lib/Checkbox'
1611

@@ -29,34 +24,35 @@ export const CheckboxField = <
2924
control,
3025
name,
3126
...props
32-
}: CheckboxFieldProps<TFieldValues, TName>) => {
33-
const {
34-
field: { onChange, value },
35-
} = useController({ name, control })
36-
return (
37-
<Checkbox
38-
{...props}
39-
// If value is an array, we're dealing with a set of checkboxes that
40-
// have the same name and different `value` attrs, and are therefore
41-
// supposed to produce an array of the values that are checked. `value`
42-
// is the value in form state, which can be a bool or array.
43-
// `props.value` is the value string of the current checkbox, which is
44-
// only relevant in the array case
45-
onChange={(e) => {
46-
if (Array.isArray(value) && props.value) {
47-
// it's one of a set of checkboxes. if it was just checked, we're
48-
// adding it to the array, otherwise we're removing it
49-
const valueArray = value as string[]
50-
const newValue = e.target.checked
51-
? [...valueArray, props.value]
52-
: valueArray.filter((x) => x !== props.value)
53-
onChange(newValue)
54-
} else {
55-
// it's a single checkbox
56-
onChange(e.target.checked)
57-
}
58-
}}
59-
checked={Array.isArray(value) ? value.includes(props.value) : value}
60-
/>
61-
)
62-
}
27+
}: CheckboxFieldProps<TFieldValues, TName>) => (
28+
<Controller
29+
name={name}
30+
control={control}
31+
render={({ field: { onChange, value } }) => (
32+
<Checkbox
33+
{...props}
34+
// If value is an array, we're dealing with a set of checkboxes that
35+
// have the same name and different `value` attrs, and are therefore
36+
// supposed to produce an array of the values that are checked. `value`
37+
// is the value in form state, which can be a bool or array.
38+
// `props.value` is the value string of the current checkbox, which is
39+
// only relevant in the array case
40+
onChange={(e) => {
41+
if (Array.isArray(value) && props.value) {
42+
// it's one of a set of checkboxes. if it was just checked, we're
43+
// adding it to the array, otherwise we're removing it
44+
const valueArray = value as string[]
45+
const newValue = e.target.checked
46+
? [...valueArray, props.value]
47+
: valueArray.filter((x) => x !== props.value)
48+
onChange(newValue)
49+
} else {
50+
// it's a single checkbox
51+
onChange(e.target.checked)
52+
}
53+
}}
54+
checked={Array.isArray(value) ? value.includes(props.value) : value}
55+
/>
56+
)}
57+
/>
58+
)

app/components/form/fields/FileField.tsx

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@
55
*
66
* Copyright Oxide Computer Company
77
*/
8-
import {
9-
useController,
10-
type Control,
11-
type FieldPath,
12-
type FieldValues,
13-
} from 'react-hook-form'
8+
import { Controller, type Control, type FieldPath, type FieldValues } from 'react-hook-form'
149

1510
import { FieldLabel } from '~/ui/lib/FieldLabel'
1611
import { FileInput } from '~/ui/lib/FileInput'
@@ -42,27 +37,37 @@ export function FileField<
4237
description?: string | React.ReactNode
4338
disabled?: boolean
4439
}) {
45-
const {
46-
field: { value: _, ...rest },
47-
fieldState: { error },
48-
} = useController({ name, control, rules: { required } })
4940
return (
50-
<div>
51-
<div className="mb-2">
52-
<FieldLabel id={`${id}-label`} htmlFor={id} tip={tooltipText} optional={!required}>
53-
{label}
54-
</FieldLabel>
55-
{description && <TextInputHint id={`${id}-help-text`}>{description}</TextInputHint>}
56-
</div>
57-
<FileInput
58-
id={id}
59-
className="mt-2"
60-
accept={accept}
61-
disabled={disabled}
62-
{...rest}
63-
error={!!error}
64-
/>
65-
<ErrorMessage error={error} label={label} />
66-
</div>
41+
<Controller
42+
name={name}
43+
control={control}
44+
rules={{ required }}
45+
render={({ field: { value: _value, ...rest }, fieldState: { error } }) => (
46+
<div>
47+
<div className="mb-2">
48+
<FieldLabel
49+
id={`${id}-label`}
50+
htmlFor={id}
51+
tip={tooltipText}
52+
optional={!required}
53+
>
54+
{label}
55+
</FieldLabel>
56+
{description && (
57+
<TextInputHint id={`${id}-help-text`}>{description}</TextInputHint>
58+
)}
59+
</div>
60+
<FileInput
61+
id={id}
62+
className="mt-2"
63+
accept={accept}
64+
disabled={disabled}
65+
{...rest}
66+
error={!!error}
67+
/>
68+
<ErrorMessage error={error} label={label} />
69+
</div>
70+
)}
71+
/>
6772
)
6873
}

app/components/form/fields/ListboxField.tsx

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,7 @@
66
* Copyright Oxide Computer Company
77
*/
88
import cn from 'classnames'
9-
import {
10-
useController,
11-
type Control,
12-
type FieldPath,
13-
type FieldValues,
14-
} from 'react-hook-form'
9+
import { Controller, type Control, type FieldPath, type FieldValues } from 'react-hook-form'
1510

1611
import { Listbox, type ListboxItem } from '~/ui/lib/Listbox'
1712
import { capitalize } from '~/util/str'
@@ -55,29 +50,37 @@ export function ListboxField<
5550
}: ListboxFieldProps<TFieldValues, TName>) {
5651
// TODO: recreate this logic
5752
// validate: (v) => (required && !v ? `${name} is required` : undefined),
58-
const { field, fieldState } = useController({ name, control, rules: { required } })
5953
return (
6054
<div className={cn('max-w-lg', className)}>
61-
<Listbox
62-
description={description}
63-
label={label}
64-
tooltipText={tooltipText}
65-
required={required}
66-
placeholder={placeholder}
67-
selected={field.value || null}
68-
items={items}
69-
onChange={(value) => {
70-
field.onChange(value)
71-
onChange?.(value)
72-
}}
73-
// required to get required error to trigger on blur
74-
// onBlur={field.onBlur}
75-
disabled={disabled}
55+
<Controller
7656
name={name}
77-
hasError={fieldState.error !== undefined}
78-
isLoading={isLoading}
57+
rules={{ required }}
58+
control={control}
59+
render={({ field, fieldState: { error } }) => (
60+
<>
61+
<Listbox
62+
description={description}
63+
label={label}
64+
tooltipText={tooltipText}
65+
required={required}
66+
placeholder={placeholder}
67+
selected={field.value || null}
68+
items={items}
69+
onChange={(value) => {
70+
field.onChange(value)
71+
onChange?.(value)
72+
}}
73+
// required to get required error to trigger on blur
74+
// onBlur={field.onBlur}
75+
disabled={disabled}
76+
name={name}
77+
hasError={error !== undefined}
78+
isLoading={isLoading}
79+
/>
80+
<ErrorMessage error={error} label={label} />
81+
</>
82+
)}
7983
/>
80-
<ErrorMessage error={fieldState.error} label={label} />
8184
</div>
8285
)
8386
}

app/components/form/fields/NumberField.tsx

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88
import cn from 'classnames'
99
import { useId } from 'react'
10-
import { useController, type FieldPathByValue, type FieldValues } from 'react-hook-form'
10+
import { Controller, type FieldPathByValue, type FieldValues } from 'react-hook-form'
1111

1212
import { FieldLabel } from '~/ui/lib/FieldLabel'
1313
import { NumberInput } from '~/ui/lib/NumberInput'
@@ -77,25 +77,33 @@ export const NumberFieldInner = <
7777
const generatedId = useId()
7878
const id = idProp || generatedId
7979

80-
const {
81-
field,
82-
fieldState: { error },
83-
} = useController({ name, control, rules: { required, validate } })
84-
8580
return (
86-
<>
87-
<NumberInput
88-
id={id}
89-
error={!!error}
90-
aria-labelledby={cn(`${id}-label`, !!tooltipText && `${id}-help-text`)}
91-
aria-describedby={tooltipText ? `${id}-label-tip` : undefined}
92-
isDisabled={disabled}
93-
maxValue={max ? Number(max) : undefined}
94-
minValue={min !== undefined ? Number(min) : undefined}
95-
{...field}
96-
formatOptions={{ useGrouping: false }}
97-
/>
98-
<ErrorMessage error={error} label={label} />
99-
</>
81+
<Controller
82+
name={name}
83+
control={control}
84+
rules={{ required, validate }}
85+
render={({ field, fieldState: { error } }) => {
86+
return (
87+
<>
88+
<NumberInput
89+
id={id}
90+
error={!!error}
91+
aria-labelledby={cn(`${id}-label`, {
92+
[`${id}-help-text`]: !!tooltipText,
93+
})}
94+
aria-describedby={tooltipText ? `${id}-label-tip` : undefined}
95+
isDisabled={disabled}
96+
maxValue={max ? Number(max) : undefined}
97+
minValue={min !== undefined ? Number(min) : undefined}
98+
{...field}
99+
formatOptions={{
100+
useGrouping: false,
101+
}}
102+
/>
103+
<ErrorMessage error={error} label={label} />
104+
</>
105+
)
106+
}}
107+
/>
100108
)
101109
}

0 commit comments

Comments
 (0)