Skip to content
Open
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ env:
jobs:
lint:
name: Static code analysis
runs-on: ubuntu-latest
runs-on: ubuntu-24.04-arm

steps:
- name: Checkout
Expand All @@ -26,7 +26,7 @@ jobs:

typescript:
name: Type checking
runs-on: ubuntu-latest
runs-on: ubuntu-24.04-arm

steps:
- name: Checkout
Expand Down Expand Up @@ -61,7 +61,7 @@ jobs:

format:
name: Formatting
runs-on: ubuntu-latest
runs-on: ubuntu-24.04-arm

steps:
- name: Checkout
Expand All @@ -75,7 +75,7 @@ jobs:

unit:
name: Unit tests
runs-on: ubuntu-latest
runs-on: ubuntu-24.04-arm

steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/close-stale-issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
jobs:
close-issues:
name: Close stale issues
runs-on: ubuntu-latest
runs-on: ubuntu-24.04-arm

steps:
- name: Close stale issues
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ permissions:
jobs:
publish:
name: Publish
runs-on: ubuntu-latest
runs-on: ubuntu-24.04-arm

steps:
- name: Checkout
Expand Down
4 changes: 2 additions & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"recommendations": ["biomejs.biome", "eamodio.gitlens"],
"unwantedRecommendations": ["dbaeumer.jshint"]
"recommendations": ["biomejs.biome"],
"unwantedRecommendations": ["dbaeumer.jshint", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
"devDependencies": {
"husky": "^9.0.0"
},
"packageManager": "yarn@4.3.1"
"packageManager": "yarn@4.6.0"
}
2 changes: 1 addition & 1 deletion packages/react-calendar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"react-dom": "^18.2.0",
"rimraf": "^6.0.0",
"typescript": "^5.5.2",
"vitest": "^2.1.1"
"vitest": "^3.0.5"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
Expand Down
59 changes: 47 additions & 12 deletions packages/react-calendar/src/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ import type {
formatWeekday as defaultFormatWeekday,
formatYear as defaultFormatYear,
} from './shared/dateFormatter.js';
import WeekView from './WeekView.js';

const baseClassName = 'react-calendar';
const allViews = ['century', 'decade', 'year', 'month'] as const;
const allValueTypes = ['decade', 'year', 'month', 'day'] as const;
const allViews = ['century', 'decade', 'year', 'month', 'week'] as const;
const allValueTypes = ['decade', 'year', 'month', 'day', 'day'] as const;

const defaultMinDate = new Date();
defaultMinDate.setFullYear(1, 0, 1);
Expand Down Expand Up @@ -487,13 +488,14 @@ function getValue(value: LooseValue | undefined, index: 0 | 1): Date | null {
}

type DetailArgs = {
calendarType?: CalendarType;
value?: LooseValue;
minDate?: Date;
maxDate?: Date;
maxDetail: Detail;
};

function getDetailValue({ value, minDate, maxDate, maxDetail }: DetailArgs, index: 0 | 1) {
function getDetailValue({ calendarType, value, minDate, maxDate, maxDetail }: DetailArgs, index: 0 | 1) {
const valuePiece = getValue(value, index);

if (!valuePiece) {
Expand All @@ -505,9 +507,9 @@ function getDetailValue({ value, minDate, maxDate, maxDetail }: DetailArgs, inde
const detailValueFrom = (() => {
switch (index) {
case 0:
return getBegin(valueType, valuePiece);
return getBegin(valueType, valuePiece, calendarType);
case 1:
return getEnd(valueType, valuePiece);
return getEnd(valueType, valuePiece, calendarType);
default:
throw new Error(`Invalid index value: ${index}`);
}
Expand All @@ -527,6 +529,7 @@ const getDetailValueArray = (args: DetailArgs) =>
];

function getActiveStartDate({
calendarType,
maxDate,
maxDetail,
minDate,
Expand All @@ -540,17 +543,19 @@ function getActiveStartDate({
const rangeType = getView(view, minDetail, maxDetail);
const valueFrom =
getDetailValueFrom({
calendarType,
value,
minDate,
maxDate,
maxDetail,
}) || new Date();

return getBegin(rangeType, valueFrom);
return getBegin(rangeType, valueFrom, calendarType);
}

function getInitialActiveStartDate({
activeStartDate,
calendarType,
defaultActiveStartDate,
defaultValue,
defaultView,
Expand All @@ -562,6 +567,7 @@ function getInitialActiveStartDate({
view,
}: {
activeStartDate?: Date;
calendarType?: CalendarType;
defaultActiveStartDate?: Date;
defaultValue?: LooseValue;
defaultView?: View;
Expand All @@ -576,10 +582,11 @@ function getInitialActiveStartDate({
const valueFrom = activeStartDate || defaultActiveStartDate;

if (valueFrom) {
return getBegin(rangeType, valueFrom);
return getBegin(rangeType, valueFrom, calendarType);
}

return getActiveStartDate({
calendarType,
maxDate,
maxDetail,
minDate,
Expand Down Expand Up @@ -675,6 +682,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
activeStartDateProps ||
activeStartDateState ||
getInitialActiveStartDate({
calendarType,
activeStartDate: activeStartDateProps,
defaultActiveStartDate,
defaultValue,
Expand Down Expand Up @@ -736,13 +744,14 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
})();

return processFunction({
calendarType,
maxDate,
maxDetail,
minDate,
value,
});
},
[maxDate, maxDetail, minDate, returnValue],
[calendarType, maxDate, maxDetail, minDate, returnValue],
);

const setActiveStartDate = useCallback(
Expand Down Expand Up @@ -773,6 +782,8 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
return onClickYear;
case 'year':
return onClickMonth;
case 'week':
return onClickDay;
case 'month':
return onClickDay;
default:
Expand Down Expand Up @@ -845,7 +856,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
throw new Error('Attempted to drill up from the highest view.');
}

const nextActiveStartDate = getBegin(nextView, activeStartDate);
const nextActiveStartDate = getBegin(nextView, activeStartDate, calendarType);

setActiveStartDateState(nextActiveStartDate);
setViewState(nextView);
Expand All @@ -870,6 +881,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
}
}, [
activeStartDate,
calendarType,
drillUpAvailable,
onActiveStartDateChange,
onDrillUp,
Expand All @@ -894,7 +906,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
if (isFirstValueInRange) {
// Value has 0 or 2 elements - either way we're starting a new array
// First value
nextValue = getBegin(valueType, rawNextValue);
nextValue = getBegin(valueType, rawNextValue, calendarType);
} else {
if (!previousValue) {
throw new Error('previousValue is required');
Expand All @@ -920,6 +932,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
// Range selection turned on, second value, goToRangeStartOnSelect toggled on
goToRangeStartOnSelect
? getActiveStartDate({
calendarType,
maxDate,
maxDetail,
minDate,
Expand Down Expand Up @@ -966,6 +979,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
[
activeStartDate,
allowPartialRange,
calendarType,
getProcessedValue,
goToRangeStartOnSelect,
maxDate,
Expand Down Expand Up @@ -1006,8 +1020,8 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu

function renderContent(next?: boolean) {
const currentActiveStartDate = next
? getBeginNext(view, activeStartDate)
: getBegin(view, activeStartDate);
? getBeginNext(view, activeStartDate, calendarType)
: getBegin(view, activeStartDate, calendarType);

const onClick = drillDownAvailable ? drillDown : onChange;

Expand Down Expand Up @@ -1075,6 +1089,26 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
/>
);
}
case 'week': {
return (
<WeekView
calendarType={calendarType}
formatDay={formatDay}
formatLongDate={formatLongDate}
formatShortWeekday={formatShortWeekday}
formatWeekday={formatWeekday}
onClickWeekNumber={onClickWeekNumber}
onMouseLeave={selectRange ? onMouseLeave : undefined}
showFixedNumberOfWeeks={
typeof showFixedNumberOfWeeks !== 'undefined'
? showFixedNumberOfWeeks
: showDoubleView
}
showWeekNumbers={showWeekNumbers}
{...commonProps}
/>
);
}
default:
throw new Error(`Invalid view: ${view}.`);
}
Expand All @@ -1088,6 +1122,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
return (
<Navigation
activeStartDate={activeStartDate}
calendarType={calendarType}
drillUp={drillUp}
formatMonthYear={formatMonthYear}
formatYear={formatYear}
Expand Down
2 changes: 1 addition & 1 deletion packages/react-calendar/src/Calendar/Navigation.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { fireEvent, render } from '@testing-library/react';

import Navigation from './Navigation.js';

const allViews = ['century', 'decade', 'year', 'month'];
const allViews = ['century', 'decade', 'year', 'month', 'week'];

describe('Navigation', () => {
const defaultProps = {
Expand Down
Loading
Loading