diff --git a/README.md b/README.md
index 658a9445..70ad3eee 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,15 @@ Then, import the components you need to use with Formik in the file you have you
- Switch
- TextField
+Avaliable with [@material-ui/pickers](https://github.com/mui-org/material-ui-pickers) peer dep
+
+- DatePicker
+- KeyboardDatePicker
+- TimePicker
+- KeyboardTimePicker
+- DateTimePicker
+- KeyboardDateTimePicker
+
In this case we will use ``.
```diff
diff --git a/package.json b/package.json
index e9280fb7..7dbdea32 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
"typings": "dist/main.d.ts",
"peerDependencies": {
"@material-ui/core": ">=4.0.0",
+ "@material-ui/pickers": ">=3.2.8",
"formik": "<2.0.0",
"react": "^16.8.0"
},
@@ -42,6 +43,9 @@
},
"devDependencies": {
"@babel/core": "^7.1.6",
+ "@date-io/date-fns": "^1.3.11",
+ "@material-ui/core": "^4.8.3",
+ "@material-ui/pickers": "^3.2.8",
"@material-ui/core": "^4.8.3",
"@storybook/addon-actions": "^5.0.11",
"@storybook/addon-links": "^5.0.11",
@@ -58,6 +62,7 @@
"babel-loader": "^8.0.4",
"coveralls": "^3.0.2",
"cross-env": "^5.2.0",
+ "date-fns": "^2.7.0",
"eslint": "^5.15.3",
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-jest": "^22.7.1",
diff --git a/src/DatePicker.tsx b/src/DatePicker.tsx
new file mode 100644
index 00000000..c589d602
--- /dev/null
+++ b/src/DatePicker.tsx
@@ -0,0 +1,48 @@
+import * as React from 'react';
+import {
+ DatePicker as MuiDatePicker,
+ DatePickerProps as MuiDatePickerProps,
+} from '@material-ui/pickers';
+
+import { FieldProps, getIn } from 'formik';
+
+export type DatePickerProps = FieldProps &
+ Omit;
+
+export const fieldToDatePicker = ({
+ field,
+ form,
+ disabled,
+ ...props
+}: DatePickerProps): MuiDatePickerProps => {
+ const { name } = field;
+ const { touched, errors, isSubmitting, setFieldValue, setFieldError } = form;
+
+ const fieldError = getIn(errors, name);
+ const showError = getIn(touched, name) && !!fieldError;
+
+ return {
+ ...props,
+ ...field,
+ error: showError,
+ helperText: showError ? fieldError : props.helperText,
+ disabled: disabled != undefined ? disabled : isSubmitting,
+ onChange(date) {
+ setFieldValue(name, date);
+ },
+ onError(error) {
+ if (error !== fieldError) {
+ setFieldError(name, String(error));
+ }
+ },
+ };
+};
+
+export const DatePicker: React.ComponentType = ({
+ children,
+ ...props
+}: DatePickerProps) => (
+ {children}
+);
+
+DatePicker.displayName = 'FormikMaterialUIDatePicker';
diff --git a/src/DateTimePicker.tsx b/src/DateTimePicker.tsx
new file mode 100644
index 00000000..b34329bd
--- /dev/null
+++ b/src/DateTimePicker.tsx
@@ -0,0 +1,49 @@
+import * as React from 'react';
+import {
+ DateTimePicker as MuiDateTimePicker,
+ DateTimePickerProps as MuiDateTimePickerProps,
+} from '@material-ui/pickers';
+import { FieldProps, getIn } from 'formik';
+
+export type DateTimePickerProps = FieldProps &
+ Omit;
+
+export const fieldToDateTimePicker = ({
+ field,
+ form,
+ disabled,
+ ...props
+}: DateTimePickerProps): MuiDateTimePickerProps => {
+ const { name } = field;
+ const { touched, errors, isSubmitting, setFieldValue, setFieldError } = form;
+
+ const fieldError = getIn(errors, name);
+ const showError = getIn(touched, name) && !!fieldError;
+
+ return {
+ ...props,
+ ...field,
+ error: showError,
+ helperText: showError ? fieldError : props.helperText,
+ disabled: disabled != undefined ? disabled : isSubmitting,
+ onChange(date) {
+ setFieldValue(name, date);
+ },
+ onError(error) {
+ if (error !== fieldError) {
+ setFieldError(name, String(error));
+ }
+ },
+ };
+};
+
+export const DateTimePicker: React.ComponentType = ({
+ children,
+ ...props
+}: DateTimePickerProps) => (
+
+ {children}
+
+);
+
+DateTimePicker.displayName = 'FormikMaterialUIDateTimePicker';
diff --git a/src/KeyboardDatePicker.tsx b/src/KeyboardDatePicker.tsx
new file mode 100644
index 00000000..160c0f14
--- /dev/null
+++ b/src/KeyboardDatePicker.tsx
@@ -0,0 +1,49 @@
+import * as React from 'react';
+import {
+ KeyboardDatePicker as MuiKeyboardDatePicker,
+ KeyboardDatePickerProps as MuiKeyboardDatePickerProps,
+} from '@material-ui/pickers';
+import { FieldProps, getIn } from 'formik';
+
+export type KeyboardDatePickerProps = FieldProps &
+ Omit;
+
+export const fieldToKeyboardDatePicker = ({
+ field,
+ form,
+ disabled,
+ ...props
+}: KeyboardDatePickerProps): MuiKeyboardDatePickerProps => {
+ const { name } = field;
+ const { touched, errors, isSubmitting, setFieldValue, setFieldError } = form;
+
+ const fieldError = getIn(errors, name);
+ const showError = getIn(touched, name) && !!fieldError;
+
+ return {
+ ...props,
+ ...field,
+ error: showError,
+ helperText: showError ? fieldError : props.helperText,
+ disabled: disabled != undefined ? disabled : isSubmitting,
+ onChange(date) {
+ setFieldValue(name, date);
+ },
+ onError(error) {
+ if (error !== fieldError) {
+ setFieldError(name, String(error));
+ }
+ },
+ };
+};
+
+export const KeyboardDatePicker: React.ComponentType = ({
+ children,
+ ...props
+}: KeyboardDatePickerProps) => (
+
+ {children}
+
+);
+
+KeyboardDatePicker.displayName = 'FormikMaterialUIKeyboardDatePicker';
diff --git a/src/KeyboardDateTimePicker.tsx b/src/KeyboardDateTimePicker.tsx
new file mode 100644
index 00000000..5827a1c9
--- /dev/null
+++ b/src/KeyboardDateTimePicker.tsx
@@ -0,0 +1,49 @@
+import * as React from 'react';
+import {
+ KeyboardDateTimePicker as MuiKeyboardDateTimePicker,
+ KeyboardDateTimePickerProps as MuiKeyboardDateTimePickerProps,
+} from '@material-ui/pickers';
+import { FieldProps, getIn } from 'formik';
+
+export type KeyboardDateTimePickerProps = FieldProps &
+ Omit;
+
+export const fieldToKeyboardDateTimePicker = ({
+ field,
+ form,
+ disabled,
+ ...props
+}: KeyboardDateTimePickerProps): MuiKeyboardDateTimePickerProps => {
+ const { name } = field;
+ const { touched, errors, isSubmitting, setFieldValue, setFieldError } = form;
+
+ const fieldError = getIn(errors, name);
+ const showError = getIn(touched, name) && !!fieldError;
+
+ return {
+ ...props,
+ ...field,
+ error: showError,
+ helperText: showError ? fieldError : props.helperText,
+ disabled: disabled != undefined ? disabled : isSubmitting,
+ onChange(date) {
+ setFieldValue(name, date);
+ },
+ onError(error) {
+ if (error !== fieldError) {
+ setFieldError(name, String(error));
+ }
+ },
+ };
+};
+
+export const KeyboardDateTimePicker: React.ComponentType = ({
+ children,
+ ...props
+}: KeyboardDateTimePickerProps) => (
+
+ {children}
+
+);
+
+KeyboardDateTimePicker.displayName = 'FormikMaterialUIKeyboardDateTimePicker';
diff --git a/src/KeyboardTimePicker.tsx b/src/KeyboardTimePicker.tsx
new file mode 100644
index 00000000..69853ee3
--- /dev/null
+++ b/src/KeyboardTimePicker.tsx
@@ -0,0 +1,49 @@
+import * as React from 'react';
+import {
+ KeyboardTimePicker as MuiKeyboardTimePicker,
+ KeyboardTimePickerProps as MuiKeyboardTimePickerProps,
+} from '@material-ui/pickers';
+import { FieldProps, getIn } from 'formik';
+
+export type KeyboardTimePickerProps = FieldProps &
+ Omit;
+
+export const fieldToKeyboardTimePicker = ({
+ field,
+ form,
+ disabled,
+ ...props
+}: KeyboardTimePickerProps): MuiKeyboardTimePickerProps => {
+ const { name } = field;
+ const { touched, errors, isSubmitting, setFieldValue, setFieldError } = form;
+
+ const fieldError = getIn(errors, name);
+ const showError = getIn(touched, name) && !!fieldError;
+
+ return {
+ ...props,
+ ...field,
+ error: showError,
+ helperText: showError ? fieldError : props.helperText,
+ disabled: disabled != undefined ? disabled : isSubmitting,
+ onChange(date) {
+ setFieldValue(name, date);
+ },
+ onError(error) {
+ if (error !== fieldError) {
+ setFieldError(name, String(error));
+ }
+ },
+ };
+};
+
+export const KeyboardTimePicker: React.ComponentType = ({
+ children,
+ ...props
+}: KeyboardTimePickerProps) => (
+
+ {children}
+
+);
+
+KeyboardTimePicker.displayName = 'FormikMaterialUIKeyboardTimePicker';
diff --git a/src/TimePicker.tsx b/src/TimePicker.tsx
new file mode 100644
index 00000000..b048a257
--- /dev/null
+++ b/src/TimePicker.tsx
@@ -0,0 +1,47 @@
+import * as React from 'react';
+import {
+ TimePicker as MuiTimePicker,
+ TimePickerProps as MuiTimePickerProps,
+} from '@material-ui/pickers';
+import { FieldProps, getIn } from 'formik';
+
+export type TimePickerProps = FieldProps &
+ Omit;
+
+export const fieldToTimePicker = ({
+ field,
+ form,
+ disabled,
+ ...props
+}: TimePickerProps): MuiTimePickerProps => {
+ const { name } = field;
+ const { touched, errors, isSubmitting, setFieldValue, setFieldError } = form;
+
+ const fieldError = getIn(errors, name);
+ const showError = getIn(touched, name) && !!fieldError;
+
+ return {
+ ...props,
+ ...field,
+ error: showError,
+ helperText: showError ? fieldError : props.helperText,
+ disabled: disabled != undefined ? disabled : isSubmitting,
+ onChange(date) {
+ setFieldValue(name, date);
+ },
+ onError(error) {
+ if (error !== fieldError) {
+ setFieldError(name, String(error));
+ }
+ },
+ };
+};
+
+export const TimePicker: React.ComponentType = ({
+ children,
+ ...props
+}: TimePickerProps) => (
+ {children}
+);
+
+TimePicker.displayName = 'FormikMaterialUITimePicker';
diff --git a/src/__tests__/DatePicker.test.tsx b/src/__tests__/DatePicker.test.tsx
new file mode 100644
index 00000000..659e23bc
--- /dev/null
+++ b/src/__tests__/DatePicker.test.tsx
@@ -0,0 +1,21 @@
+import * as React from 'react';
+import { Formik, Field, Form } from 'formik';
+import renderer from 'react-test-renderer';
+import { MuiPickersUtilsProvider } from '@material-ui/pickers';
+import DateFnsUtils from '@date-io/date-fns';
+
+import { DatePicker } from '../DatePicker';
+
+test('DatePicker Renders Correctly', () => {
+ const component = renderer.create(
+
+ null}>
+
+
+
+ );
+
+ expect(component.toJSON()).toMatchSnapshot();
+});
diff --git a/src/__tests__/DateTimePicker.test.tsx b/src/__tests__/DateTimePicker.test.tsx
new file mode 100644
index 00000000..13168bda
--- /dev/null
+++ b/src/__tests__/DateTimePicker.test.tsx
@@ -0,0 +1,21 @@
+import * as React from 'react';
+import { Formik, Field, Form } from 'formik';
+import renderer from 'react-test-renderer';
+import { MuiPickersUtilsProvider } from '@material-ui/pickers';
+import DateFnsUtils from '@date-io/date-fns';
+
+import { DateTimePicker } from '../DateTimePicker';
+
+test('DateTimePicker Renders Correctly', () => {
+ const component = renderer.create(
+
+ null}>
+
+
+
+ );
+
+ expect(component.toJSON()).toMatchSnapshot();
+});
diff --git a/src/__tests__/KeyboardDatePicker.test.tsx b/src/__tests__/KeyboardDatePicker.test.tsx
new file mode 100644
index 00000000..2b1abd43
--- /dev/null
+++ b/src/__tests__/KeyboardDatePicker.test.tsx
@@ -0,0 +1,21 @@
+import * as React from 'react';
+import { Formik, Field, Form } from 'formik';
+import renderer from 'react-test-renderer';
+import { MuiPickersUtilsProvider } from '@material-ui/pickers';
+import DateFnsUtils from '@date-io/date-fns';
+
+import { KeyboardDatePicker } from '../KeyboardDatePicker';
+
+test('KeyboardDatePicker Renders Correctly', () => {
+ const component = renderer.create(
+
+ null}>
+
+
+
+ );
+
+ expect(component.toJSON()).toMatchSnapshot();
+});
diff --git a/src/__tests__/KeyboardDateTimePicker.test.tsx b/src/__tests__/KeyboardDateTimePicker.test.tsx
new file mode 100644
index 00000000..bfa30df5
--- /dev/null
+++ b/src/__tests__/KeyboardDateTimePicker.test.tsx
@@ -0,0 +1,25 @@
+import * as React from 'react';
+import { Formik, Field, Form } from 'formik';
+import renderer from 'react-test-renderer';
+import { MuiPickersUtilsProvider } from '@material-ui/pickers';
+import DateFnsUtils from '@date-io/date-fns';
+
+import { KeyboardDateTimePicker } from '../KeyboardDateTimePicker';
+
+test('KeyboardDateTimePicker Renders Correctly', () => {
+ const component = renderer.create(
+
+ null}>
+
+
+
+ );
+
+ expect(component.toJSON()).toMatchSnapshot();
+});
diff --git a/src/__tests__/KeyboardTimePicker.test.tsx b/src/__tests__/KeyboardTimePicker.test.tsx
new file mode 100644
index 00000000..0a438690
--- /dev/null
+++ b/src/__tests__/KeyboardTimePicker.test.tsx
@@ -0,0 +1,21 @@
+import * as React from 'react';
+import { Formik, Field, Form } from 'formik';
+import renderer from 'react-test-renderer';
+import { MuiPickersUtilsProvider } from '@material-ui/pickers';
+import DateFnsUtils from '@date-io/date-fns';
+
+import { KeyboardTimePicker } from '../KeyboardTimePicker';
+
+test('KeyboardTimePicker Renders Correctly', () => {
+ const component = renderer.create(
+
+ null}>
+
+
+
+ );
+
+ expect(component.toJSON()).toMatchSnapshot();
+});
diff --git a/src/__tests__/TimePicker.test.tsx b/src/__tests__/TimePicker.test.tsx
new file mode 100644
index 00000000..7c6d564e
--- /dev/null
+++ b/src/__tests__/TimePicker.test.tsx
@@ -0,0 +1,21 @@
+import * as React from 'react';
+import { Formik, Field, Form } from 'formik';
+import renderer from 'react-test-renderer';
+import { MuiPickersUtilsProvider } from '@material-ui/pickers';
+import DateFnsUtils from '@date-io/date-fns'
+
+import { TimePicker } from '../TimePicker';
+
+test('TimePicker Renders Correctly', () => {
+ const component = renderer.create(
+
+ null}>
+
+
+
+ );
+
+ expect(component.toJSON()).toMatchSnapshot();
+});
diff --git a/src/main.tsx b/src/main.tsx
index efaa4faa..782ef8fd 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -6,3 +6,9 @@ export * from './Select';
export * from './SimpleFileUpload';
export * from './RadioGroup';
export * from './InputBase';
+export * from './DatePicker';
+export * from './KeyboardDatePicker';
+export * from './TimePicker';
+export * from './KeyboardTimePicker';
+export * from './DateTimePicker';
+export * from './KeyboardDateTimePicker';
diff --git a/stories/DatePicker.story.tsx b/stories/DatePicker.story.tsx
new file mode 100644
index 00000000..052701bc
--- /dev/null
+++ b/stories/DatePicker.story.tsx
@@ -0,0 +1,69 @@
+import * as React from 'react';
+import Button from '@material-ui/core/Button';
+import { Formik, Field, Form } from 'formik';
+import { LinearProgress } from '@material-ui/core';
+import { action } from '@storybook/addon-actions';
+import * as yup from 'yup';
+
+import Wrapper from './Wrapper';
+
+import { DatePicker } from '../src/DatePicker';
+import { KeyboardDatePicker } from '../src/KeyboardDatePicker';
+import FormValues from './FormValues';
+
+interface Values {
+ date: Date | null;
+}
+
+const schema = yup.object().shape({
+ date: yup.date().required(),
+});
+
+export default () => (
+
+
+ initialValues={{
+ date: new Date(),
+ }}
+ validationSchema={schema}
+ onSubmit={(values, { setSubmitting }) => {
+ setTimeout(() => {
+ setSubmitting(false);
+ action('submit')(values);
+ }, 2000);
+ }}
+ render={({ submitForm, isSubmitting, values }) => (
+
+ )}
+ />
+
+);
diff --git a/stories/DateTimePicker.story.tsx b/stories/DateTimePicker.story.tsx
new file mode 100644
index 00000000..b145ff74
--- /dev/null
+++ b/stories/DateTimePicker.story.tsx
@@ -0,0 +1,73 @@
+import * as React from 'react';
+import Button from '@material-ui/core/Button';
+import { Formik, Field, Form } from 'formik';
+import { LinearProgress } from '@material-ui/core';
+import { action } from '@storybook/addon-actions';
+import * as yup from 'yup';
+
+import Wrapper from './Wrapper';
+
+import { DateTimePicker } from '../src/DateTimePicker';
+import { KeyboardDateTimePicker } from '../src/KeyboardDateTimePicker';
+import FormValues from './FormValues';
+
+interface Values {
+ date: Date | null;
+}
+
+const schema = yup.object().shape({
+ date: yup.date().required(),
+});
+
+export default () => (
+
+
+ initialValues={{
+ date: new Date(),
+ }}
+ validationSchema={schema}
+ onSubmit={(values, { setSubmitting }) => {
+ setTimeout(() => {
+ setSubmitting(false);
+ action('submit')(values);
+ }, 2000);
+ }}
+ render={({ submitForm, isSubmitting, values }) => (
+
+ )}
+ />
+
+);
diff --git a/stories/TimePicker.story.tsx b/stories/TimePicker.story.tsx
new file mode 100644
index 00000000..e31941b9
--- /dev/null
+++ b/stories/TimePicker.story.tsx
@@ -0,0 +1,61 @@
+import * as React from 'react';
+import Button from '@material-ui/core/Button';
+import { Formik, Field, Form } from 'formik';
+import { LinearProgress } from '@material-ui/core';
+import { action } from '@storybook/addon-actions';
+import * as yup from 'yup';
+
+import Wrapper from './Wrapper';
+
+import { TimePicker } from '../src/TimePicker';
+import { KeyboardTimePicker } from '../src/KeyboardTimePicker';
+import FormValues from './FormValues';
+
+interface Values {
+ time: Date | null;
+}
+
+const schema = yup.object().shape({
+ time: yup.date().required(),
+});
+
+export default () => (
+
+
+ initialValues={{
+ time: new Date(),
+ }}
+ validationSchema={schema}
+ onSubmit={(values, { setSubmitting }) => {
+ setTimeout(() => {
+ setSubmitting(false);
+ action('submit')(values);
+ }, 2000);
+ }}
+ render={({ submitForm, isSubmitting, values }) => (
+
+ )}
+ />
+
+);
diff --git a/stories/Wrapper.tsx b/stories/Wrapper.tsx
index eb409701..b4445825 100644
--- a/stories/Wrapper.tsx
+++ b/stories/Wrapper.tsx
@@ -7,6 +7,8 @@ import {
WithStyles,
createStyles,
} from '@material-ui/core/styles';
+import { MuiPickersUtilsProvider } from '@material-ui/pickers';
+import DateFnsUtils from '@date-io/date-fns';
const styles = (theme: Theme) =>
createStyles({
@@ -34,7 +36,9 @@ const Wrapper = ({ title, children }: Props) => (
{title}
- {children}
+
+ {children}
+
);
diff --git a/stories/index.stories.js b/stories/index.stories.js
index 7ee5e92d..3c8e2e73 100644
--- a/stories/index.stories.js
+++ b/stories/index.stories.js
@@ -9,6 +9,9 @@ import SelectorStory from './Selector.story';
import SelectStory from './Select.story';
import SimpleFileUploadStory from './SimpleFileUpload.story';
import RadioGroupStory from './RadioGroup.story.tsx';
+import DatePickerStory from './DatePicker.story.tsx';
+import TimePickerStory from './TimePicker.story.tsx';
+import DateTimePickerStory from './DateTimePicker.story.tsx';
storiesOf('Formik', module)
.add('Text Field', () => )
@@ -17,4 +20,7 @@ storiesOf('Formik', module)
.add('Selectors', () => )
.add('Select', () => )
.add('Simple File Upload', () => )
- .add('Kitchen Sink', () => );
+ .add('Kitchen Sink', () => )
+ .add('Date Picker', () => )
+ .add('Time Picker', () => )
+ .add('Date and Time Picker', () => );