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
4 changes: 3 additions & 1 deletion packages/@react-aria/combobox/src/useComboBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {AriaComboBoxProps} from '@react-types/combobox';
import {ariaHideOutside} from '@react-aria/overlays';
import {AriaListBoxOptions, getItemId, listData} from '@react-aria/listbox';
import {BaseEvent, DOMAttributes, KeyboardDelegate, LayoutDelegate, PressEvent, RefObject, RouterOptions, ValidationResult} from '@react-types/shared';
import {chain, getActiveElement, getOwnerDocument, isAppleDevice, mergeProps, useEvent, useLabels, useRouter, useUpdateEffect} from '@react-aria/utils';
import {chain, getActiveElement, getOwnerDocument, isAppleDevice, mergeProps, useEvent, useFormReset, useLabels, useRouter, useUpdateEffect} from '@react-aria/utils';
import {ComboBoxState} from '@react-stately/combobox';
import {dispatchVirtualFocus} from '@react-aria/focus';
import {FocusEvent, InputHTMLAttributes, KeyboardEvent, TouchEvent, useEffect, useMemo, useRef} from 'react';
Expand Down Expand Up @@ -220,6 +220,8 @@ export function useComboBox<T>(props: AriaComboBoxOptions<T>, state: ComboBoxSta
[privateValidationStateProp]: state
}, inputRef);

useFormReset(inputRef, state.defaultSelectedKey, state.setSelectedKey);

// Press handlers for the ComboBox button
let onPress = (e: PressEvent) => {
if (e.pointerType === 'touch') {
Expand Down
8 changes: 6 additions & 2 deletions packages/@react-aria/listbox/src/useListBoxSection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,15 @@ export function useListBoxSection(props: AriaListBoxSectionProps): ListBoxSectio
role: 'presentation'
},
headingProps: heading ? {
// Techincally, listbox cannot contain headings according to ARIA.
// Technically, listbox cannot contain headings according to ARIA.
// We hide the heading from assistive technology, using role="presentation",
// and only use it as a visual label for the nested group.
id: headingId,
role: 'presentation'
role: 'presentation',
onMouseDown: (e) => {
// Prevent DOM focus from moving on mouse down when using virtual focus
e.preventDefault();
}
} : {},
groupProps: {
role: 'group',
Expand Down
16 changes: 11 additions & 5 deletions packages/@react-aria/menu/src/useMenuItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,13 @@ export interface AriaMenuItemProps extends DOMProps, PressEvents, HoverEvents, K

/**
* Whether the menu should close when the menu item is selected.
* @default true
* @deprecated - use shouldCloseOnSelect instead.
*/
closeOnSelect?: boolean,

/** Whether the menu should close when the menu item is selected. */
shouldCloseOnSelect?: boolean,

/** Whether the menu item is contained in a virtual scrolling menu. */
isVirtualized?: boolean,

Expand Down Expand Up @@ -109,6 +112,7 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
id,
key,
closeOnSelect,
shouldCloseOnSelect,
isVirtualized,
'aria-haspopup': hasPopup,
onPressStart,
Expand Down Expand Up @@ -221,8 +225,10 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
? interaction.current?.key === 'Enter' || selectionManager.selectionMode === 'none' || selectionManager.isLink(key)
// Close except if multi-select is enabled.
: selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key);

shouldClose = closeOnSelect ?? shouldClose;


shouldClose = shouldCloseOnSelect ?? closeOnSelect ?? shouldClose;

if (onClose && !isTrigger && shouldClose) {
onClose();
}
Expand Down Expand Up @@ -312,8 +318,8 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
...mergeProps(
domProps,
linkProps,
isTrigger
? {onFocus: itemProps.onFocus, 'data-collection': itemProps['data-collection'], 'data-key': itemProps['data-key']}
isTrigger
? {onFocus: itemProps.onFocus, 'data-collection': itemProps['data-collection'], 'data-key': itemProps['data-key']}
: itemProps,
pressProps,
hoverProps,
Expand Down
9 changes: 8 additions & 1 deletion packages/@react-aria/utils/src/useEffectEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import {useLayoutEffect} from './useLayoutEffect';
// before all layout effects, but is available only in React 18 and later.
const useEarlyEffect = React['useInsertionEffect'] ?? useLayoutEffect;

export function useEffectEvent<T extends Function>(fn?: T): T {
// Starting with React 19.2, this hook has been internalized.
const useModernEffectEvent = React['useEffectEvent'] ?? useLegacyEffectEvent;

function useLegacyEffectEvent<T extends Function>(fn?: T): T {
const ref = useRef<T | null | undefined>(null);
useEarlyEffect(() => {
ref.current = fn;
Expand All @@ -28,3 +31,7 @@ export function useEffectEvent<T extends Function>(fn?: T): T {
return f?.(...args);
}, []);
}

export function useEffectEvent<T extends Function>(fn: T): T {
return useModernEffectEvent(fn);
}
5 changes: 3 additions & 2 deletions packages/@react-aria/utils/src/useEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/

import {RefObject} from '@react-types/shared';
import {useEffect} from 'react';
import {useCallback, useEffect} from 'react';
import {useEffectEvent} from './useEffectEvent';

export function useEvent<K extends keyof GlobalEventHandlersEventMap>(
Expand All @@ -20,7 +20,8 @@ export function useEvent<K extends keyof GlobalEventHandlersEventMap>(
handler?: (this: Document, ev: GlobalEventHandlersEventMap[K]) => any,
options?: boolean | AddEventListenerOptions
): void {
let handleEvent = useEffectEvent(handler);
let noop = useCallback(() => {}, []);
let handleEvent = useEffectEvent(handler ?? noop);
let isDisabled = handler == null;

useEffect(() => {
Expand Down
20 changes: 14 additions & 6 deletions packages/@react-spectrum/combobox/test/ComboBox.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5268,26 +5268,30 @@ describe('ComboBox', function () {

if (parseInt(React.version, 10) >= 19) {
it('resets to defaultSelectedKey when submitting form action', async () => {
function Test() {
function Test(props) {
const [value, formAction] = React.useActionState(() => '2', '1');

return (
<Provider theme={theme}>
<form action={formAction}>
<ExampleComboBox defaultSelectedKey={value} />
<ExampleComboBox defaultSelectedKey={value} name="combobox" {...props} />
<input type="submit" data-testid="submit" />
</form>
</Provider>
);
}

let {getByTestId, getByRole} = render(<Test />);
let {getByTestId, getByRole, rerender} = render(<Test />);
let input = getByRole('combobox');
expect(input).toHaveValue('One');

let button = getByTestId('submit');
await act(async () => await user.click(button));
expect(input).toHaveValue('Two');

rerender(<Test formValue="key" />);
await act(async () => await user.click(button));
expect(document.querySelector('input[name=combobox]')).toHaveValue('2');
});
}

Expand Down Expand Up @@ -5597,26 +5601,30 @@ describe('ComboBox', function () {

if (parseInt(React.version, 10) >= 19) {
it('resets to defaultSelectedKey when submitting form action', async () => {
function Test() {
function Test(props) {
const [value, formAction] = React.useActionState(() => '2', '1');

return (
<Provider theme={theme}>
<form action={formAction}>
<ExampleComboBox name="combobox" defaultSelectedKey={value} />
<ExampleComboBox name="combobox" defaultSelectedKey={value} {...props} />
<input type="submit" data-testid="submit" />
</form>
</Provider>
);
}

let {getByTestId} = render(<Test />);
let {getByTestId, rerender} = render(<Test />);
let input = document.querySelector('input[name=combobox]');
expect(input).toHaveValue('One');

let button = getByTestId('submit');
await act(async () => await user.click(button));
expect(input).toHaveValue('Two');

rerender(<Test formValue="key" />);
await act(async () => await user.click(button));
expect(input).toHaveValue('2');
});
}

Expand Down
2 changes: 1 addition & 1 deletion packages/@react-types/radio/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
} from '@react-types/shared';
import {ReactElement, ReactNode} from 'react';

export interface RadioGroupProps extends ValueBase<string|null, string>, InputBase, Pick<InputDOMProps, 'name'>, Validation<string | null>, LabelableProps, HelpTextProps, FocusEvents {
export interface RadioGroupProps extends ValueBase<string|null, string>, InputBase, Pick<InputDOMProps, 'name'>, Validation<string>, LabelableProps, HelpTextProps, FocusEvents {
/**
* The axis the Radio Button(s) should align with.
* @default 'vertical'
Expand Down
4 changes: 2 additions & 2 deletions packages/dev/s2-docs/pages/react-aria/ComboBox.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const description = 'Combines a text input with a listbox, allowing users
<PageDescription>{docs.exports.ComboBox.description}</PageDescription>

<ExampleSwitcher>
```tsx render docs={vanillaDocs.exports.ComboBox} links={vanillaDocs.links} props={['label', 'isDisabled']} initialProps={{label: 'Favorite Animal', placeholder: 'Select a flavor'}} type="vanilla" files={["starters/docs/src/ComboBox.tsx", "starters/docs/src/ComboBox.css"]}
```tsx render docs={vanillaDocs.exports.ComboBox} links={vanillaDocs.links} props={['label', 'isDisabled']} initialProps={{label: 'Favorite Animal', placeholder: 'Select an animal'}} type="vanilla" files={["starters/docs/src/ComboBox.tsx", "starters/docs/src/ComboBox.css"]}
"use client";
import {ComboBox, ComboBoxItem} from 'vanilla-starter/ComboBox';

Expand All @@ -34,7 +34,7 @@ export const description = 'Combines a text input with a listbox, allowing users
</ComboBox>
```

```tsx render docs={vanillaDocs.exports.ComboBox} links={vanillaDocs.links} props={['label', 'isDisabled']} initialProps={{label: 'Favorite Animal', placeholder: 'Select a flavor'}} type="tailwind" files={["starters/tailwind/src/ComboBox.tsx"]}
```tsx render docs={vanillaDocs.exports.ComboBox} links={vanillaDocs.links} props={['label', 'isDisabled']} initialProps={{label: 'Favorite Animal', placeholder: 'Select an animal'}} type="tailwind" files={["starters/tailwind/src/ComboBox.tsx"]}
"use client";
import {ComboBox, ComboBoxItem} from 'tailwind-starter/ComboBox';

Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/Toast.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ Include a `<Button slot="close">` to allow users to dismiss the toast manually.

<InlineAlert variant="notice">
<Heading>Accessibility</Heading>
<Content>We recommend that that the close button should be rendered as a sibling of `<ToastContent>` rather than inside it, so that screen readers announce the toast content without the close button first.</Content>
<Content>We recommend that the close button should be rendered as a sibling of `<ToastContent>` rather than inside it, so that screen readers announce the toast content without the close button first.</Content>
</InlineAlert>

## Dismissal
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/Tree/testing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ let testUtilUser = new User({
});
// ...

it('Tree can select and expand a item via keyboard', async function () {
it('Tree can select and expand an item via keyboard', async function () {
// Render your test component/app and initialize the Tree tester
let {getByTestId} = render(
<Tree data-testid="test-tree" selectionMode="multiple">
Expand Down
4 changes: 2 additions & 2 deletions packages/dev/s2-docs/pages/react-aria/forms.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ Supported constraints include:

* `isRequired` indicates that a field must have a value before the form can be submitted.
* `minValue` and `maxValue` specify the minimum and maximum value in a date picker or number field.
* `minLength` and `maxLength` specify the minimum and length of text input.
* `minLength` and `maxLength` specify the minimum and maximum length of text input.
* `pattern` provides a custom [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions) that a text input must conform to.
* `type="email"` and `type="url"` provide builtin validation for email addresses and URLs.

Expand Down Expand Up @@ -261,7 +261,7 @@ By default, invalid fields block forms from being submitted. To avoid this, use

Client side validation is useful to give the user immediate feedback, but data should always be validated on the backend for security and reliability. Your business logic may also include rules which cannot be validated on the frontend.

To display server validation errors, set the the `validationErrors` prop on the [Form](Form) component. This accepts an object that maps each field's `name` prop to one or more error messages. These are displayed as soon as the `validationErrors` prop is set, and cleared after the user modifies each field's value.
To display server validation errors, set the `validationErrors` prop on the [Form](Form) component. This accepts an object that maps each field's `name` prop to one or more error messages. These are displayed as soon as the `validationErrors` prop is set, and cleared after the user modifies each field's value.

```tsx render
'use client';
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/frameworks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ export const description = 'How to integrate with your framework.';
```ts
// vite.config.ts
import {defineConfig} from 'vite';
import localesPlugin from '@react-aria/optimize-locales-plugin';
import optimizeLocales from '@react-aria/optimize-locales-plugin';

export default defineConfig({
plugins: [
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ For more information, see the [Claude Code MCP documentation](https://docs.claud

Create or edit the configuration file `~/.codex/config.toml` and add:

```js
```
[mcp_servers.react-aria]
command = "npx"
args = ["@react-aria/mcp@latest"]
Expand Down
4 changes: 2 additions & 2 deletions packages/dev/s2-docs/pages/react-aria/releases/v1-0-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ In this release, we made a few last API updates to React Aria Components as they
* Docs for `useLandmark` - [@reidbarber](https://github.com/reidbarber) - [PR](https://github.com/adobe/react-spectrum/pull/5418)
* Fix prop table in docs - [@yihuiliao](https://github.com/yihuiliao) - [PR](https://github.com/adobe/react-spectrum/pull/5532)
* Update `FileTrigger` directory prop name and docs - [@yihuiliao](https://github.com/yihuiliao) - [PR](https://github.com/adobe/react-spectrum/pull/5512)
* Fix broken links in the the docs - [@ktabors](https://github.com/ktabors) - [PR](https://github.com/adobe/react-spectrum/pull/5572)
* Fix broken links in the docs - [@ktabors](https://github.com/ktabors) - [PR](https://github.com/adobe/react-spectrum/pull/5572)
* Update collections and selection guides for React Aria Components - [@devongovett](https://github.com/devongovett) - [PR](https://github.com/adobe/react-spectrum/pull/5455)

## Released packages

```json
```
- react-aria@3.31.0
- react-aria-components@1.0.0
- react-stately@3.29.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-1-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ As always, huge thanks and appreciation for everyone in our community for their

## Released packages

```json
```
- react-aria@3.32.0
- react-aria-components@1.1.0
- react-stately@3.30.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-10-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ As always, thank you to our community for their support and contributions!

## Released packages

```json
```
- react-aria@3.41.0
- react-aria-components@1.10.0
- react-stately@3.39.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-11-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ As always, thanks so much to everyone who contributed to this release!

## Released packages

```json
```
- react-aria@3.42.0
- react-aria-components@1.11.0
- react-stately@3.40.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-12-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ As always, a big thank you to everyone in the community for your feedback and co

## Released packages

```json
```
- react-aria@3.43.0
- react-aria-components@1.12.0
- react-stately@3.41.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-13-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ To support multi-selection in React Aria Select, we are updating the API from `s

## Released packages

```json
```
- react-aria@3.44.0
- react-aria-components@1.13.0
- react-stately@3.42.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-14-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ As usual, we have included various new features and bug fixes, including support

## Released packages

```json
```
- @internationalized/date@3.10.1
- @react-aria/actiongroup@3.7.22
- @react-aria/autocomplete@3.0.0-rc.4
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-2-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ Last but not least, we want to acknowledge all the wonderful contributors who ha

## Released packages

```json
```
- react-aria@3.33.0
- react-aria-components@1.2.0
- react-stately@3.31.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-3-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ Because of various breaking changes, several packages are being bumped a major v

## Released packages

```json
```
- react-aria@3.34.0
- react-aria-components@1.3.0
- react-stately@3.32.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-4-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Huge thanks as always to everyone who contributed to this release! 😍

## Released packages

```json
```
- react-aria-components@1.4.0
- react-aria@3.35.0
- react-stately@3.33.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-5-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ React Aria is now [Typescript Strict](https://www.typescriptlang.org/tsconfig/#s

## Released packages

```json
```
- react-aria@3.36.0
- react-aria-components@1.5.0
- react-stately@3.34.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-6-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ We are also excited to announce the alpha release of the [@react-aria/test-utils

## Released packages

```json
```
- react-aria@3.37.0
- react-aria-components@1.6.0
- react-stately@3.35.0
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/react-aria/releases/v1-7-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Autocomplete

## Released packages

```json
```
- react-aria@3.38.0
- react-aria-components@1.7.0
- react-stately@3.36.0
Expand Down
Loading
Loading