diff --git a/docs/pages/_app.tsx b/docs/pages/_app.tsx index b83db47ae42cb8..1b9cbfc6708626 100644 --- a/docs/pages/_app.tsx +++ b/docs/pages/_app.tsx @@ -18,6 +18,14 @@ class MyApp extends App<{ theme: ThemeType }> { return { theme, pageProps }; } + componentDidMount() { + // Remove the server-side injected CSS. + const jssStyles = document.querySelector('#jss-server-side'); + if (jssStyles && jssStyles.parentNode) { + jssStyles.parentNode.removeChild(jssStyles); + } + } + render() { const { Component, pageProps, theme } = this.props; diff --git a/docs/pages/demo/datepicker/StaticDatePicker.example.jsx b/docs/pages/demo/datepicker/StaticDatePicker.example.jsx index 973ef079c38c50..e108c07194b27a 100644 --- a/docs/pages/demo/datepicker/StaticDatePicker.example.jsx +++ b/docs/pages/demo/datepicker/StaticDatePicker.example.jsx @@ -4,10 +4,25 @@ import { DatePicker } from '@material-ui/pickers'; const StaticDatePicker = () => { const [date, changeDate] = useState(new Date()); + // prettier-ignore return ( <> - - + + + ); }; diff --git a/docs/pages/demo/timepicker/StaticTimePicker.example.jsx b/docs/pages/demo/timepicker/StaticTimePicker.example.jsx index c0ade5ac589e77..6e363667b6376f 100644 --- a/docs/pages/demo/timepicker/StaticTimePicker.example.jsx +++ b/docs/pages/demo/timepicker/StaticTimePicker.example.jsx @@ -4,10 +4,25 @@ import { TimePicker } from '@material-ui/pickers'; const StaticTimePicker = () => { const [date, changeDate] = useState(new Date()); + // prettier-ignore return ( <> - - + + + ); }; diff --git a/docs/pages/localization/Hijri.example.jsx b/docs/pages/localization/Hijri.example.jsx index 7f35bc14791588..9f3e93b74de2f2 100644 --- a/docs/pages/localization/Hijri.example.jsx +++ b/docs/pages/localization/Hijri.example.jsx @@ -22,7 +22,6 @@ function HijriExample() { labelFunc={date => (date ? date.format('iYYYY/iMM/iDD') : '')} value={selectedDate} onChange={handleDateChange} - animateYearScrolling={false} minDate="1937-03-14" maxDate="2076-11-26" /> diff --git a/docs/pages/localization/Persian.example.jsx b/docs/pages/localization/Persian.example.jsx index 1d88bf57e5964b..b630734ed24976 100644 --- a/docs/pages/localization/Persian.example.jsx +++ b/docs/pages/localization/Persian.example.jsx @@ -24,7 +24,6 @@ function PersianExample() { labelFunc={date => (date ? date.format('jYYYY/jMM/jDD') : '')} value={selectedDate} onChange={handleDateChange} - animateYearScrolling={false} /> @@ -15,7 +15,7 @@ material-ui documentation page before proceeding. Install the specified npm packages below for Jalaali or Hijri depending on which calendar system you will be using. -#### Persian calendar system +#### Jalaali calendar system Install `@date-io/jalaali` package from npm. @@ -23,13 +23,13 @@ Install `@date-io/jalaali` package from npm. npm install @date-io/jalaali ``` -##### Example +#### Example You can use the examples below. It is recommended that you change the font. -
+
#### Hijri calendar system @@ -41,21 +41,23 @@ npm install @date-io/hijri moment-hijri To use it with Arabic locale, make sure to import `moment/locale/ar-sa` -``` +```javascript import 'moment/locale/ar-sa'; ``` -By default, the `DatePicker` uses 1900-01-01 for minDate and 2100-01-01 for maxDate. `moment-hijri` only supports dates from 1356-01-01 H (1937-03-14) to 1499-12-29 H (2076-11-26) so you will need to set `minDate` and `maxDate` on your `DatePicker` component otherwise your component will not work properly. +By default, the `DatePicker` uses `1900-01-01` for minDate and `2100-01-01` for maxDate. +`moment-hijri` only supports dates from `1356-01-01` H (1937-03-14) to `1499-12-29` H (2076-11-26) +so you will need to set `minDate` and `maxDate` on your `DatePicker` component otherwise your component will not work properly. -``` +```jsx ``` -##### Example +#### Example You can use the examples below. It is recommended that you change the font. diff --git a/docs/prop-types.json b/docs/prop-types.json index 10ba54ec4f1be9..00d1aeb62ff1db 100644 --- a/docs/prop-types.json +++ b/docs/prop-types.json @@ -277,6 +277,17 @@ "required": false, "type": { "name": "boolean" } }, + "orientation": { + "defaultValue": { "value": "\"portrait\"" }, + "description": "Force rendering in particular orientation", + "name": "orientation", + "parent": { + "fileName": "material-ui-pickers/lib/src/typings/BasePicker.tsx", + "name": "BasePickerProps" + }, + "required": false, + "type": { "name": "\"portrait\" | \"landscape\"" } + }, "variant": { "defaultValue": { "value": "'dialog'" }, "description": "Displaying variant", @@ -286,7 +297,7 @@ "name": "BasePickerProps" }, "required": false, - "type": { "name": "\"dialog\" | \"inline\"" } + "type": { "name": "\"dialog\" | \"inline\" | \"static\"" } }, "PopoverProps": { "defaultValue": null, @@ -631,7 +642,7 @@ "name": "BasePickerProps" }, "required": false, - "type": { "name": "\"dialog\" | \"inline\"" } + "type": { "name": "\"dialog\" | \"inline\" | \"static\"" } }, "onError": { "defaultValue": null, @@ -743,6 +754,17 @@ "required": false, "type": { "name": "boolean" } }, + "orientation": { + "defaultValue": { "value": "\"portrait\"" }, + "description": "Force rendering in particular orientation", + "name": "orientation", + "parent": { + "fileName": "material-ui-pickers/lib/src/typings/BasePicker.tsx", + "name": "BasePickerProps" + }, + "required": false, + "type": { "name": "\"portrait\" | \"landscape\"" } + }, "PopoverProps": { "defaultValue": null, "description": "Popover props passed to material-ui Popover (with variant=\"inline\")", @@ -1253,6 +1275,17 @@ "required": false, "type": { "name": "boolean" } }, + "orientation": { + "defaultValue": { "value": "\"portrait\"" }, + "description": "Force rendering in particular orientation", + "name": "orientation", + "parent": { + "fileName": "material-ui-pickers/lib/src/typings/BasePicker.tsx", + "name": "BasePickerProps" + }, + "required": false, + "type": { "name": "\"portrait\" | \"landscape\"" } + }, "variant": { "defaultValue": { "value": "'dialog'" }, "description": "Displaying variant", @@ -1262,7 +1295,7 @@ "name": "BasePickerProps" }, "required": false, - "type": { "name": "\"dialog\" | \"inline\"" } + "type": { "name": "\"dialog\" | \"inline\" | \"static\"" } }, "PopoverProps": { "defaultValue": null, @@ -1440,7 +1473,7 @@ "name": "BasePickerProps" }, "required": false, - "type": { "name": "\"dialog\" | \"inline\"" } + "type": { "name": "\"dialog\" | \"inline\" | \"static\"" } }, "onError": { "defaultValue": null, @@ -1563,6 +1596,17 @@ "required": false, "type": { "name": "boolean" } }, + "orientation": { + "defaultValue": { "value": "\"portrait\"" }, + "description": "Force rendering in particular orientation", + "name": "orientation", + "parent": { + "fileName": "material-ui-pickers/lib/src/typings/BasePicker.tsx", + "name": "BasePickerProps" + }, + "required": false, + "type": { "name": "\"portrait\" | \"landscape\"" } + }, "PopoverProps": { "defaultValue": null, "description": "Popover props passed to material-ui Popover (with variant=\"inline\")", @@ -1917,6 +1961,17 @@ "required": false, "type": { "name": "boolean" } }, + "orientation": { + "defaultValue": { "value": "\"portrait\"" }, + "description": "Force rendering in particular orientation", + "name": "orientation", + "parent": { + "fileName": "material-ui-pickers/lib/src/typings/BasePicker.tsx", + "name": "BasePickerProps" + }, + "required": false, + "type": { "name": "\"portrait\" | \"landscape\"" } + }, "variant": { "defaultValue": { "value": "'dialog'" }, "description": "Displaying variant", @@ -1926,7 +1981,7 @@ "name": "BasePickerProps" }, "required": false, - "type": { "name": "\"dialog\" | \"inline\"" } + "type": { "name": "\"dialog\" | \"inline\" | \"static\"" } }, "PopoverProps": { "defaultValue": null, @@ -2315,7 +2370,7 @@ "name": "BasePickerProps" }, "required": false, - "type": { "name": "\"dialog\" | \"inline\"" } + "type": { "name": "\"dialog\" | \"inline\" | \"static\"" } }, "onError": { "defaultValue": null, @@ -2438,6 +2493,17 @@ "required": false, "type": { "name": "boolean" } }, + "orientation": { + "defaultValue": { "value": "\"portrait\"" }, + "description": "Force rendering in particular orientation", + "name": "orientation", + "parent": { + "fileName": "material-ui-pickers/lib/src/typings/BasePicker.tsx", + "name": "BasePickerProps" + }, + "required": false, + "type": { "name": "\"portrait\" | \"landscape\"" } + }, "PopoverProps": { "defaultValue": null, "description": "Popover props passed to material-ui Popover (with variant=\"inline\")", diff --git a/lib/src/DatePicker/DatePickerToolbar.tsx b/lib/src/DatePicker/DatePickerToolbar.tsx index 1e06b269b398aa..dbccededd929ee 100644 --- a/lib/src/DatePicker/DatePickerToolbar.tsx +++ b/lib/src/DatePicker/DatePickerToolbar.tsx @@ -9,9 +9,15 @@ import { isYearAndMonthViews, isYearOnlyView } from '../_helpers/date-utils'; export const useStyles = makeStyles( { - toolbarCenter: { - flexDirection: 'row', - alignItems: 'center', + toolbar: { + flexDirection: 'column', + alignItems: 'flex-start', + }, + toolbarLandscape: { + padding: 16, + }, + dateLandscape: { + marginRight: 16, }, }, { name: 'MuiPickersDatePickerRoot' } @@ -21,6 +27,7 @@ export const DatePickerToolbar: React.FC = ({ date, views, setOpenView, + isLandscape, openView, }) => { const utils = useUtils(); @@ -30,7 +37,13 @@ export const DatePickerToolbar: React.FC = ({ const isYearAndMonth = React.useMemo(() => isYearAndMonthViews(views as any), [views]); return ( - + setOpenView('year')} @@ -41,9 +54,11 @@ export const DatePickerToolbar: React.FC = ({ {!isYearOnly && !isYearAndMonth && ( setOpenView('date')} selected={openView === 'date'} + onClick={() => setOpenView('date')} + align={isLandscape ? 'left' : 'center'} label={utils.getDatePickerHeaderText(date)} + className={clsx({ [classes.dateLandscape]: isLandscape })} /> )} diff --git a/lib/src/DateTimePicker/DateTimePicker.tsx b/lib/src/DateTimePicker/DateTimePicker.tsx index 1d1e54b377598d..e6bc226e9f83e8 100644 --- a/lib/src/DateTimePicker/DateTimePicker.tsx +++ b/lib/src/DateTimePicker/DateTimePicker.tsx @@ -31,6 +31,7 @@ export type KeyboardDateTimePickerProps = WrappedKeyboardPickerProps & DateTimeP const defaultProps = { ...dateTimePickerDefaultProps, wider: true, + orientation: 'portrait' as const, openTo: 'date' as DateTimePickerView, views: ['year', 'date', 'hours', 'minutes'] as DateTimePickerView[], }; @@ -38,6 +39,10 @@ const defaultProps = { function useOptions(props: DateTimePickerProps | KeyboardDateTimePickerProps) { const utils = useUtils(); + if (props.orientation !== 'portrait') { + throw new Error('We are not supporting custom orientation for DateTimePicker yet :('); + } + return { getDefaultFormat: () => pick12hOr24hFormat(props.format, props.ampm, { diff --git a/lib/src/DateTimePicker/DateTimePickerToolbar.tsx b/lib/src/DateTimePicker/DateTimePickerToolbar.tsx index 93f9fbe425fe79..3c22c8762ec04f 100644 --- a/lib/src/DateTimePicker/DateTimePickerToolbar.tsx +++ b/lib/src/DateTimePicker/DateTimePickerToolbar.tsx @@ -13,8 +13,6 @@ import { useMeridiemMode } from '../TimePicker/TimePickerToolbar'; export const useStyles = makeStyles( _ => ({ toolbar: { - flexDirection: 'row', - alignItems: 'center', paddingLeft: 16, paddingRight: 16, justifyContent: 'space-around', @@ -46,7 +44,7 @@ export const DateTimePickerToolbar: React.FC = ({ return ( <> - +
diff --git a/lib/src/Picker/Picker.tsx b/lib/src/Picker/Picker.tsx index 2dc0bd7d5402fc..591d6fdb713cf1 100644 --- a/lib/src/Picker/Picker.tsx +++ b/lib/src/Picker/Picker.tsx @@ -1,15 +1,19 @@ import * as React from 'react'; +import clsx from 'clsx'; import Calendar from '../views/Calendar/Calendar'; import { useUtils } from '../_shared/hooks/useUtils'; import { useViews } from '../_shared/hooks/useViews'; import { makeStyles } from '@material-ui/core/styles'; import { YearSelection } from '../views/Year/YearView'; import { MaterialUiPickersDate } from '../typings/date'; -import { MonthSelection } from '../views/Month/MonthView'; +import { BasePickerProps } from '../typings/BasePicker'; import { TimePickerView } from '../views/Clock/ClockView'; +import { MonthSelection } from '../views/Month/MonthView'; import { BaseTimePickerProps } from '../TimePicker/TimePicker'; import { BaseDatePickerProps } from '../DatePicker/DatePicker'; +import { useIsLandscape } from '../_shared/hooks/useIsLandscape'; import { datePickerDefaultProps } from '../constants/prop-types'; +import { DIALOG_WIDTH_WIDER, DIALOG_WIDTH, VIEW_HEIGHT } from '../constants/dimensions'; const viewsMap = { year: YearSelection, @@ -33,6 +37,7 @@ export type ToolbarComponentProps = BaseDatePickerProps & hideTabs?: boolean; dateRangeIcon?: React.ReactNode; timeIcon?: React.ReactNode; + isLandscape: boolean; }; export interface PickerViewProps extends BaseDatePickerProps, BaseTimePickerProps { @@ -48,17 +53,31 @@ export interface PickerViewProps extends BaseDatePickerProps, BaseTimePickerProp interface PickerProps extends PickerViewProps { date: MaterialUiPickersDate; + orientation?: BasePickerProps['orientation']; onChange: (date: MaterialUiPickersDate, isFinish?: boolean) => void; } const useStyles = makeStyles( { + container: { + display: 'flex', + flexDirection: 'column', + }, + containerLandscape: { + flexDirection: 'row', + }, pickerView: { - minHeight: 305, + overflowX: 'hidden', + minHeight: VIEW_HEIGHT, + minWidth: DIALOG_WIDTH, + maxWidth: DIALOG_WIDTH_WIDER, display: 'flex', flexDirection: 'column', justifyContent: 'center', }, + pickerViewLandscape: { + padding: '0 8px', + }, }, { name: 'MuiPickersBasePicker' } ); @@ -91,17 +110,23 @@ export const Picker: React.FunctionComponent = props => { rightArrowButtonProps, ToolbarComponent, loadingIndicator, + orientation, } = props; const utils = useUtils(); const classes = useStyles(); + const isLandscape = useIsLandscape(orientation); const { openView, setOpenView, handleChangeAndOpenNext } = useViews(views, openTo, onChange); const minDate = React.useMemo(() => utils.date(unparsedMinDate)!, [unparsedMinDate, utils]); const maxDate = React.useMemo(() => utils.date(unparsedMaxDate)!, [unparsedMaxDate, utils]); return ( - <> +
{!disableToolbar && ( = props => { hideTabs={hideTabs} dateRangeIcon={dateRangeIcon} timeIcon={timeIcon} + isLandscape={isLandscape} {...props} /> )} -
+
{openView === 'year' && ( = props => { /> )}
- +
); }; diff --git a/lib/src/Picker/WrappedKeyboardPicker.tsx b/lib/src/Picker/WrappedKeyboardPicker.tsx index eddd5276998074..9f84c07127bf99 100644 --- a/lib/src/Picker/WrappedKeyboardPicker.tsx +++ b/lib/src/Picker/WrappedKeyboardPicker.tsx @@ -63,6 +63,7 @@ export function makeKeyboardPicker({ emptyLabel, invalidLabel, timeIcon, + orientation, variant, disableToolbar, loadingIndicator, @@ -85,6 +86,7 @@ export function makeKeyboardPicker({ ToolbarComponent={ToolbarComponent} disableToolbar={disableToolbar} hideTabs={hideTabs} + orientation={orientation} ampm={ampm} views={views} openTo={openTo} diff --git a/lib/src/Picker/WrappedPurePicker.tsx b/lib/src/Picker/WrappedPurePicker.tsx index ce28c64efaa069..3956cdc4fa57e7 100644 --- a/lib/src/Picker/WrappedPurePicker.tsx +++ b/lib/src/Picker/WrappedPurePicker.tsx @@ -55,6 +55,7 @@ export function makePurePicker({ timeIcon, value, variant, + orientation, disableToolbar, loadingIndicator, ...other @@ -73,6 +74,7 @@ export function makePurePicker({ > = ({ ampm, openView, onChange, + isLandscape, setOpenView, }) => { const utils = useUtils(); @@ -84,19 +90,25 @@ const TimePickerToolbar: React.FC = ({ const classes = useStyles(); const { meridiemMode, handleMeridiemChange } = useMeridiemMode(date, ampm, onChange); - const hourMinuteClassName = - theme.direction === 'rtl' ? classes.hourMinuteLabelReverse : classes.hourMinuteLabel; + const clockTypographyVariant = isLandscape ? 'h3' : 'h2'; return ( -
+
{arrayIncludes(views, 'hours') && ( setOpenView(ClockType.HOURS)} selected={openView === ClockType.HOURS} label={utils.getHourText(date, Boolean(ampm))} @@ -104,12 +116,17 @@ const TimePickerToolbar: React.FC = ({ )} {arrayIncludes(views, ['hours', 'minutes']) && ( - + )} {arrayIncludes(views, 'minutes') && ( setOpenView(ClockType.MINUTES)} selected={openView === ClockType.MINUTES} label={utils.getMinuteText(date)} @@ -133,6 +150,7 @@ const TimePickerToolbar: React.FC = ({ {ampm && (
diff --git a/lib/src/__tests__/e2e/DarkTheme.test.tsx b/lib/src/__tests__/e2e/Theme.test.tsx similarity index 68% rename from lib/src/__tests__/e2e/DarkTheme.test.tsx rename to lib/src/__tests__/e2e/Theme.test.tsx index d08e4463227edd..087f56c147fad8 100644 --- a/lib/src/__tests__/e2e/DarkTheme.test.tsx +++ b/lib/src/__tests__/e2e/Theme.test.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { mount } from '../test-utils'; +import { DatePicker } from '../../DatePicker'; import { createMuiTheme } from '@material-ui/core'; import { ThemeProvider } from '@material-ui/styles'; import { DateTimePicker } from '../../DateTimePicker/DateTimePicker'; @@ -19,3 +20,11 @@ test('Should renders without crash in dark theme', () => { expect(component).toBeTruthy(); }); + +test('Should render component with different orientation', () => { + const component = mount( + + ); + + expect(component).toBeTruthy(); +}); diff --git a/lib/src/_shared/ModalDialog.tsx b/lib/src/_shared/ModalDialog.tsx index 8a6cbfb884f2f1..650d812ea10dd6 100644 --- a/lib/src/_shared/ModalDialog.tsx +++ b/lib/src/_shared/ModalDialog.tsx @@ -4,7 +4,7 @@ import Button from '@material-ui/core/Button'; import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; import Dialog, { DialogProps } from '@material-ui/core/Dialog'; -import { DIALOG_WIDTH, DIALOG_WIDTH_WIDER } from '../constants/dimensions'; +import { DIALOG_WIDTH } from '../constants/dimensions'; import { createStyles, WithStyles, withStyles } from '@material-ui/core/styles'; export interface ModalDialogProps extends DialogProps { @@ -90,15 +90,12 @@ ModalDialog.displayName = 'ModalDialog'; export const styles = createStyles({ dialogRoot: { minWidth: DIALOG_WIDTH, - maxWidth: DIALOG_WIDTH_WIDER, + // maxWidth: DIALOG_WIDTH_WIDER, }, dialogRootWider: { - minWidth: DIALOG_WIDTH_WIDER, + // minWidth: DIALOG_WIDTH_WIDER, }, dialog: { - // minHeight: dialogHeight, - overflow: 'hidden', - '&:first-child': { padding: 0, }, diff --git a/lib/src/_shared/PickerToolbar.tsx b/lib/src/_shared/PickerToolbar.tsx index bbd02e9be11196..c47fa7c82aa786 100644 --- a/lib/src/_shared/PickerToolbar.tsx +++ b/lib/src/_shared/PickerToolbar.tsx @@ -8,8 +8,8 @@ export const useStyles = makeStyles( theme => ({ toolbar: { display: 'flex', - flexDirection: 'column', - alignItems: 'flex-start', + flexDirection: 'row', + alignItems: 'center', justifyContent: 'center', height: 100, backgroundColor: @@ -17,19 +17,33 @@ export const useStyles = makeStyles( ? theme.palette.primary.main : theme.palette.background.default, }, + toolbarLandscape: { + height: 'auto', + maxWidth: 150, + padding: 8, + justifyContent: 'flex-start', + }, }), { name: 'MuiPickersToolbar' } ); -const PickerToolbar: React.SFC> = ({ +interface PickerToolbarProps extends ExtendMui { + isLandscape: boolean; +} + +const PickerToolbar: React.SFC = ({ children, + isLandscape, className = null, ...other }) => { const classes = useStyles(); return ( - + {children} ); diff --git a/lib/src/_shared/ToolbarButton.tsx b/lib/src/_shared/ToolbarButton.tsx index 37ea2f19c28c32..110528f39d4c42 100644 --- a/lib/src/_shared/ToolbarButton.tsx +++ b/lib/src/_shared/ToolbarButton.tsx @@ -13,6 +13,7 @@ export interface ToolbarButtonProps variant: TypographyProps['variant']; selected: boolean; label: string; + align?: TypographyProps['align']; typographyClassName?: string; } @@ -22,12 +23,14 @@ const ToolbarButton: React.FunctionComponent = ({ label, selected, variant, + align, typographyClassName, ...other }) => { return (