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

[DatePicker] Migrate CalendarPicker to emotion #26390

Merged
merged 7 commits into from
May 21, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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 docs/pages/api-docs/calendar-picker.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
},
"name": "CalendarPicker",
"styles": {
"classes": ["root", "viewTransitionContainer", "fullHeightContainer"],
siriwatknp marked this conversation as resolved.
Show resolved Hide resolved
"classes": ["root", "viewTransitionContainer"],
"globalClasses": {},
"name": "MuiCalendarPicker"
},
Expand All @@ -50,6 +50,6 @@
"filename": "/packages/material-ui-lab/src/CalendarPicker/CalendarPicker.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/components/date-picker/\">Date Picker</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,11 @@
"view": "Controlled open view.",
"views": "Views for calendar picker."
},
"classDescriptions": {}
"classDescriptions": {
"root": { "description": "Styles applied to the root element." },
"viewTransitionContainer": {
"description": "Styles applied to {{nodeName}}.",
"nodeName": "the transition group element"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
import * as React from 'react';
import { expect } from 'chai';
import { getClasses, createMount, fireEvent, screen, describeConformance } from 'test/utils';
import { createMount, fireEvent, screen, describeConformanceV5 } from 'test/utils';
import LocalizationProvider from '@material-ui/lab/LocalizationProvider';
import AdapterDateFns from '@material-ui/lab/AdapterDateFns';
import CalendarPicker from '@material-ui/lab/CalendarPicker';
import CalendarPicker, { calendarPickerClasses as classes } from '@material-ui/lab/CalendarPicker';
import { adapterToUse, createPickerRender, getAllByMuiTest } from '../internal/pickers/test-utils';

describe('<CalendarPicker />', () => {
const mount = createMount();
const render = createPickerRender({ strict: false });
let classes: Record<string, string>;

const localizedMount = (node: React.ReactNode) => {
return mount(<LocalizationProvider dateAdapter={AdapterDateFns}>{node}</LocalizationProvider>);
};

before(() => {
classes = getClasses(<CalendarPicker date={adapterToUse.date()} onChange={() => {}} />);
});

describeConformance(<CalendarPicker date={adapterToUse.date()} onChange={() => {}} />, () => ({
describeConformanceV5(<CalendarPicker date={adapterToUse.date()} onChange={() => {}} />, () => ({
classes,
inheritComponent: 'div',
render,
muiName: 'MuiCalendarPicker',
mount: localizedMount,
refInstanceof: window.HTMLDivElement,
// cannot test reactTestRenderer because of required context
skip: ['componentProp', 'propsSpread', 'reactTestRenderer'],
skip: [
'componentProp',
'componentsProp',
'propsSpread',
'reactTestRenderer',
// TODO: Fix CalendarPicker is not spreading props on root
'themeDefaultProps',
'themeVariants',
siriwatknp marked this conversation as resolved.
Show resolved Hide resolved
],
}));

it('renders calendar standalone', () => {
Expand Down
107 changes: 79 additions & 28 deletions packages/material-ui-lab/src/CalendarPicker/CalendarPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { MuiStyles, withStyles, WithStyles } from '@material-ui/core/styles';
import clsx from 'clsx';
import {
experimentalStyled as styled,
Theme,
unstable_useThemeProps as useThemeProps,
} from '@material-ui/core/styles';
import {
unstable_composeClasses as composeClasses,
generateUtilityClass,
generateUtilityClasses,
} from '@material-ui/unstyled';
import MonthPicker from '../MonthPicker/MonthPicker';
import { useCalendarState } from './useCalendarState';
import { useUtils } from '../internal/pickers/hooks/useUtils';
import FadeTransitionGroup from './PickersFadeTransitionGroup';
import PickersCalendar, { ExportedCalendarProps } from './PickersCalendar';
import { PickerOnChangeFn, useViews } from '../internal/pickers/hooks/useViews';
import { DAY_SIZE, DAY_MARGIN } from '../internal/pickers/constants/dimensions';
import PickersCalendarHeader, { ExportedCalendarHeaderProps } from './PickersCalendarHeader';
import YearPicker, { ExportedYearPickerProps } from '../YearPicker/YearPicker';
import { defaultMinDate, defaultMaxDate } from '../internal/pickers/constants/prop-types';
Expand All @@ -17,6 +25,15 @@ import { findClosestEnabledDate } from '../internal/pickers/date-utils';
import { CalendarPickerView } from './shared';
import PickerView from '../internal/pickers/Picker/PickerView';

export interface CalendarPickerClasses {
/** Styles applied to the root element. */
root: string;
/** Styles applied to the transition group element. */
viewTransitionContainer: string;
}

export type CalendarPickerClassKey = keyof CalendarPickerClasses;

export interface CalendarPickerProps<TDate>
extends ExportedCalendarProps<TDate>,
ExportedYearPickerProps<TDate>,
Expand Down Expand Up @@ -98,41 +115,71 @@ export type ExportedCalendarPickerProps<TDate> = Omit<
| 'className'
>;

export type CalendarPickerClassKey = 'root' | 'viewTransitionContainer' | 'fullHeightContainer';
interface CalendarPickerPropsWithClasses<TDate> extends CalendarPickerProps<TDate> {
classes?: Partial<CalendarPickerClasses>;
}

export const styles: MuiStyles<CalendarPickerClassKey> = {
root: {
display: 'flex',
flexDirection: 'column',
},
viewTransitionContainer: {
overflowY: 'auto',
},
fullHeightContainer: {
flex: 1,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: (DAY_SIZE + DAY_MARGIN * 4) * 7,
height: '100%',
},
siriwatknp marked this conversation as resolved.
Show resolved Hide resolved
export function getCalendarPickerUtilityClass(slot: string) {
return generateUtilityClass('MuiCalendarPicker', slot);
}

export const calendarPickerClasses: CalendarPickerClasses = generateUtilityClasses(
'MuiCalendarPicker',
['root', 'viewTransitionContainer'],
);

const useUtilityClasses = (
styleProps: CalendarPickerProps<any> & { classes?: Partial<CalendarPickerClasses> },
) => {
const { classes } = styleProps;
const slots = {
root: ['root'],
viewTransitionContainer: ['viewTransitionContainer'],
};

return composeClasses(slots, getCalendarPickerUtilityClass, classes);
};

const CalendarPickerRoot = styled(
PickerView,
{},
{ name: 'MuiCalendarPicker', slot: 'Root', overridesResolver: (props, styles) => styles.root },
)({
display: 'flex',
flexDirection: 'column',
});

const CalendarPickerViewTransitionContainer = styled(
FadeTransitionGroup,
{},
{
name: 'MuiCalendarPicker',
slot: 'ViewTransitionContainer',
overridesResolver: (props, styles) => styles.viewTransitionContainer,
},
)({
overflowY: 'auto',
});

export const defaultReduceAnimations =
typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent);

const CalendarPicker = React.forwardRef(function CalendarPicker<TDate extends any>(
props: CalendarPickerProps<TDate> & WithStyles<typeof styles>,
inProps: CalendarPickerPropsWithClasses<TDate>,
ref: React.Ref<HTMLDivElement>,
) {
const props = useThemeProps<Theme, CalendarPickerProps<TDate>, 'MuiCalendarPicker'>({
props: inProps,
name: 'MuiCalendarPicker',
});

const {
allowKeyboardControl: allowKeyboardControlProp,
onViewChange,
date,
disableFuture = false,
disablePast = false,
defaultCalendarMonth,
classes,
loading = false,
maxDate: maxDateProp,
minDate: minDateProp,
Expand Down Expand Up @@ -207,8 +254,12 @@ const CalendarPicker = React.forwardRef(function CalendarPicker<TDate extends an
}
}, [date]); // eslint-disable-line

// TODO: convert to simple assignment after the type error in defaultPropsHandler.js:60:6 is fixed
const styleProps = { ...props };
siriwatknp marked this conversation as resolved.
Show resolved Hide resolved
const classes = useUtilityClasses(styleProps);

return (
<PickerView ref={ref} className={clsx(classes.root, className)}>
<CalendarPickerRoot ref={ref} className={clsx(classes.root, className)}>
<PickersCalendarHeader
{...other}
views={views}
Expand All @@ -222,7 +273,7 @@ const CalendarPicker = React.forwardRef(function CalendarPicker<TDate extends an
disableFuture={disableFuture}
reduceAnimations={reduceAnimations}
/>
<FadeTransitionGroup
<CalendarPickerViewTransitionContainer
reduceAnimations={reduceAnimations}
className={classes.viewTransitionContainer}
transKey={openView}
Expand Down Expand Up @@ -271,8 +322,8 @@ const CalendarPicker = React.forwardRef(function CalendarPicker<TDate extends an
/>
)}
</div>
</FadeTransitionGroup>
</PickerView>
</CalendarPickerViewTransitionContainer>
</CalendarPickerRoot>
);
});

Expand All @@ -289,7 +340,7 @@ CalendarPicker.propTypes /* remove-proptypes */ = {
/**
* @ignore
*/
classes: PropTypes.object.isRequired,
classes: PropTypes.object,
/**
* @ignore
*/
Expand Down Expand Up @@ -381,6 +432,6 @@ CalendarPicker.propTypes /* remove-proptypes */ = {
*
* - [CalendarPicker API](https://material-ui.com/api/calendar-picker/)
*/
export default withStyles(styles, { name: 'MuiCalendarPicker' })(CalendarPicker) as <TDate>(
props: CalendarPickerProps<TDate> & React.RefAttributes<HTMLDivElement>,
export default CalendarPicker as <TDate>(
props: CalendarPickerPropsWithClasses<TDate> & React.RefAttributes<HTMLDivElement>,
) => JSX.Element;
3 changes: 2 additions & 1 deletion packages/material-ui-lab/src/CalendarPicker/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default } from './CalendarPicker';
export { default, calendarPickerClasses } from './CalendarPicker';

export type CalendarPickerClassKey = import('./CalendarPicker').CalendarPickerClassKey;
export type CalendarPickerClasses = import('./CalendarPicker').CalendarPickerClasses;
export type CalendarPickerProps<TDate> = import('./CalendarPicker').CalendarPickerProps<TDate>;
export type CalendarPickerView = NonNullable<CalendarPickerProps<unknown>['view']>;