@material-ui/lab#Value TypeScript Examples
The following examples show how to use
@material-ui/lab#Value.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Autocomplete.tsx From abacus with GNU General Public License v2.0 | 4 votes |
export default function AbacusAutocomplete<Multiple extends boolean>(
props: AutocompleteProps<AutocompleteItem, Multiple, false, false>,
): JSX.Element {
const {
form: { setFieldValue },
field: { name },
multiple,
} = props
// ## Translating OuterValues (value | value[]) <-> InnerValues (AutocompleteItem | AutocompleteItem[])
//
// Typescript and eslint make this look much more complicated than it is, we are just keeping the form value type
// in the form (string | number, and array version for multiple), and inside here we are using Autocomplete.
//
// We transform on the way in and on the way out.
type InnerValue = Multiple extends true ? InnerValueSingle[] : InnerValueSingle
type OuterValue = Multiple extends true ? OuterValueSingle[] : OuterValueSingle
const outerSingleToInnerSingle = (value: OuterValueSingle): InnerValueSingle => {
// istanbul ignore next; the ?? shouldn't occur
return props.options.find((autocompleteItem) => autocompleteItem.value === value) ?? emptyInnerValue
}
const innerSingleToOuterSingle = useCallback(
(autocompleteItem: InnerValueSingle): OuterValueSingle => autocompleteItem.value,
// eslint-disable-next-line react-hooks/exhaustive-deps -- React strangely thinks the types should be dependecies, smh...
[],
)
const outerValue = props.field.value as OuterValue
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore; Typescript can't quite work this:
const innerValue: InnerValue = multiple
? outerValue
? (outerValue as OuterValueSingle[]).map(outerSingleToInnerSingle)
: []
: outerValue
? outerSingleToInnerSingle(outerValue as OuterValueSingle)
: emptyInnerValue
const onChange = useCallback(
(_event, newInnerValue: AutocompleteItem | AutocompleteItem[] | null) => {
if (newInnerValue === null) {
// This happens on clear, it should never occur on multiple as we receive a []
setFieldValue(name, '')
} else if (_.isArray(newInnerValue)) {
setFieldValue(name, newInnerValue.map(innerSingleToOuterSingle))
} else {
setFieldValue(name, innerSingleToOuterSingle(newInnerValue))
}
},
[setFieldValue, name, innerSingleToOuterSingle],
)
// Autocomplete doesn't like it when it is set to a value which isn't available as a option.
// So we add it here like this and it works well enough.
const options =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore; Typescript can't quite work this:
!multiple && innerValue.value === emptyInnerValue.value ? [emptyInnerValue, ...props.options] : props.options
const error = _.get(props.form.touched, props.field.name) && _.get(props.form.errors, props.field.name)
return (
<Autocomplete
{...fieldToAutocomplete({
...props,
options,
field: {
...props.field,
// This just disables a warning, we actually handle it below
value: multiple ? [] : undefined,
},
})}
getOptionLabel={(option) => option.name}
getOptionSelected={(optionA, optionB) => optionA.value === optionB.value}
renderInput={(params) => {
// istanbul ignore else; Doesn't occur at all, it's just here for completeness
if (props.renderInput) {
return props.renderInput({
...params,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - It does exist
error: !!error,
helperText: _.isString(error) ? error : undefined,
})
} else {
return <TextField {...params} error={!!error} helperText={_.isString(error) ? error : undefined} />
}
}}
value={innerValue as unknown as Value<AutocompleteItem, Multiple, false, false>}
onChange={onChange}
/>
)
}