Skip to content

Commit 92fe5c8

Browse files
committed
feat: Added a WeekView
change index for week pass calendarType
1 parent b66d28e commit 92fe5c8

25 files changed

+2083
-660
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@
2121
"devDependencies": {
2222
"husky": "^9.0.0"
2323
},
24-
"packageManager": "yarn@4.3.1"
24+
"packageManager": "yarn@4.6.0"
2525
}

packages/react-calendar/src/Calendar.tsx

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,11 @@ import type {
3939
formatWeekday as defaultFormatWeekday,
4040
formatYear as defaultFormatYear,
4141
} from './shared/dateFormatter.js';
42+
import WeekView from './WeekView.js';
4243

4344
const baseClassName = 'react-calendar';
44-
const allViews = ['century', 'decade', 'year', 'month'] as const;
45-
const allValueTypes = ['decade', 'year', 'month', 'day'] as const;
45+
const allViews = ['century', 'decade', 'year', 'month', 'week'] as const;
46+
const allValueTypes = ['decade', 'year', 'month', 'day', 'day'] as const;
4647

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

489490
type DetailArgs = {
491+
calendarType?: CalendarType;
490492
value?: LooseValue;
491493
minDate?: Date;
492494
maxDate?: Date;
493495
maxDetail: Detail;
494496
};
495497

496-
function getDetailValue({ value, minDate, maxDate, maxDetail }: DetailArgs, index: 0 | 1) {
498+
function getDetailValue({ calendarType, value, minDate, maxDate, maxDetail }: DetailArgs, index: 0 | 1) {
497499
const valuePiece = getValue(value, index);
498500

499501
if (!valuePiece) {
@@ -505,9 +507,9 @@ function getDetailValue({ value, minDate, maxDate, maxDetail }: DetailArgs, inde
505507
const detailValueFrom = (() => {
506508
switch (index) {
507509
case 0:
508-
return getBegin(valueType, valuePiece);
510+
return getBegin(valueType, valuePiece, calendarType);
509511
case 1:
510-
return getEnd(valueType, valuePiece);
512+
return getEnd(valueType, valuePiece, calendarType);
511513
default:
512514
throw new Error(`Invalid index value: ${index}`);
513515
}
@@ -527,6 +529,7 @@ const getDetailValueArray = (args: DetailArgs) =>
527529
];
528530

529531
function getActiveStartDate({
532+
calendarType,
530533
maxDate,
531534
maxDetail,
532535
minDate,
@@ -540,17 +543,19 @@ function getActiveStartDate({
540543
const rangeType = getView(view, minDetail, maxDetail);
541544
const valueFrom =
542545
getDetailValueFrom({
546+
calendarType,
543547
value,
544548
minDate,
545549
maxDate,
546550
maxDetail,
547551
}) || new Date();
548552

549-
return getBegin(rangeType, valueFrom);
553+
return getBegin(rangeType, valueFrom, calendarType);
550554
}
551555

552556
function getInitialActiveStartDate({
553557
activeStartDate,
558+
calendarType,
554559
defaultActiveStartDate,
555560
defaultValue,
556561
defaultView,
@@ -562,6 +567,7 @@ function getInitialActiveStartDate({
562567
view,
563568
}: {
564569
activeStartDate?: Date;
570+
calendarType?: CalendarType;
565571
defaultActiveStartDate?: Date;
566572
defaultValue?: LooseValue;
567573
defaultView?: View;
@@ -576,10 +582,11 @@ function getInitialActiveStartDate({
576582
const valueFrom = activeStartDate || defaultActiveStartDate;
577583

578584
if (valueFrom) {
579-
return getBegin(rangeType, valueFrom);
585+
return getBegin(rangeType, valueFrom, calendarType);
580586
}
581587

582588
return getActiveStartDate({
589+
calendarType,
583590
maxDate,
584591
maxDetail,
585592
minDate,
@@ -675,6 +682,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
675682
activeStartDateProps ||
676683
activeStartDateState ||
677684
getInitialActiveStartDate({
685+
calendarType,
678686
activeStartDate: activeStartDateProps,
679687
defaultActiveStartDate,
680688
defaultValue,
@@ -736,13 +744,14 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
736744
})();
737745

738746
return processFunction({
747+
calendarType,
739748
maxDate,
740749
maxDetail,
741750
minDate,
742751
value,
743752
});
744753
},
745-
[maxDate, maxDetail, minDate, returnValue],
754+
[calendarType, maxDate, maxDetail, minDate, returnValue],
746755
);
747756

748757
const setActiveStartDate = useCallback(
@@ -773,6 +782,8 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
773782
return onClickYear;
774783
case 'year':
775784
return onClickMonth;
785+
case 'week':
786+
return onClickDay;
776787
case 'month':
777788
return onClickDay;
778789
default:
@@ -845,7 +856,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
845856
throw new Error('Attempted to drill up from the highest view.');
846857
}
847858

848-
const nextActiveStartDate = getBegin(nextView, activeStartDate);
859+
const nextActiveStartDate = getBegin(nextView, activeStartDate, calendarType);
849860

850861
setActiveStartDateState(nextActiveStartDate);
851862
setViewState(nextView);
@@ -870,6 +881,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
870881
}
871882
}, [
872883
activeStartDate,
884+
calendarType,
873885
drillUpAvailable,
874886
onActiveStartDateChange,
875887
onDrillUp,
@@ -894,7 +906,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
894906
if (isFirstValueInRange) {
895907
// Value has 0 or 2 elements - either way we're starting a new array
896908
// First value
897-
nextValue = getBegin(valueType, rawNextValue);
909+
nextValue = getBegin(valueType, rawNextValue, calendarType);
898910
} else {
899911
if (!previousValue) {
900912
throw new Error('previousValue is required');
@@ -920,6 +932,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
920932
// Range selection turned on, second value, goToRangeStartOnSelect toggled on
921933
goToRangeStartOnSelect
922934
? getActiveStartDate({
935+
calendarType,
923936
maxDate,
924937
maxDetail,
925938
minDate,
@@ -966,6 +979,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
966979
[
967980
activeStartDate,
968981
allowPartialRange,
982+
calendarType,
969983
getProcessedValue,
970984
goToRangeStartOnSelect,
971985
maxDate,
@@ -1006,8 +1020,8 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
10061020

10071021
function renderContent(next?: boolean) {
10081022
const currentActiveStartDate = next
1009-
? getBeginNext(view, activeStartDate)
1010-
: getBegin(view, activeStartDate);
1023+
? getBeginNext(view, activeStartDate, calendarType)
1024+
: getBegin(view, activeStartDate, calendarType);
10111025

10121026
const onClick = drillDownAvailable ? drillDown : onChange;
10131027

@@ -1075,6 +1089,26 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
10751089
/>
10761090
);
10771091
}
1092+
case 'week': {
1093+
return (
1094+
<WeekView
1095+
calendarType={calendarType}
1096+
formatDay={formatDay}
1097+
formatLongDate={formatLongDate}
1098+
formatShortWeekday={formatShortWeekday}
1099+
formatWeekday={formatWeekday}
1100+
onClickWeekNumber={onClickWeekNumber}
1101+
onMouseLeave={selectRange ? onMouseLeave : undefined}
1102+
showFixedNumberOfWeeks={
1103+
typeof showFixedNumberOfWeeks !== 'undefined'
1104+
? showFixedNumberOfWeeks
1105+
: showDoubleView
1106+
}
1107+
showWeekNumbers={showWeekNumbers}
1108+
{...commonProps}
1109+
/>
1110+
);
1111+
}
10781112
default:
10791113
throw new Error(`Invalid view: ${view}.`);
10801114
}
@@ -1088,6 +1122,7 @@ const Calendar: React.ForwardRefExoticComponent<CalendarProps & React.RefAttribu
10881122
return (
10891123
<Navigation
10901124
activeStartDate={activeStartDate}
1125+
calendarType={calendarType}
10911126
drillUp={drillUp}
10921127
formatMonthYear={formatMonthYear}
10931128
formatYear={formatYear}

packages/react-calendar/src/Calendar/Navigation.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { fireEvent, render } from '@testing-library/react';
33

44
import Navigation from './Navigation.js';
55

6-
const allViews = ['century', 'decade', 'year', 'month'];
6+
const allViews = ['century', 'decade', 'year', 'month', 'week'];
77

88
describe('Navigation', () => {
99
const defaultProps = {

packages/react-calendar/src/Calendar/Navigation.tsx

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ import {
1111
getBeginPrevious2,
1212
getEndPrevious,
1313
getEndPrevious2,
14+
getWeekEndDate,
15+
getWeekStartDate,
1416
} from '../shared/dates.js';
1517
import {
1618
formatMonthYear as defaultFormatMonthYear,
1719
formatYear as defaultFormatYear,
20+
formatShortDayMonthYear,
1821
} from '../shared/dateFormatter.js';
1922

20-
import type { Action, NavigationLabelFunc, RangeType } from '../shared/types.js';
23+
import type { Action, CalendarType, NavigationLabelFunc, RangeType } from '../shared/types.js';
2124

2225
const className = 'react-calendar__navigation';
2326

@@ -28,6 +31,12 @@ type NavigationProps = {
2831
* @example new Date(2017, 0, 1)
2932
*/
3033
activeStartDate: Date;
34+
35+
/**
36+
* Assists with "week" view to know which day to start on
37+
*/
38+
calendarType?: CalendarType;
39+
3140
drillUp: () => void;
3241
/**
3342
* Function called to override default formatting of months and years. Can be used to use your own formatting function.
@@ -151,6 +160,7 @@ type NavigationProps = {
151160

152161
export default function Navigation({
153162
activeStartDate,
163+
calendarType,
154164
drillUp,
155165
formatMonthYear = defaultFormatMonthYear,
156166
formatYear = defaultFormatYear,
@@ -176,20 +186,20 @@ export default function Navigation({
176186
const drillUpAvailable = views.indexOf(view) > 0;
177187
const shouldShowPrevNext2Buttons = view !== 'century';
178188

179-
const previousActiveStartDate = getBeginPrevious(view, activeStartDate);
189+
const previousActiveStartDate = getBeginPrevious(view, activeStartDate, calendarType);
180190
const previousActiveStartDate2 = shouldShowPrevNext2Buttons
181-
? getBeginPrevious2(view, activeStartDate)
191+
? getBeginPrevious2(view, activeStartDate, calendarType)
182192
: undefined;
183-
const nextActiveStartDate = getBeginNext(view, activeStartDate);
193+
const nextActiveStartDate = getBeginNext(view, activeStartDate, calendarType);
184194
const nextActiveStartDate2 = shouldShowPrevNext2Buttons
185-
? getBeginNext2(view, activeStartDate)
195+
? getBeginNext2(view, activeStartDate, calendarType)
186196
: undefined;
187197

188198
const prevButtonDisabled = (() => {
189199
if (previousActiveStartDate.getFullYear() < 0) {
190200
return true;
191201
}
192-
const previousActiveEndDate = getEndPrevious(view, activeStartDate);
202+
const previousActiveEndDate = getEndPrevious(view, activeStartDate, calendarType);
193203
return minDate && minDate >= previousActiveEndDate;
194204
})();
195205

@@ -199,7 +209,7 @@ export default function Navigation({
199209
if ((previousActiveStartDate2 as Date).getFullYear() < 0) {
200210
return true;
201211
}
202-
const previousActiveEndDate = getEndPrevious2(view, activeStartDate);
212+
const previousActiveEndDate = getEndPrevious2(view, activeStartDate, calendarType);
203213
return minDate && minDate >= previousActiveEndDate;
204214
})();
205215

@@ -224,7 +234,7 @@ export default function Navigation({
224234
setActiveStartDate(nextActiveStartDate2 as Date, 'next2');
225235
}
226236

227-
function renderLabel(date: Date) {
237+
function renderLabel(date: Date, calendarType?: CalendarType) {
228238
const label = (() => {
229239
switch (view) {
230240
case 'century':
@@ -235,6 +245,13 @@ export default function Navigation({
235245
return formatYear(locale, date);
236246
case 'month':
237247
return formatMonthYear(locale, date);
248+
case 'week': {
249+
// start
250+
const startDate = getWeekStartDate(date, calendarType);
251+
// end
252+
const endDate = getWeekEndDate(date, calendarType);
253+
return `${formatShortDayMonthYear(locale, startDate)}-${formatShortDayMonthYear(locale, endDate)}`;
254+
}
238255
default:
239256
throw new Error(`Invalid view: ${view}.`);
240257
}
@@ -263,13 +280,13 @@ export default function Navigation({
263280
type="button"
264281
>
265282
<span className={`${labelClassName}__labelText ${labelClassName}__labelText--from`}>
266-
{renderLabel(activeStartDate)}
283+
{renderLabel(activeStartDate, calendarType)}
267284
</span>
268285
{showDoubleView ? (
269286
<>
270287
<span className={`${labelClassName}__divider`}></span>
271288
<span className={`${labelClassName}__labelText ${labelClassName}__labelText--to`}>
272-
{renderLabel(nextActiveStartDate)}
289+
{renderLabel(nextActiveStartDate, calendarType)}
273290
</span>
274291
</>
275292
) : null}

0 commit comments

Comments
 (0)