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

Bug fixing for Calendar components and some new features #214

Merged
merged 10 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
41 changes: 38 additions & 3 deletions packages/react/src/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ export interface CalendarProps
| 'isYearDisabled'
| 'isYearInRange'
| 'onYearHover'>;
/**
* Disabled `Month` calendar button click
* @default false
*/
disabledMonthSwitch?: boolean;
/**
* Disabled `Year` calendar button click
* @default false
*/
disabledYearSwitch?: boolean;
/**
* Use this prop to switch calendars.
* @default 'day'
Expand Down Expand Up @@ -131,8 +141,10 @@ const Calendar = forwardRef<HTMLDivElement, CalendarProps>(function Calendar(pro
calendarWeeksProps,
calendarYearsProps,
className,
disabledMonthSwitch,
disableOnNext,
disableOnPrev,
disabledYearSwitch,
displayMonthLocale = displayMonthLocaleFromConfig,
displayWeekDayLocale,
isDateDisabled,
Expand Down Expand Up @@ -167,6 +179,8 @@ const Calendar = forwardRef<HTMLDivElement, CalendarProps>(function Calendar(pro
displayCalendar = (
<CalendarDays
{...calendarDaysProps}
isYearDisabled={isYearDisabled}
isMonthDisabled={isMonthDisabled}
isDateDisabled={isDateDisabled}
isDateInRange={isDateInRange}
onClick={onChange}
Expand All @@ -180,6 +194,8 @@ const Calendar = forwardRef<HTMLDivElement, CalendarProps>(function Calendar(pro
displayCalendar = (
<CalendarWeeks
{...calendarWeeksProps}
isYearDisabled={isYearDisabled}
isMonthDisabled={isMonthDisabled}
isWeekDisabled={isWeekDisabled}
isWeekInRange={isWeekInRange}
onClick={onChange}
Expand All @@ -193,6 +209,7 @@ const Calendar = forwardRef<HTMLDivElement, CalendarProps>(function Calendar(pro
displayCalendar = (
<CalendarMonths
{...calendarMonthsProps}
isYearDisabled={isYearDisabled}
isMonthDisabled={isMonthDisabled}
isMonthInRange={isMonthInRange}
onClick={onChange}
Expand Down Expand Up @@ -225,14 +242,26 @@ const Calendar = forwardRef<HTMLDivElement, CalendarProps>(function Calendar(pro
<>
<button
type="button"
className={cx(classes.button, classes.controlsButton)}
className={cx(
classes.button,
classes.controlsButton,
disabledMonthSwitch && classes.buttonDisabled,
)}
disabled={disabledMonthSwitch}
aria-disabled={disabledMonthSwitch}
onClick={onMonthControlClick}
>
{getMonthShortName(getMonth(referenceDate), displayMonthLocale)}
</button>
<button
type="button"
className={cx(classes.button, classes.controlsButton)}
className={cx(
classes.button,
classes.controlsButton,
disabledYearSwitch && classes.buttonDisabled,
)}
disabled={disabledYearSwitch}
aria-disabled={disabledYearSwitch}
onClick={onYearControlClick}
>
{getYear(referenceDate)}
Expand All @@ -243,7 +272,13 @@ const Calendar = forwardRef<HTMLDivElement, CalendarProps>(function Calendar(pro
controls = (
<button
type="button"
className={cx(classes.button, classes.controlsButton)}
className={cx(
classes.button,
classes.controlsButton,
disabledYearSwitch && classes.buttonDisabled,
)}
disabled={disabledYearSwitch}
aria-disabled={disabledYearSwitch}
onClick={onYearControlClick}
>
{getYear(referenceDate)}
Expand Down
8 changes: 7 additions & 1 deletion packages/react/src/Calendar/CalendarDays.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
import { cx } from '../utils/cx';
import CalendarDayOfWeek, { CalendarDayOfWeekProps } from './CalendarDayOfWeek';
import { useCalendarContext } from './CalendarContext';
import type { CalendarYearsProps } from './CalendarYears';
import type { CalendarMonthsProps } from './CalendarMonths';

export interface CalendarDaysProps
extends
Pick<CalendarDayOfWeekProps, 'displayWeekDayLocale'>,
Pick<CalendarYearsProps, 'isYearDisabled'>,
Pick<CalendarMonthsProps, 'isMonthDisabled'>,
Omit<NativeElementPropsWithoutKeyAndRef<'div'>, 'onClick' | 'children'> {
/**
* Provide if you have a custom disabling logic. The method takes the date object as its parameter.
Expand Down Expand Up @@ -60,6 +64,8 @@ function CalendarDays(props: CalendarDaysProps) {
const {
className,
displayWeekDayLocale = displayWeekDayLocaleFromConfig,
isYearDisabled,
isMonthDisabled,
isDateDisabled,
isDateInRange,
onClick: onClickProp,
Expand Down Expand Up @@ -98,7 +104,7 @@ function CalendarDays(props: CalendarDaysProps) {
? thisMonth + 1
: thisMonth;
const date = setDate(setMonth(referenceDate, month), dateNum);
const disabled = isDateDisabled && isDateDisabled(date);
const disabled = (isYearDisabled?.(date) || isMonthDisabled?.(date) || isDateDisabled?.(date)) || false;
const inactive = !disabled && (isPrevMonth || isNextMonth);
const inRange = !inactive && isDateInRange && isDateInRange(date);
const active = !disabled && !inactive && value && isDateIncluded(date, value);
Expand Down
8 changes: 6 additions & 2 deletions packages/react/src/Calendar/CalendarMonths.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import {
DateType,
calendarMonths,
} from '@mezzanine-ui/core/calendar';
import type { CalendarYearsProps } from './CalendarYears';
import { cx } from '../utils/cx';
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
import { useCalendarContext } from './CalendarContext';

export interface CalendarMonthsProps
extends
Omit<NativeElementPropsWithoutKeyAndRef<'div'>, 'onClick' | 'children'> {
Omit<NativeElementPropsWithoutKeyAndRef<'div'>, 'onClick' | 'children'>,
Pick<CalendarYearsProps, 'isYearDisabled'> {
/**
* The locale you want to use when rendering the names of month.
* If none provided, it will use the `displayMonthLocale` from calendar context.
Expand Down Expand Up @@ -59,6 +61,7 @@ function CalendarMonths(props: CalendarMonthsProps) {
displayMonthLocale = displayMonthLocaleFromConfig,
isMonthDisabled,
isMonthInRange,
isYearDisabled,
onClick: onClickProp,
onMonthHover,
referenceDate,
Expand All @@ -80,7 +83,8 @@ function CalendarMonths(props: CalendarMonthsProps) {
{calendarMonths.map((month) => {
const monthDateType = setMonth(referenceDate, month);
const active = value && isMonthIncluded(monthDateType, value);
const disabled = isMonthDisabled && isMonthDisabled(monthDateType);
/** @NOTE Current month should be disabled when current year is disabled */
const disabled = (isYearDisabled?.(monthDateType) || isMonthDisabled?.(monthDateType)) || false;
const inRange = isMonthInRange && isMonthInRange(monthDateType);

const onClick = onClickProp ? () => { onClickProp(monthDateType); } : undefined;
Expand Down
8 changes: 7 additions & 1 deletion packages/react/src/Calendar/CalendarWeeks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
import { cx } from '../utils/cx';
import CalendarDayOfWeek, { CalendarDayOfWeekProps } from './CalendarDayOfWeek';
import { useCalendarContext } from './CalendarContext';
import type { CalendarYearsProps } from './CalendarYears';
import type { CalendarMonthsProps } from './CalendarMonths';

export interface CalendarWeeksProps
extends
Pick<CalendarDayOfWeekProps, 'displayWeekDayLocale'>,
Pick<CalendarYearsProps, 'isYearDisabled'>,
Pick<CalendarMonthsProps, 'isMonthDisabled'>,
Omit<NativeElementPropsWithoutKeyAndRef<'div'>, 'onClick' | 'children'> {
/**
* Provide if you have a custom disabling logic.
Expand Down Expand Up @@ -64,6 +68,8 @@ function CalendarWeeks(props: CalendarWeeksProps) {
const {
className,
displayWeekDayLocale = displayWeekDayLocaleFromConfig,
isYearDisabled,
isMonthDisabled,
isWeekDisabled,
isWeekInRange,
onClick: onClickProp,
Expand Down Expand Up @@ -105,7 +111,7 @@ function CalendarWeeks(props: CalendarWeeksProps) {
dates.push(date);
});

const disabled = isWeekDisabled && isWeekDisabled(dates[0]);
const disabled = (isYearDisabled?.(dates[0]) || isMonthDisabled?.(dates[0]) || isWeekDisabled?.(dates[0])) || false;
const inactive = !disabled && (weekStartInPrevMonth || weekStartInNextMonth);
const active = !disabled && !inactive && value && isWeekIncluded(dates[0], value);
const inRange = !disabled && !inactive && isWeekInRange && isWeekInRange(dates[0]);
Expand Down
106 changes: 88 additions & 18 deletions packages/react/src/DatePicker/DatePicker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import CalendarMethodsDayjs from '@mezzanine-ui/core/calendarMethodsDayjs';
import CalendarMethodsMoment from '@mezzanine-ui/core/calendarMethodsMoment';
import CalendarMethodsLuxon from '@mezzanine-ui/core/calendarMethodsLuxon';
import { useState } from 'react';
import { CSSProperties, useState } from 'react';
import moment from 'moment';
import DatePicker, { DatePickerProps } from './DatePicker';
import Typography from '../Typography';
Expand All @@ -18,7 +18,7 @@ export default {
} as Meta;

function usePickerChange() {
const [val, setVal] = useState<DateType | undefined>('2022-01-05');
const [val, setVal] = useState<DateType | undefined>(new Date().toISOString());
const onChange = (v?: DateType) => { setVal(v); };

return [val, onChange] as const;
Expand Down Expand Up @@ -135,7 +135,7 @@ export const Basic = () => {
export const Method = () => {
const containerStyle = { margin: '0 0 24px 0' };
const typoStyle = { margin: '0 0 12px 0' };
const [val, setVal] = useState<DateType>(new Date());
const [val, setVal] = useState<DateType | undefined>(new Date().toISOString());
const onChange = (v?: DateType) => { setVal(v); };

return (
Expand Down Expand Up @@ -277,18 +277,21 @@ export const Modes = () => {

export const CustomDisable = () => {
const containerStyle = { margin: '0 0 24px 0' };
const typoStyle = { margin: '0 0 12px 0' };
const typoStyle = { margin: '0 0 12px 0', whiteSpace: 'pre-line' } as CSSProperties;
const [valD, onChangeD] = usePickerChange();
const [valW, onChangeW] = usePickerChange();
const [valM, onChangeM] = usePickerChange();
const [valY, onChangeY] = usePickerChange();

// We use moment.date instead of moment.add is because storybook currently has internal conflict with the method.
const disabledDatesStart = moment().date(moment().date() - 7);
const disabledDatesStart = moment().date(moment().date() + 3);
const disabledDatesEnd = moment().date(moment().date() + 7);
const disabledMonthsStart = moment().month(moment().month() - 2);
const disabledMonthsEnd = moment().month(moment().month() + 2);
const disabledYearsStart = moment().year(moment().year() - 2);
const disabledYearsEnd = moment().year(moment().year() + 2);
const disabledWeeksStart = moment().week(moment().week() - 5);
const disabledWeeksEnd = moment().week(moment().week() - 2);
const disabledMonthsStart = moment().month(moment().month() - 5);
const disabledMonthsEnd = moment().month(moment().month() - 1);
const disabledYearsStart = moment().year(moment().year() - 20);
const disabledYearsEnd = moment().year(moment().year() - 1);

const isDateDisabled = (target: DateType) => (
moment(target).isBetween(
Expand All @@ -299,6 +302,15 @@ export const CustomDisable = () => {
)
);

const isWeekDisabled = (target: DateType) => (
moment(target).isBetween(
disabledWeeksStart,
disabledWeeksEnd,
'week',
'[]',
)
);

const isMonthDisabled = (target: DateType) => (
moment(target).isBetween(
disabledMonthsStart,
Expand All @@ -321,7 +333,31 @@ export const CustomDisable = () => {
<CalendarConfigProvider methods={CalendarMethodsMoment}>
<div style={containerStyle}>
<Typography variant="h5" style={typoStyle}>
{`Disabled Dates: ${disabledDatesStart.format('YYYY-MM-DD')} ~ ${disabledDatesEnd.format('YYYY-MM-DD')}`}
{`(mode='day')
disabledMonthSwitch = true
disabledYearSwitch = true
disableOnNext = true
disableOnPrev = true`}
</Typography>
<DatePicker
value={valD}
onChange={onChangeD}
mode="day"
format="YYYY-MM-DD"
placeholder="YYYY-MM-DD"
disabledMonthSwitch
disabledYearSwitch
disableOnNext
disableOnPrev
/>
</div>
<div style={containerStyle}>
<Typography variant="h5" style={typoStyle}>
{`(mode='day') Disabled
Years: ${disabledYearsStart.format('YYYY')} ~ ${disabledYearsEnd.format('YYYY')}
Months: ${disabledMonthsStart.format('YYYY-MM')} ~ ${disabledMonthsEnd.format('YYYY-MM')}
Dates: ${disabledDatesStart.format('YYYY-MM-DD')} ~ ${disabledDatesEnd.format('YYYY-MM-DD')}
`}
</Typography>
<DatePicker
value={valD}
Expand All @@ -330,33 +366,67 @@ export const CustomDisable = () => {
format="YYYY-MM-DD"
placeholder="YYYY-MM-DD"
isDateDisabled={isDateDisabled}
isMonthDisabled={isMonthDisabled}
isYearDisabled={isYearDisabled}
/>
</div>
<div style={containerStyle}>
<Typography variant="h5" style={typoStyle}>
{`Disabled Months:
${disabledMonthsStart.format('YYYY-MM')} ~ ${disabledMonthsEnd.format('YYYY-MM')}`}
{`(mode='week') Disabled
Years: ${disabledYearsStart.format('YYYY')} ~ ${disabledYearsEnd.format('YYYY')}
Months: ${disabledMonthsStart.format('YYYY-MM')} ~ ${disabledMonthsEnd.format('YYYY-MM')}
Weeks: ${disabledWeeksStart.format(getDefaultModeFormat('week'))} ~ ${disabledWeeksEnd.format(getDefaultModeFormat('week'))}`}
</Typography>
<DatePicker
value={valW}
onChange={onChangeW}
mode="week"
format={getDefaultModeFormat('week')}
placeholder={getDefaultModeFormat('week')}
isYearDisabled={isYearDisabled}
isMonthDisabled={isMonthDisabled}
isWeekDisabled={isWeekDisabled}
/>
</div>
<div style={containerStyle}>
<Typography variant="h5" style={typoStyle}>
{`(mode='day') Disabled Dates:
${disabledDatesStart.format(getDefaultModeFormat('day'))} ~ ${disabledDatesEnd.format(getDefaultModeFormat('day'))}`}
</Typography>
<DatePicker
value={valD}
onChange={onChangeD}
mode="day"
format={getDefaultModeFormat('day')}
placeholder={getDefaultModeFormat('day')}
isDateDisabled={isDateDisabled}
/>
</div>
<div style={containerStyle}>
<Typography variant="h5" style={typoStyle}>
{`(mode='month') Disabled Months:
${disabledMonthsStart.format(getDefaultModeFormat('month'))} ~ ${disabledMonthsEnd.format(getDefaultModeFormat('month'))}`}
</Typography>
<DatePicker
value={valM}
onChange={onChangeM}
mode="month"
format="YYYY-MM"
placeholder="YYYY-MM"
format={getDefaultModeFormat('month')}
placeholder={getDefaultModeFormat('month')}
isMonthDisabled={isMonthDisabled}
/>
</div>
<div style={containerStyle}>
<Typography variant="h5" style={typoStyle}>
{`Disabled Years:
${disabledYearsStart.format('YYYY')} ~ ${disabledYearsEnd.format('YYYY')}`}
{`(mode='year') Disabled Years:
${disabledYearsStart.format(getDefaultModeFormat('year'))} ~ ${disabledYearsEnd.format(getDefaultModeFormat('year'))}`}
</Typography>
<DatePicker
value={valY}
onChange={onChangeY}
mode="year"
format="YYYY"
placeholder="YYYY"
format={getDefaultModeFormat('year')}
placeholder={getDefaultModeFormat('year')}
isYearDisabled={isYearDisabled}
/>
</div>
Expand Down
Loading
Loading