├── .eslintignore ├── .eslintrc ├── .gitignore ├── .idea ├── $PRODUCT_WORKSPACE_FILE$ ├── misc.xml ├── modules.xml └── vcs.xml ├── .storybook ├── main.js ├── preview-head.html └── preview.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── config ├── jest │ ├── jest.config.js │ └── jest.setup.js └── rollup │ └── rollup.config.js ├── docs ├── 404 │ └── index.html ├── 404.html ├── 6b859938-ad2c9b0d75c18f158f81.js ├── 6b859938-ad2c9b0d75c18f158f81.js.map ├── 6e76976840f6c24c49405a0120c53b6438406966-5288969b44ad50bed3d1.js ├── 6e76976840f6c24c49405a0120c53b6438406966-5288969b44ad50bed3d1.js.map ├── 6e76976840f6c24c49405a0120c53b6438406966-565425c638d458ade496.js ├── 6e76976840f6c24c49405a0120c53b6438406966-565425c638d458ade496.js.map ├── 6e76976840f6c24c49405a0120c53b6438406966-a1452a44e82f1171fc92.js ├── 6e76976840f6c24c49405a0120c53b6438406966-a1452a44e82f1171fc92.js.map ├── 6e76976840f6c24c49405a0120c53b6438406966-cec2d42125b66ffdb344.js ├── 6e76976840f6c24c49405a0120c53b6438406966-cec2d42125b66ffdb344.js.map ├── animatedGroup │ └── index.html ├── animatedMonthGroup │ └── index.html ├── app-0fc9d3d9dbe5f253be32.js ├── app-0fc9d3d9dbe5f253be32.js.map ├── app-8a37f9b60e74aa7bc99c.js ├── app-8a37f9b60e74aa7bc99c.js.map ├── app-95fb6ac2a63857592bd0.js ├── app-95fb6ac2a63857592bd0.js.map ├── app-9ac6fa563a2a2ae293bd.js ├── app-9ac6fa563a2a2ae293bd.js.map ├── app-a91bdd3fc9bff95510b1.js ├── app-a91bdd3fc9bff95510b1.js.map ├── bac1b955-aabd5d72bf53c652387a.js ├── bac1b955-aabd5d72bf53c652387a.js.map ├── calendar │ └── index.html ├── calendarProvider │ └── index.html ├── chunk-map.json ├── clickOutside │ └── index.html ├── component---src-docs-components-animated-group-mdx-3639de055532daef4fb0.js ├── component---src-docs-components-animated-group-mdx-3639de055532daef4fb0.js.map ├── component---src-docs-components-animated-group-mdx-54daadf10a6b5a5e7d6d.js ├── component---src-docs-components-animated-group-mdx-54daadf10a6b5a5e7d6d.js.map ├── component---src-docs-components-animated-group-mdx-64394e3b02e10abbff6e.js ├── component---src-docs-components-animated-group-mdx-64394e3b02e10abbff6e.js.map ├── component---src-docs-components-animated-month-group-mdx-1f30fea039de44502c8e.js ├── component---src-docs-components-animated-month-group-mdx-1f30fea039de44502c8e.js.map ├── component---src-docs-components-animated-month-group-mdx-331c6fcff6152a6c4475.js ├── component---src-docs-components-animated-month-group-mdx-331c6fcff6152a6c4475.js.map ├── component---src-docs-components-animated-month-group-mdx-72a94950bc0f35e7627f.js ├── component---src-docs-components-animated-month-group-mdx-72a94950bc0f35e7627f.js.map ├── component---src-docs-components-animated-month-group-mdx-fd2b5c94fdc7a1e1d424.js ├── component---src-docs-components-animated-month-group-mdx-fd2b5c94fdc7a1e1d424.js.map ├── component---src-docs-components-calendar-mdx-173f644e82164f531662.js ├── component---src-docs-components-calendar-mdx-173f644e82164f531662.js.map ├── component---src-docs-components-calendar-mdx-c959f4ce420e90dadbf5.js ├── component---src-docs-components-calendar-mdx-c959f4ce420e90dadbf5.js.map ├── component---src-docs-components-calendar-mdx-d9a3d690321c32cb5607.js ├── component---src-docs-components-calendar-mdx-d9a3d690321c32cb5607.js.map ├── component---src-docs-components-calendar-mdx-feb7e05cb2fee7a6f10e.js ├── component---src-docs-components-calendar-mdx-feb7e05cb2fee7a6f10e.js.map ├── component---src-docs-components-calendar-provider-mdx-4e90dc49e6d61b1d846b.js ├── component---src-docs-components-calendar-provider-mdx-4e90dc49e6d61b1d846b.js.map ├── component---src-docs-components-calendar-provider-mdx-4e9deea4bf5d7b94de97.js ├── component---src-docs-components-calendar-provider-mdx-4e9deea4bf5d7b94de97.js.map ├── component---src-docs-components-click-outside-mdx-058b273b42575edc8675.js ├── component---src-docs-components-click-outside-mdx-058b273b42575edc8675.js.map ├── component---src-docs-components-click-outside-mdx-5c582b449493877fd5db.js ├── component---src-docs-components-click-outside-mdx-5c582b449493877fd5db.js.map ├── component---src-docs-components-click-outside-mdx-fb95847dcd8a01d63966.js ├── component---src-docs-components-click-outside-mdx-fb95847dcd8a01d63966.js.map ├── component---src-docs-components-day-mdx-6f732653cf0bf6b2699f.js ├── component---src-docs-components-day-mdx-6f732653cf0bf6b2699f.js.map ├── component---src-docs-components-day-mdx-abcd88bed805c6cd6806.js ├── component---src-docs-components-day-mdx-abcd88bed805c6cd6806.js.map ├── component---src-docs-components-day-of-week-mdx-8d648eaf48e3db44c3be.js ├── component---src-docs-components-day-of-week-mdx-8d648eaf48e3db44c3be.js.map ├── component---src-docs-components-day-of-week-mdx-cbfd06b9e0e38ee6ef45.js ├── component---src-docs-components-day-of-week-mdx-cbfd06b9e0e38ee6ef45.js.map ├── component---src-docs-components-header-mdx-4346bba5c8ded3794fd1.js ├── component---src-docs-components-header-mdx-4346bba5c8ded3794fd1.js.map ├── component---src-docs-components-header-mdx-8b2bebc321fc6f8506f0.js ├── component---src-docs-components-header-mdx-8b2bebc321fc6f8506f0.js.map ├── component---src-docs-components-month-group-mdx-24e54c28d5875e104913.js ├── component---src-docs-components-month-group-mdx-24e54c28d5875e104913.js.map ├── component---src-docs-components-month-group-mdx-f4b748dc1d26f27841a5.js ├── component---src-docs-components-month-group-mdx-f4b748dc1d26f27841a5.js.map ├── component---src-docs-components-month-mdx-aca174b9cacb765f255b.js ├── component---src-docs-components-month-mdx-aca174b9cacb765f255b.js.map ├── component---src-docs-components-month-mdx-f07c44f9163dac7ea2ab.js ├── component---src-docs-components-month-mdx-f07c44f9163dac7ea2ab.js.map ├── component---src-docs-components-popper-mdx-2eecbf6b5cd73f3ea2be.js ├── component---src-docs-components-popper-mdx-2eecbf6b5cd73f3ea2be.js.map ├── component---src-docs-components-popper-mdx-45d66d94e9c7cc6e2151.js ├── component---src-docs-components-popper-mdx-45d66d94e9c7cc6e2151.js.map ├── component---src-docs-components-popper-mdx-6ae8be4ea93d04044206.js ├── component---src-docs-components-popper-mdx-6ae8be4ea93d04044206.js.map ├── component---src-docs-components-root-mdx-2b3658913fb2b397693f.js ├── component---src-docs-components-root-mdx-2b3658913fb2b397693f.js.map ├── component---src-docs-components-root-mdx-8b75d1117738f1ff5f1f.js ├── component---src-docs-components-root-mdx-8b75d1117738f1ff5f1f.js.map ├── component---src-docs-components-root-mdx-bcc866ed90cd241cf974.js ├── component---src-docs-components-root-mdx-bcc866ed90cd241cf974.js.map ├── component---src-docs-components-week-header-mdx-06be50db0bcd34de4506.js ├── component---src-docs-components-week-header-mdx-06be50db0bcd34de4506.js.map ├── component---src-docs-components-week-header-mdx-3ab5730289d3dcddccc0.js ├── component---src-docs-components-week-header-mdx-3ab5730289d3dcddccc0.js.map ├── component---src-docs-components-week-mdx-89271115c951d0a577e7.js ├── component---src-docs-components-week-mdx-89271115c951d0a577e7.js.map ├── component---src-docs-components-week-mdx-b2be9bfa567430d25cda.js ├── component---src-docs-components-week-mdx-b2be9bfa567430d25cda.js.map ├── component---src-docs-composition-mdx-047d3c90bcd9cbdd9226.js ├── component---src-docs-composition-mdx-047d3c90bcd9cbdd9226.js.map ├── component---src-docs-composition-mdx-b16338d97932a3cc4af2.js ├── component---src-docs-composition-mdx-b16338d97932a3cc4af2.js.map ├── component---src-docs-composition-mdx-efcafd7c85e81dade04f.js ├── component---src-docs-composition-mdx-efcafd7c85e81dade04f.js.map ├── component---src-docs-composition-mdx-f8029df17388faa47036.js ├── component---src-docs-composition-mdx-f8029df17388faa47036.js.map ├── component---src-docs-date-frameworks-mdx-0865b1340fe6077f77a4.js ├── component---src-docs-date-frameworks-mdx-0865b1340fe6077f77a4.js.map ├── component---src-docs-date-frameworks-mdx-6e3d587ef46bbf5e29d6.js ├── component---src-docs-date-frameworks-mdx-6e3d587ef46bbf5e29d6.js.map ├── component---src-docs-getting-started-mdx-96bc3a25b972c8134e1a.js ├── component---src-docs-getting-started-mdx-96bc3a25b972c8134e1a.js.map ├── component---src-docs-getting-started-mdx-a9320dc4f43e69c69136.js ├── component---src-docs-getting-started-mdx-a9320dc4f43e69c69136.js.map ├── component---src-docs-home-mdx-1efa576e828372a01f78.js ├── component---src-docs-home-mdx-1efa576e828372a01f78.js.map ├── component---src-docs-home-mdx-527d2d622f429217b0ce.js ├── component---src-docs-home-mdx-527d2d622f429217b0ce.js.map ├── component---src-docs-home-mdx-b43c4f7d6a42573c7588.js ├── component---src-docs-home-mdx-b43c4f7d6a42573c7588.js.map ├── component---src-docs-hooks-use-calendar-dispatch-mdx-7855db56cca8c49a8831.js ├── component---src-docs-hooks-use-calendar-dispatch-mdx-7855db56cca8c49a8831.js.map ├── component---src-docs-hooks-use-calendar-dispatch-mdx-8a36644d75e4629f6fff.js ├── component---src-docs-hooks-use-calendar-dispatch-mdx-8a36644d75e4629f6fff.js.map ├── component---src-docs-hooks-use-calendar-props-mdx-10945afd919ac60df23a.js ├── component---src-docs-hooks-use-calendar-props-mdx-10945afd919ac60df23a.js.map ├── component---src-docs-hooks-use-calendar-props-mdx-ae33f10f58e3c0cbc1f5.js ├── component---src-docs-hooks-use-calendar-props-mdx-ae33f10f58e3c0cbc1f5.js.map ├── component---src-docs-hooks-use-calendar-props-mdx-f2dd1b5b8aee8d77d7d2.js ├── component---src-docs-hooks-use-calendar-props-mdx-f2dd1b5b8aee8d77d7d2.js.map ├── component---src-docs-hooks-use-calendar-state-mdx-839708fa49fb1650d779.js ├── component---src-docs-hooks-use-calendar-state-mdx-839708fa49fb1650d779.js.map ├── component---src-docs-hooks-use-calendar-state-mdx-d273907bc340e564fb12.js ├── component---src-docs-hooks-use-calendar-state-mdx-d273907bc340e564fb12.js.map ├── component---src-docs-hooks-use-calendar-state-mdx-d3b2db02444906b5abb9.js ├── component---src-docs-hooks-use-calendar-state-mdx-d3b2db02444906b5abb9.js.map ├── component---src-docs-hooks-use-date-api-mdx-123d802eeaaf08dead1c.js ├── component---src-docs-hooks-use-date-api-mdx-123d802eeaaf08dead1c.js.map ├── component---src-docs-hooks-use-date-api-mdx-38c08684c8b739197baa.js ├── component---src-docs-hooks-use-date-api-mdx-38c08684c8b739197baa.js.map ├── component---src-docs-hooks-use-date-api-mdx-b7a249f5b5405ab7f36b.js ├── component---src-docs-hooks-use-date-api-mdx-b7a249f5b5405ab7f36b.js.map ├── component---src-docs-hooks-use-date-input-mdx-01e2c98dc59549f43dd6.js ├── component---src-docs-hooks-use-date-input-mdx-01e2c98dc59549f43dd6.js.map ├── component---src-docs-hooks-use-date-input-mdx-94e0d5f38582036ac3f3.js ├── component---src-docs-hooks-use-date-input-mdx-94e0d5f38582036ac3f3.js.map ├── component---src-docs-hooks-use-date-range-input-mdx-4d83aa891f0f256935ff.js ├── component---src-docs-hooks-use-date-range-input-mdx-4d83aa891f0f256935ff.js.map ├── component---src-docs-hooks-use-date-range-input-mdx-e3e19e8d51a408050b69.js ├── component---src-docs-hooks-use-date-range-input-mdx-e3e19e8d51a408050b69.js.map ├── component---src-docs-localization-mdx-70dbb68d3ca150963894.js ├── component---src-docs-localization-mdx-70dbb68d3ca150963894.js.map ├── component---src-docs-localization-mdx-b3ebf940e8a3206bb55c.js ├── component---src-docs-localization-mdx-b3ebf940e8a3206bb55c.js.map ├── component---src-docs-state-mdx-49a4f68054f7674a86aa.js ├── component---src-docs-state-mdx-49a4f68054f7674a86aa.js.map ├── component---src-docs-state-mdx-67ab27abde07d58cff3f.js ├── component---src-docs-state-mdx-67ab27abde07d58cff3f.js.map ├── component---src-docs-state-mdx-6d441f30da2f40ddef37.js ├── component---src-docs-state-mdx-6d441f30da2f40ddef37.js.map ├── component---src-docs-theming-mdx-69a21594737d7fb273e5.js ├── component---src-docs-theming-mdx-69a21594737d7fb273e5.js.map ├── component---src-docs-theming-mdx-c1ec4d152d2a3987b2af.js ├── component---src-docs-theming-mdx-c1ec4d152d2a3987b2af.js.map ├── component---src-docs-theming-mdx-c971eb1eb22e948ae315.js ├── component---src-docs-theming-mdx-c971eb1eb22e948ae315.js.map ├── component---src-pages-404-js-3b6bdb96ce97e4259fd1.js ├── component---src-pages-404-js-3b6bdb96ce97e4259fd1.js.map ├── composition │ └── index.html ├── date-frameworks │ └── index.html ├── day │ └── index.html ├── dayOfWeek │ └── index.html ├── framework-49e9022fa531a90fa82a.js ├── framework-49e9022fa531a90fa82a.js.map ├── getting-started │ └── index.html ├── header │ └── index.html ├── index.html ├── localization │ └── index.html ├── month │ └── index.html ├── monthGroup │ └── index.html ├── page-data │ ├── 404 │ │ └── page-data.json │ ├── 404.html │ │ └── page-data.json │ ├── animatedGroup │ │ └── page-data.json │ ├── animatedMonthGroup │ │ └── page-data.json │ ├── app-data.json │ ├── calendar │ │ └── page-data.json │ ├── calendarProvider │ │ └── page-data.json │ ├── clickOutside │ │ └── page-data.json │ ├── composition │ │ └── page-data.json │ ├── date-frameworks │ │ └── page-data.json │ ├── day │ │ └── page-data.json │ ├── dayOfWeek │ │ └── page-data.json │ ├── dev-404-page │ │ └── page-data.json │ ├── getting-started │ │ └── page-data.json │ ├── header │ │ └── page-data.json │ ├── index │ │ └── page-data.json │ ├── localization │ │ └── page-data.json │ ├── month │ │ └── page-data.json │ ├── monthGroup │ │ └── page-data.json │ ├── popper │ │ └── page-data.json │ ├── root │ │ └── page-data.json │ ├── state │ │ └── page-data.json │ ├── theming │ │ └── page-data.json │ ├── useCalendarDispatch │ │ └── page-data.json │ ├── useCalendarProps │ │ └── page-data.json │ ├── useCalendarState │ │ └── page-data.json │ ├── useDateAPI │ │ └── page-data.json │ ├── useDateInput │ │ └── page-data.json │ ├── useDateRangeInput │ │ └── page-data.json │ ├── week │ │ └── page-data.json │ └── weekHeader │ │ └── page-data.json ├── polyfill-3bb51120cf466dab44f3.js ├── polyfill-3bb51120cf466dab44f3.js.map ├── popper │ └── index.html ├── public │ └── cross.svg ├── root │ └── index.html ├── state │ └── index.html ├── static │ └── d │ │ └── 1635659820.json ├── styles-4b976dc17984c79c8d52.js ├── styles-4b976dc17984c79c8d52.js.map ├── styles.2543ff947a193d7f33b1.css ├── theming │ └── index.html ├── useCalendarDispatch │ └── index.html ├── useCalendarProps │ └── index.html ├── useCalendarState │ └── index.html ├── useDateAPI │ └── index.html ├── useDateInput │ └── index.html ├── useDateRangeInput │ └── index.html ├── webpack-runtime-11ef5d09fda83e610fc6.js ├── webpack-runtime-11ef5d09fda83e610fc6.js.map ├── webpack-runtime-48da2a9ee916dc1c40f6.js ├── webpack-runtime-48da2a9ee916dc1c40f6.js.map ├── webpack-runtime-5244d09f72feba69c88b.js ├── webpack-runtime-5244d09f72feba69c88b.js.map ├── webpack-runtime-74525104486de880cc18.js ├── webpack-runtime-74525104486de880cc18.js.map ├── webpack-runtime-dbdc273ff1e9c16e591c.js ├── webpack-runtime-dbdc273ff1e9c16e591c.js.map ├── webpack-runtime-f8e40170999d2b2571c4.js ├── webpack-runtime-f8e40170999d2b2571c4.js.map ├── webpack.stats.json ├── week │ └── index.html └── weekHeader │ └── index.html ├── doczrc.js ├── gatsby-config.js ├── jest.config.js ├── lerna.json ├── package.json ├── packages ├── common │ ├── .prettierignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── jest.config.js │ ├── package.json │ └── src │ │ ├── __tests__ │ │ └── index.test.js │ │ ├── formatNames.js │ │ ├── index.js │ │ └── useForkRef.js ├── core │ ├── .prettierignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── jest.config.js │ ├── package.json │ └── src │ │ ├── AnimatedGroup │ │ ├── AnimatedGroup.js │ │ ├── __tests__ │ │ │ ├── AnimatedGroup.test.js │ │ │ └── index.test.js │ │ ├── index.js │ │ └── style.js │ │ ├── AnimatedMonthGroup │ │ ├── AnimatedMonthGroup.js │ │ ├── __tests__ │ │ │ └── index.test.js │ │ └── index.js │ │ ├── Calendar.js │ │ ├── CalendarProvider.js │ │ ├── CalendarWithFocusLock.js │ │ ├── Day │ │ ├── Day.js │ │ ├── __tests__ │ │ │ ├── Day.test.js │ │ │ └── index.test.js │ │ ├── index.js │ │ └── style.js │ │ ├── DayOfWeek │ │ ├── DayOfWeek.js │ │ ├── __tests__ │ │ │ ├── DayOfWeek.test.js │ │ │ └── index.test.js │ │ ├── index.js │ │ └── style.js │ │ ├── Header │ │ ├── Header.js │ │ ├── __tests__ │ │ │ ├── Header.test.js │ │ │ └── index.test.js │ │ ├── index.js │ │ └── style.js │ │ ├── Month │ │ ├── Month.js │ │ ├── __tests__ │ │ │ ├── Month.test.js │ │ │ └── index.test.js │ │ ├── index.js │ │ └── style.js │ │ ├── MonthGroup │ │ ├── MonthGroup.js │ │ ├── __tests__ │ │ │ ├── MonthGroup.test.js │ │ │ └── index.test.js │ │ ├── index.js │ │ └── style.js │ │ ├── Root │ │ ├── Root.js │ │ ├── __tests__ │ │ │ ├── Root.test.js │ │ │ └── index.test.js │ │ ├── index.js │ │ └── style.js │ │ ├── Week │ │ ├── Week.js │ │ ├── __tests__ │ │ │ ├── Week.test.js │ │ │ └── index.test.js │ │ ├── index.js │ │ └── style.js │ │ ├── WeekHeader │ │ ├── WeekHeader.js │ │ ├── __tests__ │ │ │ ├── WeekHeader.test.js │ │ │ └── index.test.js │ │ ├── index.js │ │ └── style.js │ │ ├── __mocks__ │ │ ├── CalendarProvider.js │ │ └── react-popper.js │ │ ├── __tests__ │ │ ├── Calendar.test.js │ │ ├── CalendarProvider.test.js │ │ ├── adapter.test.js │ │ ├── callAll.test.js │ │ ├── createCalendarModel.test.js │ │ ├── createDateAPI.test.js │ │ ├── useDateInput.test.js │ │ └── useDateRangeInput.test.js │ │ ├── callAll.js │ │ ├── createCalendarModel.js │ │ ├── createDateAPI.js │ │ ├── formatNames.js │ │ ├── generateUID.js │ │ ├── index.js │ │ ├── reducers │ │ ├── __tests__ │ │ │ ├── calendarReducer.test.js │ │ │ ├── dateInputReducer.test.js │ │ │ ├── dateRangeInputReducer.test.js │ │ │ ├── dateRangeReducer.test.js │ │ │ └── singleDateReducer.test.js │ │ ├── calendarReducer.js │ │ ├── dateInputReducer.js │ │ ├── dateRangeInputReducer.js │ │ ├── dateRangeReducer.js │ │ └── singleDateReducer.js │ │ ├── setupTests.js │ │ ├── test-utils.js │ │ ├── useDateInput.js │ │ └── useDateRangeInput.js ├── date-fns-adapter │ ├── .prettierignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── jest.config.js │ ├── package.json │ └── src │ │ ├── __tests__ │ │ └── index.test.js │ │ └── index.js ├── dayjs-adapter │ ├── .prettierignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── jest.config.js │ ├── package.json │ └── src │ │ ├── __tests__ │ │ └── index.test.js │ │ └── index.js ├── luxon-adapter │ ├── .prettierignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── jest.config.js │ ├── package.json │ └── src │ │ ├── __tests__ │ │ └── index.test.js │ │ └── index.js ├── moment-adapter │ ├── .prettierignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── jest.config.js │ ├── package.json │ └── src │ │ ├── __tests__ │ │ └── index.test.js │ │ └── index.js └── popper │ ├── .prettierignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── jest.config.js │ ├── package.json │ └── src │ ├── ClickOutside.js │ ├── Popper.js │ ├── __tests__ │ ├── ClickOutside.test.js │ └── Popper.test.js │ └── index.js ├── public └── cross.svg ├── src ├── docs │ ├── components │ │ ├── animatedGroup.mdx │ │ ├── animatedMonthGroup.mdx │ │ ├── calendar.mdx │ │ ├── calendarProvider.mdx │ │ ├── clickOutside.mdx │ │ ├── day.mdx │ │ ├── dayOfWeek.mdx │ │ ├── header.mdx │ │ ├── month.mdx │ │ ├── monthGroup.mdx │ │ ├── popper.mdx │ │ ├── root.mdx │ │ ├── week.mdx │ │ └── weekHeader.mdx │ ├── composition.mdx │ ├── date-frameworks.mdx │ ├── getting-started.mdx │ ├── home.mdx │ ├── hooks │ │ ├── useCalendarDispatch.mdx │ │ ├── useCalendarProps.mdx │ │ ├── useCalendarState.mdx │ │ ├── useDateAPI.mdx │ │ ├── useDateInput.mdx │ │ └── useDateRangeInput.mdx │ ├── localization.mdx │ ├── state.mdx │ └── theming.mdx └── gatsby-theme-docz │ ├── components │ ├── Button.js │ ├── ButtonBar.js │ ├── Carousel.js │ ├── DemoContent.js │ ├── DemoHeader.js │ ├── Dropdown.js │ ├── Heading.js │ ├── Hero1.js │ ├── Hero2.js │ ├── Hero3.js │ ├── Hero4.js │ ├── Hero5.js │ ├── Hero6.js │ ├── HeroWrapper.js │ ├── Input.js │ ├── Layout │ │ ├── index.js │ │ └── styles.js │ ├── Logo │ │ ├── index.js │ │ └── styles.js │ └── Playground │ │ ├── Wrapper.js │ │ ├── index.js │ │ └── styles.js │ ├── createDate.js │ └── index.js ├── stories ├── 0 - Single Date.stories.js ├── 1 - Date Range.stories.js ├── 2 - Additional Controls.stories.js ├── 3 - Dialog.stories.js ├── 4 - Themable.stories.js ├── 5 - Date Adapter.stories.js ├── 6 - Locales.stories.js ├── 7 - Input.stories.js ├── 8 - Custom Dates.stories.js ├── AdditionalControlHeader.js ├── DateRangeDialog.js ├── Dropdown.js ├── ShortcutList.js └── sampleTheme.js ├── use-date-input.iml └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | # path/to/project/root/.eslintignore 2 | # /node_modules/* and /bower_components/* in the project root are ignored by default 3 | 4 | dist/* 5 | 6 | .docz/* 7 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "jest": true 6 | }, 7 | "parserOptions": { 8 | "ecmaVersion": 2018, 9 | "sourceType": "module", 10 | "ecmaFeatures": { 11 | "jsx": true, 12 | "experimentalObjectRestSpread": true 13 | } 14 | }, 15 | "settings": { 16 | "react": { 17 | "version": "detect" 18 | } 19 | }, 20 | "extends": [ 21 | "plugin:jest-dom/recommended", 22 | "eslint:recommended", 23 | "plugin:react/recommended", 24 | "prettier/react", 25 | "plugin:prettier/recommended" 26 | ], 27 | "plugins": ["react", "react-hooks", "prettier"], 28 | "rules": { 29 | "no-console": "warn", 30 | "no-eval": "error", 31 | "prettier/prettier": "error", 32 | "react-hooks/rules-of-hooks": "error", 33 | "react-hooks/exhaustive-deps": "warn" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # production 12 | dist 13 | stats.html 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # IDEA 27 | workspace.xml 28 | 29 | # Docz site 30 | .docz/* 31 | -------------------------------------------------------------------------------- /.idea/$PRODUCT_WORKSPACE_FILE$: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 8 | 9 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | stories: ["../stories/**/*.stories.js"], 5 | logLevel: "debug", 6 | addons: [ 7 | "@storybook/addon-actions", 8 | "@storybook/addon-links" 9 | ] 10 | }; 11 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 5 | 9 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import { addParameters } from "@storybook/react"; 2 | 3 | addParameters({ 4 | options: { 5 | // Sort stories in numeric order 6 | storySort: function(a, b) { 7 | if (a > b) return 1; 8 | if (a < b) return -1; 9 | return 0; 10 | } 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.0-beta.0 (2020-07-23) 2 | 3 | 4 | ### Features 5 | 6 | * initial commit ([6c24341](https://github.com/mark-tate/use-date-input/commit/6c24341efc30d33d6248367ee6578831c7a975ad)) 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 mark-tate 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # use-date-input 2 | 3 | This project is a React library to help compose your own date picker and calendar UI components. 4 | 5 | From simple to advanced, you can build your own date picker component in minutes. 6 | 7 | The key features of this projects 8 | 9 | - `Lightweight` - Optimized bundle size 10 | - `Control` - built with React hooks and the reducer pattern, the API gives you full control of the component's state 11 | - `Themeable` - built as a naked UI component, use the simple theming API to style 12 | - `Date Frameworks` - can be used with the date framework of your choice 13 | Either use the ready-made adapters ([dayjs](https://github.com/mark-tate/use-date-input/tree/master/packages/dayjs-adapter), [date-fns](https://github.com/mark-tate/use-date-input/tree/master/packages/date-fns-adapter), [luxon](https://github.com/mark-tate/use-date-input/tree/master/packages/luxon-adapter), [moment](https://github.com/mark-tate/use-date-input/tree/master/packages/moment-adapter)) or write your own adapter 14 | - `Composable` - can be used with any UI Framework 15 | Compose with your own UI components, to create date inputs, date dialogs or calendars with shortcut lists 16 | - `Accessible` - designed and tested for A11y, with full keyboard and screen-reader support 17 | - `Localisation` - customize region and labels 18 | - `Documentation` - fully documented with editable examples 19 | 20 | To get up and running quickly, refer to the [getting started](https://mark-tate.github.io/use-date-input/getting-started) guide. 21 | 22 | For the full documentation, refer to the [documentation](https://mark-tate.github.io/use-date-input/). 23 | 24 | ## Pay It Forward 25 | This project was built to give something back to the OpenSource community. 26 | 27 | Please raise a PR for this project or be inspired to create (or contribute) to another Open Source project. 28 | 29 | 30 | Building this component took alot of effort, so to show your appreciation, please let me know how you are using it, where you 31 | are using it and what themes you create. 32 | 33 | All feedback appreciated, message me on [Linked-In](https://twitter.com/mark.tate3). 34 | 35 | ## Credits 36 | When I started out, I wanted to create the Downshift of DatePickers. 37 | So a special mention to Kent, who inspired the journey. 38 | 39 | Documentation site built with [docz](https://www.docz.site/) 40 | -------------------------------------------------------------------------------- /config/jest/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collectCoverage: true, 3 | coveragePathIgnorePatterns: ["(tests/.*.mock).(jsx?|tsx?)$"], 4 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 5 | roots: ["/src"], 6 | setupFilesAfterEnv: ['../../config/jest/jest.setup.js'], 7 | testRegex: "(/__tests__/.*.(test|spec)).(jsx?|tsx?)$", 8 | transformIgnorePatterns: ["/node_modules/(?!@babel/runtime)"], 9 | verbose: true, 10 | }; 11 | -------------------------------------------------------------------------------- /config/jest/jest.setup.js: -------------------------------------------------------------------------------- 1 | // react-testing-library renders your components to document.body, 2 | // this adds jest-dom's custom assertions 3 | import '@testing-library/jest-dom/extend-expect'; 4 | 5 | if (window.document) { 6 | window.document.createRange = () => ({ 7 | setStart: () => {}, 8 | setEnd: () => {}, 9 | commonAncestorContainer: { 10 | nodeName: 'BODY', 11 | ownerDocument: document 12 | } 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /config/rollup/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from "@rollup/plugin-babel"; 2 | import commonjs from "@rollup/plugin-commonjs"; 3 | import filesize from "rollup-plugin-filesize"; 4 | import resolve from "@rollup/plugin-node-resolve"; 5 | import { terser } from "rollup-plugin-terser"; 6 | import visualizer from "rollup-plugin-visualizer"; 7 | import path from "path"; 8 | 9 | const pkgRootPath = process.cwd(); 10 | const pkg = require(path.join(pkgRootPath, "package.json")); 11 | 12 | const config = { 13 | input: "src/index.js", 14 | output: [ 15 | { 16 | file: "dist/index.umd.js", 17 | format: "umd", 18 | name: 'useDateInput', 19 | plugins: [ 20 | terser() 21 | ], 22 | sourcemap: true 23 | }, 24 | { 25 | file: "dist/index.js", 26 | format: "cjs", 27 | plugins: [ 28 | visualizer({ 29 | filename: "dist/stat-cjs.html", 30 | sourcemap: false 31 | }) 32 | ], 33 | sourcemap: true 34 | }, 35 | { 36 | file: "dist/index.min.js", 37 | format: "cjs", 38 | plugins: [ 39 | terser(), 40 | visualizer({ 41 | filename: "dist/stat-cjs-min.html", 42 | sourcemap: false 43 | }) 44 | ], 45 | sourcemap: true 46 | }, 47 | { 48 | file: "dist/index.esm.js", 49 | format: "esm", 50 | plugins: [ 51 | visualizer({ 52 | filename: "dist/stat-esm.html", 53 | sourcemap: false 54 | }) 55 | ], 56 | sourcemap: true 57 | } 58 | ], 59 | plugins: [ 60 | resolve(), 61 | babel({ 62 | exclude: "**/node_modules/**", 63 | babelHelpers: "runtime" 64 | }), 65 | commonjs(), 66 | filesize(), 67 | visualizer(), 68 | terser() 69 | ], 70 | external: [ 71 | /@babel\/runtime/, 72 | "dayjs/plugin/weekday", 73 | "dayjs/plugin/advancedFormat", 74 | "dayjs/plugin/customParseFormat", 75 | "dayjs/plugin/isBetween", 76 | "dayjs/plugin/isSameOrAfter", 77 | "dayjs/plugin/isSameOrBefore", 78 | ...Object.keys(pkg.dependencies || {}), 79 | ...Object.keys(pkg.peerDependencies || {}) 80 | ] 81 | }; 82 | 83 | export default config; 84 | -------------------------------------------------------------------------------- /docs/component---src-docs-home-mdx-1efa576e828372a01f78.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[22],{Rs4b:function(e,t,o){"use strict";o.r(t),o.d(t,"_frontmatter",(function(){return f})),o.d(t,"default",(function(){return O}));var a=o("Fcif"),n=o("+I+c"),r=(o("mXGw"),o("/FXl")),i=o("TjRS"),p=o("0BI5"),s=o("Uf7D"),c=o("Jpf6"),b=o("+tan"),m=o("CPF+"),u=o("Wo/x"),d=o("jGq8"),l=o("bD26"),h=o("i28S"),f=(o("aD51"),{});void 0!==f&&f&&f===Object(f)&&Object.isExtensible(f)&&!f.hasOwnProperty("__filemeta")&&Object.defineProperty(f,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/docs/home.mdx"}});var j={_frontmatter:f},x=i.a;function O(e){var t=e.components,o=Object(n.a)(e,["components"]);return Object(r.b)(x,Object(a.a)({},j,o,{components:t,mdxType:"MDXLayout"}),Object(r.b)(s.a,{mdxType:"Heading"},"use-date-input"),Object(r.b)(p.a,{mdxType:"Carousel"},Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/calendar",linkText:"Show Me",title:"Calendar",description:"Use as a single or date range calendar component",showBackground:!0,mdxType:"HeroWrapper"},Object(r.b)(b.a,{mdxType:"Hero1"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/composition",linkText:"Show Me",title:"Composable",description:"Compose into your own UI component",showBackground:!0,mdxType:"HeroWrapper"},Object(r.b)(m.a,{mdxType:"Hero2"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/useDateInput",linkText:"Show Me",title:"useDateInput Hook",description:"Compose with an input for single dates",mdxType:"HeroWrapper"},Object(r.b)(u.a,{mdxType:"Hero3"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/useDateRangeInput",linkText:"Show Me",title:"useDateRangeInput Hook",description:"Compose with multiple inputs for date ranges",mdxType:"HeroWrapper"},Object(r.b)(d.a,{mdxType:"Hero4"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/theming",linkText:"Show Me",title:"Themable",description:"Style it with your own theme",mdxType:"HeroWrapper"},Object(r.b)(l.a,{mdxType:"Hero5"})),Object(r.b)(h.a,{mdxType:"Hero6"})))}void 0!==O&&O&&O===Object(O)&&Object.isExtensible(O)&&!O.hasOwnProperty("__filemeta")&&Object.defineProperty(O,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/docs/home.mdx"}}),O.isMDXComponent=!0}}]); 2 | //# sourceMappingURL=component---src-docs-home-mdx-1efa576e828372a01f78.js.map -------------------------------------------------------------------------------- /docs/component---src-docs-home-mdx-527d2d622f429217b0ce.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[22],{Rs4b:function(e,t,o){"use strict";o.r(t),o.d(t,"_frontmatter",(function(){return f})),o.d(t,"default",(function(){return O}));var a=o("Fcif"),n=o("+I+c"),r=(o("mXGw"),o("/FXl")),i=o("TjRS"),p=o("0BI5"),s=o("Uf7D"),c=o("Jpf6"),b=o("+tan"),m=o("CPF+"),d=o("Wo/x"),u=o("jGq8"),h=o("bD26"),l=o("i28S"),f=(o("aD51"),{});void 0!==f&&f&&f===Object(f)&&Object.isExtensible(f)&&!f.hasOwnProperty("__filemeta")&&Object.defineProperty(f,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/docs/home.mdx"}});var j={_frontmatter:f},x=i.a;function O(e){var t=e.components,o=Object(n.a)(e,["components"]);return Object(r.b)(x,Object(a.a)({},j,o,{components:t,mdxType:"MDXLayout"}),Object(r.b)(s.a,{mdxType:"Heading"},"use-date-input"),Object(r.b)(p.a,{mdxType:"Carousel"},Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/calendar",linkText:"Show Me",title:"Calendar",description:"Use as a single or date range calendar component",showBackground:!0,mdxType:"HeroWrapper"},Object(r.b)(b.a,{mdxType:"Hero1"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/composition",linkText:"Show Me",title:"Composable",description:"Compose into your own UI component",showBackground:!0,mdxType:"HeroWrapper"},Object(r.b)(m.a,{mdxType:"Hero2"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/useDateInput",linkText:"Show Me",title:"useDateInput Hook",description:"Compose with an input for single dates",mdxType:"HeroWrapper"},Object(r.b)(d.a,{mdxType:"Hero3"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/useDateRangeInput",linkText:"Show Me",title:"useDateRangeInput Hook",description:"Compose with an input for date ranges",mdxType:"HeroWrapper"},Object(r.b)(u.a,{mdxType:"Hero4"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/theming",linkText:"Show Me",title:"Themable",description:"Style it with your own theme",mdxType:"HeroWrapper"},Object(r.b)(h.a,{mdxType:"Hero5"})),Object(r.b)(l.a,{mdxType:"Hero6"})))}void 0!==O&&O&&O===Object(O)&&Object.isExtensible(O)&&!O.hasOwnProperty("__filemeta")&&Object.defineProperty(O,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/docs/home.mdx"}}),O.isMDXComponent=!0}}]); 2 | //# sourceMappingURL=component---src-docs-home-mdx-527d2d622f429217b0ce.js.map -------------------------------------------------------------------------------- /docs/component---src-docs-home-mdx-b43c4f7d6a42573c7588.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[22],{Rs4b:function(e,t,o){"use strict";o.r(t),o.d(t,"_frontmatter",(function(){return f})),o.d(t,"default",(function(){return O}));var a=o("Fcif"),n=o("+I+c"),r=(o("mXGw"),o("/FXl")),i=o("TjRS"),p=o("0BI5"),s=o("Uf7D"),c=o("Jpf6"),b=o("+tan"),m=o("CPF+"),u=o("Wo/x"),d=o("jGq8"),l=o("bD26"),h=o("i28S"),f=(o("aD51"),{});void 0!==f&&f&&f===Object(f)&&Object.isExtensible(f)&&!f.hasOwnProperty("__filemeta")&&Object.defineProperty(f,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/docs/home.mdx"}});var j={_frontmatter:f},x=i.a;function O(e){var t=e.components,o=Object(n.a)(e,["components"]);return Object(r.b)(x,Object(a.a)({},j,o,{components:t,mdxType:"MDXLayout"}),Object(r.b)(s.a,{mdxType:"Heading"},"use-date-input"),Object(r.b)(p.a,{mdxType:"Carousel"},Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/calendar",linkText:"Show Me",title:"Calendar",description:"Use as a single or date range calendar component",showBackground:!0,mdxType:"HeroWrapper"},Object(r.b)(b.a,{mdxType:"Hero1"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/composition",linkText:"Show Me",title:"Composable",description:"Compose into your own UI component",showBackground:!0,mdxType:"HeroWrapper"},Object(r.b)(m.a,{mdxType:"Hero2"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/useDateInput",linkText:"Show Me",title:"useDateInput Hook",description:"Compose with an input for single dates",mdxType:"HeroWrapper"},Object(r.b)(u.a,{mdxType:"Hero3"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/useDateRangeInput",linkText:"Show Me",title:"useDateRangeInput Hook",description:"Compose with multiple inputs for date ranges",mdxType:"HeroWrapper"},Object(r.b)(d.a,{mdxType:"Hero4"})),Object(r.b)(c.a,{href:"https://mark-tate.github.io/use-date-input/theming",linkText:"Show Me",title:"Themable",description:"Style it with your own theme",mdxType:"HeroWrapper"},Object(r.b)(l.a,{mdxType:"Hero5"})),Object(r.b)(h.a,{mdxType:"Hero6"})))}void 0!==O&&O&&O===Object(O)&&Object.isExtensible(O)&&!O.hasOwnProperty("__filemeta")&&Object.defineProperty(O,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/docs/home.mdx"}}),O.isMDXComponent=!0}}]); 2 | //# sourceMappingURL=component---src-docs-home-mdx-b43c4f7d6a42573c7588.js.map -------------------------------------------------------------------------------- /docs/component---src-docs-hooks-use-calendar-state-mdx-839708fa49fb1650d779.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[25],{"8sOg":function(e,t,a){"use strict";a.r(t),a.d(t,"_frontmatter",(function(){return u})),a.d(t,"default",(function(){return D}));var n=a("Fcif"),r=a("+I+c"),o=a("mXGw"),d=a("/FXl"),c=a("TjRS"),s=a("ZFoC"),l=a("GYKu"),b=a("Tmbg"),i=a("9b5V"),u=(a("aD51"),{});void 0!==u&&u&&u===Object(u)&&Object.isExtensible(u)&&!u.hasOwnProperty("__filemeta")&&Object.defineProperty(u,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/docs/hooks/useCalendarState.mdx"}});m="DateLabel";var m,p={_frontmatter:u},f=c.a;function D(e){var t,a=e.components,m=Object(r.a)(e,["components"]);return Object(d.b)(f,Object(n.a)({},p,m,{components:a,mdxType:"MDXLayout"}),Object(d.b)("h1",{id:"usecalendarstate"},"useCalendarState"),Object(d.b)("p",null,Object(d.b)("inlineCode",{parentName:"p"},"useCalendarState")," is a hook which will provide the current state of your components."),Object(d.b)("h2",{id:"example"},"Example"),Object(d.b)(s.c,{__position:0,__code:"() => {\n const DateLabel = () => {\n const { format, getDateFormat } = useDateAPI()\n const { startDate: selectedDate } = useCalendarState()\n let dateLabel = 'Select A Date'\n if (selectedDate) {\n const formatter = getDateFormat(formatNames.ARIA_DAY_LABEL)\n dateLabel = format(selectedDate, formatter)\n }\n return

{dateLabel}

\n }\n return (\n \n \n \n \n )\n}",__scope:(t={props:m,DefaultLayout:c.a,useState:o.useState,Playground:s.c,useDateAPI:l.t,useCalendarState:l.s,Calendar:l.c,CalendarProvider:l.d,formatNames:b.a,dateAdapter:i.a},t.DefaultLayout=c.a,t._frontmatter=u,t),mdxType:"Playground"},(function(){return Object(d.b)(l.d,{adapter:i.a,mdxType:"CalendarProvider"},Object(d.b)((function(){var e=Object(l.t)(),t=e.format,a=e.getDateFormat,n=Object(l.s)().startDate,r="Select A Date";n&&(r=t(n,a(b.a.ARIA_DAY_LABEL)));return Object(d.b)("p",{style:{padding:"8px"}},r)}),{mdxType:"DateLabel"}),Object(d.b)(l.c,{mdxType:"Calendar"}))})))}void 0!==D&&D&&D===Object(D)&&Object.isExtensible(D)&&!D.hasOwnProperty("__filemeta")&&Object.defineProperty(D,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/docs/hooks/useCalendarState.mdx"}}),D.isMDXComponent=!0}}]); 2 | //# sourceMappingURL=component---src-docs-hooks-use-calendar-state-mdx-839708fa49fb1650d779.js.map -------------------------------------------------------------------------------- /docs/component---src-docs-hooks-use-calendar-state-mdx-d273907bc340e564fb12.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[25],{"8sOg":function(e,t,a){"use strict";a.r(t),a.d(t,"_frontmatter",(function(){return u})),a.d(t,"default",(function(){return D}));var n=a("Fcif"),r=a("+I+c"),o=a("mXGw"),d=a("/FXl"),c=a("TjRS"),s=a("ZFoC"),l=a("GYKu"),b=a("Tmbg"),i=a("9b5V"),u=(a("aD51"),{});void 0!==u&&u&&u===Object(u)&&Object.isExtensible(u)&&!u.hasOwnProperty("__filemeta")&&Object.defineProperty(u,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/docs/hooks/useCalendarState.mdx"}});m="DateLabel";var m,p={_frontmatter:u},f=c.a;function D(e){var t,a=e.components,m=Object(r.a)(e,["components"]);return Object(d.b)(f,Object(n.a)({},p,m,{components:a,mdxType:"MDXLayout"}),Object(d.b)("h1",{id:"usecalendarstate"},"useCalendarState"),Object(d.b)("p",null,Object(d.b)("inlineCode",{parentName:"p"},"useCalendarState")," is a hook which will provide the current state of your components."),Object(d.b)("h2",{id:"example"},"Example"),Object(d.b)(s.c,{__position:0,__code:"() => {\n const DateLabel = () => {\n const { format, getDateFormat } = useDateAPI()\n const { startDate: selectedDate } = useCalendarState()\n let dateLabel = 'Select A Date'\n if (selectedDate) {\n const formatter = getDateFormat(formatNames.ARIA_DAY_LABEL)\n dateLabel = format(selectedDate, formatter)\n }\n return

{dateLabel}

\n }\n return (\n \n \n \n \n )\n}",__scope:(t={props:m,DefaultLayout:c.a,useState:o.useState,Playground:s.c,useDateAPI:l.t,useCalendarState:l.s,Calendar:l.c,CalendarProvider:l.d,formatNames:b.a,dateAdapter:i.a},t.DefaultLayout=c.a,t._frontmatter=u,t),mdxType:"Playground"},(function(){return Object(d.b)(l.d,{adapter:i.a,mdxType:"CalendarProvider"},Object(d.b)((function(){var e=Object(l.t)(),t=e.format,a=e.getDateFormat,n=Object(l.s)().startDate,r="Select A Date";n&&(r=t(n,a(b.a.ARIA_DAY_LABEL)));return Object(d.b)("p",{style:{padding:"8px"}},r)}),{mdxType:"DateLabel"}),Object(d.b)(l.c,{mdxType:"Calendar"}))})))}void 0!==D&&D&&D===Object(D)&&Object.isExtensible(D)&&!D.hasOwnProperty("__filemeta")&&Object.defineProperty(D,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/docs/hooks/useCalendarState.mdx"}}),D.isMDXComponent=!0}}]); 2 | //# sourceMappingURL=component---src-docs-hooks-use-calendar-state-mdx-d273907bc340e564fb12.js.map -------------------------------------------------------------------------------- /docs/component---src-docs-hooks-use-calendar-state-mdx-d3b2db02444906b5abb9.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[25],{"8sOg":function(e,t,a){"use strict";a.r(t),a.d(t,"_frontmatter",(function(){return i})),a.d(t,"default",(function(){return D}));var n=a("Fcif"),r=a("+I+c"),o=a("mXGw"),c=a("/FXl"),d=a("TjRS"),l=a("ZFoC"),s=a("GYKu"),b=a("Tmbg"),u=a("9b5V"),i=(a("aD51"),{});void 0!==i&&i&&i===Object(i)&&Object.isExtensible(i)&&!i.hasOwnProperty("__filemeta")&&Object.defineProperty(i,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/docs/hooks/useCalendarState.mdx"}});m="DateLabel";var m,p={_frontmatter:i},f=d.a;function D(e){var t,a=e.components,m=Object(r.a)(e,["components"]);return Object(c.b)(f,Object(n.a)({},p,m,{components:a,mdxType:"MDXLayout"}),Object(c.b)("h1",{id:"usecalendarstate"},"useCalendarState"),Object(c.b)("p",null,Object(c.b)("inlineCode",{parentName:"p"},"useCalendarState")," is a hook which will provide the current state of your components."),Object(c.b)("h2",{id:"example"},"Example"),Object(c.b)(l.c,{__position:0,__code:"() => {\n const DateLabel = () => {\n const { format, getDateFormat } = useDateAPI()\n const { startDate: selectedDate } = useCalendarState()\n let dateLabel = 'Select A Date'\n if (selectedDate) {\n const formatter = getDateFormat(formatNames.ARIA_DAY_LABEL)\n dateLabel = format(selectedDate, formatter)\n }\n return

{dateLabel}

\n }\n return (\n \n \n \n \n )\n}",__scope:(t={props:m,DefaultLayout:d.a,useState:o.useState,Playground:l.c,useDateAPI:s.t,useCalendarState:s.s,Calendar:s.c,CalendarProvider:s.d,formatNames:b.a,dateAdapter:u.a},t.DefaultLayout=d.a,t._frontmatter=i,t),mdxType:"Playground"},(function(){return Object(c.b)(s.d,{adapter:u.a,mdxType:"CalendarProvider"},Object(c.b)((function(){var e=Object(s.t)(),t=e.format,a=e.getDateFormat,n=Object(s.s)().startDate,r="Select A Date";n&&(r=t(n,a(b.a.ARIA_DAY_LABEL)));return Object(c.b)("p",null,r)}),{mdxType:"DateLabel"}),Object(c.b)(s.c,{mdxType:"Calendar"}))})))}void 0!==D&&D&&D===Object(D)&&Object.isExtensible(D)&&!D.hasOwnProperty("__filemeta")&&Object.defineProperty(D,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/docs/hooks/useCalendarState.mdx"}}),D.isMDXComponent=!0}}]); 2 | //# sourceMappingURL=component---src-docs-hooks-use-calendar-state-mdx-d3b2db02444906b5abb9.js.map -------------------------------------------------------------------------------- /docs/component---src-pages-404-js-3b6bdb96ce97e4259fd1.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[32],{w2l6:function(t,e,n){"use strict";n.r(e);n("mXGw");var i=n("aD51");e.default=function(){return Object(i.c)("div",{style:{display:"flex",alignItems:"center",justifyContent:"center",height:"100vh",width:"100vw",fontSize:32}},"Not Found")}}}]); 2 | //# sourceMappingURL=component---src-pages-404-js-3b6bdb96ce97e4259fd1.js.map -------------------------------------------------------------------------------- /docs/component---src-pages-404-js-3b6bdb96ce97e4259fd1.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///./src/pages/404.js"],"names":["style","display","alignItems","justifyContent","height","width","fontSize"],"mappings":"4FAAA,iCAeA,UAbiB,WAUf,OAAO,mBAAKA,MATE,CACZC,QADY,OAEZC,WAFY,SAGZC,eAHY,SAIZC,OAJY,QAKZC,MALY,QAMZC,SAAU,KAGZ","file":"component---src-pages-404-js-3b6bdb96ce97e4259fd1.js","sourcesContent":["import * as React from 'react'\n\nconst NotFound = () => {\n const style = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100vh',\n width: '100vw',\n fontSize: 32,\n }\n\n return
Not Found
\n}\n\nexport default NotFound\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /docs/page-data/404.html/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-pages-404-js","path":"/404.html","result":{"pageContext":{}},"staticQueryHashes":[]} -------------------------------------------------------------------------------- /docs/page-data/404/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-pages-404-js","path":"/404/","result":{"pageContext":{}},"staticQueryHashes":[]} -------------------------------------------------------------------------------- /docs/page-data/animatedGroup/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-animated-group-mdx","path":"/animatedGroup","result":{"pageContext":{"frontmatter":{"name":"AnimatedGroup","route":"/animatedGroup"},"entry":{"id":"271a11548524d6b6a93870ce3e46aac6","filepath":"src/src/docs/components/animatedGroup.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/animatedGroup.mdx","route":"/animatedGroup","slug":"src-src-docs-components-animated-group","name":"AnimatedGroup","menu":"","headings":[{"slug":"animatedgroup","depth":1,"value":"AnimatedGroup"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"},{"slug":"importing","depth":2,"value":"Importing"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/animatedMonthGroup/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-animated-month-group-mdx","path":"/animatedMonthGroup","result":{"pageContext":{"frontmatter":{"name":"AnimatedMonthGroup","route":"/animatedMonthGroup"},"entry":{"id":"34f28ddc510ba74a5ec407c20f110ce7","filepath":"src/src/docs/components/animatedMonthGroup.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/animatedMonthGroup.mdx","route":"/animatedMonthGroup","slug":"src-src-docs-components-animated-month-group","name":"AnimatedMonthGroup","menu":"","headings":[{"slug":"animatedmonthgroup","depth":1,"value":"AnimatedMonthGroup"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"},{"slug":"importing","depth":2,"value":"Importing"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/app-data.json: -------------------------------------------------------------------------------- 1 | {"webpackCompilationHash":"4b57b7db5a15e6553399"} 2 | -------------------------------------------------------------------------------- /docs/page-data/calendar/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-calendar-mdx","path":"/calendar","result":{"pageContext":{"frontmatter":{"name":"Calendar","route":"/calendar"},"entry":{"id":"8ef8c7af6a248a6c82dce6e73e17a623","filepath":"src/src/docs/components/calendar.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/calendar.mdx","route":"/calendar","slug":"src-src-docs-components-calendar","name":"Calendar","menu":"","headings":[{"slug":"calendar","depth":1,"value":"Calendar"},{"slug":"single-date","depth":2,"value":"Single Date"},{"slug":"date-range","depth":2,"value":"Date Range"},{"slug":"setting-initial-state","depth":2,"value":"Setting Initial State"},{"slug":"custom-day-renderers","depth":2,"value":"Custom Day Renderers"},{"slug":"block-dates","depth":2,"value":"Block dates"},{"slug":"validate-date-ranges","depth":2,"value":"Validate Date Ranges"},{"slug":"props","depth":2,"value":"Props"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/calendarProvider/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-calendar-provider-mdx","path":"/calendarProvider","result":{"pageContext":{"frontmatter":{"name":"CalendarProvider","route":"/calendarProvider"},"entry":{"id":"815cfbb6d9e0acd49760dec8835c2bc1","filepath":"src/src/docs/components/calendarProvider.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/calendarProvider.mdx","route":"/calendarProvider","slug":"src-src-docs-components-calendar-provider","name":"CalendarProvider","menu":"","headings":[{"slug":"calendarprovider","depth":1,"value":"CalendarProvider"},{"slug":"props","depth":2,"value":"Props"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/clickOutside/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-click-outside-mdx","path":"/clickOutside","result":{"pageContext":{"frontmatter":{"name":"ClickOutside","route":"/clickOutside"},"entry":{"id":"88346afe7b6a6a5368c2dde413b0e5db","filepath":"src/src/docs/components/clickOutside.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/clickOutside.mdx","route":"/clickOutside","slug":"src-src-docs-components-click-outside","name":"ClickOutside","menu":"","headings":[{"slug":"clickoutside","depth":1,"value":"ClickOutside"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/composition/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-composition-mdx","path":"/composition","result":{"pageContext":{"frontmatter":{"name":"Composition","route":"/composition"},"entry":{"id":"17be4339c431dcdce33d7c211a9e7c70","filepath":"src/src/docs/composition.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/composition.mdx","route":"/composition","slug":"src-src-docs-composition","name":"Composition","menu":"","headings":[{"slug":"composition","depth":1,"value":"Composition"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/date-frameworks/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-date-frameworks-mdx","path":"/date-frameworks","result":{"pageContext":{"frontmatter":{"name":"Date Frameworks","route":"/date-frameworks"},"entry":{"id":"91930323605139ecf6bb0063b539b95f","filepath":"src/src/docs/date-frameworks.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/date-frameworks.mdx","route":"/date-frameworks","slug":"src-src-docs-date-frameworks","name":"Date Frameworks","menu":"","headings":[{"slug":"date-frameworks","depth":1,"value":"Date Frameworks"},{"slug":"with-date-fns","depth":2,"value":"With date-fns"},{"slug":"with-dayjs","depth":2,"value":"With dayjs"},{"slug":"with-luxon","depth":2,"value":"With luxon"},{"slug":"with-moment","depth":2,"value":"With moment"},{"slug":"week-offset","depth":2,"value":"Week Offset"},{"slug":"write-your-own-adapter","depth":2,"value":"Write Your Own Adapter"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/day/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-day-mdx","path":"/day","result":{"pageContext":{"frontmatter":{"name":"Day","route":"/day"},"entry":{"id":"9dcc04b2f7bbfaa110413a0a6d409de7","filepath":"src/src/docs/components/day.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/day.mdx","route":"/day","slug":"src-src-docs-components-day","name":"Day","menu":"","headings":[{"slug":"day","depth":1,"value":"Day"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"},{"slug":"importing","depth":2,"value":"Importing"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/dayOfWeek/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-day-of-week-mdx","path":"/dayOfWeek","result":{"pageContext":{"frontmatter":{"name":"DayOfWeek","route":"/dayOfWeek"},"entry":{"id":"0a063c11d539720a9a71a6dea402d37c","filepath":"src/src/docs/components/dayOfWeek.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/dayOfWeek.mdx","route":"/dayOfWeek","slug":"src-src-docs-components-day-of-week","name":"DayOfWeek","menu":"","headings":[{"slug":"dayofweek","depth":1,"value":"DayOfWeek"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"},{"slug":"importing","depth":2,"value":"Importing"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/dev-404-page/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---cache-dev-404-page-js","path":"/dev-404-page/","result":{"data":{"allSitePage":{"nodes":[{"path":"/composition"},{"path":"/date-frameworks"},{"path":"/getting-started"},{"path":"/"},{"path":"/localization"},{"path":"/state"},{"path":"/theming"},{"path":"/animatedMonthGroup"},{"path":"/calendar"},{"path":"/calendarProvider"},{"path":"/clickOutside"},{"path":"/animatedGroup"},{"path":"/dayOfWeek"},{"path":"/header"},{"path":"/day"},{"path":"/month"},{"path":"/monthGroup"},{"path":"/popper"},{"path":"/root"},{"path":"/week"},{"path":"/useCalendarDispatch"},{"path":"/weekHeader"},{"path":"/useCalendarState"},{"path":"/useDateInput"},{"path":"/useCalendarProps"},{"path":"/useDateAPI"},{"path":"/useDateRangeInput"},{"path":"/404/"},{"path":"/404.html"}]}},"pageContext":{}},"staticQueryHashes":[]} -------------------------------------------------------------------------------- /docs/page-data/getting-started/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-getting-started-mdx","path":"/getting-started","result":{"pageContext":{"frontmatter":{"name":"Getting Started","route":"/getting-started"},"entry":{"id":"b1b116734563eb658dab1f854825977a","filepath":"src/src/docs/getting-started.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/getting-started.mdx","route":"/getting-started","slug":"src-src-docs-getting-started","name":"Getting Started","menu":"","headings":[{"slug":"getting-started","depth":2,"value":"Getting Started"},{"slug":"for-date-fns-users","depth":3,"value":"For date-fns users"},{"slug":"for-dayjs-users","depth":3,"value":"For dayjs users"},{"slug":"for-luxon-users","depth":3,"value":"For luxon users"},{"slug":"for-moment-users","depth":3,"value":"For moment users"},{"slug":"calendar-example","depth":2,"value":"Calendar Example"},{"slug":"input--calendar-example","depth":2,"value":"Input & Calendar Example"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/header/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-header-mdx","path":"/header","result":{"pageContext":{"frontmatter":{"name":"Header","route":"/header"},"entry":{"id":"d56db73595463ad62fdf32842cbaa6e8","filepath":"src/src/docs/components/header.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/header.mdx","route":"/header","slug":"src-src-docs-components-header","name":"Header","menu":"","headings":[{"slug":"header","depth":1,"value":"Header"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"},{"slug":"importing","depth":2,"value":"Importing"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/index/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-home-mdx","path":"/","result":{"pageContext":{"frontmatter":{"name":"Home","route":"/","fullPage":true},"entry":{"id":"e955be39a544e8cd7f90ce3094314f68","filepath":"src/src/docs/home.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/home.mdx","route":"/","slug":"src-src-docs-home","name":"Home","menu":"","headings":[]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/localization/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-localization-mdx","path":"/localization","result":{"pageContext":{"frontmatter":{"name":"Localization","route":"/localization"},"entry":{"id":"0a4a5c790c811daf29765f90c5ee0626","filepath":"src/src/docs/localization.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/localization.mdx","route":"/localization","slug":"src-src-docs-localization","name":"Localization","menu":"","headings":[{"slug":"localization","depth":1,"value":"Localization"},{"slug":"format-names","depth":2,"value":"Format Names"},{"slug":"date-fns-with-a-russian-locale","depth":2,"value":"Date-fns with a Russian locale"},{"slug":"dayjs-with-a-chinese-locale","depth":2,"value":"Dayjs with a Chinese locale"},{"slug":"luxon-with-a-french-locale","depth":2,"value":"Luxon with a French locale"},{"slug":"moment-with-a-spanish-locale","depth":2,"value":"Moment with a Spanish locale"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/month/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-month-mdx","path":"/month","result":{"pageContext":{"frontmatter":{"name":"Month","route":"/month"},"entry":{"id":"f41bd0dbdf947ccb162d09af481ab0fa","filepath":"src/src/docs/components/month.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/month.mdx","route":"/month","slug":"src-src-docs-components-month","name":"Month","menu":"","headings":[{"slug":"month","depth":1,"value":"Month"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"},{"slug":"importing","depth":2,"value":"Importing"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/monthGroup/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-month-group-mdx","path":"/monthGroup","result":{"pageContext":{"frontmatter":{"name":"MonthGroup","route":"/monthGroup"},"entry":{"id":"059052332e522bba64fbc4c9ec55e0a8","filepath":"src/src/docs/components/monthGroup.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/monthGroup.mdx","route":"/monthGroup","slug":"src-src-docs-components-month-group","name":"MonthGroup","menu":"","headings":[{"slug":"monthgroup","depth":1,"value":"MonthGroup"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"},{"slug":"importing","depth":2,"value":"Importing"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/popper/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-popper-mdx","path":"/popper","result":{"pageContext":{"frontmatter":{"name":"Popper","route":"/popper"},"entry":{"id":"b904d0e8ef222029f3e1dba816cb27d6","filepath":"src/src/docs/components/popper.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/popper.mdx","route":"/popper","slug":"src-src-docs-components-popper","name":"Popper","menu":"","headings":[{"slug":"popper","depth":2,"value":"Popper"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/root/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-root-mdx","path":"/root","result":{"pageContext":{"frontmatter":{"name":"Root","route":"/root"},"entry":{"id":"a710ad3fb034f6357621494e6632459a","filepath":"src/src/docs/components/root.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/root.mdx","route":"/root","slug":"src-src-docs-components-root","name":"Root","menu":"","headings":[{"slug":"root","depth":1,"value":"Root"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"},{"slug":"importing","depth":2,"value":"Importing"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/state/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-state-mdx","path":"/state","result":{"pageContext":{"frontmatter":{"name":"State","route":"/state"},"entry":{"id":"4393139ba0f485f9f99a67632290f1de","filepath":"src/src/docs/state.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/state.mdx","route":"/state","slug":"src-src-docs-state","name":"State","menu":"","headings":[{"slug":"state","depth":1,"value":"State"},{"slug":"default-reducers","depth":2,"value":"Default Reducers"},{"slug":"calendarreducer","depth":3,"value":"calendarReducer"},{"slug":"singledatereducer","depth":3,"value":"singleDateReducer"},{"slug":"daterangereducer","depth":3,"value":"dateRangeReducer"},{"slug":"dateinputreducer","depth":3,"value":"dateInputReducer"},{"slug":"daterangeinputreducer","depth":3,"value":"dateRangeInputReducer"},{"slug":"reading-state","depth":2,"value":"Reading State"},{"slug":"changing-state","depth":2,"value":"Changing State"},{"slug":"usecalendardispatch","depth":3,"value":"useCalendarDispatch"},{"slug":"actions-ref","depth":3,"value":"Actions Ref"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/theming/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-theming-mdx","path":"/theming","result":{"pageContext":{"frontmatter":{"name":"Theming","route":"/theming"},"entry":{"id":"ddc096c44672ac53caac2f28df119b8f","filepath":"src/src/docs/theming.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/theming.mdx","route":"/theming","slug":"src-src-docs-theming","name":"Theming","menu":"","headings":[{"slug":"theming","depth":1,"value":"Theming"},{"slug":"create-your-own-theme","depth":2,"value":"Create Your Own Theme"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/useCalendarDispatch/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-hooks-use-calendar-dispatch-mdx","path":"/useCalendarDispatch","result":{"pageContext":{"frontmatter":{"name":"useCalendarDispatch","route":"/useCalendarDispatch"},"entry":{"id":"2a2e42235acc1c7bb99d1a8db725f582","filepath":"src/src/docs/hooks/useCalendarDispatch.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/hooks/useCalendarDispatch.mdx","route":"/useCalendarDispatch","slug":"src-src-docs-hooks-use-calendar-dispatch","name":"useCalendarDispatch","menu":"","headings":[{"slug":"usecalendardispatch","depth":1,"value":"useCalendarDispatch"},{"slug":"using-the-dispatcher","depth":2,"value":"Using the dispatcher"},{"slug":"using-the-helper-api","depth":2,"value":"Using the helper API"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/useCalendarProps/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-hooks-use-calendar-props-mdx","path":"/useCalendarProps","result":{"pageContext":{"frontmatter":{"name":"useCalendarProps","route":"/useCalendarProps"},"entry":{"id":"f77ecbae7a6735ee5ecd807267482341","filepath":"src/src/docs/hooks/useCalendarProps.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/hooks/useCalendarProps.mdx","route":"/useCalendarProps","slug":"src-src-docs-hooks-use-calendar-props","name":"useCalendarProps","menu":"","headings":[{"slug":"usecalendarprops","depth":1,"value":"useCalendarProps"},{"slug":"example","depth":2,"value":"Example"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/useCalendarState/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-hooks-use-calendar-state-mdx","path":"/useCalendarState","result":{"pageContext":{"frontmatter":{"name":"useCalendarState","route":"/useCalendarState"},"entry":{"id":"a01e5c9e4f260276b9ab70368dac9d9b","filepath":"src/src/docs/hooks/useCalendarState.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/hooks/useCalendarState.mdx","route":"/useCalendarState","slug":"src-src-docs-hooks-use-calendar-state","name":"useCalendarState","menu":"","headings":[{"slug":"usecalendarstate","depth":1,"value":"useCalendarState"},{"slug":"example","depth":2,"value":"Example"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/useDateAPI/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-hooks-use-date-api-mdx","path":"/useDateAPI","result":{"pageContext":{"frontmatter":{"name":"useDateAPI","route":"/useDateAPI"},"entry":{"id":"7182a5788b009ab88caa19a211d70eb4","filepath":"src/src/docs/hooks/useDateAPI.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/hooks/useDateAPI.mdx","route":"/useDateAPI","slug":"src-src-docs-hooks-use-date-api","name":"useDateAPI","menu":"","headings":[{"slug":"usedateapi","depth":1,"value":"useDateAPI"},{"slug":"example","depth":2,"value":"Example"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/useDateInput/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-hooks-use-date-input-mdx","path":"/useDateInput","result":{"pageContext":{"frontmatter":{"name":"useDateInput","route":"/useDateInput"},"entry":{"id":"11c10eefd78f41aab570723c844c87e1","filepath":"src/src/docs/hooks/useDateInput.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/hooks/useDateInput.mdx","route":"/useDateInput","slug":"src-src-docs-hooks-use-date-input","name":"useDateInput","menu":"","headings":[{"slug":"usedateinput","depth":1,"value":"useDateInput"},{"slug":"example","depth":2,"value":"Example"},{"slug":"actions","depth":2,"value":"Actions"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/useDateRangeInput/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-hooks-use-date-range-input-mdx","path":"/useDateRangeInput","result":{"pageContext":{"frontmatter":{"name":"useDateRangeInput","route":"/useDateRangeInput"},"entry":{"id":"81bba19baba082a81196bd68541a957f","filepath":"src/src/docs/hooks/useDateRangeInput.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/hooks/useDateRangeInput.mdx","route":"/useDateRangeInput","slug":"src-src-docs-hooks-use-date-range-input","name":"useDateRangeInput","menu":"","headings":[{"slug":"usedaterangeinput","depth":1,"value":"useDateRangeInput"},{"slug":"example","depth":2,"value":"Example"},{"slug":"actions","depth":2,"value":"Actions"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/week/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-week-mdx","path":"/week","result":{"pageContext":{"frontmatter":{"name":"Week","route":"/week"},"entry":{"id":"aaf0ee6556c068ca2540cdb9271d45b0","filepath":"src/src/docs/components/week.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/week.mdx","route":"/week","slug":"src-src-docs-components-week","name":"Week","menu":"","headings":[{"slug":"week","depth":1,"value":"Week"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"},{"slug":"importing","depth":2,"value":"Importing"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/page-data/weekHeader/page-data.json: -------------------------------------------------------------------------------- 1 | {"componentChunkName":"component---src-docs-components-week-header-mdx","path":"/weekHeader","result":{"pageContext":{"frontmatter":{"name":"WeekHeader","route":"/weekHeader"},"entry":{"id":"501ae8632f15e56a93b67582cb20bde9","filepath":"src/src/docs/components/weekHeader.mdx","fullpath":"/Users/mark/Documents/use-date-input-patch/src/docs/components/weekHeader.mdx","route":"/weekHeader","slug":"src-src-docs-components-week-header","name":"WeekHeader","menu":"","headings":[{"slug":"weekheader","depth":1,"value":"WeekHeader"},{"slug":"example","depth":2,"value":"Example"},{"slug":"props","depth":2,"value":"Props"},{"slug":"importing","depth":2,"value":"Importing"}]}}},"staticQueryHashes":["1635659820"]} -------------------------------------------------------------------------------- /docs/public/cross.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/styles-4b976dc17984c79c8d52.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[35],[]]); 2 | //# sourceMappingURL=styles-4b976dc17984c79c8d52.js.map -------------------------------------------------------------------------------- /docs/styles-4b976dc17984c79c8d52.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"styles-4b976dc17984c79c8d52.js","sourceRoot":""} -------------------------------------------------------------------------------- /docs/styles.2543ff947a193d7f33b1.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Inconsolata&display=swap);@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro&display=swap); -------------------------------------------------------------------------------- /doczrc.js: -------------------------------------------------------------------------------- 1 | export default { 2 | base: '/use-date-input/', 3 | title: 'use-date-input - Build Your Own Date Picker', 4 | shortTitle: 'use-date-input', 5 | editBranch: "https://github.com/mark-tate/use-date-input", 6 | dest: './docs', 7 | propsParser: false, 8 | public: '/public', 9 | src: './src', 10 | menu: [ 11 | "Getting Started", 12 | "State", 13 | "Theming", 14 | "Composition", 15 | "Date Frameworks", 16 | "Localization", 17 | { 18 | name: "Components", 19 | menu: [ 20 | { name: "AnimatedGroup", route: "/animatedGroup" }, 21 | { name: "AnimatedMonthGroup", route: "/animatedMonthGroup" }, 22 | { name: "Calendar", route: "/calendar" }, 23 | { name: "CalendarProvider", route: "/calendarProvider" }, 24 | { name: "ClickOutside", route: "/clickOutside" }, 25 | { name: "Day", route: "/day" }, 26 | { name: "DayOfWeek", route: "/dayOfWeek" }, 27 | { name: "Header", route: "/header" }, 28 | { name: "Month", route: "/month" }, 29 | { name: "MonthGroup", route: "/monthGroup" }, 30 | { name: "Popper", route: "/popper" }, 31 | { name: "Root", route: "/root" }, 32 | { name: "Week", route: "/week" }, 33 | { name: "WeekHeader", route: "/weekHeader" }, 34 | ] 35 | }, 36 | { 37 | name: "Hooks", 38 | menu: [ 39 | { name: "useDateInput", route: "/useDateInput", menu: "Hooks" }, 40 | { name: "useDateRangeInput", route: "/useDateRangeInput", menu: "Hooks" }, 41 | { name: "useCalendarProps", route: "/useCalendarProps", menu: "Hooks" }, 42 | { name: "useCalendarState", route: "/useCalendarState", menu: "Hooks" }, 43 | { name: "useDateAPI", route: "/useDateAPI", menu: "Hooks" }, 44 | { name: "useCalendarDispatch", route: "/useCalendarDispatch", menu: "Hooks" } 45 | ] 46 | }, 47 | ] 48 | }; 49 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | { 4 | resolve: `gatsby-plugin-material-ui`, 5 | options: { 6 | stylesProvider: { 7 | injectFirst: true 8 | } 9 | } 10 | } 11 | ] 12 | }; 13 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require("./config/jest/jest.config.js"); 2 | 3 | module.exports = { 4 | ...base, 5 | projects: ["/packages/*/jest.config.js"], 6 | coverageDirectory: "/coverage/", 7 | }; 8 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "npmClient": "yarn", 4 | "useWorkspaces": true, 5 | "version": "independent" 6 | } 7 | -------------------------------------------------------------------------------- /packages/common/.prettierignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/src 3 | -------------------------------------------------------------------------------- /packages/common/README.md: -------------------------------------------------------------------------------- 1 | # @use-date-input/common 2 | 3 | The commons package for [@use-date-input](https://github.com/mark-tate/use-date-input). 4 | 5 | [@use-date-input](https://github.com/mark-tate/use-date-input) is a collection of React UI components and hooks to help compose date picker components. 6 | 7 | To get started, refer to [getting started](https://mark-tate.github.io/use-date-input/getting-started). 8 | 9 | For the full documentation, refer to the [documentation](https://mark-tate.github.io/use-date-input/). 10 | -------------------------------------------------------------------------------- /packages/common/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@babel/preset-env"], 3 | plugins: [ 4 | [ 5 | "@babel/plugin-transform-runtime", 6 | { 7 | corejs: false, 8 | helpers: true, 9 | regenerator: false, 10 | useESModules: true 11 | } 12 | ] 13 | ] 14 | }; 15 | -------------------------------------------------------------------------------- /packages/common/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require("../../config/jest/jest.config.js"); 2 | 3 | module.exports = { 4 | ...base, 5 | name: "@use-date-input/common", 6 | displayName: "@use-date-input/common" 7 | }; 8 | -------------------------------------------------------------------------------- /packages/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@use-date-input/common", 3 | "version": "0.2.0-beta.0", 4 | "author": "Mark Tate <143323+mark-tate@users.noreply.github.com>", 5 | "description": "@use-date-input - Commons library", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "jsnext:main": "dist/index.esm.js", 9 | "module": "dist/index.esm.js", 10 | "keywords": [ 11 | "calendar", 12 | "date", 13 | "datepicker", 14 | "date-picker", 15 | "date-input", 16 | "date-range", 17 | "hook", 18 | "input", 19 | "use-date-input", 20 | "useDateInput", 21 | "useDateRange", 22 | "react", 23 | "react-component" 24 | ], 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/mark-tate/use-date-input.git", 28 | "directory": "packages/common" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/mark-tate/use-date-input/issues" 32 | }, 33 | "peerDependencies": { 34 | "react": ">=16.8.0", 35 | "react-dom": ">=16.8.0" 36 | }, 37 | "publishConfig": { 38 | "access": "public" 39 | }, 40 | "files": [ 41 | "dist/index*.js" 42 | ], 43 | "sideEffects": false, 44 | "scripts": { 45 | "build": "rollup -c", 46 | "prettier": "prettier --write \"**/*.+(js|jsx|json|css|md)\"", 47 | "lint": "eslint --ext .js,.jsx,.ts,.tsx src --color", 48 | "test": "jest" 49 | }, 50 | "browserslist": { 51 | "production": [ 52 | ">0.2%", 53 | "not dead", 54 | "not op_mini all" 55 | ], 56 | "development": [ 57 | "last 1 chrome version", 58 | "last 1 firefox version", 59 | "last 1 safari version" 60 | ] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/common/src/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import { formatNames } from "../index"; 2 | 3 | describe("given formatNames", () => { 4 | it("is defined", () => { 5 | expect(formatNames).toBeDefined(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/common/src/formatNames.js: -------------------------------------------------------------------------------- 1 | const formatNames = { 2 | ARIA_DAY_LABEL: "ARIA_DAY_LABEL", 3 | ARIA_START_LABEL: "ARIA_START_LABEL", 4 | ARIA_END_LABEL: "ARIA_END_LABEL", 5 | ISO: "ISO", 6 | HEADER: "HEADER", 7 | DAY: "DAY", 8 | DAY_OF_WEEK_ABBREVIATED: "DAY_OF_WEEK_ABBREVIATED", 9 | DAY_OF_WEEK_FULL: "DAY_OF_WEEK_FULL", 10 | MONTH: "MONTH", 11 | MONTH_ABBREVIATED: "MONTH_ABBREVIATED", 12 | MONTH_FULL: "MONTH_FULL", 13 | YEAR: "YEAR" 14 | }; 15 | 16 | export default formatNames; 17 | -------------------------------------------------------------------------------- /packages/common/src/index.js: -------------------------------------------------------------------------------- 1 | export { default as formatNames } from "./formatNames"; 2 | export { default as useForkRef } from "./useForkRef"; 3 | -------------------------------------------------------------------------------- /packages/common/src/useForkRef.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function setRef(ref, value) { 4 | if (typeof ref === "function") { 5 | ref(value); 6 | } else if (ref) { 7 | ref.current = value; 8 | } 9 | } 10 | 11 | export default function useForkRef(refA, refB) { 12 | /** 13 | * This will create a new function if the ref props change and are defined. 14 | * This means react will call the old forkRef with `null` and the new forkRef 15 | * with the ref. Cleanup naturally emerges from this behavior 16 | */ 17 | return React.useMemo(() => { 18 | if (refA == null && refB == null) { 19 | return null; 20 | } 21 | return refValue => { 22 | setRef(refA, refValue); 23 | setRef(refB, refValue); 24 | }; 25 | }, [refA, refB]); 26 | } 27 | -------------------------------------------------------------------------------- /packages/core/.prettierignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/src 3 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # @use-date-core 2 | 3 | The core package for [@use-date-input](https://github.com/mark-tate/use-date-input). 4 | 5 | [@use-date-input](https://github.com/mark-tate/use-date-input) is a collection of React UI components and hooks to help compose date picker components. 6 | 7 | To get started, refer to [getting started](https://mark-tate.github.io/use-date-input/getting-started). 8 | 9 | For the full documentation, refer to the [documentation](https://mark-tate.github.io/use-date-input/). 10 | -------------------------------------------------------------------------------- /packages/core/babel.config.js: -------------------------------------------------------------------------------- 1 | const { NODE_ENV } = process.env; 2 | 3 | const inProduction = NODE_ENV === "production"; 4 | const inDevelopment = NODE_ENV === "development"; 5 | 6 | const environmentConfig = { 7 | test: { 8 | compact: false, 9 | presets: [ 10 | [ 11 | "@babel/preset-env", 12 | { 13 | modules: "cjs", 14 | debug: false 15 | } 16 | ], 17 | "@babel/preset-react" 18 | ], 19 | plugins: [ 20 | [ 21 | "@babel/plugin-transform-runtime", 22 | { 23 | corejs: false, 24 | helpers: true, 25 | regenerator: true, 26 | useESModules: true 27 | } 28 | ], 29 | ["@babel/plugin-proposal-object-rest-spread", { loose: true }], 30 | "@babel/plugin-proposal-class-properties" 31 | ] 32 | }, 33 | production: { 34 | presets: [["@babel/preset-env", { modules: false }], "@babel/preset-react"], 35 | plugins: [ 36 | [ 37 | "@babel/plugin-transform-runtime", 38 | { 39 | corejs: false, 40 | helpers: true, 41 | regenerator: false, 42 | useESModules: true 43 | } 44 | ], 45 | ["@babel/plugin-proposal-object-rest-spread", { loose: true }], 46 | "@babel/plugin-proposal-class-properties", 47 | "babel-plugin-styled-components" 48 | ] 49 | }, 50 | development: { 51 | compact: false, 52 | presets: [["@babel/preset-env", { modules: false }], "@babel/preset-react"], 53 | plugins: [ 54 | [ 55 | "@babel/plugin-transform-runtime", 56 | { 57 | corejs: false, 58 | helpers: true, 59 | regenerator: false, 60 | useESModules: true 61 | } 62 | ], 63 | ["@babel/plugin-proposal-object-rest-spread", { loose: true }], 64 | "@babel/plugin-proposal-class-properties", 65 | "babel-plugin-styled-components" 66 | ] 67 | } 68 | }; 69 | 70 | module.exports = api => { 71 | api.cache.using(() => process.env.NODE_ENV); 72 | return environmentConfig[process.env.NODE_ENV || "development"]; 73 | }; 74 | -------------------------------------------------------------------------------- /packages/core/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require("../../config/jest/jest.config.js"); 2 | 3 | module.exports = { 4 | ...base, 5 | moduleNameMapper: { 6 | "test-utils": "/src/test-utils.js" 7 | }, 8 | name: "@use-date-input/core", 9 | displayName: "@use-date-input/core" 10 | }; 11 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@use-date-input/core", 3 | "version": "0.2.1-beta.0", 4 | "author": "Mark Tate <143323+mark-tate@users.noreply.github.com>", 5 | "description": "@use-date-input - Core component and hooks", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "jsnext:main": "dist/index.esm.js", 9 | "module": "dist/index.esm.js", 10 | "keywords": [ 11 | "calendar", 12 | "date", 13 | "datepicker", 14 | "date-picker", 15 | "date-input", 16 | "date-range", 17 | "hook", 18 | "input", 19 | "use-date-input", 20 | "useDateInput", 21 | "useDateRange", 22 | "react", 23 | "react-component" 24 | ], 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/mark-tate/use-date-input.git", 28 | "directory": "packages/core" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/mark-tate/use-date-input/issues" 32 | }, 33 | "dependencies": { 34 | "@seznam/compose-react-refs": "1.0.4", 35 | "@use-date-input/common": "^0.2.0-beta.0", 36 | "clsx": "^1.0.2", 37 | "prop-types": "^15.7.2", 38 | "react-focus-lock": "^2.2.1", 39 | "react-transition-group": "^4.3.0", 40 | "styled-components": "5.1.0", 41 | "use-debounce": "^3.4.0" 42 | }, 43 | "devDependencies": { 44 | "date-fns": "^2.12.0", 45 | "dayjs": "^1.8.24", 46 | "luxon": "^1.23.0", 47 | "moment": "^2.24.0" 48 | }, 49 | "peerDependencies": { 50 | "react": ">=16.8.0", 51 | "react-dom": ">=16.8.0", 52 | "styled-components": ">=5.1.0" 53 | }, 54 | "publishConfig": { 55 | "access": "public" 56 | }, 57 | "files": [ 58 | "dist/index*.js" 59 | ], 60 | "sideEffects": false, 61 | "scripts": { 62 | "build": "rollup -c", 63 | "prettier": "prettier --write \"**/*.+(js|jsx|json|css|md)\"", 64 | "lint": "eslint --ext .js,.jsx,.ts,.tsx src --color", 65 | "test": "jest" 66 | }, 67 | "browserslist": { 68 | "production": [ 69 | ">0.2%", 70 | "not dead", 71 | "not op_mini all" 72 | ], 73 | "development": [ 74 | "last 1 chrome version", 75 | "last 1 firefox version", 76 | "last 1 safari version" 77 | ] 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /packages/core/src/AnimatedGroup/AnimatedGroup.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { CSSTransition, TransitionGroup } from "react-transition-group"; 4 | 5 | import { StyledPage } from "./style"; 6 | 7 | const AnimatedGroup = forwardRef(function AnimatedGroup( 8 | { 9 | children, 10 | className, 11 | direction, 12 | durationMsecs, 13 | movement, 14 | onEnter, 15 | onExited, 16 | transitionKey 17 | }, 18 | ref 19 | ) { 20 | const childFactory = child => 21 | React.cloneElement(child, { direction, movement }); 22 | return ( 23 | 29 | 36 | 41 | {children} 42 | 43 | 44 | 45 | ); 46 | }); 47 | 48 | AnimatedGroup.defaultProps = { 49 | durationMsecs: 1200 50 | }; 51 | 52 | AnimatedGroup.propTypes = { 53 | /** Children */ 54 | children: PropTypes.node, 55 | /** Class name of root element */ 56 | className: PropTypes.string, 57 | /** Duration of animation in msecs */ 58 | durationMsecs: PropTypes.number, 59 | /** Direction of animation */ 60 | direction: PropTypes.oneOf(["forward", "back"]), 61 | /** Pixel movement required */ 62 | movement: PropTypes.number, 63 | /** Callback called onEnter */ 64 | onEnter: PropTypes.func, 65 | /** Callback called onExited */ 66 | onExited: PropTypes.func, 67 | /** Key for animation */ 68 | transitionKey: PropTypes.string.isRequired 69 | }; 70 | 71 | export default AnimatedGroup; 72 | -------------------------------------------------------------------------------- /packages/core/src/AnimatedGroup/__tests__/AnimatedGroup.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { CSSTransition } from "react-transition-group"; 3 | import { render } from "@testing-library/react"; 4 | 5 | import AnimatedGroup from "../AnimatedGroup"; 6 | 7 | jest.mock("react-transition-group", () => { 8 | const FakeTransitionGroup = jest.fn(({ children }) => children); 9 | const FakeTransition = jest.fn(({ children }) => children); 10 | const FakeCSSTransition = jest.fn(props => ( 11 | {props.children} 12 | )); 13 | return { 14 | CSSTransition: FakeCSSTransition, 15 | Transition: FakeTransition, 16 | TransitionGroup: FakeTransitionGroup 17 | }; 18 | }); 19 | 20 | describe("given AnimatedGroup", () => { 21 | it("renders an animated group", () => { 22 | const children = expect.any(Object); 23 | const onEnterMock = jest.fn(); 24 | const onExitedMock = jest.fn(); 25 | const { getByText } = render( 26 | 31 | 2020 32 | 33 | ); 34 | const defaultProps = { 35 | children, 36 | timeout: 1200, 37 | classNames: "page", 38 | onEnter: onEnterMock, 39 | onExited: onExitedMock 40 | }; 41 | const context = expect.any(Object); 42 | expect(CSSTransition).toHaveBeenCalledWith( 43 | expect.objectContaining(defaultProps), 44 | context 45 | ); 46 | expect(getByText("2020")).toBeInTheDocument(); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/core/src/AnimatedGroup/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | 4 | import { setComponents } from "../../CalendarProvider"; 5 | import { CustomisableAnimatedGroup } from "../index"; 6 | 7 | jest.mock("../../CalendarProvider"); 8 | 9 | describe("given AnimatedGroup", () => { 10 | it("can be overriden with a custom component", () => { 11 | const TestComponent = () => "TEST CUSTOM COMPONENT"; 12 | setComponents({ AnimatedGroup: TestComponent }); 13 | const { getByText } = render(); 14 | expect(getByText("TEST CUSTOM COMPONENT")).toBeInTheDocument(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/core/src/AnimatedGroup/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | 3 | import { useCalendarComponent } from "../CalendarProvider"; 4 | import UnstyledAnimatedGroup from "./AnimatedGroup"; 5 | import { withStyledGroup } from "./style"; 6 | 7 | const DefaultAnimatedGroup = withStyledGroup(UnstyledAnimatedGroup); 8 | 9 | export const CustomisableAnimatedGroup = forwardRef( 10 | function CustomisableAnimatedGroup(props, ref) { 11 | const { 12 | AnimatedGroup: Component = DefaultAnimatedGroup 13 | } = useCalendarComponent(); 14 | return ; 15 | } 16 | ); 17 | 18 | export default DefaultAnimatedGroup; 19 | -------------------------------------------------------------------------------- /packages/core/src/AnimatedGroup/style.js: -------------------------------------------------------------------------------- 1 | import styled, { keyframes } from "styled-components"; 2 | 3 | const slideInLeft = movement => keyframes` 4 | from { 5 | tranform-origin: 100%; 6 | transform: translate3d(-${movement}px, 0, 0); 7 | } 8 | to { 9 | transform: translate3d(0, 0 ,0); 10 | } 11 | `; 12 | 13 | const slideOutLeft = movement => keyframes` 14 | from { 15 | transform: translate3d(0, 0, 0); 16 | } 17 | to { 18 | transform: translate3d(-${movement}px, 0 ,0); 19 | } 20 | `; 21 | 22 | const slideInRight = movement => keyframes` 23 | from { 24 | transform: translate3d(${movement}px, 0, 0); 25 | } 26 | to { 27 | transform: translate3d(0, 0, 0); 28 | } 29 | `; 30 | 31 | const slideOutRight = movement => keyframes` 32 | from { 33 | transform: translate3d(0, 0, 0); 34 | } 35 | to { 36 | transform: translate3d(${movement}px, 0 ,0); 37 | } 38 | `; 39 | 40 | export const StyledPage = styled.div` 41 | animation-duration: ${({ durationMsecs }) => `${durationMsecs}ms`}; 42 | animation-timing-function: ease-in-out; 43 | &.page-enter { 44 | pointer-events: none; 45 | } 46 | &.page-enter-active { 47 | animation-name: ${({ direction, movement }) => 48 | direction === "forward" ? slideInRight(movement) : slideInLeft(movement)}; 49 | } 50 | &.page-exit-active { 51 | animation-name: ${({ direction, movement }) => 52 | direction === "forward" 53 | ? slideOutLeft(movement) 54 | : slideOutRight(movement)}; 55 | } 56 | &.page-exit { 57 | pointer-events: none; 58 | position: absolute; 59 | } 60 | `; 61 | 62 | export const withStyledGroup = GroupComponent => styled(GroupComponent)` 63 | overflow: hidden; 64 | display: flex; 65 | position: relative; 66 | flex-direction: ${({ direction }) => 67 | direction === "forward" ? "row-reverse" : "row"}; 68 | `; 69 | -------------------------------------------------------------------------------- /packages/core/src/AnimatedMonthGroup/AnimatedMonthGroup.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef } from "react"; 2 | import { CustomisableAnimatedGroup } from "../AnimatedGroup"; 3 | import PropTypes from "prop-types"; 4 | import { useCalendarProps, useDateAPI } from "../CalendarProvider"; 5 | 6 | function AnimatedMonthGroup({ 7 | firstColumnRef, 8 | groupRef, 9 | visibleFromDate, 10 | ...rest 11 | }) { 12 | const { numOfColumns } = useCalendarProps(); 13 | const dateAPI = useDateAPI(); 14 | 15 | const lastMovement = useRef(0); 16 | const lastDirection = useRef(); 17 | const firstColumnWidth = useRef(0); 18 | const groupWidth = useRef(0); 19 | 20 | const lastAnimatedDate = useRef(visibleFromDate); 21 | 22 | useEffect(() => { 23 | if (firstColumnRef.current) { 24 | firstColumnWidth.current = firstColumnRef.current.clientWidth; 25 | } 26 | if (groupRef.current) { 27 | groupWidth.current = groupRef.current.clientWidth; 28 | } 29 | }); 30 | 31 | let movement = lastMovement.current; 32 | const dateDiff = dateAPI.diffInMonths( 33 | lastAnimatedDate.current, 34 | visibleFromDate 35 | ); 36 | const absDateDiff = Math.abs(dateDiff); 37 | if (absDateDiff >= numOfColumns) { 38 | movement = groupWidth.current; 39 | } else if (absDateDiff >= 1) { 40 | movement = absDateDiff * firstColumnWidth.current; 41 | } 42 | 43 | let animationDirection = lastDirection.current; 44 | if (dateDiff > 0) { 45 | animationDirection = "back"; 46 | } else if (dateDiff < 0) { 47 | animationDirection = "forward"; 48 | } 49 | 50 | const key = `${dateAPI.toFormattedDate(visibleFromDate)}`; 51 | lastAnimatedDate.current = visibleFromDate; 52 | lastDirection.current = animationDirection; 53 | lastMovement.current = movement; 54 | return ( 55 | 62 | ); 63 | } 64 | AnimatedMonthGroup.propTypes = { 65 | /** Children */ 66 | children: PropTypes.element, 67 | /** Ref to the first column */ 68 | firstColumnRef: PropTypes.object.isRequired, 69 | /** Ref to the MonthGroup */ 70 | groupRef: PropTypes.object.isRequired, 71 | /** Visible from date, used to control animation between columns and MonthGroup */ 72 | visibleFromDate: PropTypes.object.isRequired 73 | }; 74 | 75 | export default AnimatedMonthGroup; 76 | -------------------------------------------------------------------------------- /packages/core/src/AnimatedMonthGroup/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | 4 | import { setComponents } from "../../CalendarProvider"; 5 | import { CustomisableAnimatedMonthGroup } from "../index"; 6 | 7 | jest.mock("../../CalendarProvider"); 8 | 9 | describe("given AnimatedMonthGroup", () => { 10 | it("can be overriden with a custom component", () => { 11 | const TestComponent = () => "TEST CUSTOM COMPONENT"; 12 | setComponents({ AnimatedGroup: TestComponent }); 13 | const { getByText } = render(); 14 | expect(getByText("TEST CUSTOM COMPONENT")).toBeInTheDocument(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/core/src/AnimatedMonthGroup/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | 3 | import { useCalendarComponent } from "../CalendarProvider"; 4 | import DefaultAnimatedMonthGroup from "./AnimatedMonthGroup"; 5 | 6 | export const CustomisableAnimatedMonthGroup = forwardRef( 7 | function CustomisableAnimatedMonthGroup(props, ref) { 8 | const { 9 | AnimatedGroup: Component = DefaultAnimatedMonthGroup 10 | } = useCalendarComponent(); 11 | return ; 12 | } 13 | ); 14 | 15 | export default DefaultAnimatedMonthGroup; 16 | -------------------------------------------------------------------------------- /packages/core/src/CalendarWithFocusLock.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | import { useCalendarDispatch, useCalendarState } from "./CalendarProvider"; 3 | import { dateInputActions } from "./reducers/dateInputReducer"; 4 | import FocusLock from "react-focus-lock"; 5 | import Calendar from "./Calendar"; 6 | 7 | const CalendarWithFocusLock = forwardRef(function CalendarWithFocusLock( 8 | props, 9 | ref 10 | ) { 11 | const { dispatch } = useCalendarDispatch(); 12 | const { focusLock } = useCalendarState(); 13 | 14 | const handleBlur = event => { 15 | if (focusLock && !event.currentTarget.contains(event.relatedTarget)) { 16 | dispatch({ type: dateInputActions.focusLock, enable: false }); 17 | } 18 | }; 19 | 20 | const handleFocus = () => { 21 | if (!focusLock) { 22 | dispatch({ type: dateInputActions.focusLock, enable: true }); 23 | } 24 | }; 25 | 26 | return ( 27 |
28 | 29 | 30 | 31 |
32 | ); 33 | }); 34 | 35 | export default CalendarWithFocusLock; 36 | -------------------------------------------------------------------------------- /packages/core/src/Day/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import createDateAPI from "../../createDateAPI"; 4 | import { adapter as dateFnsAdapter } from "@use-date-input/date-fns-adapter"; 5 | 6 | import { setComponents } from "../../CalendarProvider"; 7 | 8 | import { CustomisableDay } from "../index"; 9 | import Day from "../Day"; 10 | 11 | jest.mock("../../CalendarProvider"); 12 | 13 | describe("given Day", () => { 14 | it("passes the ref to the DOM", () => { 15 | const dateAPI = createDateAPI({ adapter: dateFnsAdapter }); 16 | const { createDate, toFormattedDate } = dateAPI; 17 | const ref = React.createRef(); 18 | const day = createDate("2019-01-10"); 19 | render(); 20 | expect(ref.current).toBeInstanceOf(HTMLSpanElement); 21 | }); 22 | 23 | it("can be overriden with a custom component", () => { 24 | const TestComponent = () => "TEST CUSTOM COMPONENT"; 25 | setComponents({ Day: TestComponent }); 26 | const { getByText } = render(); 27 | expect(getByText("TEST CUSTOM COMPONENT")).toBeInTheDocument(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/core/src/Day/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, memo } from "react"; 2 | 3 | import { useCalendarComponent } from "../CalendarProvider"; 4 | import UnstyledDay from "./Day"; 5 | import { withStyledDay } from "./style"; 6 | 7 | const DefaultDay = withStyledDay(UnstyledDay); 8 | 9 | const Day = forwardRef(function CustomisableDay(props, ref) { 10 | const { Day: Component = DefaultDay } = useCalendarComponent(); 11 | return ; 12 | }); 13 | export const CustomisableDay = memo(Day); 14 | 15 | export default DefaultDay; 16 | -------------------------------------------------------------------------------- /packages/core/src/DayOfWeek/DayOfWeek.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | export const DayOfWeek = forwardRef(function DayOfWeek( 5 | { children, className, description }, 6 | ref 7 | ) { 8 | return ( 9 |
10 | {children} 11 |
12 | ); 13 | }); 14 | DayOfWeek.propTypes = { 15 | /** Day of week node */ 16 | children: PropTypes.node, 17 | /** Class name of root element */ 18 | className: PropTypes.string, 19 | /** Day of week expanded label */ 20 | description: PropTypes.string 21 | }; 22 | 23 | export default DayOfWeek; 24 | -------------------------------------------------------------------------------- /packages/core/src/DayOfWeek/__tests__/DayOfWeek.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "test-utils"; 3 | 4 | import DayOfWeek from "../DayOfWeek"; 5 | 6 | describe("given DayOfWeek", () => { 7 | it("passes the ref to the DOM", () => { 8 | const ref = React.createRef(); 9 | render(); 10 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 11 | }); 12 | 13 | it("renders a day of the week", () => { 14 | const { getByText, getByLabelText } = render( 15 | TestDay 16 | ); 17 | expect(getByText("TestDay")).toBeInTheDocument(); 18 | expect(getByLabelText("test day")).toBeInTheDocument(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/core/src/DayOfWeek/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import { setComponents } from "../../CalendarProvider"; 4 | import TestUtils from "../../test-utils"; 5 | 6 | import { CustomisableDayOfWeek } from "../index"; 7 | 8 | jest.mock("../../CalendarProvider"); 9 | 10 | describe("given DayOfWeek", () => { 11 | it("passes the ref to the DOM", () => { 12 | const ref = React.createRef(); 13 | render( 14 | 15 | 16 | 17 | ); 18 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 19 | }); 20 | 21 | it("can be overriden with a custom component", () => { 22 | const TestComponent = () => "TEST CUSTOM COMPONENT"; 23 | setComponents({ DayOfWeek: TestComponent }); 24 | const { getByText } = render(); 25 | expect(getByText("TEST CUSTOM COMPONENT")).toBeInTheDocument(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /packages/core/src/DayOfWeek/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | 3 | import { useCalendarComponent } from "../CalendarProvider"; 4 | import UnstyledDayOfWeek from "./DayOfWeek"; 5 | import { withStyledDayOfWeek } from "./style"; 6 | 7 | const DefaultDayOfweek = withStyledDayOfWeek(UnstyledDayOfWeek); 8 | 9 | export const CustomisableDayOfWeek = forwardRef(function CustomisableDayOfWeek( 10 | props, 11 | ref 12 | ) { 13 | const { DayOfWeek: Component = DefaultDayOfweek } = useCalendarComponent(); 14 | return ; 15 | }); 16 | 17 | export default DefaultDayOfweek; 18 | -------------------------------------------------------------------------------- /packages/core/src/DayOfWeek/style.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export function withStyledDayOfWeek(component) { 4 | const StyledComponent = styled(component)(props => { 5 | const componentOverrides = 6 | props.theme && props.theme.getCalendarOverrides 7 | ? props.theme.getCalendarOverrides("DayOfWeek")(props) 8 | : {}; 9 | return { 10 | display: "inline-block", 11 | boxSizing: "border-box", 12 | width: "20px", 13 | textAlign: "center", 14 | padding: "2px", 15 | ...componentOverrides 16 | }; 17 | }); 18 | return StyledComponent; 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/Header/Header.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | import { formatNames } from "@use-date-input/common"; 5 | import { 6 | StyledNextButton, 7 | StyledPreviousButton, 8 | StyledYearTitle 9 | } from "./style"; 10 | import { 11 | useCalendarDispatch, 12 | useCalendarState, 13 | useDateAPI 14 | } from "../CalendarProvider"; 15 | 16 | const Header = forwardRef(function Header({ className }, ref) { 17 | const { visibleFromDate } = useCalendarState(); 18 | const { navigateNext, navigatePrevious } = useCalendarDispatch(); 19 | const { toFormattedDate } = useDateAPI(); 20 | return ( 21 |
22 | 28 | 33 | {visibleFromDate && 34 | toFormattedDate(visibleFromDate, formatNames.HEADER)} 35 | 36 | 42 |
43 | ); 44 | }); 45 | 46 | Header.propTypes = { 47 | /** Class name of root element */ 48 | className: PropTypes.string 49 | }; 50 | 51 | export default Header; 52 | -------------------------------------------------------------------------------- /packages/core/src/Header/__tests__/Header.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { fireEvent, render } from "test-utils"; 3 | import { 4 | navigateNextMock, 5 | navigatePreviousMock, 6 | resetMocks, 7 | setVisibleFromDate, 8 | setWeekOffset 9 | } from "../../CalendarProvider"; 10 | import { adapter as dateFnsAdapter } from "@use-date-input/date-fns-adapter"; 11 | import { adapter as dayjsAdapter } from "@use-date-input/dayjs-adapter"; 12 | import { adapter as luxonAdapter } from "@use-date-input/luxon-adapter"; 13 | import { adapter as momentAdapter } from "@use-date-input/moment-adapter"; 14 | import createDateAPI from "../../createDateAPI"; 15 | import { setAdapter } from "../../CalendarProvider"; 16 | 17 | import Header from "../Header"; 18 | 19 | jest.mock("../../CalendarProvider"); 20 | 21 | describe("given Header", () => { 22 | describe.each` 23 | api | adapter | weekOffset 24 | ${"date-fns"} | ${dateFnsAdapter} | ${0} 25 | ${"dayjs"} | ${dayjsAdapter} | ${0} 26 | ${"luxon"} | ${luxonAdapter} | ${-1} 27 | ${"moment"} | ${momentAdapter} | ${0} 28 | `("for $api", ({ adapter, weekOffset }) => { 29 | beforeEach(() => { 30 | const { createDate } = createDateAPI({ adapter, weekOffset }); 31 | const month = createDate("2019-01-01"); 32 | setVisibleFromDate(month); 33 | setAdapter(adapter); 34 | setWeekOffset(weekOffset); 35 | }); 36 | afterEach(() => { 37 | resetMocks(); 38 | }); 39 | 40 | it("passes the ref to the DOM", () => { 41 | const ref = React.createRef(); 42 | render(
); 43 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 44 | }); 45 | 46 | it("can navigate to previous month", () => { 47 | const { getByLabelText } = render(
); 48 | fireEvent.click(getByLabelText(/move to previous month/)); 49 | expect(navigatePreviousMock).toHaveBeenCalled(); 50 | }); 51 | 52 | it("can navigate to next month", () => { 53 | const { getByLabelText } = render(
); 54 | fireEvent.click(getByLabelText(/move to next month/)); 55 | expect(navigateNextMock).toHaveBeenCalled(); 56 | }); 57 | 58 | it("renders the current year in the header", () => { 59 | const { getByText } = render(
); 60 | expect(getByText("2019")).toBeInTheDocument(); 61 | }); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /packages/core/src/Header/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import { setComponents } from "../../CalendarProvider"; 4 | 5 | import { CustomisableHeader } from "../index"; 6 | import TestUtils from "../../test-utils"; 7 | 8 | jest.mock("../../CalendarProvider"); 9 | 10 | describe("given Header", () => { 11 | it("passes the ref to the DOM", () => { 12 | const ref = React.createRef(); 13 | render( 14 | 15 | 16 | 17 | ); 18 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 19 | }); 20 | it("can be overriden with a custom component", () => { 21 | const TestComponent = () => "TEST CUSTOM COMPONENT"; 22 | setComponents({ Header: TestComponent }); 23 | const { getByText } = render(); 24 | expect(getByText("TEST CUSTOM COMPONENT")).toBeInTheDocument(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/core/src/Header/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | 3 | import { useCalendarComponent } from "../CalendarProvider"; 4 | import UnstyledHeader from "./Header"; 5 | import { withStyledHeader } from "./style"; 6 | 7 | const DefaultHeader = withStyledHeader(UnstyledHeader); 8 | 9 | export const CustomisableHeader = forwardRef(function CustomisableHeader( 10 | props, 11 | ref 12 | ) { 13 | const { Header: Component = DefaultHeader } = useCalendarComponent(); 14 | return ; 15 | }); 16 | 17 | export default DefaultHeader; 18 | -------------------------------------------------------------------------------- /packages/core/src/Header/style.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export const StyledYearTitle = styled.span(props => { 4 | const componentOverrides = 5 | props.theme && props.theme.getCalendarOverrides 6 | ? props.theme.getCalendarOverrides("YearTitle")(props) 7 | : {}; 8 | return { 9 | alignSelf: "center", 10 | ...componentOverrides 11 | }; 12 | }); 13 | 14 | export const StyledPreviousButton = styled.button(props => { 15 | const componentOverrides = 16 | props.theme && props.theme.getCalendarOverrides 17 | ? props.theme.getCalendarOverrides("PreviousButton")(props) 18 | : {}; 19 | return { 20 | marginLeft: "5px", 21 | "::before": { 22 | content: "'<'" 23 | }, 24 | ...componentOverrides 25 | }; 26 | }); 27 | 28 | export const StyledNextButton = styled.button(props => { 29 | const componentOverrides = 30 | props.theme && props.theme.getCalendarOverrides 31 | ? props.theme.getCalendarOverrides("NextButton")(props) 32 | : {}; 33 | return { 34 | marginRight: "5px", 35 | "::before": { 36 | content: "'>'" 37 | }, 38 | ...componentOverrides 39 | }; 40 | }); 41 | 42 | export function withStyledHeader(component) { 43 | const StyledComponent = styled(component)(props => { 44 | const componentOverrides = 45 | props.theme && props.theme.getCalendarOverrides 46 | ? props.theme.getCalendarOverrides("Header")(props) 47 | : {}; 48 | return { 49 | display: "flex", 50 | justifyContent: "space-between", 51 | ...componentOverrides 52 | }; 53 | }); 54 | return StyledComponent; 55 | } 56 | -------------------------------------------------------------------------------- /packages/core/src/Month/Month.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, memo, useMemo } from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | import { formatNames } from "@use-date-input/common"; 5 | import createCalendarModel from "../createCalendarModel"; 6 | import { useDateAPI } from "../CalendarProvider"; 7 | import { StyledMonthTitle, StyledWeekRow } from "./style"; 8 | import { CustomisableWeek } from "../Week"; 9 | import { CustomisableWeekHeader } from "../WeekHeader"; 10 | 11 | const Month = forwardRef(function Month({ className, month }, ref) { 12 | const dateAPI = useDateAPI(); 13 | const { toFormattedDate } = dateAPI; 14 | const children = useMemo(() => { 15 | const calendarModel = createCalendarModel(month, dateAPI); 16 | return calendarModel.map((week, weekNum) => ( 17 | 22 | )); 23 | }, [dateAPI, month]); 24 | 25 | return ( 26 |
27 | 28 | {toFormattedDate(month, formatNames.MONTH_FULL)} 29 | 30 | 31 | {children} 32 |
33 | ); 34 | }); 35 | 36 | Month.propTypes = { 37 | /** Class name of root element */ 38 | className: PropTypes.string, 39 | /** Month */ 40 | month: PropTypes.object 41 | }; 42 | 43 | export default memo(Month); 44 | -------------------------------------------------------------------------------- /packages/core/src/Month/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | 4 | import createDateAPI from "../../createDateAPI"; 5 | import { adapter as dateFnsAdapter } from "@use-date-input/date-fns-adapter"; 6 | import { setComponents } from "../../CalendarProvider"; 7 | import { CustomisableMonth } from "../index"; 8 | import TestUtils from "../../test-utils"; 9 | import Month from "../Month"; 10 | 11 | jest.mock("../../CalendarProvider"); 12 | 13 | describe("given Month", () => { 14 | it("passes the ref to the DOM", () => { 15 | const dateAPI = createDateAPI({ adapter: dateFnsAdapter }); 16 | const { createDate } = dateAPI; 17 | const ref = React.createRef(); 18 | const month = createDate("2019-01-01"); 19 | render( 20 | 21 | 22 | 23 | ); 24 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 25 | }); 26 | 27 | it("can be overriden with a custom component", () => { 28 | const TestComponent = () => "TEST CUSTOM COMPONENT"; 29 | setComponents({ Month: TestComponent }); 30 | const { getByText } = render(); 31 | expect(getByText("TEST CUSTOM COMPONENT")).toBeInTheDocument(); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/core/src/Month/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, memo } from "react"; 2 | 3 | import { useCalendarComponent } from "../CalendarProvider"; 4 | import UnstyledMonth from "./Month"; 5 | import { withStyledMonth } from "./style"; 6 | 7 | const DefaultMonth = withStyledMonth(UnstyledMonth); 8 | 9 | const Month = forwardRef(function CustomisableMonth(props, ref) { 10 | const { Month: Component = DefaultMonth } = useCalendarComponent(); 11 | return ; 12 | }); 13 | 14 | export const CustomisableMonth = memo(Month); 15 | 16 | export default DefaultMonth; 17 | -------------------------------------------------------------------------------- /packages/core/src/Month/style.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export const StyledMonthTitle = styled.span(props => { 4 | const componentOverrides = 5 | props.theme && props.theme.getCalendarOverrides 6 | ? props.theme.getCalendarOverrides("MonthTitle")(props) 7 | : {}; 8 | return { 9 | justifyContent: "center", 10 | alignContent: "center", 11 | display: "flex", 12 | ...componentOverrides 13 | }; 14 | }); 15 | export const StyledWeekRow = styled.div(props => { 16 | const componentOverrides = 17 | props.theme && props.theme.getCalendarOverrides 18 | ? props.theme.getCalendarOverrides("WeekRow")(props) 19 | : {}; 20 | return componentOverrides; 21 | }); 22 | 23 | export function withStyledMonth(component) { 24 | const StyledComponent = styled(component)(props => { 25 | const componentOverrides = 26 | props.theme && props.theme.getCalendarOverrides 27 | ? props.theme.getCalendarOverrides("Month")(props) 28 | : {}; 29 | return componentOverrides; 30 | }); 31 | return StyledComponent; 32 | } 33 | -------------------------------------------------------------------------------- /packages/core/src/MonthGroup/__tests__/MonthGroup.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "test-utils"; 3 | import { 4 | resetMocks, 5 | setAdapter, 6 | setNumOfColumns, 7 | setNumOfVisibleMonths, 8 | setVisibleFromDate, 9 | setWeekOffset 10 | } from "../../CalendarProvider"; 11 | import { adapter as dateFnsAdapter } from "@use-date-input/date-fns-adapter"; 12 | import { adapter as dayjsAdapter } from "@use-date-input/dayjs-adapter"; 13 | import { adapter as luxonAdapter } from "@use-date-input/luxon-adapter"; 14 | import { adapter as momentAdapter } from "@use-date-input/moment-adapter"; 15 | import createDateAPI from "../../createDateAPI"; 16 | import { act } from "@testing-library/react"; 17 | 18 | import MonthGroup from "../MonthGroup"; 19 | 20 | jest.mock("../../CalendarProvider"); 21 | jest.useFakeTimers(); 22 | 23 | describe.only("given MonthGroup", () => { 24 | describe.each` 25 | api | adapter | weekOffset 26 | ${"date-fns"} | ${dateFnsAdapter} | ${0} 27 | ${"dayjs"} | ${dayjsAdapter} | ${0} 28 | ${"luxon"} | ${luxonAdapter} | ${-1} 29 | ${"moment"} | ${momentAdapter} | ${0} 30 | `("for $api", ({ adapter, weekOffset }) => { 31 | const { createDate } = createDateAPI({ adapter, weekOffset }); 32 | beforeEach(() => { 33 | setAdapter(adapter); 34 | setWeekOffset(weekOffset); 35 | setNumOfColumns(3); 36 | setNumOfVisibleMonths(6); 37 | }); 38 | afterEach(() => { 39 | resetMocks(); 40 | }); 41 | 42 | it("passes the ref to the DOM", () => { 43 | const ref = React.createRef(); 44 | render( 45 | 46 | ); 47 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 48 | }); 49 | 50 | it("renders a month group", () => { 51 | const { getByText, getAllByTestId } = render( 52 | 53 | ); 54 | const rows = getAllByTestId("month-group-row"); 55 | expect(getByText("August")).toBeInTheDocument(); 56 | expect(rows.length).toEqual(2); 57 | expect(rows[0].children.length).toEqual(3); 58 | expect(rows[1].children.length).toEqual(3); 59 | setVisibleFromDate(createDate("2019-09-03")); 60 | act(() => { 61 | jest.runAllTimers(); 62 | }); 63 | expect(getByText("September")).toBeInTheDocument(); 64 | }); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /packages/core/src/MonthGroup/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import { setComponents } from "../../CalendarProvider"; 4 | import { adapter as dateFnsAdapter } from "@use-date-input/date-fns-adapter"; 5 | 6 | import { CustomisableMonthGroup } from "../index"; 7 | import TestUtils from "../../test-utils"; 8 | import createDateAPI from "../../createDateAPI"; 9 | 10 | jest.mock("../../CalendarProvider"); 11 | 12 | describe("given MonthGroup", () => { 13 | const { createDate } = createDateAPI({ adapter: dateFnsAdapter }); 14 | it("passes the ref to the DOM", () => { 15 | const ref = React.createRef(); 16 | render( 17 | 18 | 22 | 23 | ); 24 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 25 | }); 26 | 27 | it("can be overriden with a custom component", () => { 28 | const TestComponent = () => "TEST CUSTOM COMPONENT"; 29 | setComponents({ MonthGroup: TestComponent }); 30 | const { getByText } = render( 31 | 32 | ); 33 | expect(getByText("TEST CUSTOM COMPONENT")).toBeInTheDocument(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/core/src/MonthGroup/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, memo } from "react"; 2 | 3 | import { useCalendarComponent } from "../CalendarProvider"; 4 | import UnstyledMonthGroup from "./MonthGroup"; 5 | import { withStyledMonthGroup } from "./style"; 6 | 7 | const DefaultMonthGroup = withStyledMonthGroup(UnstyledMonthGroup); 8 | 9 | const MonthGroup = forwardRef(function CustomisableMonthGroup(props, ref) { 10 | const { MonthGroup: Component = DefaultMonthGroup } = useCalendarComponent(); 11 | return ; 12 | }); 13 | 14 | export const CustomisableMonthGroup = memo(MonthGroup); 15 | 16 | export default DefaultMonthGroup; 17 | -------------------------------------------------------------------------------- /packages/core/src/MonthGroup/style.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export const StyledRow = styled.div(props => { 4 | const componentOverrides = 5 | props.theme && props.theme.getCalendarOverrides 6 | ? props.theme.getCalendarOverrides("MonthRow")(props) 7 | : {}; 8 | return componentOverrides; 9 | }); 10 | 11 | export const StyledCell = styled.div(props => { 12 | const componentOverrides = 13 | props.theme && props.theme.getCalendarOverrides 14 | ? props.theme.getCalendarOverrides("MonthCell")(props) 15 | : {}; 16 | return { 17 | display: "inline-block", 18 | verticalAlign: "top", 19 | marginBottom: "10px", 20 | paddingRight: "10px", 21 | boxSizing: "border-box", 22 | "&:last-child": { 23 | paddingRight: "0px" 24 | }, 25 | ...componentOverrides 26 | }; 27 | }); 28 | 29 | export function withStyledMonthGroup(component) { 30 | const StyledComponent = styled(component)(props => { 31 | const componentOverrides = 32 | props.theme && props.theme.getCalendarOverrides 33 | ? props.theme.getCalendarOverrides("MonthGroup")(props) 34 | : {}; 35 | return { 36 | paddingTop: "10px", 37 | paddingLeft: "5px", 38 | paddingRight: "5px", 39 | ...componentOverrides 40 | }; 41 | }); 42 | return StyledComponent; 43 | } 44 | -------------------------------------------------------------------------------- /packages/core/src/Root/Root.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, memo, useCallback } from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | import { useCalendarDispatch, useCalendarState } from "../CalendarProvider"; 5 | import { CustomisableHeader } from "../Header"; 6 | import { CustomisableMonthGroup } from "../MonthGroup"; 7 | 8 | const Root = forwardRef(function Root({ className }, ref) { 9 | const { 10 | setEnableKeyboardNavigation, 11 | setMouseCursor, 12 | setKeyPress 13 | } = useCalendarDispatch(); 14 | const { enableKeyboardNavigation, visibleFromDate } = useCalendarState(); 15 | const handleKeyDown = useCallback( 16 | event => { 17 | const { key, ctrlKey, shiftKey } = event; 18 | if (event.key !== "Tab") { 19 | event.nativeEvent.preventDefault(); 20 | } 21 | setKeyPress({ 22 | key, 23 | ctrlKey, 24 | shiftKey 25 | }); 26 | }, 27 | [setKeyPress] 28 | ); 29 | 30 | const handleBlur = useCallback( 31 | event => { 32 | if ( 33 | enableKeyboardNavigation && 34 | !event.currentTarget.contains(event.relatedTarget) 35 | ) { 36 | setEnableKeyboardNavigation(false); 37 | } 38 | }, 39 | [enableKeyboardNavigation, setEnableKeyboardNavigation] 40 | ); 41 | 42 | const handleFocus = useCallback(() => { 43 | if (!enableKeyboardNavigation) { 44 | setEnableKeyboardNavigation(true); 45 | } 46 | }, [enableKeyboardNavigation, setEnableKeyboardNavigation]); 47 | 48 | const handleMouseLeave = useCallback(() => { 49 | setMouseCursor(undefined); 50 | }, [setMouseCursor]); 51 | 52 | return ( 53 |
54 | 55 |
62 | 63 |
64 |
65 | ); 66 | }); 67 | Root.propTypes = { 68 | className: PropTypes.string 69 | }; 70 | 71 | export default memo(Root); 72 | -------------------------------------------------------------------------------- /packages/core/src/Root/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import { setComponents } from "../../CalendarProvider"; 4 | 5 | import { CustomisableRoot } from "../index"; 6 | import TestUtils from "../../test-utils"; 7 | import { setVisibleFromDate } from "../../CalendarProvider"; 8 | import createDateAPI from "../../createDateAPI"; 9 | import { adapter as dateFnsAdapter } from "@use-date-input/date-fns-adapter"; 10 | 11 | jest.mock("../../CalendarProvider"); 12 | 13 | describe("given Root", () => { 14 | it("passes the ref to the DOM", () => { 15 | const ref = React.createRef(); 16 | const dateAPI = createDateAPI({ adapter: dateFnsAdapter }); 17 | setVisibleFromDate(dateAPI.createDate("2019-08-01")); 18 | render( 19 | 20 | 21 | 22 | ); 23 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 24 | }); 25 | 26 | it("can be overriden with a custom component", () => { 27 | const TestComponent = () => "TEST CUSTOM COMPONENT"; 28 | setComponents({ Root: TestComponent }); 29 | const { getByText } = render(); 30 | expect(getByText("TEST CUSTOM COMPONENT")).toBeInTheDocument(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /packages/core/src/Root/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, memo } from "react"; 2 | 3 | import { useCalendarComponent } from "../CalendarProvider"; 4 | import UnstyledRoot from "./Root"; 5 | import { withStyledRoot } from "./style"; 6 | 7 | const DefaultRoot = withStyledRoot(UnstyledRoot); 8 | 9 | const Root = forwardRef(function CustomisableRoot(props, ref) { 10 | const { Root: Component = DefaultRoot } = useCalendarComponent(); 11 | return ; 12 | }); 13 | 14 | export const CustomisableRoot = memo(Root); 15 | 16 | export default DefaultRoot; 17 | -------------------------------------------------------------------------------- /packages/core/src/Root/style.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export function withStyledRoot(component) { 4 | const StyledComponent = styled(component)(props => { 5 | const getComponentOverrides = props.theme.getCalendarOverrides("Root"); 6 | return { 7 | color: "black", 8 | fontSize: "12px", 9 | paddingTop: "10px", 10 | display: "inline-block", 11 | ...getComponentOverrides(props) 12 | }; 13 | }); 14 | return StyledComponent; 15 | } 16 | -------------------------------------------------------------------------------- /packages/core/src/Week/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import { setComponents } from "../../CalendarProvider"; 4 | 5 | import { CustomisableWeek } from "../index"; 6 | import TestUtils from "../../test-utils"; 7 | 8 | jest.mock("../../CalendarProvider"); 9 | 10 | describe("given Week", () => { 11 | it("passes the ref to the DOM", () => { 12 | const ref = React.createRef(); 13 | render( 14 | 15 | 16 | 17 | ); 18 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 19 | }); 20 | 21 | it("can be overriden with a custom component", () => { 22 | const TestComponent = () => "TEST CUSTOM COMPONENT"; 23 | setComponents({ Week: TestComponent }); 24 | const { getByText } = render(); 25 | expect(getByText("TEST CUSTOM COMPONENT")).toBeInTheDocument(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /packages/core/src/Week/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, memo } from "react"; 2 | 3 | import { useCalendarComponent } from "../CalendarProvider"; 4 | import UnstyledWeek from "./Week"; 5 | import { withStyledWeek } from "./style"; 6 | 7 | const DefaultWeek = withStyledWeek(UnstyledWeek); 8 | 9 | export const Week = forwardRef(function CustomisableRoot(props, ref) { 10 | const { Week: Component = DefaultWeek } = useCalendarComponent(); 11 | return ; 12 | }); 13 | 14 | export const CustomisableWeek = memo(Week); 15 | 16 | export default DefaultWeek; 17 | -------------------------------------------------------------------------------- /packages/core/src/Week/style.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export function withStyledWeek(component) { 4 | const StyledComponent = styled(component)(props => { 5 | const componentOverrides = 6 | props.theme && props.theme.getCalendarOverrides 7 | ? props.theme.getCalendarOverrides("Week")(props) 8 | : {}; 9 | return { 10 | display: "flex", 11 | flex: 1, 12 | ...componentOverrides 13 | }; 14 | }); 15 | return StyledComponent; 16 | } 17 | -------------------------------------------------------------------------------- /packages/core/src/WeekHeader/WeekHeader.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, memo, useMemo } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { CustomisableDayOfWeek } from "../DayOfWeek"; 4 | import { useDateAPI } from "../CalendarProvider"; 5 | import { formatNames } from "@use-date-input/common"; 6 | 7 | const WeekHeader = forwardRef(function WeekHeader({ className }, ref) { 8 | const { addDays, createDate, startOfWeek, toFormattedDate } = useDateAPI(); 9 | const children = useMemo(() => { 10 | const firstDayOfWeek = startOfWeek(createDate()); 11 | const weekdays = [...new Array(7)].map((value, index) => 12 | addDays(firstDayOfWeek, index) 13 | ); 14 | return weekdays.map(dow => { 15 | const dowShortLabel = toFormattedDate( 16 | dow, 17 | formatNames.DAY_OF_WEEK_ABBREVIATED 18 | ); 19 | const dowLongLabel = toFormattedDate(dow, formatNames.DAY_OF_WEEK_FULL); 20 | return ( 21 | 22 | {dowShortLabel} 23 | 24 | ); 25 | }); 26 | }, [addDays, createDate, toFormattedDate, startOfWeek]); 27 | return ( 28 |
29 | {children} 30 |
31 | ); 32 | }); 33 | 34 | WeekHeader.propTypes = { 35 | /** Class name of root element */ 36 | className: PropTypes.string 37 | }; 38 | 39 | export default memo(WeekHeader); 40 | -------------------------------------------------------------------------------- /packages/core/src/WeekHeader/__tests__/WeekHeader.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "test-utils"; 3 | import { setWeekOffset, resetMocks, setAdapter } from "../../CalendarProvider"; 4 | import { formatNames } from "@use-date-input/common"; 5 | import { adapter as dateFnsAdapter } from "@use-date-input/date-fns-adapter"; 6 | import { adapter as dayjsAdapter } from "@use-date-input/dayjs-adapter"; 7 | import { adapter as luxonAdapter } from "@use-date-input/luxon-adapter"; 8 | import { adapter as momentAdapter } from "@use-date-input/moment-adapter"; 9 | import createDateAPI from "../../createDateAPI"; 10 | 11 | import WeekHeader from "../WeekHeader"; 12 | 13 | jest.mock("../../CalendarProvider"); 14 | 15 | describe("given WeekHeader", () => { 16 | describe.each` 17 | api | adapter | weekOffset 18 | ${"date-fns"} | ${dateFnsAdapter} | ${0} 19 | ${"dayjs"} | ${dayjsAdapter} | ${0} 20 | ${"luxon"} | ${luxonAdapter} | ${-1} 21 | ${"moment"} | ${momentAdapter} | ${0} 22 | `("for $api", ({ adapter, weekOffset }) => { 23 | let dateAPI; 24 | beforeEach(() => { 25 | dateAPI = createDateAPI({ adapter, weekOffset }); 26 | setAdapter(adapter); 27 | setWeekOffset(weekOffset); 28 | }); 29 | afterEach(() => { 30 | resetMocks(); 31 | }); 32 | 33 | it("passes the ref to the DOM", () => { 34 | const ref = React.createRef(); 35 | render(); 36 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 37 | }); 38 | 39 | it("renders the default header with no offset", () => { 40 | const sampleDay = dateAPI.createDate("2019-01-01"); 41 | const firstDayOfWeek = dateAPI.toFormattedDate( 42 | dateAPI.startOfWeek(sampleDay), 43 | formatNames.DAY_OF_WEEK_ABBREVIATED 44 | ); 45 | const { getAllByText } = render(); 46 | 47 | const days = getAllByText(/M|T|W|F|S/); 48 | expect(days.length).toEqual(7); 49 | expect(days[0].textContent).toEqual(firstDayOfWeek); 50 | }); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /packages/core/src/WeekHeader/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import { setComponents } from "../../CalendarProvider"; 4 | 5 | import { CustomisableWeekHeader } from "../index"; 6 | import TestUtils from "../../test-utils"; 7 | 8 | jest.mock("../../CalendarProvider"); 9 | 10 | describe("given WeekHeader", () => { 11 | it("passes the ref to the DOM", () => { 12 | const ref = React.createRef(); 13 | render( 14 | 15 | 16 | 17 | ); 18 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 19 | }); 20 | 21 | it("can be overriden with a custom component", () => { 22 | const TestComponent = () => "TEST CUSTOM COMPONENT"; 23 | setComponents({ WeekHeader: TestComponent }); 24 | const { getByText } = render(); 25 | expect(getByText("TEST CUSTOM COMPONENT")).toBeInTheDocument(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /packages/core/src/WeekHeader/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, memo } from "react"; 2 | 3 | import { useCalendarComponent } from "../CalendarProvider"; 4 | import UnstyledWeekHeader from "./WeekHeader"; 5 | import { withStyledWeekHeader } from "./style"; 6 | 7 | const DefaultWeekHeader = withStyledWeekHeader(UnstyledWeekHeader); 8 | 9 | const WeekHeader = forwardRef(function CustomisableWeekHeader(props, ref) { 10 | const { WeekHeader: Component = DefaultWeekHeader } = useCalendarComponent(); 11 | return ; 12 | }); 13 | 14 | export const CustomisableWeekHeader = memo(WeekHeader); 15 | 16 | export default DefaultWeekHeader; 17 | -------------------------------------------------------------------------------- /packages/core/src/WeekHeader/style.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export function withStyledWeekHeader(component) { 4 | const StyledComponent = styled(component)(props => { 5 | const componentOverrides = 6 | props.theme && props.theme.getCalendarOverrides 7 | ? props.theme.getCalendarOverrides("WeekHeader")(props) 8 | : {}; 9 | return { 10 | width: "100%", 11 | ...componentOverrides 12 | }; 13 | }); 14 | return StyledComponent; 15 | } 16 | -------------------------------------------------------------------------------- /packages/core/src/__mocks__/react-popper.js: -------------------------------------------------------------------------------- 1 | export const usePopper = () => ({ 2 | styles: {}, 3 | attributes: {} 4 | }); 5 | -------------------------------------------------------------------------------- /packages/core/src/__tests__/callAll.test.js: -------------------------------------------------------------------------------- 1 | import callAll from "../callAll"; 2 | 3 | describe("given callAll", () => { 4 | it("calls multiple defined methods from one function", () => { 5 | const funcA = jest.fn(); 6 | const funcB = jest.fn(); 7 | const combinedFunc = callAll(funcA, undefined, funcB); 8 | combinedFunc("arg1", "arg2"); 9 | expect(funcA).toHaveBeenCalledWith("arg1", "arg2"); 10 | expect(funcB).toHaveBeenCalledWith("arg1", "arg2"); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/core/src/__tests__/createCalendarModel.test.js: -------------------------------------------------------------------------------- 1 | import { adapter as dateFnsAdapter } from "@use-date-input/date-fns-adapter"; 2 | import { adapter as dayjsAdapter } from "@use-date-input/dayjs-adapter"; 3 | import { adapter as luxonAdapter } from "@use-date-input/luxon-adapter"; 4 | import { adapter as momentAdapter } from "@use-date-input/moment-adapter"; 5 | import createDateAPI from "../createDateAPI"; 6 | 7 | import createCalendarModel from "../createCalendarModel"; 8 | 9 | describe("given createCalendarModel", () => { 10 | describe.each` 11 | api | adapter | weekOffset 12 | ${"date-fns"} | ${dateFnsAdapter} | ${0} 13 | ${"dayjs"} | ${dayjsAdapter} | ${0} 14 | ${"luxon"} | ${luxonAdapter} | ${-1} 15 | ${"moment"} | ${momentAdapter} | ${0} 16 | `("with $api and a date of 2019-08-28", ({ adapter, weekOffset }) => { 17 | const dateAPI = createDateAPI({ adapter, weekOffset }); 18 | const { createDate, toFormattedDate } = dateAPI; 19 | const calendar = createCalendarModel(createDate("2019-08-28"), dateAPI); 20 | 21 | it("a model includes remaining days from the previous month", () => { 22 | expect(calendar.length).toEqual(6); 23 | expect(calendar[0].length).toEqual(7); 24 | }); 25 | 26 | it("a model includes days for the last week in July", () => { 27 | expect(calendar[0].length).toEqual(7); 28 | expect(toFormattedDate(calendar[0][0])).toEqual("2019-07-28"); 29 | }); 30 | 31 | it("a model includes days for the first week in August", () => { 32 | expect(calendar[1].length).toEqual(7); 33 | expect(toFormattedDate(calendar[1][0])).toEqual("2019-08-04"); 34 | }); 35 | 36 | it("a model includes days for the second week in August", () => { 37 | expect(calendar[2].length).toEqual(7); 38 | expect(toFormattedDate(calendar[2][0])).toEqual("2019-08-11"); 39 | }); 40 | 41 | it("a model includes days for the third week in August", () => { 42 | expect(calendar[3].length).toEqual(7); 43 | expect(toFormattedDate(calendar[3][0])).toEqual("2019-08-18"); 44 | }); 45 | 46 | it("a model includes days for the last week in August", () => { 47 | expect(calendar[4].length).toEqual(7); 48 | expect(toFormattedDate(calendar[4][0])).toEqual("2019-08-25"); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /packages/core/src/__tests__/createDateAPI.test.js: -------------------------------------------------------------------------------- 1 | import { adapter as dateFnsAdapter } from "@use-date-input/date-fns-adapter"; 2 | import { adapter as dayjsAdapter } from "@use-date-input/dayjs-adapter"; 3 | import { adapter as luxonAdapter } from "@use-date-input/luxon-adapter"; 4 | import { adapter as momentAdapter } from "@use-date-input/moment-adapter"; 5 | 6 | import createDateAPI from "../createDateAPI"; 7 | 8 | describe.only("given createDateAPI", () => { 9 | describe.each` 10 | api | adapter | weekOffset 11 | ${"date-fns"} | ${dateFnsAdapter} | ${0} 12 | ${"dayjs"} | ${dayjsAdapter} | ${0} 13 | ${"luxon"} | ${luxonAdapter} | ${-1} 14 | ${"moment"} | ${momentAdapter} | ${0} 15 | `("with $api and a date of 2019-08-28", ({ adapter, weekOffset }) => { 16 | let startDate; 17 | const isDayDisabled = date => adapter().isSameMonth(startDate, date); 18 | const dateAPI = createDateAPI({ 19 | adapter, 20 | isDayDisabled, 21 | weekOffset, 22 | numOfVisibleMonths: 6 23 | }); 24 | const { createDate, toFormattedDate } = dateAPI; 25 | startDate = createDate("2019-01-01"); 26 | 27 | it("getLastVisibleDate returns the last visible date", () => { 28 | expect(toFormattedDate(dateAPI.getLastVisibleDate(startDate))).toEqual( 29 | "2019-06-30" 30 | ); 31 | }); 32 | it("getNumberVisibleMonths returns the number of visible months", () => { 33 | expect(dateAPI.getNumberVisibleMonths()).toEqual(6); 34 | }); 35 | it("nextEnabledDate returns the next enabled date", () => { 36 | expect(toFormattedDate(dateAPI.nextEnabledDate(startDate))).toEqual( 37 | "2019-02-01" 38 | ); 39 | }); 40 | it("previousEnabledDate returns the previous enabled date", () => { 41 | expect(toFormattedDate(dateAPI.previousEnabledDate(startDate))).toEqual( 42 | "2018-12-31" 43 | ); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /packages/core/src/callAll.js: -------------------------------------------------------------------------------- 1 | function callAll(...fns) { 2 | return function callAllImpl(event, ...args) { 3 | return fns.some(function invoke(fn) { 4 | if (fn) { 5 | return fn(event, ...args); 6 | } 7 | return undefined; 8 | }); 9 | }; 10 | } 11 | 12 | export default callAll; 13 | -------------------------------------------------------------------------------- /packages/core/src/createCalendarModel.js: -------------------------------------------------------------------------------- 1 | const chunk = (values, chunkSize = 1) => { 2 | const valueCopy = [...values]; 3 | const result = []; 4 | while (valueCopy.length) result.push(valueCopy.splice(0, chunkSize)); 5 | return result; 6 | }; 7 | 8 | export default function createCalendarModel( 9 | date, 10 | { 11 | addDays, 12 | dayOfWeek, 13 | daysInMonth, 14 | diffInDays, 15 | endOfWeek, 16 | getFirstDayOfWeek, 17 | startOfMonth, 18 | subtractDays, 19 | startOfWeek 20 | } 21 | ) { 22 | const monthStart = startOfMonth(date); 23 | const weekStart = startOfWeek(monthStart); 24 | let prevMonthDays = []; 25 | if (dayOfWeek(monthStart) !== getFirstDayOfWeek()) { 26 | const prevMonthDaysOffset = diffInDays(weekStart, monthStart); 27 | if (prevMonthDaysOffset < 0) { 28 | const prevMonthDaysLength = prevMonthDaysOffset * -1; 29 | prevMonthDays = [...new Array(prevMonthDaysLength)].map((value, day) => 30 | subtractDays(monthStart, prevMonthDaysLength - day) 31 | ); 32 | } 33 | } 34 | const currentMonthDays = [ 35 | ...new Array(daysInMonth(monthStart)) 36 | ].map((value, day) => addDays(monthStart, day)); 37 | let lastWeekInMonth = endOfWeek( 38 | currentMonthDays[currentMonthDays.length - 1] 39 | ); 40 | let nextMonthDays = []; 41 | const lastWeekInMonthLength = diffInDays( 42 | lastWeekInMonth, 43 | currentMonthDays[currentMonthDays.length - 1] 44 | ); 45 | 46 | if (lastWeekInMonthLength > 0) { 47 | nextMonthDays = [...new Array(lastWeekInMonthLength)].map((value, day) => 48 | addDays(currentMonthDays[currentMonthDays.length - 1], day + 1) 49 | ); 50 | } 51 | 52 | const visibleDays = [...prevMonthDays, ...currentMonthDays, ...nextMonthDays]; 53 | const numOfVisibleWeeks = Math.floor(visibleDays.length / 7); 54 | 55 | let equalizeNumOfRows = []; 56 | if (numOfVisibleWeeks !== 6) { 57 | equalizeNumOfRows = [...new Array(7)].map((value, day) => 58 | addDays(visibleDays[visibleDays.length - 1], day + 1) 59 | ); 60 | } 61 | return chunk([...visibleDays, ...equalizeNumOfRows], 7); 62 | } 63 | -------------------------------------------------------------------------------- /packages/core/src/createDateAPI.js: -------------------------------------------------------------------------------- 1 | import { formatNames } from "@use-date-input/common"; 2 | 3 | const createDateAPI = ({ 4 | adapter, 5 | isDayDisabled, 6 | numOfVisibleMonths = 1, 7 | weekOffset = 0 8 | } = {}) => { 9 | if (!adapter) { 10 | throw new Error("createDateAPI called without an adapter"); 11 | } 12 | const adaptedDateAPI = adapter({ weekOffset }); 13 | const { 14 | addDays, 15 | addMonths, 16 | createDate, 17 | dayOfWeek, 18 | endOfMonth, 19 | endOfWeek, 20 | format, 21 | getDateFormat, 22 | subtractDays, 23 | startOfWeek 24 | } = adaptedDateAPI; 25 | return { 26 | getLastVisibleDate: startVisibleDate => 27 | endOfMonth(addMonths(startVisibleDate, numOfVisibleMonths - 1)), 28 | getNumberVisibleMonths: () => numOfVisibleMonths, 29 | getFirstDayOfWeek: () => { 30 | const firstDOW = startOfWeek(createDate()); 31 | return dayOfWeek(firstDOW); 32 | }, 33 | getLastDayOfWeek: () => { 34 | const lastDOW = endOfWeek(createDate()); 35 | return dayOfWeek(lastDOW); 36 | }, 37 | isDayDisabled, 38 | nextEnabledDate: date => { 39 | let nextEnabledDate = date; 40 | while (isDayDisabled(nextEnabledDate)) { 41 | nextEnabledDate = addDays(nextEnabledDate, 1); 42 | } 43 | return nextEnabledDate; 44 | }, 45 | previousEnabledDate: date => { 46 | let prevEnabledDate = date; 47 | while (isDayDisabled(prevEnabledDate)) { 48 | prevEnabledDate = subtractDays(prevEnabledDate, 1); 49 | } 50 | return prevEnabledDate; 51 | }, 52 | toFormattedDate: (date, formatName = formatNames.ISO) => { 53 | const formatter = getDateFormat(formatName); 54 | return typeof formatter === "function" 55 | ? formatter(date) 56 | : format(date, formatter); 57 | }, 58 | ...adaptedDateAPI 59 | }; 60 | }; 61 | 62 | export default createDateAPI; 63 | -------------------------------------------------------------------------------- /packages/core/src/formatNames.js: -------------------------------------------------------------------------------- 1 | const formatNames = { 2 | ARIA_DAY_LABEL: "ARIA_DAY_LABEL", 3 | ARIA_START_LABEL: "ARIA_START_LABEL", 4 | ARIA_END_LABEL: "ARIA_END_LABEL", 5 | ISO: "ISO", 6 | HEADER: "HEADER", 7 | DAY: "DAY", 8 | DAY_OF_WEEK_ABBREVIATED: "DAY_OF_WEEK_ABBREVIATED", 9 | DAY_OF_WEEK_FULL: "DAY_OF_WEEK_FULL", 10 | MONTH: "MONTH", 11 | MONTH_ABBREVIATED: "MONTH_ABBREVIATED", 12 | MONTH_FULL: "MONTH_FULL", 13 | YEAR: "YEAR" 14 | }; 15 | 16 | export default formatNames; 17 | -------------------------------------------------------------------------------- /packages/core/src/generateUID.js: -------------------------------------------------------------------------------- 1 | function generateUID() { 2 | return Math.random() 3 | .toString(36) 4 | .replace(/[^a-z]+/g, "") 5 | .substr(2, 10); 6 | } 7 | 8 | export default generateUID; 9 | -------------------------------------------------------------------------------- /packages/core/src/index.js: -------------------------------------------------------------------------------- 1 | export { default as Calendar } from "./Calendar"; 2 | export * from "./CalendarProvider"; 3 | export { default as useDateInput } from "./useDateInput"; 4 | export { default as useDateRangeInput } from "./useDateRangeInput"; 5 | 6 | export { 7 | CustomisableAnimatedGroup, 8 | default as AnimatedGroup 9 | } from "./AnimatedGroup"; 10 | export { 11 | CustomisableAnimatedMonthGroup, 12 | default as AnimatedMonthGroup 13 | } from "./AnimatedMonthGroup"; 14 | export { CustomisableDay, default as Day } from "./Day"; 15 | export { CustomisableDayOfWeek, default as DayOfWeek } from "./DayOfWeek"; 16 | export { CustomisableHeader, default as Header } from "./Header"; 17 | export { CustomisableMonth, default as Month } from "./Month"; 18 | export { CustomisableMonthGroup, default as MonthGroup } from "./MonthGroup"; 19 | export { CustomisableRoot, default as Root } from "./Root"; 20 | export { CustomisableWeek, default as Week } from "./Week"; 21 | export { CustomisableWeekHeader, default as WeekHeader } from "./WeekHeader"; 22 | export { default as CalendarWithFocusLock } from "./CalendarWithFocusLock"; 23 | 24 | export { 25 | default as calendarReducer, 26 | calendarActions, 27 | cursorType 28 | } from "./reducers/calendarReducer"; 29 | export { 30 | default as dateInputReducer, 31 | dateInputActions 32 | } from "./reducers/dateInputReducer"; 33 | export { 34 | default as dateRangeInputReducer, 35 | dateRangeInputActions, 36 | dateRangeInputType 37 | } from "./reducers/dateRangeInputReducer"; 38 | export { default as dateRangeReducer } from "./reducers/dateRangeReducer"; 39 | export { default as singleDateReducer } from "./reducers/singleDateReducer"; 40 | 41 | export { default as callAll } from "./callAll"; 42 | export { default as createCalendarModel } from "./createCalendarModel"; 43 | export { default as createDateAPI } from "./createDateAPI"; 44 | -------------------------------------------------------------------------------- /packages/core/src/reducers/dateInputReducer.js: -------------------------------------------------------------------------------- 1 | import singleDateReducer from "./singleDateReducer"; 2 | import { calendarActions } from "./calendarReducer"; 3 | 4 | export const dateInputActions = { 5 | blurInput: "BLUR_INPUT", 6 | focusInput: "FOCUS_INPUT", 7 | focusLock: "FOCUS_LOCK" 8 | }; 9 | 10 | const dateInputReducer = (state, action, dateAPI) => { 11 | let changes = {}; 12 | if (action.type === calendarActions.setOpen) { 13 | changes = { 14 | focusLock: false, 15 | open: action.open 16 | }; 17 | if (action.open) { 18 | const startDate = state.startDate || state.visibleFromDate; 19 | let updatedVisibleFromDate = dateAPI.startOfMonth(startDate); 20 | updatedVisibleFromDate = dateAPI.isSameDay( 21 | updatedVisibleFromDate, 22 | state.visibleFromDate 23 | ) 24 | ? state.visibleFromDate 25 | : updatedVisibleFromDate; 26 | changes = { 27 | ...changes, 28 | focusableDate: startDate, 29 | keyboardCursor: startDate, 30 | visibleFromDate: updatedVisibleFromDate 31 | }; 32 | } 33 | } else if (action.type === dateInputActions.focusLock) { 34 | changes = { 35 | focusLock: action.enable 36 | }; 37 | } else if (action.type === dateInputActions.focusInput) { 38 | changes = { 39 | open: true 40 | }; 41 | } else if (action.type === dateInputActions.blurInput) { 42 | changes = { 43 | open: false 44 | }; 45 | } else if ( 46 | action.type === calendarActions.selectDate || 47 | (action.type === calendarActions.keyPress && action.key.key === "Enter") 48 | ) { 49 | changes = { 50 | open: false, 51 | enableKeyboardNavigation: false, 52 | focusedDate: undefined, 53 | focusLock: false 54 | }; 55 | } else if (action.type === calendarActions.mouseClickOutside) { 56 | changes = { 57 | focusLock: false 58 | }; 59 | } 60 | return { ...state, ...singleDateReducer(state, action, dateAPI), ...changes }; 61 | }; 62 | 63 | export default dateInputReducer; 64 | -------------------------------------------------------------------------------- /packages/core/src/reducers/singleDateReducer.js: -------------------------------------------------------------------------------- 1 | import { calendarActions } from "./calendarReducer"; 2 | 3 | const singleDateReducer = (state, action, dateAPI) => { 4 | if (action.type === calendarActions.setStartDate) { 5 | return { 6 | ...state, 7 | focusableDate: action.date, 8 | focusedDate: undefined, 9 | startDate: action.date 10 | }; 11 | } else if ( 12 | action.type === calendarActions.selectDate || 13 | (action.type === calendarActions.keyPress && action.key.key === "Enter") 14 | ) { 15 | const cursor = 16 | action.type === calendarActions.selectDate 17 | ? action.date 18 | : state.keyboardCursor; 19 | if (!dateAPI.isSameDay(state.startDate, cursor)) { 20 | return { 21 | ...state, 22 | focusedDate: cursor, 23 | focusableDate: cursor, 24 | keyboardCursor: cursor, 25 | mouseCursor: undefined, 26 | startDate: cursor 27 | }; 28 | } 29 | } else if (action.type === calendarActions.setEnableKeyboardNavigation) { 30 | if (!action.enable) { 31 | return { 32 | ...state, 33 | focusedDate: undefined 34 | }; 35 | } 36 | } 37 | return state; 38 | }; 39 | 40 | export default singleDateReducer; 41 | -------------------------------------------------------------------------------- /packages/core/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // react-testing-library renders your components to document.body, 2 | // this adds jest-dom's custom assertions 3 | import "@testing-library/jest-dom/extend-expect"; 4 | 5 | if (window.document) { 6 | window.document.createRange = () => ({ 7 | setStart: () => {}, 8 | setEnd: () => {}, 9 | commonAncestorContainer: { 10 | nodeName: "BODY", 11 | ownerDocument: document 12 | } 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/src/test-utils.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ThemeProvider } from "styled-components"; 3 | import { render } from "@testing-library/react"; 4 | import PropTypes from "prop-types"; 5 | 6 | const mockTheme = { 7 | calendarOverrides: {}, 8 | getCalendarOverrides: jest.fn(() => () => ({})) 9 | }; 10 | 11 | function TestUtils({ children }) { 12 | return {children}; 13 | } 14 | TestUtils.propTypes = { 15 | children: PropTypes.node 16 | }; 17 | export default TestUtils; 18 | 19 | const customRender = (ui, options) => 20 | render(ui, { wrapper: TestUtils, ...options }); 21 | 22 | // re-export everything 23 | export * from "@testing-library/react"; 24 | 25 | // override render method 26 | export { customRender as render }; 27 | -------------------------------------------------------------------------------- /packages/date-fns-adapter/.prettierignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/src 3 | -------------------------------------------------------------------------------- /packages/date-fns-adapter/README.md: -------------------------------------------------------------------------------- 1 | # @use-date-input/date-fns-adapter 2 | 3 | The [date-fns](https://date-fns.org/) adapter for [@use-date-input](https://github.com/mark-tate/use-date-input). 4 | 5 | [@use-date-input](https://github.com/mark-tate/use-date-input) is a collection of React UI components and hooks to help compose date picker components. 6 | 7 | To get started, refer to [getting started](https://mark-tate.github.io/use-date-input/getting-started#for-date-fns-users) guide and then the [how to guide for date-fns](https://mark-tate.github.io/use-date-input/date-frameworks#with-date-fns). 8 | 9 | For the full documentation, refer to the [documentation](https://mark-tate.github.io/use-date-input/). 10 | -------------------------------------------------------------------------------- /packages/date-fns-adapter/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@babel/preset-env"], 3 | plugins: [ 4 | [ 5 | "@babel/plugin-transform-runtime", 6 | { 7 | corejs: false, 8 | helpers: true, 9 | regenerator: false, 10 | useESModules: true 11 | } 12 | ], 13 | ["@babel/plugin-proposal-object-rest-spread", { loose: true }], 14 | "@babel/plugin-proposal-class-properties" 15 | ] 16 | }; 17 | -------------------------------------------------------------------------------- /packages/date-fns-adapter/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require("../../config/jest/jest.config.js"); 2 | 3 | module.exports = { 4 | ...base, 5 | name: "@use-date-input/date-fns-adapter", 6 | displayName: "@use-date-input/date-fns-adapter" 7 | }; 8 | -------------------------------------------------------------------------------- /packages/date-fns-adapter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@use-date-input/date-fns-adapter", 3 | "version": "0.2.0-beta.0", 4 | "author": "Mark Tate <143323+mark-tate@users.noreply.github.com>", 5 | "description": "@use-date-input - date-fns adapter", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "jsnext:main": "dist/index.esm.js", 9 | "module": "dist/index.esm.js", 10 | "keywords": [ 11 | "adapter", 12 | "use-date-input", 13 | "useDateInput", 14 | "useDateRange" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/mark-tate/use-date-input.git", 19 | "directory": "packages/luxon-adapter" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/mark-tate/use-date-input/issues" 23 | }, 24 | "dependencies": { 25 | "@use-date-input/common": "^0.2.0-beta.0" 26 | }, 27 | "peerDependencies": { 28 | "date-fns": ">=2.12.0" 29 | }, 30 | "publishConfig": { 31 | "access": "public" 32 | }, 33 | "files": [ 34 | "dist/index*.js" 35 | ], 36 | "sideEffects": false, 37 | "scripts": { 38 | "build": "rollup -c ../../config/rollup/rollup.config.js", 39 | "prettier": "prettier --write \"**/*.+(js|jsx|json|css|md)\"", 40 | "lint": "eslint --ext .js,.jsx,.ts,.tsx src --color", 41 | "test": "jest" 42 | }, 43 | "browserslist": { 44 | "production": [ 45 | ">0.2%", 46 | "not dead", 47 | "not op_mini all" 48 | ], 49 | "development": [ 50 | "last 1 chrome version", 51 | "last 1 firefox version", 52 | "last 1 safari version" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/dayjs-adapter/.prettierignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/src 3 | -------------------------------------------------------------------------------- /packages/dayjs-adapter/README.md: -------------------------------------------------------------------------------- 1 | # @use-date-input/dayjs-adapter 2 | 3 | The [dayjs](https://day.js.org/) adapter for [@use-date-input](https://github.com/mark-tate/use-date-input). 4 | 5 | [@use-date-input](https://github.com/mark-tate/use-date-input) is a collection of React UI components and hooks to help compose date picker components. 6 | 7 | To get started, refer to [getting started](https://mark-tate.github.io/use-date-input/getting-started#for-dayjs-users) guide and then the [how to guide for dayjs](https://mark-tate.github.io/use-date-input/date-frameworks#with-dayjs). 8 | 9 | For the full documentation, refer to the [documentation](https://mark-tate.github.io/use-date-input/). 10 | -------------------------------------------------------------------------------- /packages/dayjs-adapter/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@babel/preset-env"], 3 | plugins: [ 4 | [ 5 | "@babel/plugin-transform-runtime", 6 | { 7 | corejs: false, 8 | helpers: true, 9 | regenerator: false, 10 | useESModules: true 11 | } 12 | ], 13 | ["@babel/plugin-proposal-object-rest-spread", { loose: true }], 14 | "@babel/plugin-proposal-class-properties" 15 | ] 16 | }; 17 | -------------------------------------------------------------------------------- /packages/dayjs-adapter/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require("../../config/jest/jest.config.js"); 2 | 3 | module.exports = { 4 | ...base, 5 | name: "@use-date-input/dayjs-adapter", 6 | displayName: "@use-date-input/dayjs-adapter" 7 | }; 8 | -------------------------------------------------------------------------------- /packages/dayjs-adapter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@use-date-input/dayjs-adapter", 3 | "version": "0.2.0-beta.0", 4 | "author": "Mark Tate <143323+mark-tate@users.noreply.github.com>", 5 | "description": "@use-date-input - dayjs adapter", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "jsnext:main": "dist/index.esm.js", 9 | "module": "dist/index.esm.js", 10 | "keywords": [ 11 | "adapter", 12 | "use-date-input", 13 | "useDateInput", 14 | "useDateRange" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/mark-tate/use-date-input.git", 19 | "directory": "packages/luxon-adapter" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/mark-tate/use-date-input/issues" 23 | }, 24 | "dependencies": { 25 | "@use-date-input/common": "^0.2.0-beta.0" 26 | }, 27 | "peerDependencies": { 28 | "dayjs": ">=1.8.24" 29 | }, 30 | "publishConfig": { 31 | "access": "public" 32 | }, 33 | "files": [ 34 | "dist/index*.js" 35 | ], 36 | "sideEffects": false, 37 | "scripts": { 38 | "build": "rollup -c ../../config/rollup/rollup.config.js", 39 | "prettier": "prettier --write \"**/*.+(js|jsx|json|css|md)\"", 40 | "lint": "eslint --ext .js,.jsx,.ts,.tsx src --color", 41 | "test": "jest" 42 | }, 43 | "browserslist": { 44 | "production": [ 45 | ">0.2%", 46 | "not dead", 47 | "not op_mini all" 48 | ], 49 | "development": [ 50 | "last 1 chrome version", 51 | "last 1 firefox version", 52 | "last 1 safari version" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/luxon-adapter/.prettierignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/src 3 | -------------------------------------------------------------------------------- /packages/luxon-adapter/README.md: -------------------------------------------------------------------------------- 1 | # @use-date-input/luxon-adapter 2 | 3 | The [luxon](https://moment.github.io/luxon/) adapter for [@use-date-input](https://github.com/mark-tate/use-date-input). 4 | 5 | [@use-date-input](https://github.com/mark-tate/use-date-input) is a collection of React UI components and hooks to help compose date picker components. 6 | 7 | To get started, refer to [getting started](https://mark-tate.github.io/use-date-input/getting-started#for-luxon-users) guide and then the [how to guide for luxon](https://mark-tate.github.io/use-date-input/date-frameworks#with-luxon). 8 | 9 | For the full documentation, refer to the [documentation](https://mark-tate.github.io/use-date-input/). 10 | -------------------------------------------------------------------------------- /packages/luxon-adapter/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@babel/preset-env"], 3 | plugins: [ 4 | [ 5 | "@babel/plugin-transform-runtime", 6 | { 7 | corejs: false, 8 | helpers: true, 9 | regenerator: false, 10 | useESModules: true 11 | } 12 | ], 13 | ["@babel/plugin-proposal-object-rest-spread", { loose: true }], 14 | "@babel/plugin-proposal-class-properties" 15 | ] 16 | }; 17 | -------------------------------------------------------------------------------- /packages/luxon-adapter/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require("../../config/jest/jest.config.js"); 2 | 3 | module.exports = { 4 | ...base, 5 | name: "@use-date-input/luxon-adapter", 6 | displayName: "@use-date-input/luxon-adapter" 7 | }; 8 | -------------------------------------------------------------------------------- /packages/luxon-adapter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@use-date-input/luxon-adapter", 3 | "version": "0.2.1-beta.0", 4 | "author": "Mark Tate <143323+mark-tate@users.noreply.github.com>", 5 | "description": "@use-date-input - luxon adapter", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "jsnext:main": "dist/index.esm.js", 9 | "module": "dist/index.esm.js", 10 | "keywords": [ 11 | "adapter", 12 | "use-date-input", 13 | "useDateInput", 14 | "useDateRange", 15 | "luxon" 16 | ], 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/mark-tate/use-date-input.git", 20 | "directory": "packages/luxon-adapter" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/mark-tate/use-date-input/issues" 24 | }, 25 | "dependencies": { 26 | "@use-date-input/common": "^0.2.0-beta.0" 27 | }, 28 | "peerDependencies": { 29 | "luxon": ">=1.23.0" 30 | }, 31 | "publishConfig": { 32 | "access": "public" 33 | }, 34 | "files": [ 35 | "dist/index*.js" 36 | ], 37 | "sideEffects": false, 38 | "scripts": { 39 | "build": "rollup -c ../../config/rollup/rollup.config.js", 40 | "prettier": "prettier --write \"**/*.+(js|jsx|json|css|md)\"", 41 | "lint": "eslint --ext .js,.jsx,.ts,.tsx src --color", 42 | "test": "jest" 43 | }, 44 | "browserslist": { 45 | "production": [ 46 | ">0.2%", 47 | "not dead", 48 | "not op_mini all" 49 | ], 50 | "development": [ 51 | "last 1 chrome version", 52 | "last 1 firefox version", 53 | "last 1 safari version" 54 | ] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/moment-adapter/.prettierignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/src 3 | -------------------------------------------------------------------------------- /packages/moment-adapter/README.md: -------------------------------------------------------------------------------- 1 | # @use-date-input/moment-adapter 2 | 3 | The [moment](https://momentjs.com/) adapter for [@use-date-input](https://github.com/mark-tate/use-date-input). 4 | 5 | [@use-date-input](https://github.com/mark-tate/use-date-input) is a collection of React UI components and hooks to help compose date picker components. 6 | 7 | To get started, refer to the [getting started](https://mark-tate.github.io/use-date-input/getting-started#for-moment-users) guide and then the [how to guide for moment](https://mark-tate.github.io/use-date-input/date-frameworks#with-moment). 8 | 9 | For the full documentation, refer to the [documentation](https://mark-tate.github.io/use-date-input/). 10 | -------------------------------------------------------------------------------- /packages/moment-adapter/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@babel/preset-env"], 3 | plugins: [ 4 | [ 5 | "@babel/plugin-transform-runtime", 6 | { 7 | corejs: false, 8 | helpers: true, 9 | regenerator: false, 10 | useESModules: true 11 | } 12 | ], 13 | ["@babel/plugin-proposal-object-rest-spread", { loose: true }], 14 | "@babel/plugin-proposal-class-properties" 15 | ] 16 | }; 17 | -------------------------------------------------------------------------------- /packages/moment-adapter/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require("../../config/jest/jest.config.js"); 2 | 3 | module.exports = { 4 | ...base, 5 | name: "@use-date-input/moment-adapter", 6 | displayName: "@use-date-input/moment-adapter" 7 | }; 8 | -------------------------------------------------------------------------------- /packages/moment-adapter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@use-date-input/moment-adapter", 3 | "version": "0.2.1-beta.0", 4 | "author": "Mark Tate <143323+mark-tate@users.noreply.github.com>", 5 | "description": "@use-date-input - moment adapter", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "jsnext:main": "dist/index.esm.js", 9 | "module": "dist/index.esm.js", 10 | "keywords": [ 11 | "adapter", 12 | "use-date-input", 13 | "useDateInput", 14 | "useDateRange", 15 | "moment" 16 | ], 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/mark-tate/use-date-input.git", 20 | "directory": "packages/luxon-adapter" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/mark-tate/use-date-input/issues" 24 | }, 25 | "dependencies": { 26 | "@use-date-input/common": "^0.2.0-beta.0" 27 | }, 28 | "peerDependencies": { 29 | "moment": ">=2.24.0" 30 | }, 31 | "publishConfig": { 32 | "access": "public" 33 | }, 34 | "files": [ 35 | "dist/index*.js" 36 | ], 37 | "sideEffects": false, 38 | "scripts": { 39 | "build": "rollup -c ../../config/rollup/rollup.config.js", 40 | "prettier": "prettier --write \"**/*.+(js|jsx|json|css|md)\"", 41 | "lint": "eslint --ext .js,.jsx,.ts,.tsx src --color", 42 | "test": "jest" 43 | }, 44 | "browserslist": { 45 | "production": [ 46 | ">0.2%", 47 | "not dead", 48 | "not op_mini all" 49 | ], 50 | "development": [ 51 | "last 1 chrome version", 52 | "last 1 firefox version", 53 | "last 1 safari version" 54 | ] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/popper/.prettierignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/src 3 | -------------------------------------------------------------------------------- /packages/popper/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | # 0.2.0-beta.0 (2020-08-26) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * modernize the language for allowable list of refs in Popper and move to it's own package. ([4a32c75](https://github.com/mark-tate/use-date-input/commit/4a32c75691fa96cf9b57c5e4e21f4683d54d4688)) 12 | -------------------------------------------------------------------------------- /packages/popper/README.md: -------------------------------------------------------------------------------- 1 | # @use-date-input/popper 2 | 3 | An optional popper package for [@use-date-input](https://github.com/mark-tate/use-date-input). 4 | 5 | [@use-date-input](https://github.com/mark-tate/use-date-input) is a collection of React UI components and hooks to help compose date picker components. 6 | 7 | To get started, refer to [getting started](https://mark-tate.github.io/use-date-input/getting-started). 8 | 9 | For the full documentation, refer to the [documentation](https://mark-tate.github.io/use-date-input/). 10 | -------------------------------------------------------------------------------- /packages/popper/babel.config.js: -------------------------------------------------------------------------------- 1 | const { NODE_ENV } = process.env; 2 | 3 | const inProduction = NODE_ENV === "production"; 4 | const inDevelopment = NODE_ENV === "development"; 5 | 6 | const environmentConfig = { 7 | test: { 8 | compact: false, 9 | presets: [ 10 | [ 11 | "@babel/preset-env", 12 | { 13 | modules: "cjs", 14 | debug: false 15 | } 16 | ], 17 | "@babel/preset-react" 18 | ], 19 | plugins: [ 20 | [ 21 | "@babel/plugin-transform-runtime", 22 | { 23 | corejs: false, 24 | helpers: true, 25 | regenerator: true, 26 | useESModules: true 27 | } 28 | ], 29 | ["@babel/plugin-proposal-object-rest-spread", { loose: true }], 30 | "@babel/plugin-proposal-class-properties" 31 | ] 32 | }, 33 | production: { 34 | presets: [["@babel/preset-env", { modules: false }], "@babel/preset-react"], 35 | plugins: [ 36 | [ 37 | "@babel/plugin-transform-runtime", 38 | { 39 | corejs: false, 40 | helpers: true, 41 | regenerator: false, 42 | useESModules: true 43 | } 44 | ], 45 | ["@babel/plugin-proposal-object-rest-spread", { loose: true }], 46 | "@babel/plugin-proposal-class-properties", 47 | "babel-plugin-styled-components" 48 | ] 49 | }, 50 | development: { 51 | compact: false, 52 | presets: [["@babel/preset-env", { modules: false }], "@babel/preset-react"], 53 | plugins: [ 54 | [ 55 | "@babel/plugin-transform-runtime", 56 | { 57 | corejs: false, 58 | helpers: true, 59 | regenerator: false, 60 | useESModules: true 61 | } 62 | ], 63 | ["@babel/plugin-proposal-object-rest-spread", { loose: true }], 64 | "@babel/plugin-proposal-class-properties", 65 | "babel-plugin-styled-components" 66 | ] 67 | } 68 | }; 69 | 70 | module.exports = api => { 71 | api.cache.using(() => process.env.NODE_ENV); 72 | return environmentConfig[process.env.NODE_ENV || "development"]; 73 | }; 74 | -------------------------------------------------------------------------------- /packages/popper/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require("../../config/jest/jest.config.js"); 2 | 3 | module.exports = { 4 | ...base, 5 | name: "@use-date-input/popper", 6 | displayName: "@use-date-input/popper" 7 | }; 8 | -------------------------------------------------------------------------------- /packages/popper/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@use-date-input/popper", 3 | "version": "0.2.0-beta.0", 4 | "author": "Mark Tate <143323+mark-tate@users.noreply.github.com>", 5 | "description": "@use-date-input - Popper library", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "jsnext:main": "dist/index.esm.js", 9 | "module": "dist/index.esm.js", 10 | "keywords": [ 11 | "calendar", 12 | "date", 13 | "datepicker", 14 | "date-picker", 15 | "date-input", 16 | "date-range", 17 | "hook", 18 | "input", 19 | "use-date-input", 20 | "useDateInput", 21 | "useDateRange", 22 | "react", 23 | "react-component" 24 | ], 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/mark-tate/use-date-input.git", 28 | "directory": "packages/popper" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/mark-tate/use-date-input/issues" 32 | }, 33 | "dependencies": { 34 | "@popperjs/core": "^2.4.2", 35 | "@use-date-input/common": "^0.2.0-beta.0", 36 | "prop-types": "^15.7.2", 37 | "react-popper": "^2.2.3" 38 | }, 39 | "peerDependencies": { 40 | "react": ">=16.8.0", 41 | "react-dom": ">=16.8.0" 42 | }, 43 | "publishConfig": { 44 | "access": "public" 45 | }, 46 | "files": [ 47 | "dist/index*.js" 48 | ], 49 | "sideEffects": false, 50 | "scripts": { 51 | "build": "rollup -c", 52 | "prettier": "prettier --write \"**/*.+(js|jsx|json|css|md)\"", 53 | "lint": "eslint --ext .js,.jsx,.ts,.tsx src --color", 54 | "test": "jest" 55 | }, 56 | "browserslist": { 57 | "production": [ 58 | ">0.2%", 59 | "not dead", 60 | "not op_mini all" 61 | ], 62 | "development": [ 63 | "last 1 chrome version", 64 | "last 1 firefox version", 65 | "last 1 safari version" 66 | ] 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /packages/popper/src/ClickOutside.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, useCallback, useEffect, useRef } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { useForkRef } from "@use-date-input/common"; 4 | 5 | export const ClickOutside = forwardRef(function ClickOutside( 6 | { children, onClickOutside, ignoreClickOutsideRefs = [], ...rest }, 7 | ref 8 | ) { 9 | const containerRef = useRef(null); 10 | const handleRef = useForkRef(ref, containerRef); 11 | 12 | const listener = useCallback( 13 | event => { 14 | const hasClickedIgnoreList = [ 15 | containerRef, 16 | ...ignoreClickOutsideRefs 17 | ].some(ref => { 18 | return ref.current && ref.current.contains(event.target); 19 | }); 20 | if (!hasClickedIgnoreList && onClickOutside) { 21 | onClickOutside(event); 22 | } 23 | }, 24 | [containerRef, onClickOutside, ignoreClickOutsideRefs] 25 | ); 26 | 27 | useEffect(() => { 28 | const ownerDocument = 29 | (containerRef && 30 | containerRef.current && 31 | containerRef.current.ownerDocument) || 32 | document; 33 | ownerDocument.addEventListener("mousedown", listener); 34 | ownerDocument.addEventListener("touchstart", listener); 35 | return () => { 36 | ownerDocument.removeEventListener("mousedown", listener); 37 | ownerDocument.removeEventListener("touchstart", listener); 38 | }; 39 | }, [containerRef, listener]); 40 | 41 | return ( 42 |
43 | {children} 44 |
45 | ); 46 | }); 47 | 48 | ClickOutside.propTypes = { 49 | /** Children to monitor for click outside events */ 50 | children: PropTypes.node, 51 | /** Callback called when the mouse is clicked outside */ 52 | onClickOutside: PropTypes.func, 53 | /** Additional array of refs, will ignore click outside from **/ 54 | ignoreClickOutsideRefs: PropTypes.array 55 | }; 56 | 57 | export default ClickOutside; 58 | -------------------------------------------------------------------------------- /packages/popper/src/Popper.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, useCallback } from "react"; 2 | import { createPortal } from "react-dom"; 3 | import PropTypes from "prop-types"; 4 | import ClickOutside from "./ClickOutside"; 5 | import { useForkRef } from "@use-date-input/common"; 6 | 7 | import { usePopper } from "react-popper"; 8 | 9 | const Popper = forwardRef( 10 | ( 11 | { 12 | anchorEl, 13 | children, 14 | ignoreClickOutsideRefs, 15 | onClickOutside, 16 | onEscapeKey, 17 | open, 18 | ...popperProps 19 | }, 20 | ref 21 | ) => { 22 | const [popperElement, setPopperElement] = React.useState(null); 23 | const handleRef = useForkRef(ref, setPopperElement); 24 | const { styles, attributes } = usePopper( 25 | anchorEl, 26 | popperElement, 27 | popperProps 28 | ); 29 | const handleKeyDown = useCallback( 30 | event => { 31 | if (event.key === "Escape") { 32 | onEscapeKey(); 33 | } 34 | }, 35 | [onEscapeKey] 36 | ); 37 | if (!open) { 38 | return null; 39 | } 40 | return ( 41 | <> 42 | {createPortal( 43 |
44 | 49 | {children} 50 | 51 |
, 52 | document.querySelector("body") 53 | )} 54 | 55 | ); 56 | } 57 | ); 58 | Popper.displayName = "Popper"; 59 | Popper.propTypes = { 60 | /** Anchor element */ 61 | anchorEl: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), 62 | /** Popper content */ 63 | children: PropTypes.node, 64 | /** Array of refs, will not close the Popper, if clicked **/ 65 | ignoreClickOutsideRefs: PropTypes.array, 66 | /** Callback on click outside **/ 67 | onClickOutside: PropTypes.func, 68 | /** Callback on escape key press **/ 69 | onEscapeKey: PropTypes.func, 70 | /** Open/close popper */ 71 | open: PropTypes.bool 72 | }; 73 | export default Popper; 74 | -------------------------------------------------------------------------------- /packages/popper/src/__tests__/ClickOutside.test.js: -------------------------------------------------------------------------------- 1 | import React, { createRef } from "react"; 2 | import { fireEvent, render } from "@testing-library/react"; 3 | 4 | import ClickOutside from "../ClickOutside"; 5 | 6 | describe("given ClickOutside", () => { 7 | it("passes the ref to the DOM", () => { 8 | const ref = React.createRef(); 9 | render(); 10 | expect(ref.current).toBeInstanceOf(HTMLDivElement); 11 | }); 12 | 13 | it("calls onClickOutside on ignoreList or child click event", () => { 14 | const handleClickOutsideMock = jest.fn(); 15 | const insideIgnoreListRef = createRef(); 16 | const allowIgnoreListRef = createRef(); 17 | const { getByText } = render( 18 | <> 19 | 20 | 21 | 25 | 26 | 27 | 28 | ); 29 | fireEvent.mouseDown(getByText("deny clicks")); 30 | expect(handleClickOutsideMock).toHaveBeenCalled(); 31 | handleClickOutsideMock.mockReset(); 32 | fireEvent.mouseDown(getByText("allow clicks")); 33 | expect(handleClickOutsideMock).not.toHaveBeenCalled(); 34 | handleClickOutsideMock.mockReset(); 35 | fireEvent.mouseDown(getByText("inside clickOutside")); 36 | expect(handleClickOutsideMock).not.toHaveBeenCalled(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /packages/popper/src/__tests__/Popper.test.js: -------------------------------------------------------------------------------- 1 | import React, { createRef } from "react"; 2 | import { fireEvent, render } from "@testing-library/react"; 3 | 4 | import Popper from "../Popper"; 5 | 6 | describe("given Popper", () => { 7 | it("closes on key Escape", () => { 8 | const onEscapeKey = jest.fn(); 9 | const { getByTestId } = render( 10 | 11 | 12 | 13 | ); 14 | const child = getByTestId("test-child"); 15 | fireEvent.focus(child); 16 | fireEvent.keyDown(child, { key: "Escape", keyCode: 27 }); 17 | expect(onEscapeKey).toHaveBeenCalled(); 18 | }); 19 | it("only closes when clicked outside", () => { 20 | const onClickOutside = jest.fn(); 21 | const ignoreClickOutsideRef = createRef(); 22 | const { getByTestId } = render( 23 |
24 | 25 | 29 | 35 | 36 | 37 |
38 | ); 39 | fireEvent.mouseDown(getByTestId("inside-child")); 40 | expect(onClickOutside).not.toHaveBeenCalled(); 41 | fireEvent.mouseDown(getByTestId("ignored-outside-child")); 42 | expect(onClickOutside).not.toHaveBeenCalled(); 43 | fireEvent.mouseDown(getByTestId("outside-child")); 44 | expect(onClickOutside).toHaveBeenCalled(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /packages/popper/src/index.js: -------------------------------------------------------------------------------- 1 | export { default as Popper } from "./Popper"; 2 | export { default as ClickOutside } from "./ClickOutside"; 3 | -------------------------------------------------------------------------------- /public/cross.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/docs/components/clickOutside.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: ClickOutside 3 | route: /clickOutside 4 | --- 5 | import { useRef } from "react"; 6 | import { Playground } from "docz"; 7 | import { ClickOutside } from "@use-date-input/popper"; 8 | import { Button } from "../../gatsby-theme-docz/components/Button"; 9 | import { ButtonBar } from "../../gatsby-theme-docz/components/ButtonBar"; 10 | 11 | # ClickOutside 12 | The `ClickOutside` component is used to detect when the mouse is clicked outside the calendar. 13 | 14 | In the default implementation `ClickOutside` is used to determine when to close the `Calendar` when rendered inside a `Popper`. 15 | Clicks within the `Calender` or on the associated inputs should not close the `Calendar` but everywhere else should. 16 | 17 | ## Example 18 | In this example when you click the buttons they log whether or not it considers it a click outside the rendered tree. 19 | In addition an ignored list of refs can be provided which, when clicked, will not invoke `onClickOutside`. 20 | 21 | 22 | {() => { 23 | const ignoreRef = useRef(); 24 | const ignoreListRefs=[ignoreRef]; 25 | function handleClickOutside() { 26 | console.log('you clicked outside the component'); 27 | } 28 | return ( 29 | <> 30 | 31 | 32 | 33 | 34 | 38 | 39 | 40 | 41 | ); 42 | }} 43 | 44 | 45 | ## Props 46 | | Prop Name | Type | Is Required | Default Value | Description | 47 | |-|-|-|-|-| 48 | | children| `node`| optional| | children to monitor for click outside events| 49 | | ignoreClickOutsideRefs| `array`| optional| | Additional array of refs, will ignore click outside from| 50 | | onClickOutside| `func`| optional| | Callback called when the mouse is clicked outside| 51 | -------------------------------------------------------------------------------- /src/docs/components/dayOfWeek.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: DayOfWeek 3 | route: /dayOfWeek 4 | --- 5 | import { Playground } from "docz"; 6 | import { DayOfWeek } from "@use-date-input/core"; 7 | 8 | # DayOfWeek 9 | The `DayOfWeek` components renders a day of the week. 10 | 11 | In the default implementation, [WeekHeader](https://mark-tate.github.io/use-date-input/weekHeader) is the parent of `DayOfWeek`. 12 | 13 | ## Example 14 | 15 | M 16 | 17 | 18 | ## Props 19 | | Prop Name | Type | Is Required | Default Value | Description | 20 | |-|-|-|-|-| 21 | | children| `node`| optional| | Day of week node| 22 | | className| `string`| optional| | Class name of root element| 23 | | description| `string`| optional| | Day of week expanded label| 24 | 25 | ## Importing 26 | It can be imported as either the base component 27 | 28 | ```javascript 29 | import { DayOfWeek } from "@use-date-input/core"; 30 | ``` 31 | 32 | or as an overridable component that can be replaced through the `components` prop in `CalendarProvider`. 33 | Refer to [How to replace UI components](https://mark-tate.github.io/use-date-input/theming#how-to-replace-ui-components). 34 | 35 | ```javascript 36 | import { CustomisableDayOfWeek } from "@use-date-input/core"; 37 | ``` 38 | 39 | If providing your own component, it can be useful to import the base component and use it within your composition. 40 | -------------------------------------------------------------------------------- /src/docs/components/header.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: Header 3 | route: /header 4 | --- 5 | import { Playground } from "docz"; 6 | import { Header, CalendarProvider } from "@use-date-input/core"; 7 | import { adapter as dateAdapter } from '@use-date-input/date-fns-adapter'; 8 | 9 | # Header 10 | The `Header` component renders the `Calendar` header. 11 | 12 | In the default implementation, [Root](https://mark-tate.github.io/use-date-input/root) is the parent of `Header`. 13 | By default `Header` uses the visibleFromDate and renders the current year as it's title, alongside the navigation buttons. 14 | 15 | ## Example 16 | 17 | 18 |
19 |
20 |
21 |
22 |
23 | 24 | ## Props 25 | | Prop Name | Type | Is Required | Default Value | Description | 26 | |-|-|-|-|-| 27 | | className| `string`| optional| | Class name of root element| 28 | 29 | ## Importing 30 | It can be imported as either the base component 31 | 32 | ```javascript 33 | import { Header } from "@use-date-input/core"; 34 | ``` 35 | 36 | or as an overridable component that can be replaced through the `components` prop in `CalendarProvider`. 37 | Refer to [How to replace UI components](https://mark-tate.github.io/use-date-input/theming#how-to-replace-ui-components). 38 | 39 | ```javascript 40 | import { CustomisableHeader } from "@use-date-input/core"; 41 | ``` 42 | 43 | If providing your own component, it can be useful to import the base component and use it within your composition. 44 | -------------------------------------------------------------------------------- /src/docs/components/month.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: Month 3 | route: /month 4 | --- 5 | import { Playground } from "docz"; 6 | import { Month, CalendarProvider, useDateAPI } from "@use-date-input/core"; 7 | import { adapter as dateAdapter } from "@use-date-input/date-fns-adapter"; 8 | 9 | # Month 10 | The `Month` components renders a calendar month. 11 | 12 | In the default implementation, [MonthGroup](https://mark-tate.github.io/use-date-input/monthGroup) is the parent of `Month`. 13 | 14 | ## Example 15 | 16 | {() => { 17 | function MonthExample() { 18 | const { createDate } = useDateAPI(); 19 | const month = createDate(); 20 | return (); 21 | } 22 | return ( 23 | 24 | 25 | 26 | ); 27 | }} 28 | 29 | 30 | ## Props 31 | | Prop Name | Type | Is Required | Default Value | Description | 32 | |-|-|-|-|-| 33 | | className| `string`| optional| | Class name of root element| 34 | | month| `object`| optional| | Month | 35 | 36 | ## Importing 37 | It can be imported as either the base component 38 | 39 | ```javascript 40 | import { Month } from "@use-date-input/core"; 41 | ``` 42 | 43 | or as an overridable component that can be replaced through the `components` prop in `CalendarProvider`. 44 | Refer to [How to replace UI components](https://mark-tate.github.io/use-date-input/theming#how-to-replace-ui-components). 45 | 46 | ```javascript 47 | import { CustomisableMonth } from "@use-date-input/core"; 48 | ``` 49 | 50 | If providing your own component, it can be useful to import the base component and use it within your composition. 51 | 52 | -------------------------------------------------------------------------------- /src/docs/components/monthGroup.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: MonthGroup 3 | route: /monthGroup 4 | --- 5 | import { Playground } from "docz"; 6 | import { MonthGroup, CalendarProvider, useDateAPI } from "@use-date-input/core"; 7 | import { adapter as dateAdapter } from '@use-date-input/date-fns-adapter'; 8 | 9 | # MonthGroup 10 | The `MonthGroup` components renders all the visible calendar `Month` components. 11 | 12 | ## Example 13 | 14 | {() => { 15 | function MonthGroupExample() { 16 | const { createDate } = useDateAPI(); 17 | const visibleFromDate = createDate(); 18 | return (); 19 | } 20 | return ( 21 | 22 | 23 | 24 | ); 25 | }} 26 | 27 | 28 | ## Props 29 | | Prop Name | Type | Is Required | Default Value | Description | 30 | |-|-|-|-|-| 31 | | className| `string`| optional| | Class name of root element| 32 | | visibleFromDate| `object`| optional| | Visible from date | 33 | 34 | ## Importing 35 | It can be imported as either the base component 36 | 37 | ```javascript 38 | import { MonthGroup } from "@use-date-input/core"; 39 | ``` 40 | 41 | or as an overridable component that can be replaced through the `components` prop in `CalendarProvider`. 42 | Refer to [How to replace UI components](https://mark-tate.github.io/use-date-input/theming#how-to-replace-ui-components). 43 | 44 | ```javascript 45 | import { CustomisableMonthGroup } from "@use-date-input/core"; 46 | ``` 47 | 48 | If providing your own component, it can be useful to import the base component and use it within your composition. 49 | -------------------------------------------------------------------------------- /src/docs/components/root.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: Root 3 | route: /root 4 | --- 5 | import { Playground } from "docz"; 6 | import useMediaQuery from "@material-ui/core/useMediaQuery/useMediaQuery"; 7 | import { useTheme } from "@material-ui/core/styles"; 8 | import { Calendar, CalendarProvider, Root } from "@use-date-input/core"; 9 | import { adapter as dateAdapter } from "@use-date-input/date-fns-adapter"; 10 | import { DemoContent, DemoContentSmall } from "../../gatsby-theme-docz/components/DemoContent"; 11 | 12 | # Root 13 | The `Root` component is the root component of the `Calendar`. 14 | 15 | `Root` enables you to re-compose the Calendar with additional UI elements, such as shortcut lists or additional branding. 16 | Refer to [Composition](https://mark-tate.github.io/use-date-input/composition). 17 | 18 | ## Example 19 | 20 | {() => { 21 | const theme = useTheme(); 22 | const isSmallBreakpoint = useMediaQuery(theme.breakpoints.down("sm")); 23 | const AddYourComponentHere = isSmallBreakpoint ? DemoContentSmall : DemoContent; 24 | function MyRoot(props) { 25 | return ( 26 | <> 27 |
28 | 29 | 30 |
31 | 32 | ); 33 | } 34 | return ( 35 | 36 | 37 | 38 | ); 39 | }} 40 |
41 | 42 | ## Props 43 | | Prop Name | Type | Is Required | Default Value | Description | 44 | |-|-|-|-|-| 45 | | className| `string`| optional| | Class name of root element| 46 | 47 | ## Importing 48 | It can be imported as either the base component 49 | 50 | ```javascript 51 | import { Root } from "@use-date-input/core"; 52 | ``` 53 | 54 | or as an overridable component that can be replaced through the `components` prop in `CalendarProvider`. 55 | Refer to [How to replace UI components](https://mark-tate.github.io/use-date-input/theming#how-to-replace-ui-components). 56 | 57 | ```javascript 58 | import { CustomisableMonthRoot } from "@use-date-input/core"; 59 | ``` 60 | 61 | If providing your own component, it can be useful to import the base component and use it within your composition. 62 | -------------------------------------------------------------------------------- /src/docs/components/week.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: Week 3 | route: /week 4 | --- 5 | import { Playground } from "docz"; 6 | import { CalendarProvider, Week } from "@use-date-input/core"; 7 | import { adapter as dateAdapter } from "@use-date-input/date-fns-adapter"; 8 | 9 | # Week 10 | The `Week` components renders a week, as a row of `Day` components based on the current `Calendar` state. 11 | 12 | ## Example 13 | 14 | {() => { 15 | const { addDays, createDate } = dateAdapter(); 16 | const today = createDate(); 17 | const days = Array(7).fill(0).reduce((result, day, dayIndex) => { 18 | return [ ...result, addDays(today, dayIndex)]; 19 | }, []); 20 | return ( 21 | 22 | 23 | 24 | ); 25 | }} 26 | 27 | 28 | ## Props 29 | | Prop Name | Type | Is Required | Default Value | Description | 30 | |-|-|-|-|-| 31 | | className| `string`| optional| | Class name of root element | 32 | | days| `array`| required| | Array of dates to render | 33 | | parentMonth| `object`| required| | to determine days of weeks, which are outside of current month | 34 | 35 | ## Importing 36 | It can be imported as either the base component 37 | 38 | ```javascript 39 | import { Week } from "@use-date-input/core"; 40 | ``` 41 | 42 | or as an overridable component that can be replaced through the `components` prop in `CalendarProvider`. 43 | Refer to [How to replace UI components](https://mark-tate.github.io/use-date-input/theming#how-to-replace-ui-components). 44 | 45 | ```javascript 46 | import { Week } from "@use-date-input/core"; 47 | ``` 48 | 49 | If providing your own component, it can be useful to import the base component and use it within your composition. 50 | -------------------------------------------------------------------------------- /src/docs/components/weekHeader.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: WeekHeader 3 | route: /weekHeader 4 | --- 5 | import { Playground } from "docz"; 6 | import { CalendarProvider, WeekHeader } from "@use-date-input/core"; 7 | import { adapter as dateAdapter } from '@use-date-input/date-fns-adapter'; 8 | 9 | # WeekHeader 10 | The `WeekHeader` component renders the days of the week within the month header. 11 | 12 | ## Example 13 | 14 | {() => { 15 | return ( 16 | 17 | 18 | 19 | ); 20 | }} 21 | 22 | 23 | ## Props 24 | | Prop Name | Type | Is Required | Default Value | Description | 25 | |-|-|-|-|-| 26 | | className| `string`| optional| | Class name of root element | 27 | 28 | ## Importing 29 | It can be imported as either the base component 30 | 31 | ```javascript 32 | import { WeekHeader } from "@use-date-input/core"; 33 | ``` 34 | 35 | or as an overridable component that can be replaced through the `components` prop in `CalendarProvider`. 36 | Refer to [How to replace UI components](https://mark-tate.github.io/use-date-input/theming#how-to-replace-ui-components). 37 | 38 | ```javascript 39 | import { WeekHeader } from "@use-date-input/core"; 40 | ``` 41 | 42 | If providing your own component, it can be useful to import the base component and use it within your composition. 43 | -------------------------------------------------------------------------------- /src/docs/home.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: Home 3 | route: / 4 | fullPage: true 5 | --- 6 | 7 | import { Carousel } from "../gatsby-theme-docz/components/Carousel"; 8 | import { Heading } from "../gatsby-theme-docz/components/Heading"; 9 | import { HeroWrapper } from "../gatsby-theme-docz/components/HeroWrapper"; 10 | import { Hero1 } from "../gatsby-theme-docz/components/Hero1"; 11 | import { Hero2 } from "../gatsby-theme-docz/components/Hero2"; 12 | import { Hero3 } from "../gatsby-theme-docz/components/Hero3"; 13 | import { Hero4 } from "../gatsby-theme-docz/components/Hero4"; 14 | import { Hero5 } from "../gatsby-theme-docz/components/Hero5"; 15 | import { Hero6 } from "../gatsby-theme-docz/components/Hero6"; 16 | 17 | use-date-input 18 | 19 | 26 | 27 | 28 | 35 | 36 | 37 | 43 | 44 | 45 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/docs/hooks/useCalendarDispatch.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: useCalendarDispatch 3 | route: /useCalendarDispatch 4 | --- 5 | import { Playground } from 'docz' 6 | import { calendarActions, useCalendarDispatch, Calendar, CalendarProvider} from '@use-date-input/core'; 7 | import { adapter as dateAdapter } from "@use-date-input/date-fns-adapter"; 8 | import { Button } from "../../gatsby-theme-docz/components/Button"; 9 | import { ButtonBar } from "../../gatsby-theme-docz/components/ButtonBar"; 10 | 11 | # useCalendarDispatch 12 | `useCalendarDispatch` returns the configured reducers dispatcher, along with a helper API for common actions. 13 | 14 | ```javascript 15 | const { 16 | dispatch, 17 | mouseClickOutside, 18 | navigateNext, 19 | navigatePrevious, 20 | selectDate, 21 | setAnimating, 22 | setEnableKeyboardNavigation, 23 | setKeyboardCursor, 24 | setMouseCursor, 25 | setEndDate, 26 | setStartDate, 27 | setOpen, 28 | setKeyPress, 29 | setVisibleFromDate 30 | } = useCalendarDispatch(); 31 | ``` 32 | 33 | ## Using the dispatcher 34 | Using the dispatcher we can dispatch any action to the reducers. 35 | 36 | 37 | {() => { 38 | const MyPanel = () => { 39 | const { dispatch } = useCalendarDispatch(); 40 | const handleClick = () => dispatch({ type: calendarActions.navigateNext }); 41 | return ( 42 | 43 | 44 | 45 | ); 46 | }; 47 | return ( 48 | 49 | 50 | 51 | 52 | ); 53 | }} 54 | 55 | 56 | ## Using the helper API 57 | Using the dispatcher we can dispatch the most common actions, through helper methods. 58 | 59 | 60 | {() => { 61 | function MyPanel() { 62 | const { navigateNext } = useCalendarDispatch(); 63 | const handleClick = () =>navigateNext(); 64 | return ( 65 | 66 | 67 | 68 | ); 69 | }; 70 | return ( 71 | 72 | 73 | 74 | 75 | ); 76 | }} 77 | 78 | -------------------------------------------------------------------------------- /src/docs/hooks/useCalendarProps.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: useCalendarProps 3 | route: /useCalendarProps 4 | --- 5 | import { useState } from 'react'; 6 | import { Playground } from 'docz' 7 | import { useDateAPI, useCalendarProps, Calendar, CalendarProvider} from '@use-date-input/core'; 8 | import { formatNames } from '@use-date-input/common'; 9 | import { adapter as dateAdapter } from '@use-date-input/date-fns-adapter'; 10 | 11 | # useCalendarProps 12 | 13 | `useCalendarProps` is a hook which will provide the props provided to `CalendarProvider`. 14 | 15 | This hook can be used to add yuor own props to the context. 16 | 17 | ## Example 18 | 19 | {() => { 20 | const [selectedDate, setSelectedDate] = useState(); 21 | const DateLabel = ({ selectedDate }) => { 22 | const { format, getDateFormat } = useDateAPI(); 23 | const props = useCalendarProps(); 24 | let dateLabel = 'Select A Date'; 25 | if (selectedDate) { 26 | const formatter = getDateFormat(formatNames.ARIA_DAY_LABEL); 27 | dateLabel = format(selectedDate, formatter); 28 | } 29 | return (
{props.myExtraLabel}

{dateLabel}

); 30 | }; 31 | return ( 32 | 37 | 38 | 39 | 40 | ); 41 | }} 42 |
43 | -------------------------------------------------------------------------------- /src/docs/hooks/useCalendarState.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: useCalendarState 3 | route: /useCalendarState 4 | --- 5 | import { useState } from 'react'; 6 | import { Playground } from 'docz' 7 | import { useDateAPI, useCalendarState, Calendar, CalendarProvider} from '@use-date-input/core'; 8 | import { formatNames } from '@use-date-input/common'; 9 | import { adapter as dateAdapter } from '@use-date-input/date-fns-adapter'; 10 | 11 | # useCalendarState 12 | 13 | `useCalendarState` is a hook which will provide the current state of your components. 14 | 15 | ## Example 16 | 17 | {() => { 18 | const DateLabel = () => { 19 | const { format, getDateFormat } = useDateAPI(); 20 | const { startDate:selectedDate } = useCalendarState(); 21 | let dateLabel = 'Select A Date'; 22 | if (selectedDate) { 23 | const formatter = getDateFormat(formatNames.ARIA_DAY_LABEL); 24 | dateLabel = format(selectedDate, formatter); 25 | } 26 | return (

{dateLabel}

); 27 | }; 28 | return ( 29 | 32 | 33 | 34 | 35 | ); 36 | }} 37 |
38 | -------------------------------------------------------------------------------- /src/docs/hooks/useDateAPI.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: useDateAPI 3 | route: /useDateAPI 4 | --- 5 | import { useState } from 'react'; 6 | import { Playground } from 'docz' 7 | import { useDateAPI, Calendar, CalendarProvider} from '@use-date-input/core'; 8 | import { formatNames } from '@use-date-input/common'; 9 | import { adapter as dateAdapter } from "@use-date-input/date-fns-adapter"; 10 | 11 | # useDateAPI 12 | 13 | `useDateAPI` is a hook which will provide the dateAPI to any child of `CalendarProvider`. 14 | 15 | ## Example 16 | 17 | {() => { 18 | // import { useState } from "react"; 19 | // import { formatNames } from '@use-date-input/common'; 20 | // import { adapter as dateAdapter } from "@use-date-input/date-fns-adapter"; 21 | // import { CalendarProvider, calendar, useDateAPI } from "@use-date-input/core"; 22 | const [selectedDate, setSelectedDate] = useState(); 23 | const DateLabel = ({ selectedDate }) => { 24 | const { format, getDateFormat } = useDateAPI(); 25 | let dateLabel = 'Select A Date'; 26 | if (selectedDate) { 27 | const formatter = getDateFormat(formatNames.ARIA_DAY_LABEL); 28 | dateLabel = format(selectedDate, formatter); 29 | } 30 | return (

{dateLabel}

); 31 | }; 32 | return ( 33 | 37 | 38 | 39 | 40 | ); 41 | }} 42 |
43 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Button.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | import { default as MUIButton } from "@material-ui/core/Button"; 3 | import { makeStyles } from "@material-ui/core/styles"; 4 | 5 | const useStyles = makeStyles(() => ({ 6 | root: { 7 | textTransform: "unset" 8 | } 9 | })); 10 | 11 | export const Button = forwardRef(function Button(props, ref) { 12 | const classes = useStyles(); 13 | return ( 14 | 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/ButtonBar.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { withStyles } from "@material-ui/core"; 3 | 4 | const style = { 5 | root: { 6 | display: "flex", 7 | justifyContent: "space-around", 8 | margin: "8px" 9 | } 10 | }; 11 | 12 | function UnStyledButtonBar({ classes, ...rest }) { 13 | return
; 14 | } 15 | 16 | export const ButtonBar = withStyles(style)(UnStyledButtonBar); 17 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Carousel.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import MUICarousel from "react-material-ui-carousel"; 3 | import { makeStyles, useTheme } from "@material-ui/core/styles"; 4 | import useMediaQuery from "@material-ui/core/useMediaQuery/useMediaQuery"; 5 | 6 | const useStyles = makeStyles(() => ({ 7 | root: { 8 | minHeight: "100vh", 9 | overflow: "inherit", 10 | paddingBottom: "30px", 11 | width: "100%" 12 | }, 13 | buttonWrapper: { 14 | top: "calc(50% - 165px)" 15 | } 16 | })); 17 | 18 | export function Carousel(props) { 19 | const theme = useTheme(); 20 | const isSmallBreakpoint = useMediaQuery(theme.breakpoints.down("sm")); 21 | const classes = useStyles(); 22 | return ( 23 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/DemoContent.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | 3 | export const DemoContent = forwardRef(({ style, ...rest }, ref) => { 4 | return ( 5 |
24 |
Build your own datepicker
25 |
with use-date-input
26 |
27 | ); 28 | }); 29 | 30 | export const DemoContentSmall = forwardRef(({ style, ...rest }, ref) => { 31 | return ( 32 | 37 | ); 38 | }); 39 | 40 | export const DemoContentXSmall = forwardRef(({ style, ...rest }, ref) => { 41 | return ( 42 | 47 | ); 48 | }); 49 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Dropdown.js: -------------------------------------------------------------------------------- 1 | import { 2 | FormControl, 3 | Input, 4 | InputLabel, 5 | MenuItem, 6 | Select, 7 | makeStyles 8 | } from "@material-ui/core"; 9 | import PropTypes from "prop-types"; 10 | import React from "react"; 11 | 12 | const useStyles = makeStyles(theme => ({ 13 | container: { 14 | display: "flex", 15 | flexWrap: "wrap" 16 | }, 17 | formControl: { 18 | margin: theme.spacing(1), 19 | minWidth: 120 20 | } 21 | })); 22 | 23 | export function Dropdown({ 24 | label, 25 | labelId, 26 | onChange, 27 | selectedValue, 28 | source 29 | }) { 30 | const classes = useStyles(); 31 | const handleChange = event => onChange(event.target.value); 32 | 33 | return ( 34 | 35 | {label} 36 | 52 | 53 | ); 54 | } 55 | 56 | Dropdown.propTypes = { 57 | labelId: PropTypes.string, 58 | label: PropTypes.string, 59 | onChange: PropTypes.func, 60 | selectedValue: PropTypes.string, 61 | source: PropTypes.array 62 | }; 63 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Heading.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { withStyles } from "@material-ui/core"; 3 | 4 | const style = theme => ({ 5 | root: { 6 | alignItems: "center", 7 | display: "flex", 8 | height: "150px", 9 | margin: "auto", 10 | width: "75%" 11 | }, 12 | h1: { 13 | fontSize: "80px", 14 | height: "100%", 15 | margin: 0, 16 | padding: 0 17 | }, 18 | [theme.breakpoints.down("sm")]: { 19 | h1: { 20 | fontSize: "50px" 21 | } 22 | }, 23 | [theme.breakpoints.down("xs")]: { 24 | root: { 25 | height: "80px", 26 | width: "100%" 27 | }, 28 | h1: { 29 | fontSize: "40px" 30 | } 31 | } 32 | }); 33 | 34 | function UnstyledHeading({ classes, ...rest }) { 35 | return ( 36 |
37 |

use-date-input

38 |
39 | ); 40 | } 41 | 42 | export const Heading = withStyles(style)(UnstyledHeading); 43 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Hero1.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Calendar } from "@use-date-input/core"; 3 | import { adapter as dateAdapter } from "@use-date-input/date-fns-adapter"; 4 | 5 | export function Hero1() { 6 | return ; 7 | } 8 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Hero2.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Calendar, Root } from "@use-date-input/core"; 3 | import { adapter as dateAdapter } from "@use-date-input/date-fns-adapter"; 4 | import { DemoHeader } from "./DemoHeader"; 5 | import { useTheme } from "@material-ui/core/styles"; 6 | import useMediaQuery from "@material-ui/core/useMediaQuery"; 7 | 8 | const CustomRoot = props => ; 9 | 10 | export function Hero2() { 11 | const theme = useTheme(); 12 | const isSmallBreakpoint = useMediaQuery(theme.breakpoints.down("sm")); 13 | return ( 14 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Hero3.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useRef, useState } from 'react' 3 | import { useDateInput } from '@use-date-input/core'; 4 | import { Popper } from '@use-date-input/popper'; 5 | import { adapter as dateAdapter } from '@use-date-input/date-fns-adapter'; 6 | import { parse } from 'date-fns'; 7 | import { Input} from "./Input"; 8 | 9 | export function Hero3() { 10 | const [date, setDate] = useState(""); 11 | const actions = useRef(); 12 | const handleInputChange = event => { 13 | const { value } = event.target; 14 | console.log("input changed to", value); 15 | setDate(event.target.value); 16 | }; 17 | const handleCalendarChange = value => { 18 | console.log("calendar changed selected date", value); 19 | const { dateAPI } = actions.current; 20 | setDate(dateAPI.format(value, "dd/MM/yyyy")); 21 | }; 22 | const { 23 | Calendar, 24 | CalendarProvider, 25 | getCalendarProviderProps, 26 | getInputProps, 27 | getPopperProps 28 | } = useDateInput({ 29 | actions, 30 | parse: value => parse(value, "dd/MM/yyyy", new Date()) 31 | }); 32 | return ( 33 | <> 34 | 38 | 44 | 45 |
46 | 47 |
48 |
49 |
50 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Hero5.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Calendar } from "@use-date-input/core"; 3 | import { adapter as dateAdapter } from "@use-date-input/date-fns-adapter"; 4 | import sampleTheme from "../../../stories/sampleTheme"; 5 | 6 | export function Hero5() { 7 | return ; 8 | } 9 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Input.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from "react"; 2 | import { makeStyles } from "@material-ui/core/styles"; 3 | 4 | const useStyles = makeStyles(theme => ({ 5 | root: {}, 6 | [theme.breakpoints.down("sm")]: { 7 | root: { 8 | margin: 0 9 | } 10 | } 11 | })); 12 | 13 | export const Input = forwardRef(function Button(props, ref) { 14 | const classes = useStyles(); 15 | return ; 16 | }); 17 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Layout/index.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { useRef, useState } from "react"; 3 | import { jsx, Layout as BaseLayout, Main } from "theme-ui"; 4 | import { Global } from "@emotion/core"; 5 | 6 | import global from "~theme/global"; 7 | import { Header } from "gatsby-theme-docz/src/components/Header/index"; 8 | import { Sidebar } from "gatsby-theme-docz/src/components/Sidebar/index"; 9 | import { MainContainer } from "gatsby-theme-docz/src/components/MainContainer/index"; 10 | import * as styles from "./styles"; 11 | 12 | export const Layout = ({ children, doc }) => { 13 | const [open, setOpen] = useState(false); 14 | const nav = useRef(); 15 | return ( 16 | div": { flex: "1 1 auto" } }} data-testid="layout"> 17 | 18 |
19 | {!doc.value.fullPage &&
setOpen(s => !s)} />} 20 |
21 | {!doc.value.fullPage && ( 22 | setOpen(true)} 26 | onBlur={() => setOpen(false)} 27 | onClick={() => setOpen(false)} 28 | /> 29 | )} 30 | {children} 31 |
32 |
33 |
34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Layout/styles.js: -------------------------------------------------------------------------------- 1 | import { media } from "~theme/breakpoints"; 2 | 3 | export const main = { 4 | display: "flex", 5 | flexDirection: "column", 6 | minHeight: "100vh" 7 | }; 8 | 9 | export const wrapper = { 10 | fontFamily: "Roboto, Helvetica, Arial, sans-serif", 11 | py: 0, 12 | flex: 1, 13 | display: "grid", 14 | gridTemplateColumns: "250px minmax(0, 1fr)", 15 | minHeight: "100vh", 16 | [media.tablet]: { 17 | display: "block" 18 | } 19 | }; 20 | 21 | export const fullPageWrapper = { 22 | ...wrapper, 23 | display: "block", 24 | gridTemplateColumns: undefined 25 | }; 26 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Logo/index.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx, Flex } from 'theme-ui' 3 | import { Link, useConfig } from 'docz' 4 | import { useTheme } from '@material-ui/core/styles'; 5 | import useMediaQuery from "@material-ui/core/useMediaQuery/useMediaQuery"; 6 | 7 | import * as styles from './styles' 8 | 9 | export const Logo = () => { 10 | const config = useConfig(); 11 | const theme = useTheme(); 12 | const isSmallBreakpoint = useMediaQuery(theme.breakpoints.down("sm")); 13 | return ( 14 | 15 | 16 | {isSmallBreakpoint ? config.shortTitle : config.title} 17 | 18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Logo/styles.js: -------------------------------------------------------------------------------- 1 | export const logo = { 2 | letterSpacing: '-0.02em', 3 | fontWeight: 600, 4 | fontSize: 4, 5 | } 6 | 7 | export const link = { 8 | fontWeight: 600, 9 | color: 'header.text', 10 | textDecoration: 'none', 11 | ':hover': { 12 | color: 'primary', 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Playground/Wrapper.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { useState } from "react"; 3 | import { jsx } from "theme-ui"; 4 | import { useConfig } from "docz"; 5 | import Iframe from "react-frame-component"; 6 | import ReactResizeDetector from "react-resize-detector"; 7 | 8 | import * as styles from "./styles"; 9 | 10 | const CLEAR_PADDING = ``; 11 | const INITIAL_IFRAME_CONTENT = ` ${CLEAR_PADDING}
`; 12 | 13 | const IframeWrapper = ({ children, style }) => { 14 | const [containerHeight, setHeight] = useState(); 15 | return ( 16 | 32 | ); 33 | }; 34 | 35 | const NormalWrapper = ({ children, style }) => { 36 | return ( 37 |
43 | {children} 44 |
45 | ); 46 | }; 47 | 48 | export const Wrapper = ({ children, content, useScoping, showingCode }) => { 49 | const { 50 | themeConfig: { useScopingInPlayground } 51 | } = useConfig(); 52 | 53 | const Element = 54 | useScoping || useScopingInPlayground ? IframeWrapper : NormalWrapper; 55 | 56 | return ( 57 | 58 | {children} 59 | 60 | ); 61 | }; 62 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/components/Playground/styles.js: -------------------------------------------------------------------------------- 1 | import * as mixins from "~utils/mixins"; 2 | 3 | export const editor = theme => ({ 4 | p: 2, 5 | background: theme.plain.backgroundColor, 6 | borderRadius: "0px 4px 4px 4px", 7 | fontFamily: "monospace", 8 | fontSize: 16, 9 | "* > textarea:focus": { 10 | outline: "none" 11 | } 12 | }); 13 | 14 | export const error = { 15 | m: 0, 16 | py: 2, 17 | px: 3, 18 | bg: "#FF4757", 19 | fontSize: 1, 20 | color: "white", 21 | whiteSpace: "pre-wrap" 22 | }; 23 | 24 | export const previewWrapper = { 25 | display: "table", 26 | position: "relative" 27 | }; 28 | 29 | export const wrapper = () => ({ 30 | height: "auto", 31 | display: "block", 32 | minHeight: "100%", 33 | width: "100%", 34 | bg: "playground.bg", 35 | marginTop: "20px", 36 | marginBottom: "20px" 37 | }); 38 | 39 | export const wrapperBorder = (content) => { 40 | if (content === 'editor') { 41 | return { 42 | border: t => `1px solid ${t.colors.playground.border}`, 43 | borderRadius: "0px 4px 4px 4px" 44 | }; 45 | } 46 | return { 47 | border: "none" 48 | }; 49 | }; 50 | 51 | export const preview = { 52 | background: "white", 53 | color: "initial", 54 | display: "table", 55 | fontSize: "12px", 56 | lineHeight: "1.4em", 57 | margin: 0, 58 | padding: "20px" 59 | }; 60 | 61 | export const buttons = { 62 | display: "flex", 63 | position: "absolute", 64 | bottom: -20 65 | }; 66 | 67 | export const button = { 68 | ...mixins.ghostButton, 69 | display: "flex", 70 | alignItems: "center", 71 | py: 1, 72 | p: 2, 73 | bg: "border", 74 | color: t => t.colors.playground.border, 75 | border: t => `1px solid ${t.colors.playground.border}`, 76 | borderRadius: "4px 4px 0px 0px", 77 | borderBottom: "0px", 78 | "& ~ &": { 79 | ml: 1 80 | } 81 | }; 82 | 83 | export const link = { 84 | py: 0, 85 | ml: 1, 86 | height: 22 87 | }; 88 | -------------------------------------------------------------------------------- /src/gatsby-theme-docz/createDate.js: -------------------------------------------------------------------------------- 1 | import { createDateAPI } from "@use-date-input/core"; 2 | import { adapter as dateFnsAdapter } from "@use-date-input/date-fns-adapter"; 3 | 4 | const dateAPI = createDateAPI({ adapter: dateFnsAdapter }); 5 | 6 | export const createDate = dateAPI.createDate; 7 | export const dateAdapter = dateFnsAdapter; 8 | -------------------------------------------------------------------------------- /stories/1 - Date Range.stories.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { action } from "@storybook/addon-actions"; 3 | import { Calendar, createDateAPI } from "../packages/core"; 4 | import { adapter as dateAdapter } from "../packages/date-fns-adapter"; 5 | 6 | export default { 7 | title: "1 - Date Range" 8 | }; 9 | 10 | const { addWeeks, createDate } = createDateAPI({ adapter: dateAdapter }); 11 | 12 | const useChangeAction = () => selectedDate => { 13 | action("select date range")(selectedDate[0], selectedDate[1]); 14 | }; 15 | 16 | const useStateChangeAction = () => (state, changes) => { 17 | action("state changed")(changes, state); 18 | }; 19 | 20 | export const Month = () => { 21 | const handleChange = useChangeAction(); 22 | const handleStateChange = useStateChangeAction(); 23 | return ( 24 | 30 | ); 31 | }; 32 | Month.story = { 33 | name: "1 month" 34 | }; 35 | 36 | export const InitialSelected = () => { 37 | const handleChange = useChangeAction(); 38 | const handleStateChange = useStateChangeAction(); 39 | return ( 40 | 50 | ); 51 | }; 52 | InitialSelected.story = { 53 | name: "Initial date selected" 54 | }; 55 | 56 | export const Controlled = () => { 57 | const [date, setDate] = useState([createDate(), addWeeks(createDate(), 1)]); 58 | const handleChange = selectedDate => { 59 | setDate(selectedDate); 60 | action("select date range")(selectedDate[0], selectedDate[1]); 61 | }; 62 | const handleStateChange = useStateChangeAction(); 63 | return ( 64 | 73 | ); 74 | }; 75 | Controlled.story = { 76 | name: "Controlled state" 77 | }; 78 | -------------------------------------------------------------------------------- /stories/2 - Additional Controls.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { action } from '@storybook/addon-actions'; 3 | import { Calendar, createDateAPI, Root } from "../packages/core"; 4 | import { adapter as dateAdapter } from "../packages/date-fns-adapter"; 5 | import AdditionalControlHeader from './AdditionalControlHeader'; 6 | import ShortcutList from './ShortcutList'; 7 | 8 | const { createDate } = createDateAPI({ adapter: dateAdapter }); 9 | 10 | const useChangeAction = () => selectedDate => { 11 | action('change selected date')(selectedDate); 12 | }; 13 | 14 | const HeaderComponent = () => ; 15 | const CalendarWithShortcuts = props => ( 16 |
17 | 18 | 19 |
20 | ); 21 | 22 | export default { 23 | title: '2 - Additional Controls' 24 | }; 25 | 26 | export const CustomHeader = () => { 27 | const handleChange = useChangeAction(); 28 | return ( 29 | 39 | ); 40 | }; 41 | CustomHeader.story = { 42 | name: 'Custom header' 43 | }; 44 | 45 | export const CustomSideBar = () => { 46 | const handleChange = useChangeAction(); 47 | return ( 48 | 59 | ); 60 | }; 61 | CustomSideBar.story = { 62 | name: 'Additional sidebar of shortcuts' 63 | }; 64 | -------------------------------------------------------------------------------- /stories/3 - Dialog.stories.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { action } from '@storybook/addon-actions'; 3 | import { adapter as dateAdapter } from "../packages/date-fns-adapter"; 4 | import { Calendar, Root } from "../packages/core"; 5 | import AdditionalControlHeader from './AdditionalControlHeader'; 6 | import ShortcutList from './ShortcutList'; 7 | import DateRangeDialog from './DateRangeDialog'; 8 | import Button from '@material-ui/core/Button'; 9 | 10 | const useChangeAction = () => selectedDate => { 11 | action('change selected date')(selectedDate); 12 | }; 13 | 14 | export default { 15 | title: '3 - Dialogs' 16 | }; 17 | 18 | const CalendarWithShortcuts = props => ( 19 | <> 20 | 21 | 22 | 23 | ); 24 | 25 | export const InDialog = () => { 26 | const handleChange = useChangeAction(); 27 | const [open, setOpen] = useState(false); 28 | const [selectedDate, setSelectedDate] = useState([undefined, undefined]); 29 | const handleClickOpen = () => { 30 | setOpen(true); 31 | setSelectedDate([undefined, undefined]); 32 | }; 33 | 34 | const handleCancel = () => { 35 | setOpen(false); 36 | }; 37 | 38 | const handleOK = () => { 39 | setOpen(false); 40 | if (selectedDate) { 41 | handleChange(selectedDate); 42 | } 43 | }; 44 | 45 | return ( 46 | <> 47 | 50 | 56 | setSelectedDate(selectedDate)} 64 | numOfVisibleMonths={3} 65 | numOfColumns={3} 66 | /> 67 | 68 | 69 | ); 70 | }; 71 | InDialog.story = { 72 | name: 'Inside a dialog' 73 | }; 74 | -------------------------------------------------------------------------------- /stories/4 - Themable.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { adapter as dateAdapter } from "../packages/date-fns-adapter"; 3 | import { Calendar } from "../packages/core"; 4 | import sampleTheme from './sampleTheme'; 5 | import { action } from '@storybook/addon-actions'; 6 | 7 | export default { 8 | title: '4 - Themable Components' 9 | }; 10 | 11 | const useChangeAction = () => selectedDate => { 12 | action('changed selected date')(selectedDate); 13 | }; 14 | 15 | const useStateChangeAction = () => changes => { 16 | action('state changed')(changes); 17 | }; 18 | 19 | export const ThemedCalendar = () => { 20 | const handleChange = useChangeAction(); 21 | const handleStateChange = useStateChangeAction(); 22 | return ( 23 | 31 | ); 32 | }; 33 | ThemedCalendar.story = { 34 | name: 'Themed calendar' 35 | }; 36 | -------------------------------------------------------------------------------- /stories/DateRangeDialog.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Button from '@material-ui/core/Button'; 4 | import Dialog from '@material-ui/core/Dialog'; 5 | import DialogActions from '@material-ui/core/DialogActions'; 6 | import DialogContent from '@material-ui/core/DialogContent'; 7 | import DialogContentText from '@material-ui/core/DialogContentText'; 8 | import DialogTitle from '@material-ui/core/DialogTitle'; 9 | import { createDateAPI } from '@use-date-input/core'; 10 | import { adapter as dateAdapter } from "../packages/date-fns-adapter"; 11 | import { formatNames } from '@use-date-input/common'; 12 | 13 | const { toFormattedDate } = createDateAPI({ adapter: dateAdapter }); 14 | 15 | export default function DateRangeDialog(props) { 16 | const { children, open, onOK, onCancel, selectedDate } = props; 17 | const [startDate, endDate] = selectedDate; 18 | const startDescription = startDate 19 | ? toFormattedDate(startDate, formatNames.ARIA_DAY_LABEL) 20 | : ''; 21 | const endDescription = endDate ? toFormattedDate(endDate, formatNames.ARIA_DAY_LABEL) : ''; 22 | const description = 23 | startDescription || endDescription ? `${startDescription} - ${endDescription}` : ''; 24 | return ( 25 | 26 | Date Range Dialog Example 27 | 28 | 29 | Select a date range or use shortcuts from the List 30 | 31 | {children} 32 | {description} 33 | 34 | 35 | 38 | 41 | 42 | 43 | ); 44 | } 45 | DateRangeDialog.propTypes = { 46 | children: PropTypes.node, 47 | onCancel: PropTypes.func, 48 | onOK: PropTypes.func, 49 | open: PropTypes.bool, 50 | selectedDate: PropTypes.array 51 | }; 52 | -------------------------------------------------------------------------------- /stories/Dropdown.js: -------------------------------------------------------------------------------- 1 | import { FormControl, Input, InputLabel, MenuItem, Select, makeStyles } from '@material-ui/core'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | const useStyles = makeStyles(theme => ({ 6 | container: { 7 | display: 'flex', 8 | flexWrap: 'wrap' 9 | }, 10 | formControl: { 11 | margin: theme.spacing(1), 12 | minWidth: 120 13 | } 14 | })); 15 | 16 | export default function Dropdown({ label, labelId, onChange, selectedValue, source }) { 17 | const classes = useStyles(); 18 | const handleChange = event => onChange(event.target.value); 19 | 20 | return ( 21 | 22 | {label} 23 | 39 | 40 | ); 41 | } 42 | 43 | Dropdown.propTypes = { 44 | labelId: PropTypes.string, 45 | label: PropTypes.string, 46 | onChange: PropTypes.func, 47 | selectedValue: PropTypes.string, 48 | source: PropTypes.array 49 | }; 50 | -------------------------------------------------------------------------------- /stories/ShortcutList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { makeStyles } from '@material-ui/core/styles'; 3 | import List from '@material-ui/core/List'; 4 | import ListItem from '@material-ui/core/ListItem'; 5 | import ListItemText from '@material-ui/core/ListItemText'; 6 | import { useCalendarDispatch, useCalendarState } from '@use-date-input/core'; 7 | import { createDateAPI } from '@use-date-input/core'; 8 | import { adapter as dateAdapter } from "../packages/date-fns-adapter"; 9 | 10 | const dateAPI = createDateAPI({ adapter: dateAdapter }); 11 | 12 | const useStyles = makeStyles(theme => ({ 13 | root: { 14 | backgroundColor: theme.palette.background.paper, 15 | display: 'inline-block', 16 | paddingTop: '90px', 17 | verticalAlign: 'top', 18 | width: 150 19 | } 20 | })); 21 | 22 | export default function ShortcutList() { 23 | const { startDate } = useCalendarState(); 24 | const { setEndDate, setVisibleFromDate } = useCalendarDispatch(); 25 | const classes = useStyles(); 26 | 27 | if (!startDate) { 28 | return null; 29 | } 30 | 31 | const createNightsSelectHandler = numOfNights => () => { 32 | setEndDate(dateAPI.addDays(startDate, numOfNights)); 33 | setVisibleFromDate(dateAPI.startOfMonth(startDate)); 34 | }; 35 | const handleTenNights = createNightsSelectHandler(10); 36 | const handleSevenNights = createNightsSelectHandler(7); 37 | const handleThreeNights = createNightsSelectHandler(3); 38 | 39 | return ( 40 |
41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /use-date-input.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------