From 129d5c969f9aa76db425b3165bc9c45e6a39576f Mon Sep 17 00:00:00 2001 From: Ciaran Liedeman Date: Tue, 14 Jul 2020 13:20:53 +0200 Subject: [PATCH] feat: Normalize props Always pass a blur handler. This caters for the case when MaterialUi invokes onBlur without an event. Always pass props last so that the use can override onChange. Make sure all properties can always be overriden by the end user --- .../src/Autocomplete.tsx | 27 ++++----------- .../src/ToggleButtonGroup.tsx | 26 +++++++------- .../src/DatePicker.tsx | 27 ++++++++++----- .../src/DateTimePicker.tsx | 27 ++++++++++----- .../src/KeyboardDatePicker.tsx | 27 ++++++++++----- .../src/KeyboardDateTimePicker.tsx | 27 ++++++++++----- .../src/KeyboardTimePicker.tsx | 25 ++++++++++---- .../src/TimePicker.tsx | 34 +++++++++++-------- packages/formik-material-ui/src/Checkbox.tsx | 10 ++++-- packages/formik-material-ui/src/InputBase.tsx | 10 ++++-- .../formik-material-ui/src/RadioGroup.tsx | 11 ++++-- packages/formik-material-ui/src/Select.tsx | 10 ++++-- packages/formik-material-ui/src/Switch.tsx | 10 ++++-- packages/formik-material-ui/src/TextField.tsx | 14 +++++--- 14 files changed, 183 insertions(+), 102 deletions(-) diff --git a/packages/formik-material-ui-lab/src/Autocomplete.tsx b/packages/formik-material-ui-lab/src/Autocomplete.tsx index 9f9b1a97..42f13a08 100644 --- a/packages/formik-material-ui-lab/src/Autocomplete.tsx +++ b/packages/formik-material-ui-lab/src/Autocomplete.tsx @@ -1,13 +1,9 @@ import * as React from 'react'; import MuiAutocomplete, { AutocompleteProps as MuiAutocompleteProps, - AutocompleteChangeReason, - AutocompleteChangeDetails, - AutocompleteInputChangeReason, } from '@material-ui/lab/Autocomplete'; import { FieldProps } from 'formik'; import invariant from 'tiny-warning'; -import type { Value } from '@material-ui/lab/useAutocomplete'; export { AutocompleteRenderInputParams } from '@material-ui/lab/Autocomplete'; @@ -64,31 +60,22 @@ export function fieldToAutocomplete< return { freeSolo, - onBlur: onBlur - ? onBlur - : (event: React.FocusEvent) => { - field.onBlur(event ?? field.name); - }, + onBlur: + onBlur ?? + function (event) { + field.onBlur(event ?? field.name); + }, onInputChange: onInputChange ? onInputChange : freeSolo - ? ( - _event: React.ChangeEvent<{}>, - value: string, - _reason: AutocompleteInputChangeReason - ) => { + ? function (_event, value) { setFieldValue(field.name, value); } : undefined, onChange: onChange ? onChange : !freeSolo - ? ( - _event: React.ChangeEvent<{}>, - value: Value, - _reason: AutocompleteChangeReason, - _details?: AutocompleteChangeDetails - ) => { + ? function (_event, value) { setFieldValue(field.name, value); } : undefined, diff --git a/packages/formik-material-ui-lab/src/ToggleButtonGroup.tsx b/packages/formik-material-ui-lab/src/ToggleButtonGroup.tsx index 27dfa552..fcd39daf 100644 --- a/packages/formik-material-ui-lab/src/ToggleButtonGroup.tsx +++ b/packages/formik-material-ui-lab/src/ToggleButtonGroup.tsx @@ -13,7 +13,7 @@ export interface ToggleButtonGroupProps } export function fieldToToggleButtonGroup({ - field, + field: { onChange: _onChange, onBlur: fieldOnBlur, ...field }, type, onChange, onBlur, @@ -34,20 +34,18 @@ export function fieldToToggleButtonGroup({ } } - const { onChange: _onChange, onBlur: _onBlur, ...fieldSubselection } = field; - return { - onBlur: onBlur - ? onBlur - : (event: React.FocusEvent) => { - field.onBlur(event ?? field.name); - }, - onChange: onChange - ? onChange - : (_event: React.MouseEvent, newValue: unknown) => { - form.setFieldValue(field.name, newValue); - }, - ...fieldSubselection, + onBlur: + onBlur ?? + function () { + fieldOnBlur(field.name); + }, + onChange: + onChange ?? + function (_event, newValue) { + form.setFieldValue(field.name, newValue); + }, + ...field, ...props, }; } diff --git a/packages/formik-material-ui-pickers/src/DatePicker.tsx b/packages/formik-material-ui-pickers/src/DatePicker.tsx index a99d36de..7434f354 100644 --- a/packages/formik-material-ui-pickers/src/DatePicker.tsx +++ b/packages/formik-material-ui-pickers/src/DatePicker.tsx @@ -11,24 +11,35 @@ export interface DatePickerProps Omit {} export function fieldToDatePicker({ - field, + field: { onChange: _onChange, onBlur: fieldOnBlur, ...field }, form: { isSubmitting, touched, errors, setFieldValue, setFieldError }, disabled, + onChange, + onBlur, + onError, ...props }: DatePickerProps): MuiDatePickerProps { const fieldError = getIn(errors, field.name); const showError = getIn(touched, field.name) && !!fieldError; return { - ...props, - ...field, error: showError, helperText: showError ? fieldError : props.helperText, - disabled: disabled != undefined ? disabled : isSubmitting, - onChange(date) { - props.onChange ? props.onChange(date) : setFieldValue(field.name, date); - }, - onError: createErrorHandler(fieldError, field.name, setFieldError), + disabled: disabled ?? isSubmitting, + onChange: + onChange ?? + function (date) { + setFieldValue(field.name, date); + }, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, + onError: + onError ?? createErrorHandler(fieldError, field.name, setFieldError), + ...field, + ...props, }; } diff --git a/packages/formik-material-ui-pickers/src/DateTimePicker.tsx b/packages/formik-material-ui-pickers/src/DateTimePicker.tsx index 24490f5b..6baf8770 100644 --- a/packages/formik-material-ui-pickers/src/DateTimePicker.tsx +++ b/packages/formik-material-ui-pickers/src/DateTimePicker.tsx @@ -12,23 +12,34 @@ export interface DateTimePickerProps export function fieldToDateTimePicker({ disabled, - field, + field: { onChange: _onChange, onBlur: fieldOnBlur, ...field }, form: { isSubmitting, touched, errors, setFieldValue, setFieldError }, + onChange, + onBlur, + onError, ...props }: DateTimePickerProps): MuiDateTimePickerProps { const fieldError = getIn(errors, field.name); const showError = getIn(touched, field.name) && !!fieldError; return { - ...props, - ...field, error: showError, helperText: showError ? fieldError : props.helperText, - disabled: disabled != undefined ? disabled : isSubmitting, - onChange(date) { - props.onChange ? props.onChange(date) : setFieldValue(field.name, date); - }, - onError: createErrorHandler(fieldError, field.name, setFieldError), + disabled: disabled ?? isSubmitting, + onChange: + onChange ?? + function (date) { + setFieldValue(field.name, date); + }, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, + onError: + onError ?? createErrorHandler(fieldError, field.name, setFieldError), + ...field, + ...props, }; } diff --git a/packages/formik-material-ui-pickers/src/KeyboardDatePicker.tsx b/packages/formik-material-ui-pickers/src/KeyboardDatePicker.tsx index 7a49a587..b94a2057 100644 --- a/packages/formik-material-ui-pickers/src/KeyboardDatePicker.tsx +++ b/packages/formik-material-ui-pickers/src/KeyboardDatePicker.tsx @@ -12,23 +12,34 @@ export interface KeyboardDatePickerProps export function fieldToKeyboardDatePicker({ disabled, - field, + field: { onChange: _onChange, onBlur: fieldOnBlur, ...field }, form: { isSubmitting, touched, errors, setFieldValue, setFieldError }, + onChange, + onBlur, + onError, ...props }: KeyboardDatePickerProps): MuiKeyboardDatePickerProps { const fieldError = getIn(errors, field.name); const showError = getIn(touched, field.name) && !!fieldError; return { - ...props, - ...field, error: showError, helperText: showError ? fieldError : props.helperText, - disabled: disabled != undefined ? disabled : isSubmitting, - onChange(date) { - props.onChange ? props.onChange(date) : setFieldValue(field.name, date); - }, - onError: createErrorHandler(fieldError, field.name, setFieldError), + disabled: disabled ?? isSubmitting, + onChange: + onChange ?? + function (date) { + setFieldValue(field.name, date); + }, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, + onError: + onError ?? createErrorHandler(fieldError, field.name, setFieldError), + ...field, + ...props, }; } diff --git a/packages/formik-material-ui-pickers/src/KeyboardDateTimePicker.tsx b/packages/formik-material-ui-pickers/src/KeyboardDateTimePicker.tsx index e8ab62b5..d32457aa 100644 --- a/packages/formik-material-ui-pickers/src/KeyboardDateTimePicker.tsx +++ b/packages/formik-material-ui-pickers/src/KeyboardDateTimePicker.tsx @@ -12,23 +12,34 @@ export interface KeyboardDateTimePickerProps export function fieldToKeyboardDateTimePicker({ disabled, - field, + field: { onChange: _onChange, onBlur: fieldOnBlur, ...field }, form: { isSubmitting, touched, errors, setFieldValue, setFieldError }, + onChange, + onBlur, + onError, ...props }: KeyboardDateTimePickerProps): MuiKeyboardDateTimePickerProps { const fieldError = getIn(errors, field.name); const showError = getIn(touched, field.name) && !!fieldError; return { - ...props, - ...field, error: showError, helperText: showError ? fieldError : props.helperText, - disabled: disabled != undefined ? disabled : isSubmitting, - onChange(date) { - props.onChange ? props.onChange(date) : setFieldValue(field.name, date); - }, - onError: createErrorHandler(fieldError, field.name, setFieldError), + disabled: disabled ?? isSubmitting, + onChange: + onChange ?? + function (date) { + setFieldValue(field.name, date); + }, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, + onError: + onError ?? createErrorHandler(fieldError, field.name, setFieldError), + ...field, + ...props, }; } diff --git a/packages/formik-material-ui-pickers/src/KeyboardTimePicker.tsx b/packages/formik-material-ui-pickers/src/KeyboardTimePicker.tsx index 347124ab..2c5cb66c 100644 --- a/packages/formik-material-ui-pickers/src/KeyboardTimePicker.tsx +++ b/packages/formik-material-ui-pickers/src/KeyboardTimePicker.tsx @@ -12,23 +12,34 @@ export interface KeyboardTimePickerProps export function fieldToKeyboardTimePicker({ disabled, - field, + field: { onChange: _onChange, onBlur: fieldOnBlur, ...field }, form: { isSubmitting, touched, errors, setFieldValue, setFieldError }, + onChange, + onBlur, + onError, ...props }: KeyboardTimePickerProps): MuiKeyboardTimePickerProps { const fieldError = getIn(errors, field.name); const showError = getIn(touched, field.name) && !!fieldError; return { - ...props, - ...field, error: showError, helperText: showError ? fieldError : props.helperText, disabled: disabled != undefined ? disabled : isSubmitting, - onChange(date) { - setFieldValue(field.name, date); - }, - onError: createErrorHandler(fieldError, field.name, setFieldError), + onChange: + onChange ?? + function (date) { + setFieldValue(field.name, date); + }, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, + onError: + onError ?? createErrorHandler(fieldError, field.name, setFieldError), + ...field, + ...props, }; } diff --git a/packages/formik-material-ui-pickers/src/TimePicker.tsx b/packages/formik-material-ui-pickers/src/TimePicker.tsx index 51378fc9..21f8bb33 100644 --- a/packages/formik-material-ui-pickers/src/TimePicker.tsx +++ b/packages/formik-material-ui-pickers/src/TimePicker.tsx @@ -4,6 +4,7 @@ import { TimePickerProps as MuiTimePickerProps, } from '@material-ui/pickers'; import { FieldProps, getIn } from 'formik'; +import { createErrorHandler } from './errorHandler'; export interface TimePickerProps extends FieldProps, @@ -11,29 +12,34 @@ export interface TimePickerProps export function fieldToTimePicker({ disabled, - field, + field: { onChange: _onChange, onBlur: fieldOnBlur, ...field }, form: { isSubmitting, touched, errors, setFieldValue, setFieldError }, + onChange, + onBlur, + onError, ...props }: TimePickerProps): MuiTimePickerProps { const fieldError = getIn(errors, field.name); const showError = getIn(touched, field.name) && !!fieldError; return { - ...props, - ...field, error: showError, helperText: showError ? fieldError : props.helperText, - disabled: disabled != undefined ? disabled : isSubmitting, - onChange(date) { - props.onChange ? props.onChange(date) : setFieldValue(field.name, date); - }, - onError(error) { - if (error !== fieldError && !(error == '' && !fieldError)) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - https://github.com/jaredpalmer/formik/pull/2286 - setFieldError(field.name, error ? String(error) : undefined); - } - }, + disabled: disabled ?? isSubmitting, + onChange: + onChange ?? + function (date) { + setFieldValue(field.name, date); + }, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, + onError: + onError ?? createErrorHandler(fieldError, field.name, setFieldError), + ...field, + ...props, }; } diff --git a/packages/formik-material-ui/src/Checkbox.tsx b/packages/formik-material-ui/src/Checkbox.tsx index d92f814b..cbc69048 100644 --- a/packages/formik-material-ui/src/Checkbox.tsx +++ b/packages/formik-material-ui/src/Checkbox.tsx @@ -23,9 +23,10 @@ export interface CheckboxProps export function fieldToCheckbox({ disabled, - field, + field: { onBlur: fieldOnBlur, ...field }, form: { isSubmitting }, type, + onBlur, ...props }: CheckboxProps): MuiCheckboxProps { const indeterminate = !Array.isArray(field.value) && field.value == null; @@ -40,8 +41,13 @@ export function fieldToCheckbox({ return { disabled: disabled ?? isSubmitting, indeterminate, - ...props, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, ...field, + ...props, }; } diff --git a/packages/formik-material-ui/src/InputBase.tsx b/packages/formik-material-ui/src/InputBase.tsx index f7b79bc6..2542b247 100644 --- a/packages/formik-material-ui/src/InputBase.tsx +++ b/packages/formik-material-ui/src/InputBase.tsx @@ -10,14 +10,20 @@ export interface InputBaseProps export function fieldToInputBase({ disabled, - field, + field: { onBlur: fieldOnBlur, ...field }, form: { isSubmitting }, + onBlur, ...props }: InputBaseProps): MuiInputBaseProps { return { disabled: disabled ?? isSubmitting, - ...props, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, ...field, + ...props, }; } diff --git a/packages/formik-material-ui/src/RadioGroup.tsx b/packages/formik-material-ui/src/RadioGroup.tsx index 971232c4..bbce2af4 100644 --- a/packages/formik-material-ui/src/RadioGroup.tsx +++ b/packages/formik-material-ui/src/RadioGroup.tsx @@ -9,14 +9,19 @@ export interface RadioGroupProps Omit {} export function fieldToRadioGroup({ - field, - // Exclude Form + field: { onBlur: fieldOnBlur, ...field }, form, + onBlur, ...props }: RadioGroupProps): MuiRadioGroupProps { return { - ...props, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, ...field, + ...props, }; } diff --git a/packages/formik-material-ui/src/Select.tsx b/packages/formik-material-ui/src/Select.tsx index 503abe91..2376d931 100644 --- a/packages/formik-material-ui/src/Select.tsx +++ b/packages/formik-material-ui/src/Select.tsx @@ -10,14 +10,20 @@ export interface SelectProps export function fieldToSelect({ disabled, - field, + field: { onBlur: fieldOnBlur, ...field }, form: { isSubmitting }, + onBlur, ...props }: SelectProps): MuiSelectProps { return { disabled: disabled ?? isSubmitting, - ...props, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, ...field, + ...props, }; } diff --git a/packages/formik-material-ui/src/Switch.tsx b/packages/formik-material-ui/src/Switch.tsx index a31bdc3c..d68293f6 100644 --- a/packages/formik-material-ui/src/Switch.tsx +++ b/packages/formik-material-ui/src/Switch.tsx @@ -22,9 +22,10 @@ export interface SwitchProps export function fieldToSwitch({ disabled, - field, + field: { onBlur: fieldOnBlur, ...field }, form: { isSubmitting }, type, + onBlur, ...props }: SwitchProps): MuiSwitchProps { if (process.env.NODE_ENV !== 'production') { @@ -36,8 +37,13 @@ export function fieldToSwitch({ return { disabled: disabled ?? isSubmitting, - ...props, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, ...field, + ...props, }; } diff --git a/packages/formik-material-ui/src/TextField.tsx b/packages/formik-material-ui/src/TextField.tsx index 9271af20..7bcf0fcb 100644 --- a/packages/formik-material-ui/src/TextField.tsx +++ b/packages/formik-material-ui/src/TextField.tsx @@ -10,20 +10,26 @@ export interface TextFieldProps export function fieldToTextField({ disabled, - field, + field: { onBlur: fieldOnBlur, ...field }, form: { isSubmitting, touched, errors }, + onBlur, ...props }: TextFieldProps): MuiTextFieldProps { const fieldError = getIn(errors, field.name); const showError = getIn(touched, field.name) && !!fieldError; return { - ...props, - ...field, + variant: props.variant, error: showError, helperText: showError ? fieldError : props.helperText, disabled: disabled ?? isSubmitting, - variant: props.variant, + onBlur: + onBlur ?? + function (e) { + fieldOnBlur(e ?? field.name); + }, + ...field, + ...props, }; }