Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LocalizationProvider #1537

Merged
merged 28 commits into from
Mar 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2f22376
Rename MuiPickersUtilsPorvider => LocalizationProvider
dmtrKovalenko Feb 25, 2020
3267dda
Improve utils typings
dmtrKovalenko Feb 25, 2020
7ff010d
Implement global format override
dmtrKovalenko Feb 25, 2020
ce25632
[docs] Change name of date-io customization page
dmtrKovalenko Feb 25, 2020
98dd267
Update examples to include new wording
dmtrKovalenko Feb 25, 2020
5bd4aca
Fix prop-types typescript error
dmtrKovalenko Feb 25, 2020
02572d8
Add daetAdapter prop for passing date-io utils directly to component
dmtrKovalenko Feb 25, 2020
879bac6
Update percy and cypress
dmtrKovalenko Feb 25, 2020
03e3e94
Unskip flaky test
dmtrKovalenko Feb 25, 2020
d00436a
Fix typo in error message
dmtrKovalenko Feb 25, 2020
f5275e8
Fix cypress test
dmtrKovalenko Feb 26, 2020
5a12834
One more try to fix flaky test
dmtrKovalenko Feb 26, 2020
d228f4f
Remove flaky test
dmtrKovalenko Feb 26, 2020
3b1e4d2
Fix visual regression scenarios tests with new version of cypress
dmtrKovalenko Feb 27, 2020
ffe5df0
Run cypress tests in chrome
dmtrKovalenko Feb 27, 2020
36719aa
Ignore dark theme change in snapshots
dmtrKovalenko Feb 27, 2020
71544e1
Try to fix example styles one more time
dmtrKovalenko Feb 27, 2020
1f6c278
Fix inccorect name of cypress executor
dmtrKovalenko Feb 27, 2020
4c9eb7a
Try weird hack to reinject styles
dmtrKovalenko Feb 27, 2020
693bd49
Optimize theme toggling for visual regression
dmtrKovalenko Feb 27, 2020
e49eace
Update scenario names to get rid of duplications
dmtrKovalenko Feb 28, 2020
54f6fdd
Rename `adapter` => `dateAdapter`
dmtrKovalenko Feb 28, 2020
e2d4625
Rename libFormats => dateFormats, libInstance => dateLibInstance
dmtrKovalenko Feb 28, 2020
b2c19b0
Remove version-specific code from README.md
dmtrKovalenko Mar 1, 2020
47c9b19
Merge branch 'next' into feature/LocalizationProvider
dmtrKovalenko Mar 1, 2020
51e75b0
Fix documentation erros in installation guide
dmtrKovalenko Mar 1, 2020
d3825a3
Run prettier on README.md
dmtrKovalenko Mar 1, 2020
e0a3f71
Use edge="end" for keyboard adornment icons, closes #1545
dmtrKovalenko Mar 1, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ jobs:

cypress_tests:
description: Run cypress tests
executor: cypress/browsers-chrome73-ff68
executor: cypress/browsers-chrome78-ff70
steps:
- attach_workspace:
at: .
Expand All @@ -111,7 +111,7 @@ jobs:
environment:
VISUAL_TESTING: true
- run: npx wait-on http://localhost:3000
- run: yarn percy exec -- cypress run --record
- run: yarn percy exec -- cypress run --record --browser chrome

####################
# Workflow
Expand Down
1 change: 0 additions & 1 deletion .percy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ snapshot:
#codefund {
display: none;
}
|
31 changes: 2 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,9 @@ npm i @material-ui/pickers
yarn add @material-ui/pickers
```

Now choose the library that pickers will use to work with date. We are providing interfaces for [moment](https://momentjs.com/), [luxon](https://moment.github.io/luxon/), [dayjs](https://github.com/iamkun/dayjs) and [date-fns v2](https://date-fns.org/). If you are not using moment in the project (or don’t have it in the bundle already) we suggest using date-fns or luxon, because they are much lighter and will be correctly tree-shaked from the bundle. Note, that for v3.x version of @material-ui/pickers use v1.x version of [date-io](https://github.com/dmtrKovalenko/date-io).
### Getting started

```sh
npm i date-fns@next @date-io/date-fns@1.x
// or
npm i moment @date-io/moment@1.x
// or
npm i luxon @date-io/luxon@1.x
// or
npm i dayjs @date-io/dayjs@1.x
```

Then teach pickers which library to use with `MuiPickerUtilsProvider`. This component takes a utils property, and makes it available down the React tree thanks to React context. It should preferably be used at the root of your component tree.

```jsx
import MomentUtils from '@date-io/moment';
import DateFnsUtils from '@date-io/date-fns';
import LuxonUtils from '@date-io/luxon';
import { MuiPickersUtilsProvider } from '@material-ui/pickers';

function App() {
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Root />
</MuiPickersUtilsProvider>
);
}

render(<App />, document.querySelector('#app'));
```
[Here is instruction](https://material-ui-pickers.dev/getting-started/installation#peer-library) of how to get started with `@material-ui/pickers`.

## Documentation

Expand Down
6 changes: 3 additions & 3 deletions docs/layout/PageWithContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { create } from 'jss';
import { SnackbarProvider } from 'notistack';
import { setPrismTheme } from '../utils/prism';
import { PageContext } from '../utils/getPageContext';
import { LocalizationProvider } from '@material-ui/pickers';
import { UtilsContext } from '../_shared/UtilsServiceContext';
import { MuiPickersUtilsProvider } from '@material-ui/pickers';
import { NotificationManager } from 'utils/NotificationManager';
import { Theme, createMuiTheme, CssBaseline } from '@material-ui/core';
import { createUtilsService, UtilsLib, utilsMap } from '../utils/utilsService';
Expand Down Expand Up @@ -99,7 +99,7 @@ export const PageWithContexts: React.SFC<Props> = ({
>
<ThemeProvider theme={muiTheme}>
<SnackbarProvider maxSnack={3}>
<MuiPickersUtilsProvider utils={utilsMap[lib]}>
<LocalizationProvider dateAdapter={utilsMap[lib]}>
<ThemeContext.Provider value={theme}>
<UtilsContext.Provider value={createUtilsService(lib)}>
<CssBaseline />
Expand All @@ -113,7 +113,7 @@ export const PageWithContexts: React.SFC<Props> = ({
/>
</UtilsContext.Provider>
</ThemeContext.Provider>
</MuiPickersUtilsProvider>
</LocalizationProvider>
</SnackbarProvider>
</ThemeProvider>
</StylesProvider>
Expand Down
3 changes: 2 additions & 1 deletion docs/layout/components/navigationMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export const navItems = [
{ title: 'Accessibility', href: '/guides/accessibility' },
{ title: 'Form integration', href: '/guides/form-integration' },
{ title: 'CSS overrides', href: '/guides/css-overrides' },
{ title: 'Global format customization', href: '/guides/formats' },
{ title: 'Passing date adapter', href: '/guides/date-adapter-passing' },
{ title: 'Date management customization', href: '/guides/date-io-customization' },
{
title: 'Open pickers programmatically',
href: '/guides/controlling-programmatically',
Expand Down
25 changes: 13 additions & 12 deletions docs/pages/getting-started/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,38 @@ yarn add @material-ui/pickers
@material-ui/pickers was designed to use the date management library of your choice.
We are providing interfaces for [moment](https://momentjs.com/), [date-fns 2](https://date-fns.org/), [luxon](https://moment.github.io/luxon/) and [dayjs](https://github.com/iamkun/dayjs).

**Important:** we only support date-fns versions `v2` upwards.

```
npm i @date-io/date-fns date-fns@next
npm i date-fns
// or
npm i @date-io/moment moment
npm i moment
// or
npm i -s @date-io/luxon luxon
npm i luxon
// or
npm i -s @date-io/dayjs dayjs
npm i dayjs
```

Tell pickers which date management library it should use with `MuiPickersUtilsProvider`. This component takes a utils
`prop`, and makes it available down the React tree with [React Context](https://reactjs.org/docs/context.html). It should
Tell pickers which date management library it should use with `LocalizationProvider`. This component takes a `dateAdapter`
prop, and makes it available down the React tree thanks to [React Context](https://reactjs.org/docs/context.html). It should
be used at the root of your component tree, or at the highest level you wish the pickers to be available.

```jsx
import { MuiPickersUtilsProvider } from '@material-ui/pickers';
import { LocalizationProvider } from '@material-ui/pickers';

// pick a date util library
// pick an adapter for your date library
import MomentUtils from '@material-ui-pickers/adapter/moment';
import DateFnsUtils from '@material-ui-pickers/adapter/date-fns';
import LuxonUtils from '@material-ui-pickers/adapter/luxon';

function App() {
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<LocalizationProvider dateAdapter={DateFnsUtils}>
<Root />
</MuiPickersUtilsProvider>
</LocalizationProvider>
);
}

ReactDOM.render(<App />, document.querySelector('#app'));
```

Also it is possible to pass [date adapter directly to picker](/guides/date-adapter-passing) and avoid using context,
but please use this possibility widely.
11 changes: 3 additions & 8 deletions docs/pages/getting-started/usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,17 @@ import { CODESANDBOX_EXAMPLE_ID } from '_constants';
```jsx
import React, { useState } from 'react';
import DateFnsUtils from '@material-ui-pickers/adapter/date-fns'; // choose your lib
import {
DatePicker,
TimePicker,
DateTimePicker,
MuiPickersUtilsProvider,
} from '@material-ui/pickers';
import { DatePicker, TimePicker, DateTimePicker, LocalizationProvider } from '@material-ui/pickers';

function App() {
const [selectedDate, handleDateChange] = useState(new Date());

return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<LocalizationProvider dateAdapter={DateFnsUtils}>
<DatePicker value={selectedDate} onChange={date => handleDateChange(date)} />
<TimePicker value={selectedDate} onChange={date => handleDateChange(date)} />
<DateTimePicker value={selectedDate} onChange={date => handleDateChange(date)} />
</MuiPickersUtilsProvider>
</LocalizationProvider>
);
}
```
Expand Down
35 changes: 35 additions & 0 deletions docs/pages/guides/DateAdapterProp.example.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useState } from 'react';
Copy link
Member

Choose a reason for hiding this comment

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

What do you think of using React.useState?

Suggested change
import React, { useState } from 'react';
import React from 'react';

Copy link
Member Author

Choose a reason for hiding this comment

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

It is even more invalid, somewhere I thought that this kind of import will be deprecated. We are primarily using import * as React, but in examples using this notation.
I have no preference and can change

Copy link
Member

Choose a reason for hiding this comment

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

There is a related thread on this topic at mui/material-ui#19802.
What approach have you seen the more frequently used by TypeScript users on one side? And by JavaScript users on the other?

There are no clear guidelines by React on the matter, but I could find these two examples:

Copy link
Member Author

@dmtrKovalenko dmtrKovalenko Feb 28, 2020

Choose a reason for hiding this comment

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

For typescript codebase, it is much easier to use import * as React because a lot of internal types are also exported, like React.ReactNode, React.HtmlProps and so on.

My own notice: It is easier to visual recognize default react hooks like useEffect or useState when they are used like React.useEffect, thus all custom hooks are easily distinguishable

import ruLocale from 'date-fns/locale/ru';
import deLocale from 'date-fns/locale/de';
import DateFnsAdapter from '@material-ui/pickers/adapter/date-fns';
import { useMemo } from 'react';
import { DatePicker } from '@material-ui/pickers';

const staticDateAdapter = new DateFnsAdapter({ locale: ruLocale });

function UsingDateAdapterProp() {
const [locale] = useState(deLocale);
const [selectedDate, handleDateChange] = useState(new Date());
const memoizedDateAdapter = useMemo(() => {
return new DateFnsAdapter({ locale });
}, [locale]);

return (
<>
<DatePicker
value={selectedDate}
onChange={date => handleDateChange(date)}
dateAdapter={staticDateAdapter}
/>

<DatePicker
helperText="In case you need to generate adapter from state"
value={selectedDate}
onChange={date => handleDateChange(date)}
dateAdapter={memoizedDateAdapter}
/>
</>
);
}

export default UsingDateAdapterProp;
18 changes: 8 additions & 10 deletions docs/pages/guides/Formats.example.jsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
import format from 'date-fns/format';
import React, { useState } from 'react';
import frLocale from 'date-fns/locale/fr';
import DateFnsAdapter from '@material-ui/pickers/adapter/date-fns';
import { DatePicker } from '@material-ui/pickers';
import { MuiPickersUtilsProvider } from '@material-ui/pickers';
import { LocalizationProvider } from '@material-ui/pickers';

class LocalizedUtils extends DateFnsAdapter {
getDatePickerHeaderText(date) {
return format(date, 'd MMM yyyy', { locale: this.locale });
}
}
/** @type Partial<import('@date-io/core/IUtils').DateIOFormats> */
const formats = {
normalDate: 'd MMM yyy',
keyboardDate: 'd MMM yyy',
};

function DateFnsLocalizationExample() {
const [selectedDate, handleDateChange] = useState(new Date());

return (
<MuiPickersUtilsProvider utils={LocalizedUtils} locale={frLocale}>
<LocalizationProvider dateAdapter={DateFnsAdapter} locale={frLocale} dateFormats={formats}>
<DatePicker
clearable
helperText="Localization done right"
inputFormat="d MMM yyyy"
value={selectedDate}
onChange={handleDateChange}
clearLabel="vider"
cancelLabel="annuler"
/>
</MuiPickersUtilsProvider>
</LocalizationProvider>
);
}

Expand Down
24 changes: 24 additions & 0 deletions docs/pages/guides/OverrideLogic.example.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useState } from 'react';
import DateFnsAdapter from '@material-ui/pickers/adapter/date-fns';
import { DatePicker } from '@material-ui/pickers';
import { LocalizationProvider } from '@material-ui/pickers';

// Simple example, in some cases it can be helpful to reverse year order (from future to past).
// Here we are simply override called by pickers function and reversing the result
class OverriddenAdapter extends DateFnsAdapter {
getYearRange(start, end) {
return super.getYearRange(start, end).reverse();
}
}

function DateFnsLocalizationExample() {
const [selectedDate, handleDateChange] = useState(new Date());

return (
<LocalizationProvider dateAdapter={OverriddenAdapter}>
<DatePicker openTo="year" value={selectedDate} onChange={handleDateChange} />
</LocalizationProvider>
);
}

export default DateFnsLocalizationExample;
26 changes: 26 additions & 0 deletions docs/pages/guides/date-adapter-passing.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Ad from '_shared/Ad';
import Code from '_shared/Code.tsx';
import Example from '_shared/Example';
import PageMeta from '_shared/PageMeta';
import * as DateAdapterProp from './DateAdapterProp.example';

<PageMeta title="Customize date management logic" />

## Passing date adapter down to pickers

There are a couple of ways to pass date-io adapter to pickers components.

<Ad />

#### Context vs dateAdapter prop

Recomended way to pass date adapter is using our `LocalizationProvider` and pass it through the context.
Also there is a `dateAdapter` prop available, it allows to get rid of additional context.

But you need to understand a few things:

- `dateAdapter` will create a new context instance inside the date-picker, it may impact rendering performance if you have a lot of pickers on the screen
- You must make sure your adapter is properly memoized before passing it down
(if not – all components tree inside any picker will always rerender on your component change)

<Example source={DateAdapterProp} />
38 changes: 38 additions & 0 deletions docs/pages/guides/date-io-customization.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Ad from '_shared/Ad';
import Code from '_shared/Code.tsx';
import Example from '_shared/Example';
import PageMeta from '_shared/PageMeta';
import utilsInterfaceCode from '!raw-loader!@date-io/core/IUtils.d.ts';
import * as FormatsExample from './Formats.example';
import * as OverrideLogicExample from './OverrideLogic.example';

<PageMeta title="Customize date management logic" />

## Customization date management logic

For some reason, like timezone management and localization you may need to control how datepickers are working
with your date management library.

<Ad />

#### Global formats customization

All the formats used by the datepicker can be changed by `libFormats` prop in `LocalizationProvider`.
Find all availble formats in [Adapter interface](#utils-interface)

<Example source={FormatsExample} />

#### Override date logic

It is also possible to extend any adapter we providing and change the logic of date manipulations.
Simply extend exported version of `date-io` adapter, and make it work as you need accordingly to [used interface](#utils-interface)

> You can use ES6 class syntax or override values with the help of `.prototype` Object property.

<Example source={OverrideLogicExample} />

#### Utils interface

_Note_ TDate - date object passed from the state (moment, native Date or Luxon`s DateTime)

<Code language="ts" children={utilsInterfaceCode} />
30 changes: 0 additions & 30 deletions docs/pages/guides/formats.mdx

This file was deleted.

2 changes: 1 addition & 1 deletion docs/pages/guides/upgrading-to-v3.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ So less `any` from our side :)
#### 🙈 Misc

- Improved accessibility by making the toolbar button actually focusable `<button />`
- Rename `moment` property of `MuiPickersUtilsProvider` to `libInstance`
- Rename `moment` property of `LocalizationProvider` to `libInstance`
- Rename `onlyCalendar` prop to `disableToolbar`
- Remove `withUtils` HOC, and provide `useUtils` hook
- Remove `BasePicker` HOC, and provide `usePickerState` and `useKeyboardPickerState` hooks
Expand Down
Loading