Skip to content

feat: S2 DateField/DatePicker/Calendar #8428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 36 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c143634
feat: S2 DateField/DatePicker/Calendar
snowystinger Jun 19, 2025
3b4f669
fix lint
snowystinger Jun 19, 2025
6401de3
start calendar
snowystinger Jun 19, 2025
7bbdd47
Style calendar and fix some datepicker styles
snowystinger Jun 20, 2025
0716d72
changing ring size
snowystinger Jun 23, 2025
b67342f
fix hover
snowystinger Jun 23, 2025
beb5265
revert outline size change
snowystinger Jun 23, 2025
fb693ab
add range calendar
snowystinger Jun 23, 2025
1ab4699
fix yarn lock
snowystinger Jun 23, 2025
f51db9c
fix cell styles for different size ring and gap
snowystinger Jun 24, 2025
b1d5752
Merge branch 'main' into s2-datepicker
snowystinger Jun 24, 2025
c8e2ef2
add spectrum context
snowystinger Jun 24, 2025
eb5c4ff
Add DateRangePicker
snowystinger Jun 24, 2025
aa71a83
add comment
snowystinger Jun 24, 2025
8b864c3
fix test
snowystinger Jun 24, 2025
0cbd107
Add TimeField and aria labels
snowystinger Jun 24, 2025
559c1bc
add press scaling
snowystinger Jun 26, 2025
0f697a8
Merge branch 'main' into s2-datepicker
snowystinger Jun 26, 2025
90332c7
fix non-contiguous ranges styles
snowystinger Jun 26, 2025
6fbf922
fix lint
snowystinger Jun 26, 2025
a82e047
remove explicit modules
snowystinger Jun 26, 2025
3db69f6
Merge branch 'main' into s2-datepicker
snowystinger Jun 27, 2025
356148a
Add time fields to date pickers
snowystinger Jun 27, 2025
b0f6cac
fix buttons in date picker popover
snowystinger Jun 27, 2025
eb9685a
remove console log
snowystinger Jun 27, 2025
6da6c82
fix storybook intermittent crash from implicit actions, scrolling
snowystinger Jun 27, 2025
5ee804b
fix accessibility violation
snowystinger Jun 27, 2025
f065877
review changes and deduplicating code
snowystinger Jun 30, 2025
d17b7fd
make outline in range smaller
snowystinger Jun 30, 2025
be9560f
Label instead of aria label the stories by default
snowystinger Jun 30, 2025
3450170
reduce duplication, fix styles
snowystinger Jul 1, 2025
aa7701d
remove added api for day/week index and add storybook decorators for …
snowystinger Jul 1, 2025
27c4230
field widths, share more
snowystinger Jul 1, 2025
33628a0
Add hcm support
snowystinger Jul 1, 2025
fad7550
add chromatic stories and fix bugs
snowystinger Jul 1, 2025
6ee3dc6
remove problematic story
snowystinger Jul 1, 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
1 change: 1 addition & 0 deletions packages/@react-aria/calendar/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export {useCalendar} from './useCalendar';
export {useRangeCalendar} from './useRangeCalendar';
export {useCalendarGrid} from './useCalendarGrid';
export {useCalendarCell} from './useCalendarCell';
export {getEraFormat} from './utils';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another way to do this? see RangeCalendar implementation for use


export type {AriaCalendarProps, AriaRangeCalendarProps, CalendarProps, DateValue, RangeCalendarProps} from '@react-types/calendar';
export type {CalendarAria} from './useCalendarBase';
Expand Down
131 changes: 131 additions & 0 deletions packages/@react-spectrum/s2/chromatic/Calendar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright 2024 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import {Calendar} from '../src';
import {CalendarDate} from '@internationalized/date';
import {Custom454Calendar} from '../../../@internationalized/date/tests/customCalendarImpl';
import {DateValue} from 'react-aria';
import type {Meta, StoryObj} from '@storybook/react';
import {screen, userEvent, within} from '@storybook/test';

const meta: Meta<typeof Calendar> = {
component: Calendar,
parameters: {
chromaticProvider: {disableAnimations: true}
},
title: 'S2 Chromatic/Calendar'
};

export default meta;

type Story = StoryObj<typeof Calendar>;

const date = new CalendarDate(2022, 2, 3);

export const Default: Story = {
args: {
defaultFocusedValue: date
}
};

export const MultiMonth: Story = {
args: {
defaultFocusedValue: date,
visibleMonths: 3
}
};

export const UnavailableDays: Story = {
args: {
defaultFocusedValue: date,
minValue: new CalendarDate(2022, 2, 2),
maxValue: new CalendarDate(2022, 2, 20),
isDateUnavailable: (date: DateValue) => {
return date.day >= 15 && date.day <= 18;
},
isInvalid: true,
errorMessage: 'Invalid date'
}
};

export const CustomCalendar: Story = {
args: {
defaultFocusedValue: date,
createCalendar: () => new Custom454Calendar()
},
parameters: {
chromaticProvider: {
// only works for en-US?
locales: ['en-US']
}
}
};

export const DefaultHover: Story = {
args: {
defaultFocusedValue: date
},
play: async () => {
let grid = screen.getByRole('grid');
let cell = within(grid).getAllByRole('button')[7];
await userEvent.hover(cell);
},
parameters: {
chromaticProvider: {
colorSchemes: ['light'],
backgrounds: ['base'],
locales: ['en-US'],
disableAnimations: true
}
}
};

export const DefaultKeyboardFocus: Story = {
args: {
defaultFocusedValue: date
},
play: async () => {
await userEvent.tab();
await userEvent.tab();
await userEvent.tab();
await userEvent.keyboard('{ArrowDown}');
},
parameters: {
chromaticProvider: {
colorSchemes: ['light'],
backgrounds: ['base'],
locales: ['en-US'],
disableAnimations: true
}
}
};

export const DefaultKeyboardSelected: Story = {
args: {
defaultFocusedValue: date
},
play: async () => {
await userEvent.tab();
await userEvent.tab();
await userEvent.tab();
await userEvent.keyboard('{ArrowDown}');
await userEvent.keyboard('{Enter}');
},
parameters: {
chromaticProvider: {
colorSchemes: ['light'],
backgrounds: ['base'],
locales: ['en-US'],
disableAnimations: true
}
}
};
62 changes: 62 additions & 0 deletions packages/@react-spectrum/s2/chromatic/DateField.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2024 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import {CalendarDate} from '@internationalized/date';
import {DateField} from '../';
import type {Meta, StoryObj} from '@storybook/react';
import {userEvent} from '@storybook/test';

const meta: Meta<typeof DateField> = {
component: DateField,
parameters: {
chromaticProvider: {disableAnimations: true}
},
title: 'S2 Chromatic/DateField'
};

export default meta;

type Story = StoryObj<typeof DateField>;

const date = new CalendarDate(2022, 2, 3);

export const Default: Story = {
args: {
label: 'Date of birth'
}
};

export const WithValue: Story = {
args: {
label: 'Date of birth',
value: date
}
};

export const Focused: Story = {
args: {
label: 'Date of birth',
value: date
},
play: async () => {
await userEvent.tab();
await userEvent.keyboard('{ArrowRight}');
},
parameters: {
chromaticProvider: {
colorSchemes: ['light'],
backgrounds: ['base'],
locales: ['en-US'],
disableAnimations: true
}
}
};
111 changes: 111 additions & 0 deletions packages/@react-spectrum/s2/chromatic/DatePicker.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright 2024 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import {CalendarDate, CalendarDateTime} from '@internationalized/date';
import {DatePicker} from '../';
import type {Meta, StoryObj} from '@storybook/react';
import {userEvent} from '@storybook/test';

const meta: Meta<typeof DatePicker> = {
component: DatePicker,
parameters: {
chromaticProvider: {disableAnimations: true}
},
title: 'S2 Chromatic/DatePicker'
};

export default meta;

type Story = StoryObj<typeof DatePicker>;

const date = new CalendarDate(2022, 2, 3);

export const Default: Story = {
args: {
label: 'Date of birth'
}
};

export const WithValue: Story = {
args: {
label: 'Date of birth',
value: date
}
};

export const Focused: Story = {
args: {
label: 'Date of birth',
value: date
},
play: async () => {
await userEvent.tab();
await userEvent.keyboard('{ArrowRight}');
},
parameters: {
chromaticProvider: {
colorSchemes: ['light'],
backgrounds: ['base'],
locales: ['en-US'],
disableAnimations: true
}
}
};

export const OpenPicker: Story = {
args: {
label: 'Date of birth',
value: date
},
play: async () => {
await userEvent.tab();
await userEvent.keyboard('{ArrowRight}');
await userEvent.keyboard('{ArrowRight}');
await userEvent.keyboard('{ArrowRight}');
await userEvent.keyboard('{Enter}');
},
parameters: {
chromaticProvider: {
colorSchemes: ['light'],
backgrounds: ['base'],
locales: ['en-US'],
disableAnimations: true
}
}
};

export const OpenPickerWithTime: Story = {
args: {
label: 'Date of birth',
value: new CalendarDateTime(2022, 2, 3, 12, 0, 0),
granularity: 'second'
},
play: async () => {
await userEvent.tab();
await userEvent.keyboard('{ArrowRight}');
await userEvent.keyboard('{ArrowRight}');
await userEvent.keyboard('{ArrowRight}');
await userEvent.keyboard('{ArrowRight}');
await userEvent.keyboard('{ArrowRight}');
await userEvent.keyboard('{ArrowRight}');
await userEvent.keyboard('{ArrowRight}');
await userEvent.keyboard('{Enter}');
},
parameters: {
chromaticProvider: {
colorSchemes: ['light'],
backgrounds: ['base'],
locales: ['en-US'],
disableAnimations: true
}
}
};
Loading