Skip to content

Commit

Permalink
Sync input fields with parsed data
Browse files Browse the repository at this point in the history
  • Loading branch information
sunnysingh committed Jun 17, 2022
1 parent e4e377b commit 8b5cbfd
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 9 deletions.
17 changes: 14 additions & 3 deletions packages/material/src/controls/MaterialDateControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ import {
LocalizationProvider
} from '@mui/lab';
import AdapterDayjs from '@mui/lab/AdapterDayjs';
import { createOnChangeHandler, getData, useFocus } from '../util';
import {
createOnChangeHandler,
getData,
useFocus,
useParsedDateSynchronizer,
} from '../util';

export const MaterialDateControl = (props: ControlProps)=> {
const [focused, onFocus, onBlur] = useFocus();
Expand Down Expand Up @@ -79,6 +84,7 @@ export const MaterialDateControl = (props: ControlProps)=> {
handleChange,
saveFormat
),[path, handleChange, saveFormat]);
const parsedDateSynchronizer = useParsedDateSynchronizer({ data, onBlur });

return (
<Hidden xsUp={!visible}>
Expand All @@ -103,10 +109,15 @@ export const MaterialDateControl = (props: ControlProps)=> {
autoFocus={appliedUiSchemaOptions.focus}
error={!isValid}
fullWidth={!appliedUiSchemaOptions.trim}
inputProps={{ ...params.inputProps, type: 'text' }}
inputProps={{
...params.inputProps,
type: 'text',
value: parsedDateSynchronizer.value,
onChange: parsedDateSynchronizer.createOnChangeHandler(params.inputProps.onChange),
}}
InputLabelProps={data ? { shrink: true } : undefined}
onFocus={onFocus}
onBlur={onBlur}
onBlur={parsedDateSynchronizer.onBlur}
variant={'standard'}
/>
)}
Expand Down
18 changes: 15 additions & 3 deletions packages/material/src/controls/MaterialDateTimeControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ import {
LocalizationProvider
} from '@mui/lab';
import AdapterDayjs from '@mui/lab/AdapterDayjs';
import { createOnChangeHandler, getData, useFocus } from '../util';
import {
createOnChangeHandler,
getData,
useFocus,
useParsedDateSynchronizer,
} from '../util';

export const MaterialDateTimeControl = (props: ControlProps) => {
const [focused, onFocus, onBlur] = useFocus();
Expand Down Expand Up @@ -82,6 +87,8 @@ export const MaterialDateTimeControl = (props: ControlProps) => {
saveFormat
),[path, handleChange, saveFormat]);

const parsedDateSynchronizer = useParsedDateSynchronizer({ data, onBlur });

return (
<Hidden xsUp={!visible}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
Expand All @@ -106,10 +113,15 @@ export const MaterialDateTimeControl = (props: ControlProps) => {
autoFocus={appliedUiSchemaOptions.focus}
error={!isValid}
fullWidth={!appliedUiSchemaOptions.trim}
inputProps={{ ...params.inputProps, type: 'text' }}
inputProps={{
...params.inputProps,
type: 'text',
value: parsedDateSynchronizer.value,
onChange: parsedDateSynchronizer.createOnChangeHandler(params.inputProps.onChange),
}}
InputLabelProps={data ? { shrink: true } : undefined}
onFocus={onFocus}
onBlur={onBlur}
onBlur={parsedDateSynchronizer.onBlur}
variant={'standard'}
/>
)}
Expand Down
18 changes: 15 additions & 3 deletions packages/material/src/controls/MaterialTimeControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ import {
LocalizationProvider
} from '@mui/lab';
import AdapterDayjs from '@mui/lab/AdapterDayjs';
import { createOnChangeHandler, getData, useFocus } from '../util';
import {
createOnChangeHandler,
getData,
useFocus,
useParsedDateSynchronizer,
} from '../util';

export const MaterialTimeControl = (props: ControlProps) => {
const [focused, onFocus, onBlur] = useFocus();
Expand Down Expand Up @@ -82,6 +87,8 @@ export const MaterialTimeControl = (props: ControlProps) => {
saveFormat
),[path, handleChange, saveFormat]);

const parsedDateSynchronizer = useParsedDateSynchronizer({ data, onBlur });

return (
<Hidden xsUp={!visible}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
Expand All @@ -106,10 +113,15 @@ export const MaterialTimeControl = (props: ControlProps) => {
autoFocus={appliedUiSchemaOptions.focus}
error={!isValid}
fullWidth={!appliedUiSchemaOptions.trim}
inputProps={{ ...params.inputProps, type: 'text' }}
inputProps={{
...params.inputProps,
type: 'text',
value: parsedDateSynchronizer.value,
onChange: parsedDateSynchronizer.createOnChangeHandler(params.inputProps.onChange),
}}
InputLabelProps={data ? { shrink: true } : undefined}
onFocus={onFocus}
onBlur={onBlur}
onBlur={parsedDateSynchronizer.onBlur}
variant={'standard'}
/>
)}
Expand Down
36 changes: 36 additions & 0 deletions packages/material/src/util/datejs.ts
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);
Expand Down Expand Up @@ -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]
);

const createOnChangeHandler = (
onChange: (event: DateInputFormEvent) => void
) => (event: DateInputFormEvent) => {
setValue((event.target as HTMLInputElement | HTMLTextAreaElement).value);
if (onChange) onChange(event);
};

return { value, onBlur, createOnChangeHandler };
};

0 comments on commit 8b5cbfd

Please sign in to comment.