Skip to content

Commit 5f67967

Browse files
committed
Merge branch 'main' into ts-explicit-modules-s2
# Conflicts: # packages/@react-spectrum/s2/src/Tabs.tsx
2 parents e3c35d2 + 51f46e0 commit 5f67967

File tree

172 files changed

+2782
-686
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

172 files changed

+2782
-686
lines changed

.storybook-s2/docs/StyleMacro.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ function MyComponent({variant}) {
205205
display: 'flex',
206206
alignItems: 'center',
207207
columnGap: 8
208-
};
208+
} as const;
209209
210210
const styles = style({
211211
...horizontalStack,
@@ -218,7 +218,7 @@ export function horizontalStack(gap: number) {
218218
display: 'flex',
219219
alignItems: 'center',
220220
columnGap: gap
221-
};
221+
} as const;
222222
}`)}</Pre>
223223
<P>Then, import your macro and use it in a component.</P>
224224
<Pre>{highlight(`// component.tsx

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"build:s2-docs": "NODE_ENV=storybook storybook build -c .storybook-s2 --docs",
2626
"start:docs": "DOCS_ENV=dev parcel 'packages/@react-{spectrum,aria,stately}/*/docs/*.mdx' 'packages/react-aria-components/docs/**/*.mdx' 'packages/@internationalized/*/docs/*.mdx' 'packages/dev/docs/pages/**/*.mdx'",
2727
"build:docs": "DOCS_ENV=staging parcel build 'packages/@react-{spectrum,aria,stately}/*/docs/*.mdx' 'packages/react-aria-components/docs/**/*.mdx' 'packages/@internationalized/*/docs/*.mdx' 'packages/dev/docs/pages/**/*.mdx'",
28-
"test": "cross-env STRICT_MODE=1 yarn jest",
28+
"test": "cross-env STRICT_MODE=1 VIRT_ON=1 yarn jest",
2929
"test:lint": "node packages/**/*.test-lint.js",
3030
"test-loose": "cross-env VIRT_ON=1 yarn jest",
3131
"test-storybook": "test-storybook --url http://localhost:9003 --browsers chromium --no-cache",

packages/@internationalized/number/src/NumberParser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ interface Symbols {
2323
}
2424

2525
const CURRENCY_SIGN_REGEX = new RegExp('^.*\\(.*\\).*$');
26-
const NUMBERING_SYSTEMS = ['latn', 'arab', 'hanidec', 'deva', 'beng'];
26+
const NUMBERING_SYSTEMS = ['latn', 'arab', 'hanidec', 'deva', 'beng', 'fullwide'];
2727

2828
/**
2929
* A NumberParser can be used to perform locale-aware parsing of numbers from Unicode strings,

packages/@react-aria/aria-modal-polyfill/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const currentDocument = typeof document !== 'undefined' ? document : undefined;
1919
/**
2020
* Acts as a polyfill for `aria-modal` by watching for added modals and hiding any surrounding DOM elements with `aria-hidden`.
2121
*/
22-
export function watchModals(selector:string = 'body', {document = currentDocument} = {}): Revert {
22+
export function watchModals(selector:string = 'body', {document = currentDocument}: {document?: Document} = {}): Revert {
2323
/**
2424
* Listen for additions to the child list of the selected element (defaults to body). This is where providers render modal portals.
2525
* When one is added, see if there is a modal inside it, if there is, then hide everything else from screen readers.

packages/@react-aria/button/stories/useButton.stories.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@
1111
*/
1212

1313
import {AriaButtonProps} from '@react-types/button';
14-
import React, {useRef} from 'react';
14+
import React, {JSX, useRef} from 'react';
15+
import {StoryObj} from '@storybook/react';
1516
import {useButton} from '../';
1617

1718
export default {
1819
title: 'useButton'
1920
};
21+
export type InputButtonStory = StoryObj<typeof InputButton>;
2022

21-
export const InputTypeButton = {
23+
export const InputTypeButton: InputButtonStory = {
2224
render: () => <InputButton />,
2325
name: 'input type button'
2426
};
@@ -27,7 +29,7 @@ interface InputButtonProps extends AriaButtonProps<'input'> {
2729
value?: string
2830
}
2931

30-
function InputButton(props: InputButtonProps) {
32+
function InputButton(props: InputButtonProps): JSX.Element {
3133
let {
3234
value = 'Test'
3335
} = props;

packages/@react-aria/calendar/src/useCalendarCell.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ export interface AriaCalendarCellProps {
2828
* Whether the cell is disabled. By default, this is determined by the
2929
* Calendar's `minValue`, `maxValue`, and `isDisabled` props.
3030
*/
31-
isDisabled?: boolean
31+
isDisabled?: boolean,
32+
33+
/**
34+
* Whether the cell is outside of the current month.
35+
*/
36+
isOutsideMonth?: boolean
3237
}
3338

3439
export interface CalendarCellAria {
@@ -85,7 +90,7 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
8590
timeZone: state.timeZone
8691
});
8792
let isSelected = state.isSelected(date);
88-
let isFocused = state.isCellFocused(date);
93+
let isFocused = state.isCellFocused(date) && !props.isOutsideMonth;
8994
isDisabled = isDisabled || state.isCellDisabled(date);
9095
let isUnavailable = state.isCellUnavailable(date);
9196
let isSelectable = !isDisabled && !isUnavailable;

packages/@react-aria/calendar/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ interface HookData {
2525
selectedDateDescription: string
2626
}
2727

28-
export const hookData = new WeakMap<CalendarState | RangeCalendarState, HookData>();
28+
export const hookData: WeakMap<CalendarState | RangeCalendarState, HookData> = new WeakMap<CalendarState | RangeCalendarState, HookData>();
2929

3030
export function getEraFormat(date: CalendarDate | undefined): 'short' | undefined {
3131
return date?.calendar.identifier === 'gregory' && date.era === 'BC' ? 'short' : undefined;

packages/@react-aria/calendar/stories/Example.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
* OF ANY KIND, either express or implied. See the License for the specific language
1010
* governing permissions and limitations under the License.
1111
*/
12+
import {AriaCalendarProps, DateValue, useCalendar, useCalendarCell, useCalendarGrid} from '../src';
1213
import {Button} from '@react-spectrum/button';
14+
import {CalendarDate, createCalendar, DateDuration, startOfWeek} from '@internationalized/date';
1315
import {CalendarState, RangeCalendarState, useCalendarState} from '@react-stately/calendar';
14-
import {createCalendar, DateDuration, startOfWeek} from '@internationalized/date';
15-
import React, {ReactElement, useMemo, useRef} from 'react';
16-
import {useCalendar, useCalendarCell, useCalendarGrid} from '../src';
16+
import React, {JSX, ReactElement, useMemo, useRef} from 'react';
1717
import {useDateFormatter, useLocale} from '@react-aria/i18n';
1818

1919

20-
export function Example(props) {
20+
export function Example<T extends DateValue | CalendarDate>(props: AriaCalendarProps<T> & {visibleDuration: DateDuration}): JSX.Element {
2121
let {locale} = useLocale();
2222
const {visibleDuration} = props;
2323

@@ -98,7 +98,7 @@ function Cell(props) {
9898
);
9999
}
100100

101-
export function ExampleCustomFirstDay(props) {
101+
export function ExampleCustomFirstDay(props: AriaCalendarProps<DateValue>): JSX.Element {
102102
let {locale} = useLocale();
103103
const {firstDayOfWeek} = props;
104104

packages/@react-aria/calendar/stories/useCalendar.stories.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,48 +12,51 @@
1212

1313
import {Example} from './Example';
1414
import React from 'react';
15+
import {StoryObj} from '@storybook/react';
1516
import {today} from '@internationalized/date';
1617

1718
export default {
1819
title: 'Date and Time/useCalendar'
1920
};
2021

21-
export const Days3 = {
22+
export type ExampleStory = StoryObj<typeof Example>;
23+
24+
export const Days3: ExampleStory = {
2225
render: () => <Example visibleDuration={{days: 3}} />,
2326
name: 'days: 3'
2427
};
2528

26-
export const Weeks1 = {
29+
export const Weeks1: ExampleStory = {
2730
render: () => <Example visibleDuration={{weeks: 1}} />,
2831
name: 'weeks: 1'
2932
};
3033

31-
export const Weeks2 = {
34+
export const Weeks2: ExampleStory = {
3235
render: () => <Example visibleDuration={{weeks: 2}} />,
3336
name: 'weeks: 2'
3437
};
3538

36-
export const Months1 = {
39+
export const Months1: ExampleStory = {
3740
render: () => <Example visibleDuration={{months: 1}} />,
3841
name: 'months: 1'
3942
};
4043

41-
export const Months2 = {
44+
export const Months2: ExampleStory = {
4245
render: () => <Example visibleDuration={{months: 2}} />,
4346
name: 'months: 2'
4447
};
4548

46-
export const Days7SingleToday = {
47-
render: () => <Example defaultValue={today} visibleDuration={{days: 7}} pageBehavior="single" />,
49+
export const Days7SingleToday: ExampleStory = {
50+
render: () => <Example defaultValue={today('UTC')} visibleDuration={{days: 7}} pageBehavior="single" />,
4851
name: 'days: 7, pageBehavior: single, defaultValue: today'
4952
};
5053

51-
export const Weeks5SingleToday = {
52-
render: () => <Example defaultValue={today} visibleDuration={{weeks: 5}} pageBehavior="single" />,
54+
export const Weeks5SingleToday: ExampleStory = {
55+
render: () => <Example defaultValue={today('UTC')} visibleDuration={{weeks: 5}} pageBehavior="single" />,
5356
name: 'weeks: 5, pageBehavior: single, defaultValue: today'
5457
};
5558

56-
export const Months2PageBehaviorSingle = {
59+
export const Months2PageBehaviorSingle: ExampleStory = {
5760
render: () => <Example visibleDuration={{months: 2}} pageBehavior="single" />,
5861
name: 'months: 2, pageBehavior: single'
5962
};

packages/@react-aria/checkbox/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ interface CheckboxGroupData {
1919
validationBehavior: 'aria' | 'native'
2020
}
2121

22-
export const checkboxGroupData = new WeakMap<CheckboxGroupState, CheckboxGroupData>();
22+
export const checkboxGroupData: WeakMap<CheckboxGroupState, CheckboxGroupData> = new WeakMap<CheckboxGroupState, CheckboxGroupData>();

packages/@react-aria/collections/src/Document.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,11 +395,11 @@ export class ElementNode<T> extends BaseNode<T> {
395395
*/
396396
export class Document<T, C extends BaseCollection<T> = BaseCollection<T>> extends BaseNode<T> {
397397
nodeType = 11; // DOCUMENT_FRAGMENT_NODE
398-
ownerDocument = this;
398+
ownerDocument: Document<T, C> = this;
399399
dirtyNodes: Set<BaseNode<T>> = new Set();
400400
isSSR = false;
401401
nodeId = 0;
402-
nodesByProps = new WeakMap<object, ElementNode<T>>();
402+
nodesByProps: WeakMap<object, ElementNode<T>> = new WeakMap<object, ElementNode<T>>();
403403
isMounted = true;
404404
private collection: C;
405405
private nextCollection: C | null = null;

packages/@react-aria/collections/src/Hidden.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212

1313
import {forwardRefType} from '@react-types/shared';
14-
import React, {createContext, forwardRef, JSX, ReactElement, ReactNode, useContext} from 'react';
14+
import React, {Context, createContext, forwardRef, JSX, ReactElement, ReactNode, useContext} from 'react';
1515

1616
// React doesn't understand the <template> element, which doesn't have children like a normal element.
1717
// It will throw an error during hydration when it expects the firstChild to contain content rendered
@@ -33,7 +33,7 @@ if (typeof HTMLTemplateElement !== 'undefined') {
3333
});
3434
}
3535

36-
export const HiddenContext = createContext<boolean>(false);
36+
export const HiddenContext: Context<boolean> = createContext<boolean>(false);
3737

3838
export function Hidden(props: {children: ReactNode}): JSX.Element {
3939
let isHidden = useContext(HiddenContext);

packages/@react-aria/combobox/stories/example.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13+
import {AriaComboBoxProps, useComboBox} from '@react-aria/combobox';
1314
import {DismissButton, useOverlay} from '@react-aria/overlays';
1415
import {FocusScope} from '@react-aria/focus';
15-
import React from 'react';
16+
import React, {JSX} from 'react';
1617
import {useButton} from '@react-aria/button';
17-
import {useComboBox} from '@react-aria/combobox';
1818
import {useComboBoxState} from '@react-stately/combobox';
1919
import {useFilter} from '@react-aria/i18n';
2020
import {useListBox, useOption} from '@react-aria/listbox';
2121

22-
export function ComboBox(props) {
22+
export function ComboBox(props: AriaComboBoxProps<any>): JSX.Element {
2323
// Setup filter function and state.
2424
let {contains} = useFilter({sensitivity: 'base'});
2525
let state = useComboBoxState({...props, defaultFilter: contains});

packages/@react-aria/combobox/stories/useComboBox.stories.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,40 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13+
import {AriaComboBoxProps} from '@react-aria/combobox';
1314
import {ComboBox} from './example';
1415
import {Item} from '@react-stately/collections';
15-
import React from 'react';
16+
import React, {JSX} from 'react';
17+
import {StoryObj} from '@storybook/react';
1618

1719
export default {
1820
title: 'useComboBox'
1921
};
2022

23+
export type TemplateStory = StoryObj<typeof Template>;
24+
2125
let lotsOfItems: any[] = [];
2226
for (let i = 0; i < 50; i++) {
2327
lotsOfItems.push({name: 'Item ' + i});
2428
}
2529

26-
const Template = (args) => (
30+
const Template = (args: AriaComboBoxProps<any>): JSX.Element => (
2731
<ComboBox {...args} label="Example" defaultItems={lotsOfItems}>
2832
{(item: any) => <Item key={item.name}>{item.name}</Item>}
2933
</ComboBox>
3034
);
3135

32-
export const ScrollTesting = {
36+
export const ScrollTesting: TemplateStory = {
3337
render: Template,
3438
args: {}
3539
};
3640

37-
export const Disabled = {
41+
export const Disabled: TemplateStory = {
3842
render: Template,
3943
args: {isDisabled: true}
4044
};
4145

42-
export const FocusWrapping = {
46+
export const FocusWrapping: TemplateStory = {
4347
render: Template,
4448
args: {shouldFocusWrap: true}
4549
};

packages/@react-aria/datepicker/src/useDateField.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ interface HookData {
5151
focusManager: FocusManager
5252
}
5353

54-
export const hookData = new WeakMap<DateFieldState, HookData>();
54+
export const hookData: WeakMap<DateFieldState, HookData> = new WeakMap<DateFieldState, HookData>();
5555

5656
// Private props that we pass from useDatePicker/useDateRangePicker.
5757
// Ideally we'd use a Symbol for this, but React doesn't support them: https://github.com/facebook/react/issues/7552
58-
export const roleSymbol = '__role_' + Date.now();
59-
export const focusManagerSymbol = '__focusManager_' + Date.now();
58+
export const roleSymbol: string = '__role_' + Date.now();
59+
export const focusManagerSymbol: string = '__focusManager_' + Date.now();
6060

6161
/**
6262
* Provides the behavior and accessibility implementation for a date field component.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2025 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
13+
import {createCalendar, parseDate} from '@internationalized/date';
14+
import {Meta, StoryObj} from '@storybook/react';
15+
import React, {ReactElement, useRef} from 'react';
16+
import {useDateField} from '../src';
17+
import {useDateFieldState} from '@react-stately/datepicker';
18+
import {useLocale} from '@react-aria/i18n';
19+
20+
export function ProgrammaticSetValueExampleRender(): ReactElement {
21+
let {locale} = useLocale();
22+
let state = useDateFieldState({locale, createCalendar});
23+
let ref = useRef<HTMLDivElement>(null);
24+
let {fieldProps} = useDateField({'aria-label': 'Date'}, state, ref);
25+
return (
26+
<div>
27+
<div {...fieldProps} ref={ref} data-testid="field">
28+
{state.segments.map((seg, i) => <span key={i}>{seg.text}</span>)}
29+
</div>
30+
<button onClick={() => state.setValue(parseDate('2020-01-01'))} data-testid="set">Set</button>
31+
</div>
32+
);
33+
}
34+
35+
export default {
36+
title: 'Date and Time/useDatePicker',
37+
excludeStories: ['ProgrammaticSetValueExampleRender']
38+
} as Meta<typeof ProgrammaticSetValueExampleRender>;
39+
40+
type Story = StoryObj<typeof ProgrammaticSetValueExampleRender>;
41+
42+
export const ProgrammaticSetValueExample: Story = {
43+
render: () => <ProgrammaticSetValueExampleRender />
44+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2025 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
13+
import {pointerMap, render} from '@react-spectrum/test-utils-internal';
14+
import {ProgrammaticSetValueExampleRender} from '../stories/useDatePicker.stories';
15+
import React, {} from 'react';
16+
import userEvent from '@testing-library/user-event';
17+
18+
describe('useDatePicker', function () {
19+
let user;
20+
beforeAll(() => {
21+
user = userEvent.setup({delay: null, pointerMap});
22+
jest.useFakeTimers();
23+
});
24+
25+
it('should commit programmatically setValue when field is empty', async () => {
26+
let {getByTestId} = render(<ProgrammaticSetValueExampleRender />);
27+
28+
expect(getByTestId('field')).toHaveTextContent('mm/dd/yyyy');
29+
await user.click(getByTestId('set'));
30+
expect(getByTestId('field')).toHaveTextContent('2020');
31+
});
32+
});

0 commit comments

Comments
 (0)