Skip to content

Commit

Permalink
feat: Added a WeekView
Browse files Browse the repository at this point in the history
change index for week

pass calendarType
  • Loading branch information
ddemark committed Jan 3, 2025
1 parent b66d28e commit 92fe5c8
Show file tree
Hide file tree
Showing 25 changed files with 2,083 additions and 660 deletions.
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"
}
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
37 changes: 27 additions & 10 deletions packages/react-calendar/src/Calendar/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ import {
getBeginPrevious2,
getEndPrevious,
getEndPrevious2,
getWeekEndDate,
getWeekStartDate,
} from '../shared/dates.js';
import {
formatMonthYear as defaultFormatMonthYear,
formatYear as defaultFormatYear,
formatShortDayMonthYear,
} from '../shared/dateFormatter.js';

import type { Action, NavigationLabelFunc, RangeType } from '../shared/types.js';
import type { Action, CalendarType, NavigationLabelFunc, RangeType } from '../shared/types.js';

const className = 'react-calendar__navigation';

Expand All @@ -28,6 +31,12 @@ type NavigationProps = {
* @example new Date(2017, 0, 1)
*/
activeStartDate: Date;

/**
* Assists with "week" view to know which day to start on
*/
calendarType?: CalendarType;

drillUp: () => void;
/**
* Function called to override default formatting of months and years. Can be used to use your own formatting function.
Expand Down Expand Up @@ -151,6 +160,7 @@ type NavigationProps = {

export default function Navigation({
activeStartDate,
calendarType,
drillUp,
formatMonthYear = defaultFormatMonthYear,
formatYear = defaultFormatYear,
Expand All @@ -176,20 +186,20 @@ export default function Navigation({
const drillUpAvailable = views.indexOf(view) > 0;
const shouldShowPrevNext2Buttons = view !== 'century';

const previousActiveStartDate = getBeginPrevious(view, activeStartDate);
const previousActiveStartDate = getBeginPrevious(view, activeStartDate, calendarType);
const previousActiveStartDate2 = shouldShowPrevNext2Buttons
? getBeginPrevious2(view, activeStartDate)
? getBeginPrevious2(view, activeStartDate, calendarType)
: undefined;
const nextActiveStartDate = getBeginNext(view, activeStartDate);
const nextActiveStartDate = getBeginNext(view, activeStartDate, calendarType);
const nextActiveStartDate2 = shouldShowPrevNext2Buttons
? getBeginNext2(view, activeStartDate)
? getBeginNext2(view, activeStartDate, calendarType)
: undefined;

const prevButtonDisabled = (() => {
if (previousActiveStartDate.getFullYear() < 0) {
return true;
}
const previousActiveEndDate = getEndPrevious(view, activeStartDate);
const previousActiveEndDate = getEndPrevious(view, activeStartDate, calendarType);
return minDate && minDate >= previousActiveEndDate;
})();

Expand All @@ -199,7 +209,7 @@ export default function Navigation({
if ((previousActiveStartDate2 as Date).getFullYear() < 0) {
return true;
}
const previousActiveEndDate = getEndPrevious2(view, activeStartDate);
const previousActiveEndDate = getEndPrevious2(view, activeStartDate, calendarType);
return minDate && minDate >= previousActiveEndDate;
})();

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

function renderLabel(date: Date) {
function renderLabel(date: Date, calendarType?: CalendarType) {
const label = (() => {
switch (view) {
case 'century':
Expand All @@ -235,6 +245,13 @@ export default function Navigation({
return formatYear(locale, date);
case 'month':
return formatMonthYear(locale, date);
case 'week': {
// start
const startDate = getWeekStartDate(date, calendarType);
// end
const endDate = getWeekEndDate(date, calendarType);
return `${formatShortDayMonthYear(locale, startDate)}-${formatShortDayMonthYear(locale, endDate)}`;
}
default:
throw new Error(`Invalid view: ${view}.`);
}
Expand Down Expand Up @@ -263,13 +280,13 @@ export default function Navigation({
type="button"
>
<span className={`${labelClassName}__labelText ${labelClassName}__labelText--from`}>
{renderLabel(activeStartDate)}
{renderLabel(activeStartDate, calendarType)}
</span>
{showDoubleView ? (
<>
<span className={`${labelClassName}__divider`}></span>
<span className={`${labelClassName}__labelText ${labelClassName}__labelText--to`}>
{renderLabel(nextActiveStartDate)}
{renderLabel(nextActiveStartDate, calendarType)}
</span>
</>
) : null}
Expand Down
Loading

0 comments on commit 92fe5c8

Please sign in to comment.