Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
f84a158
fix: Constrain day on blur
boutahlilsoufiane Jun 11, 2025
38ab4fe
Merge branch 'main' of https://github.com/boutahlilsoufiane/react-spe…
boutahlilsoufiane Jun 21, 2025
2611a8e
feat: add tests
boutahlilsoufiane Jul 2, 2025
f130aae
feat: add blur
boutahlilsoufiane Jul 11, 2025
577bcdb
feat: update constrain
boutahlilsoufiane Jul 16, 2025
56c5849
feat: change NumberFormat
boutahlilsoufiane Jul 16, 2025
596af68
feat: fix tests
boutahlilsoufiane Jul 17, 2025
9a30cc2
feat: fix tests
boutahlilsoufiane Jul 18, 2025
56fe492
fix: remove unnecessary changes
boutahlilsoufiane Jul 18, 2025
dd9675b
fix: improve tests
boutahlilsoufiane Jul 18, 2025
ac477ec
fix: improve tests
boutahlilsoufiane Jul 18, 2025
ab552f9
fix: fix tests
boutahlilsoufiane Jul 22, 2025
5d98150
fix: Fix clear timefield
boutahlilsoufiane Jul 24, 2025
53fb4d7
fix: Fix tests
boutahlilsoufiane Jul 24, 2025
4cc6ffc
fix: Fix tests RangeDatePicker
boutahlilsoufiane Jul 26, 2025
4eb5712
fix: Fix increment value
boutahlilsoufiane Jul 27, 2025
c9945d5
fix: Fix DateRnagePickers tests
boutahlilsoufiane Jul 27, 2025
28e3927
fix: Fix test DateField.test.js
boutahlilsoufiane Jul 27, 2025
3fc093f
fix: Fix tests
boutahlilsoufiane Jul 28, 2025
b60fe24
fix: Fix tests
boutahlilsoufiane Jul 28, 2025
6c0645b
fix: Remove unnecessary changes
boutahlilsoufiane Jul 28, 2025
18967fc
fix: Add max days
boutahlilsoufiane Jul 29, 2025
6990d69
Merge branch 'main' of https://github.com/boutahlilsoufiane/react-spe…
boutahlilsoufiane Jul 29, 2025
4701afa
fix: Fix tests
boutahlilsoufiane Aug 1, 2025
8acff74
refactor: remove useRef
boutahlilsoufiane Aug 2, 2025
6a0a839
refactor: use useState
boutahlilsoufiane Aug 3, 2025
4500be8
refactor: don't update placeholder
boutahlilsoufiane Aug 3, 2025
2493f45
refactor: Remove comment
boutahlilsoufiane Aug 3, 2025
1bc224d
refactor: Remove currentValue
boutahlilsoufiane Aug 4, 2025
3fd1d6f
test: Fix linting issues
boutahlilsoufiane Aug 4, 2025
bf0d184
test: Fix linting issues
boutahlilsoufiane Aug 4, 2025
7d281e3
fix: Fix linting issue
boutahlilsoufiane Aug 4, 2025
46c9e71
fix: Fix linting issues
boutahlilsoufiane Aug 4, 2025
296d894
refactor: Add description
boutahlilsoufiane Aug 4, 2025
48bcd5a
fix: revert changes
boutahlilsoufiane Aug 20, 2025
11d37fa
fix: don't constrain day
boutahlilsoufiane Aug 20, 2025
b0f2963
fix: Fix linting issues
boutahlilsoufiane Aug 21, 2025
2d4520e
Merge branch 'main' of https://github.com/boutahlilsoufiane/react-spe…
boutahlilsoufiane Aug 21, 2025
af7884d
fix: Fix linting issues
boutahlilsoufiane Aug 21, 2025
27bed18
fix: Fix linting issues
boutahlilsoufiane Aug 21, 2025
0096396
fix: don't constrain day
boutahlilsoufiane Aug 30, 2025
5f5d411
fix: Fix linting issues
boutahlilsoufiane Aug 30, 2025
cfad64d
fix: fix rule no dup class members
boutahlilsoufiane Aug 30, 2025
984ae81
fix: fix rule no dup class members
boutahlilsoufiane Aug 30, 2025
673361b
Merge branch 'main' into constrain-date
boutahlilsoufiane Aug 30, 2025
47d9cab
Merge branch 'main' into constrain-date
snowystinger Sep 9, 2025
26cc987
fix: Fix constructor
boutahlilsoufiane Oct 24, 2025
51671bb
Merge branch 'main' into constrain-date
boutahlilsoufiane Oct 24, 2025
0c432e8
fix: Add default value
boutahlilsoufiane Oct 26, 2025
c02a20e
Merge branch 'constrain-date' of https://github.com/boutahlilsoufiane…
boutahlilsoufiane Oct 26, 2025
de9fa3c
Merge branch 'main' into constrain-date
boutahlilsoufiane Oct 26, 2025
918d8a2
fix: Remove default value
boutahlilsoufiane Oct 26, 2025
fda81ce
Merge branch 'constrain-date' of https://github.com/boutahlilsoufiane…
boutahlilsoufiane Oct 26, 2025
e9af217
feat: Add IncompleteDate class
boutahlilsoufiane Nov 19, 2025
c6f331a
fix: Fix constrain function
boutahlilsoufiane Nov 22, 2025
788e358
fix: Add balanceDate
boutahlilsoufiane Nov 22, 2025
b2b00c3
fix: Uncomment code
boutahlilsoufiane Nov 22, 2025
acc4764
Merge branch 'main' into constrain-date
boutahlilsoufiane Nov 22, 2025
7f8874f
fix: Fix typescript
boutahlilsoufiane Nov 22, 2025
5ed4803
fix: Fix typescript
boutahlilsoufiane Nov 22, 2025
d33fcec
Merge branch 'constrain-date' of https://github.com/boutahlilsoufiane…
boutahlilsoufiane Nov 22, 2025
6849402
fix: Remove imports
boutahlilsoufiane Nov 22, 2025
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
5 changes: 3 additions & 2 deletions packages/@internationalized/date/src/CalendarDate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,11 @@ export class ZonedDateTime {
}

/** Returns a new `ZonedDateTime` with the given fields set to the provided values. Other fields will be constrained accordingly. */
set(fields: DateFields & TimeFields, disambiguation?: Disambiguation): ZonedDateTime {
return setZoned(this, fields, disambiguation);
set(fields: DateFields & TimeFields, disambiguation?: Disambiguation): ZonedDateTime {
return setZoned(this, fields, disambiguation);
}


/**
* Returns a new `ZonedDateTime` with the given field adjusted by a specified amount.
* When the resulting value reaches the limits of the field, it wraps around.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ export class BuddhistCalendar extends GregorianCalendar {
getDaysInMonth(date: AnyCalendarDate): number {
return super.getDaysInMonth(toGregorian(date));
}

balanceDate(): void {}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ export class EthiopicCalendar implements Calendar {
return getDaysInMonth(date.year, date.month);
}

getMaxDays(): number {
return 30;
}

getMonthsInYear(): number {
return 13;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ export class GregorianCalendar implements Calendar {
return 12;
}

getMaxDays(): number {
return 31;
}

getDaysInYear(date: AnyCalendarDate): number {
return isLeapYear(date.year) ? 366 : 365;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ export class HebrewCalendar implements Calendar {
return getDaysInMonth(date.year, date.month);
}

getMaxDays(): number {
return 30;
}

getMonthsInYear(date: AnyCalendarDate): number {
return isLeapYear(date.year) ? 13 : 12;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ export class IslamicCivilCalendar implements Calendar {
return length;
}

getMaxDays(): number {
return 30;
}

getMonthsInYear(): number {
return 12;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export class PersianCalendar implements Calendar {
return isLeapYear ? 30 : 29;
}

getMaxDays(): number {
return 31;
}

getEras(): string[] {
return ['AP'];
}
Expand Down
4 changes: 2 additions & 2 deletions packages/@internationalized/date/src/conversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function epochFromDate(date: AnyDateTime): number {
return epochFromParts(year, date.month, date.day, date.hour, date.minute, date.second, date.millisecond);
}

function epochFromParts(year: number, month: number, day: number, hour: number, minute: number, second: number, millisecond: number): number {
export function epochFromParts(year: number, month: number, day: number, hour: number, minute: number, second: number, millisecond: number): number {
// Note: Date.UTC() interprets one and two-digit years as being in the
// 20th century, so don't use it
let date = new Date();
Expand Down Expand Up @@ -306,4 +306,4 @@ export function toTimeZone(date: ZonedDateTime, timeZone: string): ZonedDateTime
/** Converts the given `ZonedDateTime` into the user's local time zone. */
export function toLocalTimeZone(date: ZonedDateTime): ZonedDateTime {
return toTimeZone(date, getLocalTimeZone());
}
}
10 changes: 5 additions & 5 deletions packages/@internationalized/date/src/manipulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function constrainMonthDay(date: Mutable<AnyCalendarDate>) {

export function constrain(date: Mutable<AnyCalendarDate>): void {
if (date.calendar.constrainDate) {
date.calendar.constrainDate(date);
date.calendar.constrainDate(date);
}

date.year = Math.max(1, Math.min(date.calendar.getYearsInEra(date), date.year));
Expand Down Expand Up @@ -169,9 +169,9 @@ export function set(date: CalendarDate | CalendarDateTime, fields: DateFields):
return mutableDate;
}

export function setTime(value: CalendarDateTime, fields: TimeFields): CalendarDateTime;
export function setTime(value: Time, fields: TimeFields): Time;
export function setTime(value: Time | CalendarDateTime, fields: TimeFields): Mutable<Time | CalendarDateTime> {
export function setTime(value: CalendarDateTime, fields: TimeFields, ): CalendarDateTime;
export function setTime(value: Time, fields: TimeFields, ): Time;
export function setTime(value: Time | CalendarDateTime, fields: TimeFields, ): Mutable<Time | CalendarDateTime> {
let mutableValue: Mutable<Time | CalendarDateTime> = value.copy();

if (fields.hour != null) {
Expand Down Expand Up @@ -284,7 +284,7 @@ export function cycleDate(value: CalendarDate | CalendarDateTime, field: DateFie
mutable.month = cycleValue(value.month, amount, 1, value.calendar.getMonthsInYear(value), options?.round);
break;
case 'day':
mutable.day = cycleValue(value.day, amount, 1, value.calendar.getDaysInMonth(value), options?.round);
mutable.day = cycleValue(value.day, amount, 1, value.calendar.getDaysInMonth(value), options?.round);
break;
default:
throw new Error('Unsupported field ' + field);
Expand Down
2 changes: 2 additions & 0 deletions packages/@internationalized/date/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export interface Calendar {
getDaysInMonth(date: AnyCalendarDate): number,
/** Returns the number of months in the year of the given date. */
getMonthsInYear(date: AnyCalendarDate): number,
/** Returns the maximum day. */
getMaxDays(): number,
/** Returns the number of years in the era of the given date. */
getYearsInEra(date: AnyCalendarDate): number,
/** Returns a list of era identifiers for the calendar. */
Expand Down
4 changes: 4 additions & 0 deletions packages/@internationalized/date/tests/customCalendarImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export class Custom454Calendar extends GregorianCalendar {
return weekPattern[date.month - 1] * 7;
}

getMaxDays(): number {
return 35;
}

fromJulianDay(jd: number): CalendarDate {
const date = super.fromJulianDay(jd);
let year = date.year;
Expand Down
5 changes: 3 additions & 2 deletions packages/@react-aria/datepicker/src/useDateField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ export function useDateField<T extends DateValue>(props: AriaDateFieldOptions<T>
},
onBlurWithin: (e) => {
state.confirmPlaceholder();
if (state.value !== valueOnFocus.current) {
if (state.shouldValidate) {
state.commitValidation();
}
state.setShouldValidate(false);
};
props.onBlur?.(e);
},
onFocusWithinChange: props.onFocusChange
Expand Down
4 changes: 2 additions & 2 deletions packages/@react-aria/datepicker/src/useDateSegment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
onIncrementToMax: () => {
enteredKeys.current = '';
if (segment.maxValue !== undefined) {
state.setSegment(segment.type, segment.maxValue);
state.incrementToMinMax(segment.type, segment.maxValue);
}
},
onDecrementToMin: () => {
enteredKeys.current = '';
if (segment.minValue !== undefined) {
state.setSegment(segment.type, segment.minValue);
state.incrementToMinMax(segment.type, segment.minValue);
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ function Example(props) {
);
}

function ControlledExample(props) {
function ControlledExample(props) {
let [value, setValue] = React.useState(props.value);

return (
Expand Down
32 changes: 21 additions & 11 deletions packages/@react-spectrum/datepicker/test/DateField.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,11 @@ describe('DateField', function () {
errorMessage="Date unavailable." />
);
await user.tab();
await user.keyboard('01011980');
await user.keyboard('1');
await user.keyboard('[ArrowRight]');
await user.keyboard('1');
await user.keyboard('[ArrowRight]');
await user.keyboard('1980[Tab]');
expect(tree.getByText('Date unavailable.')).toBeInTheDocument();
});

Expand Down Expand Up @@ -369,6 +373,7 @@ describe('DateField', function () {
expect(input).toHaveAttribute('name', 'date');
await user.tab();
await user.keyboard('{ArrowUp}');
await user.tab({shift: true});
expect(getDescription()).toBe('Selected Date: March 3, 2020');
expect(input).toHaveValue('2020-03-03');

Expand Down Expand Up @@ -457,7 +462,7 @@ describe('DateField', function () {
expect(document.activeElement).toBe(within(group).getAllByRole('spinbutton')[0]);

await user.keyboard('[Tab][Tab][ArrowUp]');

expect(getDescription()).toContain('Value must be 2/3/2020 or later.');
expect(input.validity.valid).toBe(true);

Expand All @@ -467,9 +472,13 @@ describe('DateField', function () {

await user.tab({shift: true});
await user.keyboard('2025');

expect(getDescription()).not.toContain('Value must be 2/3/2024 or earlier.');
expect(input.validity.valid).toBe(false);
expect(input.validity.valid).toBe(true);

await user.tab();
expect(getDescription()).toContain('Value must be 2/3/2024 or earlier.');
expect(input.validity.valid).toBe(false);

act(() => {getByTestId('form').checkValidity();});
expect(getDescription()).toContain('Value must be 2/3/2024 or earlier.');
Expand Down Expand Up @@ -503,12 +512,11 @@ describe('DateField', function () {
expect(group).toHaveAttribute('aria-describedby');
expect(getDescription()).toContain('Invalid value');
expect(document.activeElement).toBe(within(group).getAllByRole('spinbutton')[0]);

await user.keyboard('[ArrowRight][ArrowRight]2024');

expect(getDescription()).toContain('Invalid value');
expect(input.validity.valid).toBe(true);

expect(input.validity.valid).toBe(false);
await user.tab();

expect(getDescription()).not.toContain('Invalid value');
Expand Down Expand Up @@ -628,10 +636,12 @@ describe('DateField', function () {
await user.keyboard('232023');

expect(group).toHaveAttribute('aria-describedby');
expect(input.validity.valid).toBe(true);
expect(input.validity.valid).toBe(false);

await user.tab();
expect(getDescription()).not.toContain('Constraints not satisfied');
expect(group).toHaveAttribute('aria-describedby');
expect(input.validity.valid).toBe(true);
});
});

Expand All @@ -649,13 +659,13 @@ describe('DateField', function () {
let getDescription = () => group.getAttribute('aria-describedby').split(' ').map(d => document.getElementById(d).textContent).join(' ');
expect(getDescription()).toContain('Value must be 2/3/2020 or later.');

await user.keyboard('[Tab][Tab][Tab][ArrowUp]');
await user.keyboard('[Tab][Tab][Tab][ArrowUp][Tab]');
expect(getDescription()).not.toContain('Value must be 2/3/2020 or later.');

await user.keyboard('[ArrowUp][ArrowUp][ArrowUp][ArrowUp][ArrowUp]');
await user.keyboard('[Tab][Tab][Tab][ArrowUp][ArrowUp][ArrowUp][ArrowUp][ArrowUp][Tab]');
expect(getDescription()).toContain('Value must be 2/3/2024 or earlier.');

await user.keyboard('[ArrowDown]');
await user.keyboard('[Tab][Tab][Tab][ArrowDown][Tab]');
expect(getDescription()).not.toContain('Value must be 2/3/2024 or earlier.');
});

Expand All @@ -673,7 +683,7 @@ describe('DateField', function () {
let getDescription = () => group.getAttribute('aria-describedby').split(' ').map(d => document.getElementById(d).textContent).join(' ');
expect(getDescription()).toContain('Invalid value');

await user.keyboard('[Tab][ArrowRight][ArrowRight]2024');
await user.keyboard('[Tab][ArrowRight][ArrowRight]2024[Tab]');
expect(getDescription()).not.toContain('Invalid value');
});

Expand Down
Loading