-
Notifications
You must be signed in to change notification settings - Fork 373
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pass through original values for invalid dates #1949
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import dayjs from 'dayjs'; | ||
import customParsing from 'dayjs/plugin/customParseFormat'; | ||
import { useState, useMemo, FormEvent, FormEventHandler } from 'react'; | ||
|
||
// required for the custom save formats in the date, time and date-time pickers | ||
dayjs.extend(customParsing); | ||
|
@@ -8,13 +9,13 @@ export const createOnChangeHandler = ( | |
path: string, | ||
handleChange: (path: string, value: any) => void, | ||
saveFormat: string | undefined | ||
) => (time: dayjs.Dayjs) => { | ||
) => (time: dayjs.Dayjs, textInputValue: string) => { | ||
if (!time) { | ||
handleChange(path, undefined); | ||
return; | ||
} | ||
const result = dayjs(time).format(saveFormat); | ||
handleChange(path, result === 'Invalid Date' ? undefined : result); | ||
handleChange(path, result === 'Invalid Date' ? textInputValue : result); | ||
}; | ||
|
||
export const getData = ( | ||
|
@@ -30,3 +31,38 @@ export const getData = ( | |
} | ||
return dayjsData; | ||
}; | ||
|
||
type DateInputFormEvent = FormEvent<HTMLInputElement | HTMLTextAreaElement>; | ||
|
||
/** | ||
* Improves the UX of date fields by controlling the rendered input value. | ||
* When a user enters a date value that ends up being different than the | ||
* the value of `data`, then on blur we sync the rendered input value. | ||
* | ||
* @param data The parsed date value. | ||
* @param onBlur Additional handler to run after input value is sync'd. | ||
* @returns Props to pass to the rendered input element. | ||
*/ | ||
export const useParsedDateSynchronizer = (props: { | ||
data: any; | ||
onBlur: FormEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined; | ||
}) => { | ||
const [value, setValue] = useState(props.data); | ||
|
||
const onBlur = useMemo( | ||
() => (event: DateInputFormEvent) => { | ||
setValue(props.data); | ||
if (props.onBlur) props.onBlur(event); | ||
}, | ||
[props.data, props.onBlur] | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can use |
||
|
||
const createOnChangeHandler = ( | ||
onChange: (event: DateInputFormEvent) => void | ||
) => (event: DateInputFormEvent) => { | ||
setValue((event.target as HTMLInputElement | HTMLTextAreaElement).value); | ||
if (onChange) onChange(event); | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This way we completely bypass the current change semantics. It can certainly work but we need to keep all edge cases in mind. It's probably easier to "simply" transform the value handed in by the picker by ignoring it when we're not focused. This also makes it overall simpler as we don't manage another explicit state. |
||
|
||
return { value, onBlur, createOnChangeHandler }; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not take into account cases where the
data
is changed differently, for example it will not update whendata
is changed via the pickers themselves or when the user hands in newdata
when externally updated.