Skip to content

Commit

Permalink
allow side by side calendar view
Browse files Browse the repository at this point in the history
  • Loading branch information
steppy452 committed Feb 13, 2024
1 parent 0425228 commit dd0b235
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 22 deletions.
10 changes: 9 additions & 1 deletion src/form/Calendar/Calendar.module.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
.container {
overflow: hidden;

.header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: var(--spacing-sm);
}
overflow: hidden;

.multiviewLabel {
display: flex;
flex-grow: 1;
justify-content: space-around;
gap: var(--spacing-lg);
}
}
15 changes: 15 additions & 0 deletions src/form/Calendar/Calendar.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,18 @@ export const Range = () => {
</Card>
);
};

export const Multiview = () => {
const [range, setRange] = useState<[Date, Date]>();

return (
<Card>
<Calendar
value={range}
onChange={val => setRange(val as [Date, Date])}
isMultiview
isRange
/>
</Card>
);
};
27 changes: 22 additions & 5 deletions src/form/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { FC, useCallback, useMemo, useState } from 'react';
import { Button } from '../../elements/Button';
import {
add,
addMonths,
addYears,
endOfDecade,
getMonth,
Expand Down Expand Up @@ -53,6 +54,11 @@ export interface CalendarProps {
*/
isRange?: boolean;

/**
* Whether the calendar should display two months side by side.
*/
isMultiview?: boolean;

/**
* The text or icon to use for next.
*/
Expand Down Expand Up @@ -90,6 +96,7 @@ export const Calendar: FC<CalendarProps> = ({
value,
disabled,
isRange,
isMultiview,
previousArrow,
nextArrow,
dateFormat,
Expand Down Expand Up @@ -220,11 +227,20 @@ export const Calendar: FC<CalendarProps> = ({
>
<SmallHeading disableMargins>
{view === 'days' && (
<DateFormat
date={viewValue}
format={dateFormat}
allowToggle={false}
/>
<div className={css.multiviewLabel}>
<DateFormat
date={viewValue}
format={dateFormat}
allowToggle={false}
/>
{isMultiview && (
<DateFormat
date={addMonths(viewValue, 1)}
format={dateFormat}
allowToggle={false}
/>
)}
</div>
)}
{view === 'months' && <>{yearValue}</>}
{view === 'years' && (
Expand Down Expand Up @@ -262,6 +278,7 @@ export const Calendar: FC<CalendarProps> = ({
max={max}
disabled={disabled}
isRange={isRange}
isMultiview={isMultiview}
current={isRange ? [rangeStart, rangeEnd] : date}
xAnimation={xAnimation}
animated={animated}
Expand Down
5 changes: 5 additions & 0 deletions src/form/Calendar/CalendarDays/CalendarDays.module.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
.container {
display: flex;
gap: var(--spacing-lg);
}

.week {
display: flex;

Expand Down
61 changes: 45 additions & 16 deletions src/form/Calendar/CalendarDays/CalendarDays.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
isSameDay,
set,
max as maxDate,
min as minDate
min as minDate,
addMonths
} from 'date-fns';
import { Button } from '../../../elements/Button';
import { getWeeks } from '../utils';
Expand Down Expand Up @@ -46,6 +47,11 @@ export interface CalendarDaysProps {
*/
isRange?: boolean;

/**
* Whether the calendar should display two months side by side.
*/
isMultiview?: boolean;

/**
* Range of selected dates
*/
Expand Down Expand Up @@ -78,6 +84,7 @@ export const CalendarDays: FC<CalendarDaysProps> = ({
value = new Date(),
current = new Date(),
isRange,
isMultiview,
disabled,
min: minLimit,
max,
Expand All @@ -87,6 +94,9 @@ export const CalendarDays: FC<CalendarDaysProps> = ({
}) => {
const [hoveringDate, setHoveringDate] = useState<Date | null>(null);
const weeks = useMemo(() => getWeeks(value), [value]);
const multiweeks = isMultiview
? useMemo(() => getWeeks(addMonths(value, 1)), [value])
: null;
const maxLimit = useMemo(() => (max === 'now' ? new Date() : max), [max]);

const renderDay = useCallback(
Expand Down Expand Up @@ -165,21 +175,40 @@ export const CalendarDays: FC<CalendarDaysProps> = ({

return (
<AnimatePresence mode="popLayout">
<motion.div
key={value.toString()}
initial={{ opacity: 0, x: xAnimation }}
animate={{ opacity: 1, x: 0 }}
transition={{
x: { type: animated ? 'keyframes' : false },
opacity: { duration: 0.2, type: animated ? 'tween' : false }
}}
>
{weeks.map((week, i) => (
<div key={`week-${i}`} className={css.week}>
{week.map(renderDay)}
</div>
))}
</motion.div>
<div className={css.container}>
<motion.div
key={value.toString()}
initial={{ opacity: 0, x: xAnimation }}
animate={{ opacity: 1, x: 0 }}
transition={{
x: { type: animated ? 'keyframes' : false },
opacity: { duration: 0.2, type: animated ? 'tween' : false }
}}
>
{weeks.map((week, i) => (
<div key={`week-${i}`} className={css.week}>
{week.map(renderDay)}
</div>
))}
</motion.div>
{isMultiview && multiweeks && (
<motion.div
key={`multiview-${value.toString()}`}
initial={{ opacity: 0, x: xAnimation }}
animate={{ opacity: 1, x: 0 }}
transition={{
x: { type: animated ? 'keyframes' : false },
opacity: { duration: 0.2, type: animated ? 'tween' : false }
}}
>
{multiweeks.map((week, i) => (
<div key={`multiweek-${i}`} className={css.week}>
{week.map(renderDay)}
</div>
))}
</motion.div>
)}
</div>
</AnimatePresence>
);
};

0 comments on commit dd0b235

Please sign in to comment.