Skip to content

Commit

Permalink
[DateRangePicker] Introduce new component 🎉 (#1602)
Browse files Browse the repository at this point in the history
* Make value for picker be a generic type

* Spread new props from passing to the dom element

* Split makePickerWith state hoc

* Better type inference for new makePickerWithWrapper

* Refactor and opimize shared prop types inference for pickers

* Rename eome type names and files

* Integrate validation back to usePickerState

* Remove DateRangePicker code

* Remove DateRangePickerUsage from index module

* Fix small linter and ts errors

* Fix build erros

* Run prettier manually

* Display calendars for date range

* [WiP] Work on displaying 2 calendars one by one

* WATER ON MY MAC

* Proper display days with margins with range highlights

* Fix unexpected month switchings

* Implement range preview

* Optimize rerenders of Day and DateRangeDay, closes #1306

* Fix crash and missing rerender

* Optimize rerendering performace of <Day />

* Use popper for date range wrapper

* Proper displaying values in DateRangePIckerInput

* Implement ClickAwayListner for popper wrapper

* Fix slide animation in date range picker

* Reorganize test folders

* Reorganize integration test folder

* Add focus managment logic

* Implement autoscrolling for switching between range start/end

* Improve date range picker with disabling min/max dates

* Update date-io adapter version to 2.5.0

* Do not display range preview on highlighted days

* Better focus and blur handling for popper

* Fix range preview border style

* Fix type erros

* Fix fantom borders appearing

* Better styling for popper and possibility to replace transition

* Fix missing mui globals

* Fix werid memoization issue in Safari

* Implement mobile version of DateRangePicker

* Better displaying in mobile mode

* Make possible to switch view by clicking on month and year header

* Properly spread props to mobile keyboard input view

* Fix ts erros and enable api generation

* Fix example ts-checks

* Fix ts error in ServerRerquest.example.jsx

* Fix error if mouning in open state

* Add props test for DateRangePickers

* Export responsive date range picker by default

* Add missing displayName to the ToolbarButton

* Small enhancmenets

* Fix inclusivity of range for non-datefns livs

* Fix ts error

* Remove fake data from range example

* Use tsx in date range picker examples

* Add `startText` and `endText` props

* Update material-ui and fix createSvgIcon import, closes #1619

* Use new TextField `focused` prop for highlighting

* Close picker after range selected

* Update jss version

* Add more date-range-manager tests

* More examples and possibility to change wrapper mode for static wrapper

* Fix ts wrapper props inferring

* Update lib/src/views/Calendar/CalendarView.tsx

Co-Authored-By: Olivier Tassinari <olivier.tassinari@gmail.com>

* Update docs/pages/demo/daterangepicker/CalendarsDateRangePicker.example.tsx

Co-Authored-By: Olivier Tassinari <olivier.tassinari@gmail.com>

* Update createSvgIcon imports

* Fix ts inferrence for static wrapper props

* Add missing props spreading

* Fix more build errors

* Update lib/src/__tests__/setup.js

Co-Authored-By: Olivier Tassinari <olivier.tassinari@gmail.com>

* Address review

* forwardRef for DateRangePicker

Co-authored-by: Olivier Tassinari <olivier.tassinari@gmail.com>
  • Loading branch information
dmtrKovalenko and oliviertassinari committed Apr 9, 2020
1 parent c38b5ed commit 7bed283
Show file tree
Hide file tree
Showing 96 changed files with 3,968 additions and 800 deletions.
2 changes: 1 addition & 1 deletion docs/_shared/Code.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ interface CodeProps {
language?: 'jsx' | 'typescript' | 'markup';
}

const Code: React.SFC<CodeProps> = ({ language = 'jsx', inline, children, withMargin }) => {
const Code: React.FC<CodeProps> = ({ language = 'typescript', inline, children, withMargin }) => {
const classes = useStyles();
const highlightedCode = highlight(children, language);

Expand Down
10 changes: 8 additions & 2 deletions docs/layout/PageWithContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@ import { PageContext } from '../utils/getPageContext';
import { LocalizationProvider } from '@material-ui/pickers';
import { UtilsContext } from '../_shared/UtilsServiceContext';
import { NotificationManager } from 'utils/NotificationManager';
import { Theme, createMuiTheme, CssBaseline } from '@material-ui/core';
import { createUtilsService, UtilsLib, utilsMap } from '../utils/utilsService';
import { ThemeProvider, jssPreset, StylesProvider } from '@material-ui/core/styles';
import {
Theme,
createMuiTheme,
CssBaseline,
ThemeProvider,
jssPreset,
StylesProvider,
} from '@material-ui/core';

export type ThemeType = 'light' | 'dark';
export type Direction = Theme['direction'];
Expand Down
2 changes: 1 addition & 1 deletion docs/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ module.exports = withBundleAnalyzer(

// Process examples to inject raw code strings
config.module.rules.push({
test: /\.example\.(js|jsx)$/,
test: /\.example\.(js|jsx|tsx|ts)$/,
include: [path.resolve(__dirname, 'pages')],
use: [
{ loader: 'next-babel-loader' },
Expand Down
1 change: 1 addition & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@material-ui/pickers": "^4.0.0-alpha.1",
"@types/fuzzy-search": "^2.1.0",
"@types/isomorphic-fetch": "^0.0.35",
"@types/jss": "^10.0.0",
"@types/luxon": "^1.11.0",
"@types/next": "^8.0.1",
"@types/prismjs": "^1.9.1",
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/demo/datepicker/ServerRequest.example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function ServerRequest() {
renderDay={(day, selectedDate, DayComponentProps) => {
const date = makeJSDateObject(day); // skip this step, it is required to support date libs
const isSelected =
DayComponentProps.isInCurrentMonth && selectedDays.includes(date.getDate());
DayComponentProps.inCurrentMonth && selectedDays.includes(date.getDate());

return (
<Badge overlap="circle" badgeContent={isSelected ? '🌚' : undefined}>
Expand Down
8 changes: 8 additions & 0 deletions docs/pages/demo/datepicker/StaticDatePicker.example.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import React, { useState } from 'react';
import isWeekend from 'date-fns/isWeekend';
import { StaticDatePicker } from '@material-ui/pickers';
import { makeJSDateObject } from '../../../utils/helpers';

function disableWeekends(date) {
// TODO: replace with implementation for your date library
return isWeekend(makeJSDateObject(date));
}

const StaticDatePickerExample = () => {
const [date, handleDateChange] = useState(new Date());
Expand All @@ -18,6 +25,7 @@ const StaticDatePickerExample = () => {
orientation="landscape"
openTo="date"
value={date}
shouldDisableDate={disableWeekends}
onChange={date => handleDateChange(date)}
/>
</>
Expand Down
10 changes: 0 additions & 10 deletions docs/pages/demo/daterangepicker/BasicDateRangePicker.example.jsx

This file was deleted.

17 changes: 17 additions & 0 deletions docs/pages/demo/daterangepicker/BasicDateRangePicker.example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from 'react';
import { DateRangePicker, DateRange } from '@material-ui/pickers';

function BasicDateRangePicker() {
const [selectedDate, handleDateChange] = React.useState<DateRange>([null, null]);

return (
<DateRangePicker
startText="Check-in"
endText="Check-out"
value={selectedDate}
onChange={date => handleDateChange(date)}
/>
);
}

export default BasicDateRangePicker;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from 'react';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import { DateRangePicker, DateRange } from '@material-ui/pickers';

function CalendarsDateRangePicker() {
const [selectedDate, handleDateChange] = React.useState<DateRange>([null, null]);

return (
<Grid container direction="column" alignItems="center">
<Typography gutterBottom> 1 calendar </Typography>
<DateRangePicker
calendars={1}
value={selectedDate}
onChange={date => handleDateChange(date)}
/>
<Typography gutterBottom> 2 calendars</Typography>
<DateRangePicker
calendars={2}
value={selectedDate}
onChange={date => handleDateChange(date)}
/>
<Typography gutterBottom> 3 calendars</Typography>
<DateRangePicker
calendars={3}
value={selectedDate}
onChange={date => handleDateChange(date)}
/>
</Grid>
);
}

export default CalendarsDateRangePicker;
27 changes: 27 additions & 0 deletions docs/pages/demo/daterangepicker/MinMaxDateRangePicker.example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as React from 'react';
import addWeeks from 'date-fns/addWeeks';
import { Dayjs } from 'dayjs';
import { Moment } from 'moment';
import { DateTime } from 'luxon';
import { makeJSDateObject } from '../../../utils/helpers';
import { DateRangePicker, DateRange } from '@material-ui/pickers';

function getWeeksAfter(date: Moment | DateTime | Dayjs | Date, amount: number) {
// TODO: replace with implementation for your date library
return date ? addWeeks(makeJSDateObject(date), amount) : undefined;
}

function MinMaxDateRangePicker() {
const [selectedRange, handleDateChange] = React.useState<DateRange>([null, null]);

return (
<DateRangePicker
disablePast
value={selectedRange}
maxDate={getWeeksAfter(selectedRange[0], 4)}
onChange={date => handleDateChange(date)}
/>
);
}

export default MinMaxDateRangePicker;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react';
import { MobileDateRangePicker, DesktopDateRangePicker, DateRange } from '@material-ui/pickers';

function ResponsiveDateRangePicker() {
const [selectedDate, handleDateChange] = React.useState<DateRange>([null, null]);

return (
<>
<MobileDateRangePicker
startText="Mobile start"
value={selectedDate}
onChange={date => handleDateChange(date)}
/>

<DesktopDateRangePicker
startText="Desktop start"
value={selectedDate}
onChange={date => handleDateChange(date)}
/>
</>
);
}

export default ResponsiveDateRangePicker;
24 changes: 24 additions & 0 deletions docs/pages/demo/daterangepicker/StaticDateRangePicker.example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react';
import { StaticDateRangePicker, DateRange } from '@material-ui/pickers';

function StaticDateRangePickerExample() {
const [selectedDate, handleDateChange] = React.useState<DateRange>([null, null]);

return (
<>
<StaticDateRangePicker
displayStaticWrapperAs="desktop"
value={selectedDate}
onChange={date => handleDateChange(date)}
/>

<StaticDateRangePicker
displayStaticWrapperAs="mobile"
value={selectedDate}
onChange={date => handleDateChange(date)}
/>
</>
);
}

export default StaticDateRangePickerExample;
36 changes: 34 additions & 2 deletions docs/pages/demo/daterangepicker/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ import Ad from '_shared/Ad';
import Example from '_shared/Example';
import PageMeta from '_shared/PageMeta';
import LinkedComponents from '_shared/LinkedComponents';
import { Hidden } from '@material-ui/core';

import * as BasicDateRangePicker from './BasicDateRangePicker.example';
import * as ResponsiveDateRangePicker from './ResponsiveDateRangePicker.example';
import * as MinMaxDateRangePicker from './MinMaxDateRangePicker.example';
import * as CalendarsDateRangePicker from './CalendarsDateRangePicker.example';
import * as StaticDateRangePicker from './StaticDateRangePicker.example';

<PageMeta component="Datepicker" />

Expand All @@ -15,6 +20,33 @@ import * as BasicDateRangePicker from './BasicDateRangePicker.example';

#### Basic usage

Will be rendered to modal dialog on mobile and textfield with popover on desktop.
Basic DateRangePicker example, make sure that you can pass almost any prop of [DatePicker]('/api/DatePicker')

<Example testId="datepicker-example" source={BasicDateRangePicker} />
<Example source={BasicDateRangePicker} />

#### Responsiveness

Date/Time pickers experience is extremely different on mobile and desktop. Here is how components will look on different devices.
The default `DateRangePicker` component is responsive, which means that `Mobile` or `Desktop` mode will be rendered according to device viewport.

<Example source={ResponsiveDateRangePicker} />

#### Different amount of calendars

Make sure that `calendars` prop is working only for desktop mode.

<Example source={CalendarsDateRangePicker} />

#### Disabling dates

Disabling dates performs just like in simple `DatePicker`

<Example source={MinMaxDateRangePicker} />

#### Static mode

It is possible to render any picker without modal or popper. For that use `StaticDateRangePicker`.

<Hidden smDown>
<Example paddingBottom source={StaticDateRangePicker} />
</Hidden>
10 changes: 9 additions & 1 deletion docs/pages/regression/Regression.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import React, { useState, useContext } from 'react';
import LeftArrowIcon from '@material-ui/icons/KeyboardArrowLeft';
import RightArrowIcon from '@material-ui/icons/KeyboardArrowRight';
import { Grid, Typography } from '@material-ui/core';
import { MuiPickersContext } from '@material-ui/pickers';
import { MuiPickersContext, DateRangePicker } from '@material-ui/pickers';
import { createRegressionDay as createRegressionDayRenderer } from './RegressionDay';
import {
DateRange,
MobileDatePicker,
DesktopDatePicker,
MobileTimePicker,
Expand All @@ -13,6 +14,7 @@ import {

function Regression() {
const utils = useContext(MuiPickersContext);
const [range, changeRange] = useState<DateRange>([new Date('2019-01-01T00:00:00.000'), null]);
const [date, changeDate] = useState<Date | null>(new Date('2019-01-01T00:00:00.000'));

const sharedProps = {
Expand Down Expand Up @@ -64,6 +66,12 @@ function Regression() {
<MobileTimePicker id="mobile-timepicker" value={date} onChange={changeDate} />
<DesktopTimePicker id="desktop-timepicker" value={date} onChange={changeDate} />
</Grid>

<Typography align="center" variant="h4" component="span" gutterBottom>
DateRangePicker
</Typography>

<DateRangePicker id="desktop-range-picker" value={range} onChange={changeRange} />
</div>
);
}
Expand Down

1 comment on commit 7bed283

@vercel
Copy link

@vercel vercel bot commented on 7bed283 Apr 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.