Skip to content

Commit

Permalink
Add normalizeRenderedWeeks to render at fixed height, like a paper ca…
Browse files Browse the repository at this point in the history
…lendar
  • Loading branch information
Zertz committed Jun 18, 2024
1 parent f979bb3 commit 0f72497
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 22 deletions.
67 changes: 45 additions & 22 deletions packages/react/src/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
getWeekdays,
} from "@tempocal/core";
import * as React from "react";
import { CSSProperties } from "react";
import { Locale } from "./useTempocal";

type Value = Temporal.PlainDate | Temporal.PlainDateTime;
Expand All @@ -13,6 +14,7 @@ type MonthProps = {
locale: Locale;
maxValue?: Temporal.PlainDate | undefined;
minValue?: Temporal.PlainDate | undefined;
normalizeRenderedWeeks?: boolean;
rollover?: boolean;
startOfWeek?: number;
value: Value;
Expand Down Expand Up @@ -76,6 +78,7 @@ export function Calendar({
minValue,
monthsAfter = 0,
monthsBefore = 0,
normalizeRenderedWeeks,
rollover,
startOfWeek,
value,
Expand Down Expand Up @@ -105,6 +108,7 @@ export function Calendar({
locale={locale}
maxValue={maxValue}
minValue={minValue}
normalizeRenderedWeeks={normalizeRenderedWeeks}
rollover={rollover}
startOfWeek={startOfWeek}
value={value.add({ months: month - monthsBefore })}
Expand All @@ -127,6 +131,7 @@ function Month({
locale,
maxValue,
minValue,
normalizeRenderedWeeks = false,
rollover = false,
startOfWeek = 7,
value,
Expand Down Expand Up @@ -160,6 +165,19 @@ function Month({
[end, start]
);

const firstDay = days.at(0);

const gridColumnStart =
!rollover && firstDay
? startOfWeek > firstDay.dayOfWeek
? firstDay.daysInWeek - (startOfWeek - firstDay.dayOfWeek) + 1
: Math.abs(startOfWeek - firstDay.dayOfWeek) + 1
: undefined;

const daysToPadAfter = normalizeRenderedWeeks
? start.daysInWeek * 6 - start.daysInMonth - (gridColumnStart || 0) + 1
: 0;

return (
<ul
{...calendarProps?.()}
Expand Down Expand Up @@ -187,17 +205,38 @@ function Month({
<Day
key={date.dayOfYear}
date={date}
day={day}
disabled={
(!!minValue && Temporal.PlainDate.compare(date, minValue) < 0) ||
(!!maxValue && Temporal.PlainDate.compare(date, maxValue) > 0)
}
dayProps={dayProps}
style={day === 0 ? { gridColumnStart } : undefined}
renderDay={renderDay}
rollover={rollover}
startOfWeek={startOfWeek}
/>
))}
{daysToPadAfter > 0 && firstDay && (
<>
{[...Array(Math.floor(daysToPadAfter / firstDay.daysInWeek))].map(
(_, index) => (
<Day
key={index}
date={firstDay}
disabled
dayProps={dayProps}
style={{
gridColumn: `span ${Math.min(
daysToPadAfter,
firstDay.daysInWeek
)}`,
opacity: daysToPadAfter,
visibility: "hidden",
}}
renderDay={renderDay}
/>
)
)}
</>
)}
{renderFooter && (
<li
{...footerProps?.({ date: monthStartDate })}
Expand All @@ -214,18 +253,14 @@ function Month({

function Day({
date,
day,
disabled,
dayProps,
renderDay,
rollover,
startOfWeek,
style,
}: Pick<MonthProps, "dayProps" | "renderDay"> & {
date: Temporal.PlainDate;
day: number;
disabled: boolean;
rollover: boolean;
startOfWeek: number;
style: CSSProperties | undefined;
}) {
const props = React.useMemo(() => {
const plainDateLike: Temporal.PlainDateLike = {
Expand All @@ -243,19 +278,7 @@ function Day({
}, [date, disabled]);

return (
<li
{...dayProps?.(props)}
style={
!rollover && day === 0
? {
gridColumnStart:
startOfWeek > date.dayOfWeek
? date.daysInWeek - (startOfWeek - date.dayOfWeek) + 1
: Math.abs(startOfWeek - date.dayOfWeek) + 1,
}
: undefined
}
>
<li {...dayProps?.(props)} style={style}>
{renderDay ? renderDay(props) : date.day}
</li>
);
Expand Down
3 changes: 3 additions & 0 deletions packages/www/examples/DateRangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ const dateFormatter = new Intl.DateTimeFormat(locale, {
export function DateRangePicker({
monthsAfter,
monthsBefore,
normalizeRenderedWeeks,
}: {
monthsAfter: number;
monthsBefore: number;
normalizeRenderedWeeks: boolean;
}) {
const [values, setValues] = React.useState<DateRange>([
Temporal.Now.plainDate("iso8601").subtract({ days: 3 }),
Expand Down Expand Up @@ -59,6 +61,7 @@ export function DateRangePicker({
{...calendarProps}
monthsBefore={monthsBefore}
monthsAfter={monthsAfter}
normalizeRenderedWeeks={normalizeRenderedWeeks}
calendarProps={() => ({
className: "gap-1 text-center w-72",
})}
Expand Down
17 changes: 17 additions & 0 deletions packages/www/pages/examples/DateRangePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { InferGetStaticPropsType } from "next";
import * as React from "react";
import { Checkbox } from "../../components/Checkbox";
import { Example } from "../../components/Example";
import { Input } from "../../components/Input";
import { DateRangePicker } from "../../examples/DateRangePicker";
Expand All @@ -11,12 +12,16 @@ export default function DateRangePickerPage(
const [monthsBefore, setMonthsBefore] = React.useState(0);
const [monthsAfter, setMonthsAfter] = React.useState(0);

const [normalizeRenderedWeeks, setNormalizeRenderedWeeks] =
React.useState(true);

return (
<Example
demo={
<DateRangePicker
monthsAfter={monthsAfter}
monthsBefore={monthsBefore}
normalizeRenderedWeeks={normalizeRenderedWeeks}
/>
}
title="DateRangePicker"
Expand Down Expand Up @@ -44,6 +49,18 @@ export default function DateRangePickerPage(
type="number"
value={monthsAfter}
/>
<Checkbox
checked={normalizeRenderedWeeks}
hint="Always render the calendar with the same number of weeks, as if it were a paper calendar."
id="normalizeRenderedWeeks"
label="normalizeRenderedWeeks"
name="normalizeRenderedWeeks"
onChange={() => {
setNormalizeRenderedWeeks(
(normalizeRenderedWeeks) => !normalizeRenderedWeeks
);
}}
/>
</fieldset>
</Example>
);
Expand Down

0 comments on commit 0f72497

Please sign in to comment.