Skip to content

Commit

Permalink
Add prop to render elements after calendar (#1795)
Browse files Browse the repository at this point in the history
This allows us to render anything after the calendar (buttons, text…)
by passing the renderCalendarInfo props to DateRangePicker.
  • Loading branch information
Julien Enselme committed Sep 8, 2020
1 parent 91dcbaf commit 05d8a95
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 38 deletions.
46 changes: 46 additions & 0 deletions docs/pages/demo/daterangepicker/CustomCalendarRender.example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from 'react';
import { DateRangePicker, DateRange, DateRangeDelimiter, PickersCalendar, PickersCalendarProps } from '@material-ui/pickers';
import TextField from "@material-ui/core/TextField";

interface CalendarWithValidationButtonProps extends PickersCalendarProps<Date> {
validateCustomPeriod: () => void;
}

function CalendarWithValidationButton ({ validateCustomPeriod, ...pickersCalendarProps }: CalendarWithValidationButtonProps) {
return (
<React.Fragment>
<PickersCalendar {...pickersCalendarProps} />

<button
type="button"
className="button date-dropdown__button--validate button--small button--alert"
onClick={validateCustomPeriod}
>
Validate
</button>
</React.Fragment>
);
}

export default function CustomCalendarRender() {
const [value, setValue] = React.useState<DateRange<Date>>([null, null]);

return (
<DateRangePicker
startText="Check-in"
endText="Check-out"
value={value}
onChange={(newValue) => setValue(newValue)}
slotComponents={{ Calendar: CalendarWithValidationButton }}
// @ts-ignore
slotProps={{ Calendar: { validateCustomPeriod: setValue } }}
renderInput={(startProps, endProps) => (
<React.Fragment>
<TextField {...startProps} />
<DateRangeDelimiter> to </DateRangeDelimiter>
<TextField {...endProps} />
</React.Fragment>
)}
/>
);
}
7 changes: 7 additions & 0 deletions docs/pages/demo/daterangepicker/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as MinMaxDateRangePicker from './MinMaxDateRangePicker.example';
import * as CalendarsDateRangePicker from './CalendarsDateRangePicker.example';
import * as StaticDateRangePicker from './StaticDateRangePicker.example';
import * as CustomRangeInputs from './CustomRangeInputs.example';
import * as CustomCalendarRender from "./CustomCalendarRender.example";

<PageMeta component="DateRangePicker" />

Expand Down Expand Up @@ -69,6 +70,12 @@ It is possible to render any picker without modal or popper. For that use `Stati
<Example paddingBottom source={StaticDateRangePicker} />
</Hidden>

#### Customize calendar rendering

It is also possible to use a custom component as `Calendar` to customize its rendering.

<Example source={CustomCalendarRender} />

#### API

<LinkedComponents components={['DateRangePicker']} />
59 changes: 38 additions & 21 deletions lib/src/DateRangePicker/DateRangePickerViewDesktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
isEndOfRange,
DateValidationProps,
} from '../_helpers/date-utils';
import { DayProps as CalendarDayProps } from "../views/Calendar/Day";

export interface ExportedDesktopDateRangeCalendarProps<TDate> {
/**
Expand All @@ -30,6 +31,19 @@ export interface ExportedDesktopDateRangeCalendarProps<TDate> {
* @example (date, DateRangeDayProps) => <DateRangePickerDay {...DateRangeDayProps} />
*/
renderDay?: (date: TDate, DateRangeDayProps: DateRangeDayProps<TDate>) => JSX.Element;
/**
* Custom components. We currently only support Calendar to customize its rendering.
*/
slotComponents?: {
Calendar?: React.ElementType;
};
/**
* Extra props passed to the custom components. You can use this to override any props
* on the base component too.
*/
slotProps?: {
Calendar?: CalendarProps<TDate>;
};
}

interface DesktopDateRangeCalendarProps<TDate>
Expand Down Expand Up @@ -102,6 +116,8 @@ export function DateRangePickerViewDesktop<TDate>(props: DesktopDateRangeCalenda
currentlySelectingRangeEnd,
currentMonth,
renderDay = (_, dateRangeProps) => <DateRangeDay {...dateRangeProps} />,
slotComponents = { Calendar },
slotProps = {},
...other
} = props;

Expand Down Expand Up @@ -153,6 +169,27 @@ export function DateRangePickerViewDesktop<TDate>(props: DesktopDateRangeCalenda
changeMonth(utils.getPreviousMonth(currentMonth));
}, [changeMonth, currentMonth, utils]);

const CalendarComponent = slotComponents.Calendar || Calendar;
const calendarProps = {
...other,
date,
className: classes.calendar,
onChange: handleDayChange,
TransitionProps: CalendarTransitionProps,
renderDay: (day: TDate, __: TDate | null, DayProps: CalendarDayProps<TDate>) =>
renderDay(day, {
isPreviewing: isWithinRange(utils, day, previewingRange),
isStartOfPreviewing: isStartOfRange(utils, day, previewingRange),
isEndOfPreviewing: isEndOfRange(utils, day, previewingRange),
isHighlighting: isWithinRange(utils, day, date),
isStartOfHighlighting: isStartOfRange(utils, day, date),
isEndOfHighlighting: isEndOfRange(utils, day, date),
onMouseEnter: () => handlePreviewDayChange(day),
...DayProps,
}),
...slotProps.Calendar,
};

return (
<div className={classes.root}>
{getCalendarsArray(calendars).map((_, index) => {
Expand All @@ -176,27 +213,7 @@ export function DateRangePickerViewDesktop<TDate>(props: DesktopDateRangeCalenda
rightArrowIcon={rightArrowIcon}
text={utils.format(monthOnIteration, 'monthAndYear')}
/>
<Calendar<TDate>
{...other}
key={index}
date={date}
className={classes.calendar}
onChange={handleDayChange}
currentMonth={monthOnIteration}
TransitionProps={CalendarTransitionProps}
renderDay={(day, __, DayProps) =>
renderDay(day, {
isPreviewing: isWithinRange(utils, day, previewingRange),
isStartOfPreviewing: isStartOfRange(utils, day, previewingRange),
isEndOfPreviewing: isEndOfRange(utils, day, previewingRange),
isHighlighting: isWithinRange(utils, day, date),
isStartOfHighlighting: isStartOfRange(utils, day, date),
isEndOfHighlighting: isEndOfRange(utils, day, date),
onMouseEnter: () => handlePreviewDayChange(day),
...DayProps,
})
}
/>
<CalendarComponent key={index} currentMonth={monthOnIteration} {...calendarProps} />
</div>
);
})}
Expand Down
53 changes: 36 additions & 17 deletions lib/src/DateRangePicker/DateRangePickerViewMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,24 @@ import {
isEndOfRange,
DateValidationProps,
} from '../_helpers/date-utils';
import { DayProps as CalendarDayProps } from "../views/Calendar/Day";

export interface ExportedMobileDateRangeCalendarProps<TDate>
extends Pick<ExportedDesktopDateRangeCalendarProps<TDate>, 'renderDay'> {}
extends Pick<ExportedDesktopDateRangeCalendarProps<TDate>, 'renderDay'> {
/**
* Custom components. We currently only support Calendar to customize its rendering.
*/
slotComponents?: {
Calendar?: React.ElementType;
};
/**
* Extra props passed to the custom components. You can use this to override any props
* on the base component too.
*/
slotProps?: {
Calendar?: CalendarProps<TDate>;
};
}

interface DesktopDateRangeCalendarProps<TDate>
extends ExportedMobileDateRangeCalendarProps<TDate>,
Expand Down Expand Up @@ -43,12 +58,31 @@ export function DateRangePickerViewMobile<TDate>(props: DesktopDateRangeCalendar
rightArrowButtonText,
rightArrowIcon,
renderDay = (_, props) => <DateRangeDay<TDate> {...props} />,
slotComponents = { Calendar },
slotProps = { Calendar: {} },
...other
} = props;

const utils = useUtils();
const minDate = __minDate || utils.date(defaultMinDate);
const maxDate = __maxDate || utils.date(defaultMaxDate);
const CalendarComponent = slotComponents.Calendar || Calendar;
const calendarProps = {
...other,
date,
onChange,
renderDay: (day: TDate, _: TDate | null, DayProps: CalendarDayProps<TDate>) =>
renderDay(day, {
isPreviewing: false,
isStartOfPreviewing: false,
isEndOfPreviewing: false,
isHighlighting: isWithinRange(utils, day, date),
isStartOfHighlighting: isStartOfRange(utils, day, date),
isEndOfHighlighting: isEndOfRange(utils, day, date),
...DayProps,
}),
...slotProps.Calendar,
};

return (
<React.Fragment>
Expand All @@ -67,22 +101,7 @@ export function DateRangePickerViewMobile<TDate>(props: DesktopDateRangeCalendar
maxDate={maxDate}
{...other}
/>
<Calendar<TDate>
{...other}
date={date}
onChange={onChange}
renderDay={(day, _, DayProps) =>
renderDay(day, {
isPreviewing: false,
isStartOfPreviewing: false,
isEndOfPreviewing: false,
isHighlighting: isWithinRange(utils, day, date),
isStartOfHighlighting: isStartOfRange(utils, day, date),
isEndOfHighlighting: isEndOfRange(utils, day, date),
...DayProps,
})
}
/>
<CalendarComponent {...calendarProps} />
</React.Fragment>
);
}

0 comments on commit 05d8a95

Please sign in to comment.