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

[@mantine/dates] Showing Week Numbers in Calendar Component #7179

Merged
merged 5 commits into from
Nov 28, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { DatePicker } from '@mantine/dates';
import { MantineDemo } from '@mantinex/demo';

const code = `
import { DatePicker } from '@mantine/dates';

function Demo() {
return <DatePicker withWeekNumbers />;
}
`;

function Demo() {
return <DatePicker withWeekNumbers />;
}

export const withWeekNumbers: MantineDemo = {
type: 'code',
centered: true,
component: Demo,
code,
};
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,8 @@ export const Demo_excludeDate = {
name: '⭐ Demo: excludeDate',
render: renderDemo(demos.excludeDate),
};

export const Demo_withWeekNumbers = {
name: '⭐ Demo: withWeekNumbers',
render: renderDemo(demos.withWeekNumbers),
};
1 change: 1 addition & 0 deletions packages/@docs/demos/src/demos/dates/DatePicker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ export { renderDay } from './DatePicker.demo.renderDay';
export { hideWeekdays } from './DatePicker.demo.hideWeekdays';
export { hideOutsideDates } from './DatePicker.demo.hideOutsideDates';
export { excludeDate } from './DatePicker.demo.excludeDate';
export { withWeekNumbers } from './DatePicker.demo.withWeekNumbers';
1 change: 1 addition & 0 deletions packages/@docs/styles-api/src/data/Dates.styles-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const MonthStylesApi: StylesApiData<MonthFactory> = {
weekdaysRow: 'Weekdays tr element',
weekday: 'Weekday th element',
day: 'Month day control',
weekNumber: 'Week number td element',
},

vars: {},
Expand Down
2 changes: 2 additions & 0 deletions packages/@mantine/dates/src/components/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ export const Calendar = factory<CalendarFactory>((_props, ref) => {
__onDayMouseEnter,
withCellSpacing,
highlightToday,
withWeekNumbers,

// YearLevelGroup props
monthsListFormat,
Expand Down Expand Up @@ -349,6 +350,7 @@ export const Calendar = factory<CalendarFactory>((_props, ref) => {
static={isStatic}
withCellSpacing={withCellSpacing}
highlightToday={highlightToday}
withWeekNumbers={withWeekNumbers}
{...stylesApiProps}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
--dch-control-size: var(--dch-control-size-sm);

display: flex;
max-width: calc(var(--dch-control-size) * 7 + rem(7px));
max-width: calc(var(--dch-control-size) * 8 + rem(7px));
margin-bottom: var(--mantine-spacing-xs);
}

Expand Down
13 changes: 13 additions & 0 deletions packages/@mantine/dates/src/components/Month/Month.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,16 @@
padding: 0.5px;
}
}

.weekNumber {
--wn-size-xs: 30px;
--wn-size-sm: 36px;
rtivital marked this conversation as resolved.
Show resolved Hide resolved
--wn-size-md: 42px;
--wn-size-lg: 48px;
--wn-size-xl: 54px;
color: var(--mantine-color-dimmed);
font-weight: normal;
font-size: var(--wn-fz, var(--mantine-font-size-sm));
text-align: center;
width: var(--wn-size, var(--wn-size-sm));
}
4 changes: 4 additions & 0 deletions packages/@mantine/dates/src/components/Month/Month.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,7 @@ export function Sizes() {
));
return sizes;
}

export function withWeekNumbers() {
return <Wrapper withWeekNumbers />;
}
19 changes: 19 additions & 0 deletions packages/@mantine/dates/src/components/Month/Month.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import dayjs from 'dayjs';
import {
Box,
BoxProps,
createVarsResolver,
ElementProps,
factory,
Factory,
getFontSize,
getSize,
MantineSize,
StylesApiProps,
useProps,
Expand All @@ -17,6 +20,7 @@ import { Day, DayProps, DayStylesNames } from '../Day';
import { WeekdaysRow } from '../WeekdaysRow';
import { getDateInTabOrder } from './get-date-in-tab-order/get-date-in-tab-order';
import { getMonthDays } from './get-month-days/get-month-days';
import { getWeekNumber } from './get-week-number/get-week-number';
import { isAfterMinDate } from './is-after-min-date/is-after-min-date';
import { isBeforeMaxDate } from './is-before-max-date/is-before-max-date';
import { isSameMonth } from './is-same-month/is-same-month';
Expand All @@ -31,6 +35,7 @@ export type MonthStylesNames =
| 'monthThead'
| 'monthTbody'
| 'monthCell'
| 'weekNumber'
| DayStylesNames;

export interface MonthSettings {
Expand Down Expand Up @@ -99,6 +104,9 @@ export interface MonthSettings {

/** Determines whether today should be highlighted with a border, `false` by default */
highlightToday?: boolean;

/** Determines whether week numbers should be displayed */
withWeekNumbers?: boolean;
}

export interface MonthProps
Expand All @@ -125,6 +133,13 @@ const defaultProps: Partial<MonthProps> = {
withCellSpacing: true,
};

const varsResolver = createVarsResolver<MonthFactory>((_, { size }) => ({
weekNumber: {
'--wn-fz': getFontSize(size),
'--wn-size': getSize(size, 'wn-size'),
},
}));

export const Month = factory<MonthFactory>((_props, ref) => {
const props = useProps('Month', defaultProps, _props);
const {
Expand Down Expand Up @@ -158,6 +173,7 @@ export const Month = factory<MonthFactory>((_props, ref) => {
withCellSpacing,
size,
highlightToday,
withWeekNumbers,
...others
} = props;

Expand All @@ -171,6 +187,7 @@ export const Month = factory<MonthFactory>((_props, ref) => {
styles,
unstyled,
vars,
varsResolver,
rootSelector: 'month',
});

Expand Down Expand Up @@ -261,6 +278,7 @@ export const Month = factory<MonthFactory>((_props, ref) => {

return (
<tr key={rowIndex} {...getStyles('monthRow')}>
{withWeekNumbers && <td {...getStyles('weekNumber')}>{getWeekNumber(row)}</td>}
{cells}
</tr>
);
Expand All @@ -279,6 +297,7 @@ export const Month = factory<MonthFactory>((_props, ref) => {
classNames={resolvedClassNames}
styles={resolvedStyles}
unstyled={unstyled}
withWeekNumbers={withWeekNumbers}
/>
</thead>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { getWeekNumber } from './get-week-number';

describe('@mantine/dates/get-week-number', () => {
it('should return the correct ISO week number for a given week', () => {
const week = [
new Date('2023-01-02'), // Monday
new Date('2023-01-03'), // Tuesday
new Date('2023-01-04'), // Wednesday
new Date('2023-01-05'), // Thursday
new Date('2023-01-06'), // Friday
new Date('2023-01-07'), // Saturday
new Date('2023-01-08'), // Sunday
];
expect(getWeekNumber(week)).toBe(1);
});

it('should return the correct ISO week number when the week spans two years', () => {
const week = [
new Date('2022-12-26'), // Monday
new Date('2022-12-27'), // Tuesday
new Date('2022-12-28'), // Wednesday
new Date('2022-12-29'), // Thursday
new Date('2022-12-30'), // Friday
new Date('2022-12-31'), // Saturday
new Date('2023-01-01'), // Sunday
];
expect(getWeekNumber(week)).toBe(52);
});

it('should return the correct ISO week number for a week in the middle of the year', () => {
const week = [
new Date('2023-06-12'), // Monday
new Date('2023-06-13'), // Tuesday
new Date('2023-06-14'), // Wednesday
new Date('2023-06-15'), // Thursday
new Date('2023-06-16'), // Friday
new Date('2023-06-17'), // Saturday
new Date('2023-06-18'), // Sunday
];
expect(getWeekNumber(week)).toBe(24);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import dayjs from 'dayjs';
import isoWeek from 'dayjs/plugin/isoWeek.js';

dayjs.extend(isoWeek);

export function getWeekNumber(week: Date[]): number {
const monday = week.find((date) => dayjs(date).day() === 1);
return dayjs(monday).isoWeek();
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export const MonthLevel = factory<MonthLevelFactory>((_props, ref) => {
__onDayMouseEnter,
withCellSpacing,
highlightToday,
withWeekNumbers,

// CalendarHeader settings
__preventFocus,
Expand Down Expand Up @@ -181,6 +182,7 @@ export const MonthLevel = factory<MonthLevelFactory>((_props, ref) => {
static={isStatic}
withCellSpacing={withCellSpacing}
highlightToday={highlightToday}
withWeekNumbers={withWeekNumbers}
{...stylesApiProps}
/>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const MonthLevelGroup = factory<MonthLevelGroupFactory>((_props, ref) =>
__onDayMouseEnter,
withCellSpacing,
highlightToday,
withWeekNumbers,

// CalendarHeader settings
__preventFocus,
Expand Down Expand Up @@ -162,6 +163,7 @@ export const MonthLevelGroup = factory<MonthLevelGroupFactory>((_props, ref) =>
static={isStatic}
withCellSpacing={withCellSpacing}
highlightToday={highlightToday}
withWeekNumbers={withWeekNumbers}
/>
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export interface WeekdaysRowProps

/** Choose cell type that will be used to render weekdays, defaults to th */
cellComponent?: 'td' | 'th';

/** Determines whether week numbers should be displayed */
withWeekNumbers?: boolean;
}

export type WeekdaysRowFactory = Factory<{
Expand Down Expand Up @@ -74,6 +77,7 @@ export const WeekdaysRow = factory<WeekdaysRowFactory>((_props, ref) => {
weekdayFormat,
cellComponent: CellComponent = 'th',
__staticSelector,
withWeekNumbers,
...others
} = props;

Expand Down Expand Up @@ -105,6 +109,7 @@ export const WeekdaysRow = factory<WeekdaysRowFactory>((_props, ref) => {

return (
<Box component="tr" ref={ref} {...getStyles('weekdaysRow')} {...others}>
{withWeekNumbers && <CellComponent {...getStyles('weekday')}>#</CellComponent>}
{weekdays}
</Box>
);
Expand Down
1 change: 1 addition & 0 deletions scripts/build/rollup/rollup-externals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const ROLLUP_EXTERNALS = [
'dayjs/plugin/customParseFormat',
'dayjs/plugin/utc.js',
'dayjs/plugin/timezone.js',
'dayjs/plugin/isoWeek.js',
'klona/full',
'highlight.js/lib/languages/typescript',
'react-is',
Expand Down