Skip to content
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
61 changes: 41 additions & 20 deletions packages/dev/s2-docs/pages/react-aria/Calendar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ import {Calendar} from 'vanilla-starter/Calendar';

```tsx render
"use client";
import type {AnyCalendarDate} from '@internationalized/date';
import {CalendarDate, startOfWeek, toCalendar, GregorianCalendar} from '@internationalized/date';
import type {AnyCalendarDate, Calendar as ICalendar} from '@internationalized/date';
import {CalendarDate, startOfWeek, GregorianCalendar} from '@internationalized/date';
import {Calendar} from 'vanilla-starter/Calendar';

export default function Example() {
Expand All @@ -100,45 +100,66 @@ export default function Example() {
// See @internationalized/date docs linked above.
///- begin collapse -///
class Custom454 extends GregorianCalendar {
weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4];
getDaysInMonth(date) {
return this.weekPattern[date.month - 1] * 7;
// The anchor date, in Gregorian calendar.
// The anchor date is a date that occurs in the first week of the first month of every fiscal year.
anchorDate = new CalendarDate(2001, 2, 4);

private getYear(year: number): [CalendarDate, number[]] {
let anchor = this.anchorDate.set({year});
let startOfYear = startOfWeek(anchor, 'en', 'sun');
let isBigYear = !startOfYear.add({weeks: 53}).compare(anchor.add({years: 1}));
let weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, isBigYear ? 5 : 4];
return [startOfYear, weekPattern];
}

getDaysInMonth(date: AnyCalendarDate): number {
let [, weekPattern] = this.getYear(date.year);
return weekPattern[date.month - 1] * 7;
}

fromJulianDay(jd: number): CalendarDate {
let gregorian = super.fromJulianDay(jd);
let year = gregorian.year;

let [monthStart, weekPattern] = this.getYear(year);
if (gregorian.compare(monthStart) < 0) {
year--;
[monthStart, weekPattern] = this.getYear(year);
}

let monthStart = startOfWeek(new CalendarDate(gregorian.year, 1, 1), 'en');
for (let months = 0; months < this.weekPattern.length; months++) {
let weeksInMonth = this.weekPattern[months];
let monthEnd = monthStart.add({weeks: weeksInMonth});
if (monthEnd.compare(gregorian) > 0) {
for (let month = 1; month <= 12; month++) {
let weeks = weekPattern[month - 1];
let nextMonth = monthStart.add({weeks});
if (nextMonth.compare(gregorian) > 0) {
let days = gregorian.compare(monthStart);
return new CalendarDate(this, monthStart.year, months + 1, days + 1);
return new CalendarDate(this, year, month, days + 1);
}
monthStart = monthEnd;
monthStart = nextMonth;
}

throw Error('Date is not in any month somehow!');
throw new Error('date not found');
}

toJulianDay(date: AnyCalendarDate): number {
let monthStart = startOfWeek(new CalendarDate(date.year, 1, 1), 'en');
let [monthStart, weekPattern] = this.getYear(date.year);
for (let month = 1; month < date.month; month++) {
monthStart = monthStart.add({weeks: this.weekPattern[month - 1]});
monthStart = monthStart.add({weeks: weekPattern[month - 1]});
}

let gregorian = monthStart.add({days: date.day - 1});
return super.toJulianDay(gregorian);
}

getFormattableMonth(date) {
let gregorian = toCalendar(date, new GregorianCalendar());
return gregorian.set({month: date.month, day: 1});
getFormattableMonth(date: AnyCalendarDate): CalendarDate {
let anchorMonth = this.anchorDate.month - 1;
let dateMonth = date.month - 1;
let month = ((anchorMonth + dateMonth) % 12) + 1;
let year = anchorMonth + dateMonth >= 12 ? date.year + 1 : date.year;
return new CalendarDate(year, month, 1);
}

isEqual(other) {
return other instanceof Custom454;
isEqual(other: ICalendar): boolean {
return other instanceof Custom454 && other.anchorDate.compare(this.anchorDate) === 0;
}
}
///- end collapse -///
Expand Down
61 changes: 41 additions & 20 deletions packages/dev/s2-docs/pages/react-aria/RangeCalendar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ import {RangeCalendar} from 'vanilla-starter/RangeCalendar';

```tsx render
"use client";
import type {AnyCalendarDate} from '@internationalized/date';
import {CalendarDate, startOfWeek, toCalendar, GregorianCalendar} from '@internationalized/date';
import type {AnyCalendarDate, Calendar} from '@internationalized/date';
import {CalendarDate, startOfWeek, GregorianCalendar} from '@internationalized/date';
import {RangeCalendar} from 'vanilla-starter/RangeCalendar';

export default function Example() {
Expand All @@ -110,45 +110,66 @@ export default function Example() {
// See @internationalized/date docs linked above.
///- begin collapse -///
class Custom454 extends GregorianCalendar {
weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4];
getDaysInMonth(date) {
return this.weekPattern[date.month - 1] * 7;
// The anchor date, in Gregorian calendar.
// The anchor date is a date that occurs in the first week of the first month of every fiscal year.
anchorDate = new CalendarDate(2001, 2, 4);

private getYear(year: number): [CalendarDate, number[]] {
let anchor = this.anchorDate.set({year});
let startOfYear = startOfWeek(anchor, 'en', 'sun');
let isBigYear = !startOfYear.add({weeks: 53}).compare(anchor.add({years: 1}));
let weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, isBigYear ? 5 : 4];
return [startOfYear, weekPattern];
}

getDaysInMonth(date: AnyCalendarDate): number {
let [, weekPattern] = this.getYear(date.year);
return weekPattern[date.month - 1] * 7;
}

fromJulianDay(jd: number): CalendarDate {
let gregorian = super.fromJulianDay(jd);
let year = gregorian.year;

let [monthStart, weekPattern] = this.getYear(year);
if (gregorian.compare(monthStart) < 0) {
year--;
[monthStart, weekPattern] = this.getYear(year);
}

let monthStart = startOfWeek(new CalendarDate(gregorian.year, 1, 1), 'en');
for (let months = 0; months < this.weekPattern.length; months++) {
let weeksInMonth = this.weekPattern[months];
let monthEnd = monthStart.add({weeks: weeksInMonth});
if (monthEnd.compare(gregorian) > 0) {
for (let month = 1; month <= 12; month++) {
let weeks = weekPattern[month - 1];
let nextMonth = monthStart.add({weeks});
if (nextMonth.compare(gregorian) > 0) {
let days = gregorian.compare(monthStart);
return new CalendarDate(this, monthStart.year, months + 1, days + 1);
return new CalendarDate(this, year, month, days + 1);
}
monthStart = monthEnd;
monthStart = nextMonth;
}

throw Error('Date is not in any month somehow!');
throw new Error('date not found');
}

toJulianDay(date: AnyCalendarDate): number {
let monthStart = startOfWeek(new CalendarDate(date.year, 1, 1), 'en');
let [monthStart, weekPattern] = this.getYear(date.year);
for (let month = 1; month < date.month; month++) {
monthStart = monthStart.add({weeks: this.weekPattern[month - 1]});
monthStart = monthStart.add({weeks: weekPattern[month - 1]});
}

let gregorian = monthStart.add({days: date.day - 1});
return super.toJulianDay(gregorian);
}

getFormattableMonth(date) {
let gregorian = toCalendar(date, new GregorianCalendar());
return gregorian.set({month: date.month, day: 1});
getFormattableMonth(date: AnyCalendarDate): CalendarDate {
let anchorMonth = this.anchorDate.month - 1;
let dateMonth = date.month - 1;
let month = ((anchorMonth + dateMonth) % 12) + 1;
let year = anchorMonth + dateMonth >= 12 ? date.year + 1 : date.year;
return new CalendarDate(year, month, 1);
}

isEqual(other) {
return other instanceof Custom454;
isEqual(other: Calendar): boolean {
return other instanceof Custom454 && other.anchorDate.compare(this.anchorDate) === 0;
}
}
///- end collapse -///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,36 +125,55 @@ The following code is an example of how you might implement a custom 4-5-4 calen
import type {AnyCalendarDate, Calendar} from '@internationalized/date';
import {CalendarDate, GregorianCalendar, startOfWeek} from '@internationalized/date';

const weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4];

// This calendar gives each month a 4-5-4 week pattern, with February as the first month of the year.
// This means that in this calendar, 2024-01-01 translates to 2024-02-04 in the Gregorian calendar.
// Months begin on day 1, and go through 7*weeksInMonth days, ending on either the 28th or 35th day of the month.
class Custom454 extends GregorianCalendar {
// Months always have either 4 or 5 full weeks.
getDaysInMonth(date) {
// The anchor date, in Gregorian calendar.
// The anchor date is a date that occurs in the first week of the first month of every fiscal year.
anchorDate = new CalendarDate(2001, 2, 4);

private getYear(year: number): [CalendarDate, number[]] {
let anchor = this.anchorDate.set({year});
let startOfYear = startOfWeek(anchor, 'en', 'sun');
let isBigYear = !startOfYear.add({weeks: 53}).compare(anchor.add({years: 1}));
let weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, isBigYear ? 5 : 4];
return [startOfYear, weekPattern];
}

getDaysInMonth(date: AnyCalendarDate): number {
// Months always have either 4 or 5 full weeks.
let [, weekPattern] = this.getYear(date.year);
return weekPattern[date.month - 1] * 7;
}

// Enable conversion between calendar systems.
fromJulianDay(jd: number): CalendarDate {
let gregorian = super.fromJulianDay(jd);
let year = gregorian.year;

let [monthStart, weekPattern] = this.getYear(year);
if (gregorian.compare(monthStart) < 0) {
year--;
[monthStart, weekPattern] = this.getYear(year);
}

// Start from the beginning of the first week of the gregorian year
// and add weeks until we find the month.
let monthStart = startOfWeek(new CalendarDate(gregorian.year, 1, 1), 'en');
for (let months = 0; months < weekPattern.length; months++) {
let weeksInMonth = weekPattern[months];
let monthEnd = monthStart.add({weeks: weeksInMonth});
if (monthEnd.compare(gregorian) > 0) {
for (let month = 1; month <= 12; month++) {
let weeks = weekPattern[month - 1];
let nextMonth = monthStart.add({weeks});
if (nextMonth.compare(gregorian) > 0) {
let days = gregorian.compare(monthStart);
return new CalendarDate(this, monthStart.year, months + 1, days + 1);
return new CalendarDate(this, year, month, days + 1);
}
monthStart = monthEnd;
monthStart = nextMonth;
}

throw Error('Date is not in any month somehow!');
throw new Error('date not found');
}

toJulianDay(date: AnyCalendarDate): number {
let monthStart = startOfWeek(new CalendarDate(date.year, 1, 1), 'en');
let [monthStart, weekPattern] = this.getYear(date.year);
for (let month = 1; month < date.month; month++) {
monthStart = monthStart.add({weeks: weekPattern[month - 1]});
}
Expand All @@ -163,8 +182,16 @@ class Custom454 extends GregorianCalendar {
return super.toJulianDay(gregorian);
}

isEqual(other: Calendar) {
return other instanceof Custom454;
getFormattableMonth(date: AnyCalendarDate): CalendarDate {
let anchorMonth = this.anchorDate.month - 1;
let dateMonth = date.month - 1;
let month = ((anchorMonth + dateMonth) % 12) + 1;
let year = anchorMonth + dateMonth >= 12 ? date.year + 1 : date.year;
return new CalendarDate(year, month, 1);
}

isEqual(other: Calendar): boolean {
return other instanceof Custom454 && other.anchorDate.compare(this.anchorDate) === 0;
}
}
```
Expand Down
61 changes: 41 additions & 20 deletions packages/dev/s2-docs/pages/s2/Calendar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ import {parseDate} from '@internationalized/date';

```tsx render
"use client";
import type {AnyCalendarDate} from '@internationalized/date';
import {CalendarDate, startOfWeek, toCalendar, GregorianCalendar} from '@internationalized/date';
import type {AnyCalendarDate, Calendar as ICalendar} from '@internationalized/date';
import {CalendarDate, startOfWeek, GregorianCalendar} from '@internationalized/date';
import {Calendar} from '@react-spectrum/s2';

export default function Example() {
Expand All @@ -91,45 +91,66 @@ export default function Example() {
// See @internationalized/date docs linked above.
///- begin collapse -///
class Custom454 extends GregorianCalendar {
weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4];
getDaysInMonth(date) {
return this.weekPattern[date.month - 1] * 7;
// The anchor date, in Gregorian calendar.
// The anchor date is a date that occurs in the first week of the first month of every fiscal year.
anchorDate = new CalendarDate(2001, 2, 4);

private getYear(year: number): [CalendarDate, number[]] {
let anchor = this.anchorDate.set({year});
let startOfYear = startOfWeek(anchor, 'en', 'sun');
let isBigYear = !startOfYear.add({weeks: 53}).compare(anchor.add({years: 1}));
let weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, isBigYear ? 5 : 4];
return [startOfYear, weekPattern];
}

getDaysInMonth(date: AnyCalendarDate): number {
let [, weekPattern] = this.getYear(date.year);
return weekPattern[date.month - 1] * 7;
}

fromJulianDay(jd: number): CalendarDate {
let gregorian = super.fromJulianDay(jd);
let year = gregorian.year;

let [monthStart, weekPattern] = this.getYear(year);
if (gregorian.compare(monthStart) < 0) {
year--;
[monthStart, weekPattern] = this.getYear(year);
}

let monthStart = startOfWeek(new CalendarDate(gregorian.year, 1, 1), 'en');
for (let months = 0; months < this.weekPattern.length; months++) {
let weeksInMonth = this.weekPattern[months];
let monthEnd = monthStart.add({weeks: weeksInMonth});
if (monthEnd.compare(gregorian) > 0) {
for (let month = 1; month <= 12; month++) {
let weeks = weekPattern[month - 1];
let nextMonth = monthStart.add({weeks});
if (nextMonth.compare(gregorian) > 0) {
let days = gregorian.compare(monthStart);
return new CalendarDate(this, monthStart.year, months + 1, days + 1);
return new CalendarDate(this, year, month, days + 1);
}
monthStart = monthEnd;
monthStart = nextMonth;
}

throw Error('Date is not in any month somehow!');
throw new Error('date not found');
}

toJulianDay(date: AnyCalendarDate): number {
let monthStart = startOfWeek(new CalendarDate(date.year, 1, 1), 'en');
let [monthStart, weekPattern] = this.getYear(date.year);
for (let month = 1; month < date.month; month++) {
monthStart = monthStart.add({weeks: this.weekPattern[month - 1]});
monthStart = monthStart.add({weeks: weekPattern[month - 1]});
}

let gregorian = monthStart.add({days: date.day - 1});
return super.toJulianDay(gregorian);
}

getFormattableMonth(date) {
let gregorian = toCalendar(date, new GregorianCalendar());
return gregorian.set({month: date.month, day: 1});
getFormattableMonth(date: AnyCalendarDate): CalendarDate {
let anchorMonth = this.anchorDate.month - 1;
let dateMonth = date.month - 1;
let month = ((anchorMonth + dateMonth) % 12) + 1;
let year = anchorMonth + dateMonth >= 12 ? date.year + 1 : date.year;
return new CalendarDate(year, month, 1);
}

isEqual(other) {
return other instanceof Custom454;
isEqual(other: ICalendar): boolean {
return other instanceof Custom454 && other.anchorDate.compare(this.anchorDate) === 0;
}
}
///- end collapse -///
Expand Down
Loading