diff --git a/eslint.config.mjs b/eslint.config.mjs index ad336dabaf3..cd41e502778 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -501,6 +501,15 @@ export default [{ message: "Use getOwnerDocument from @react-aria/utils instead.", }], }, +}, { + files: [ + "packages/@react-aria/test-utils/src/**/*.ts", + "packages/@react-aria/test-utils/src/**/*.tsx", + ], + + rules: { + "rsp-rules/no-non-shadow-contains": OFF, + }, }, { files: ["packages/@react-spectrum/s2/**", "packages/dev/s2-docs/**"], diff --git a/packages/@react-aria/test-utils/package.json b/packages/@react-aria/test-utils/package.json index ec18ecb6981..4393a60b129 100644 --- a/packages/@react-aria/test-utils/package.json +++ b/packages/@react-aria/test-utils/package.json @@ -26,7 +26,6 @@ "url": "https://github.com/adobe/react-spectrum" }, "dependencies": { - "@react-aria/utils": "^3.32.0", "@swc/helpers": "^0.5.0" }, "peerDependencies": { diff --git a/packages/@react-aria/test-utils/src/checkboxgroup.ts b/packages/@react-aria/test-utils/src/checkboxgroup.ts index 7451b7ec9cb..54e436a5cab 100644 --- a/packages/@react-aria/test-utils/src/checkboxgroup.ts +++ b/packages/@react-aria/test-utils/src/checkboxgroup.ts @@ -12,7 +12,6 @@ import {act, within} from '@testing-library/react'; import {CheckboxGroupTesterOpts, UserOpts} from './types'; -import {nodeContains} from '@react-aria/utils'; import {pressElement} from './events'; interface TriggerCheckboxOptions { @@ -95,7 +94,7 @@ export class CheckboxGroupTester { throw new Error('Checkbox provided is not in the checkbox group.'); } - if (!nodeContains(this.checkboxgroup, document.activeElement)) { + if (!this.checkboxgroup.contains(document.activeElement)) { act(() => checkboxes[0].focus()); } diff --git a/packages/@react-aria/test-utils/src/combobox.ts b/packages/@react-aria/test-utils/src/combobox.ts index 3dfb46c3946..d95ac6f5711 100644 --- a/packages/@react-aria/test-utils/src/combobox.ts +++ b/packages/@react-aria/test-utils/src/combobox.ts @@ -12,7 +12,6 @@ import {act, waitFor, within} from '@testing-library/react'; import {ComboBoxTesterOpts, UserOpts} from './types'; -import {nodeContains} from '@react-aria/utils'; interface ComboBoxOpenOpts { /** @@ -177,7 +176,7 @@ export class ComboBoxTester { if (option.getAttribute('href') == null) { await waitFor(() => { - if (nodeContains(document, listbox)) { + if (document.contains(listbox)) { throw new Error('Expected listbox element to not be in the document after selecting an option'); } else { return true; @@ -199,7 +198,7 @@ export class ComboBoxTester { await this.user.keyboard('[Escape]'); await waitFor(() => { - if (nodeContains(document, listbox)) { + if (document.contains(listbox)) { throw new Error('Expected listbox element to not be in the document after selecting an option'); } else { return true; diff --git a/packages/@react-aria/test-utils/src/dialog.ts b/packages/@react-aria/test-utils/src/dialog.ts index 10e3b22d0f5..213c86c2b1a 100644 --- a/packages/@react-aria/test-utils/src/dialog.ts +++ b/packages/@react-aria/test-utils/src/dialog.ts @@ -12,7 +12,6 @@ import {act, waitFor, within} from '@testing-library/react'; import {DialogTesterOpts, UserOpts} from './types'; -import {nodeContains} from '@react-aria/utils'; interface DialogOpenOpts { /** @@ -97,7 +96,7 @@ export class DialogTester { } }); - if (dialog && document.activeElement !== this._trigger && nodeContains(dialog, document.activeElement)) { + if (dialog && document.activeElement !== this._trigger && dialog.contains(document.activeElement)) { this._dialog = dialog; } else { throw new Error('New modal dialog doesnt contain the active element OR the active element is still the trigger. Uncertain if the proper modal dialog was found'); @@ -114,7 +113,7 @@ export class DialogTester { if (dialog) { await this.user.keyboard('[Escape]'); await waitFor(() => { - if (nodeContains(document, dialog)) { + if (document.contains(dialog)) { throw new Error('Expected the dialog to not be in the document after closing it.'); } else { this._dialog = undefined; @@ -139,6 +138,6 @@ export class DialogTester { * Returns the dialog if present. */ get dialog(): HTMLElement | null { - return this._dialog && nodeContains(document, this._dialog) ? this._dialog : null; + return this._dialog && document.contains(this._dialog) ? this._dialog : null; } } diff --git a/packages/@react-aria/test-utils/src/gridlist.ts b/packages/@react-aria/test-utils/src/gridlist.ts index ebf8af799b6..d5d1c21e082 100644 --- a/packages/@react-aria/test-utils/src/gridlist.ts +++ b/packages/@react-aria/test-utils/src/gridlist.ts @@ -13,7 +13,6 @@ import {act, within} from '@testing-library/react'; import {getAltKey, getMetaKey, pressElement, triggerLongPress} from './events'; import {GridListTesterOpts, GridRowActionOpts, ToggleGridRowOpts, UserOpts} from './types'; -import {nodeContains} from '@react-aria/utils'; interface GridListToggleRowOpts extends ToggleGridRowOpts {} interface GridListRowActionOpts extends GridRowActionOpts {} @@ -67,13 +66,13 @@ export class GridListTester { throw new Error('Option provided is not in the gridlist'); } - if (document.activeElement !== this._gridlist && !nodeContains(this._gridlist, document.activeElement)) { + if (document.activeElement !== this._gridlist && !this._gridlist.contains(document.activeElement)) { act(() => this._gridlist.focus()); } if (document.activeElement === this._gridlist) { await this.user.keyboard(`${selectionOnNav === 'none' ? `[${altKey}>]` : ''}[ArrowDown]${selectionOnNav === 'none' ? `[/${altKey}]` : ''}`); - } else if (nodeContains(this._gridlist, document.activeElement) && document.activeElement!.getAttribute('role') !== 'row') { + } else if (this._gridlist.contains(document.activeElement) && document.activeElement!.getAttribute('role') !== 'row') { do { await this.user.keyboard('[ArrowLeft]'); } while (document.activeElement!.getAttribute('role') !== 'row'); diff --git a/packages/@react-aria/test-utils/src/listbox.ts b/packages/@react-aria/test-utils/src/listbox.ts index d8fcab4a772..cac8d9d78bc 100644 --- a/packages/@react-aria/test-utils/src/listbox.ts +++ b/packages/@react-aria/test-utils/src/listbox.ts @@ -13,7 +13,6 @@ import {act, within} from '@testing-library/react'; import {getAltKey, getMetaKey, pressElement, triggerLongPress} from './events'; import {ListBoxTesterOpts, UserOpts} from './types'; -import {nodeContains} from '@react-aria/utils'; interface ListBoxToggleOptionOpts { /** @@ -104,7 +103,7 @@ export class ListBoxTester { throw new Error('Option provided is not in the listbox'); } - if (document.activeElement !== this._listbox && !nodeContains(this._listbox, document.activeElement)) { + if (document.activeElement !== this._listbox && !this._listbox.contains(document.activeElement)) { act(() => this._listbox.focus()); await this.user.keyboard(`${selectionOnNav === 'none' ? `[${altKey}>]` : ''}[ArrowDown]${selectionOnNav === 'none' ? `[/${altKey}]` : ''}`); } diff --git a/packages/@react-aria/test-utils/src/menu.ts b/packages/@react-aria/test-utils/src/menu.ts index f3dcdd3bdd0..87af5c11fd0 100644 --- a/packages/@react-aria/test-utils/src/menu.ts +++ b/packages/@react-aria/test-utils/src/menu.ts @@ -12,7 +12,6 @@ import {act, waitFor, within} from '@testing-library/react'; import {MenuTesterOpts, UserOpts} from './types'; -import {nodeContains} from '@react-aria/utils'; import {triggerLongPress} from './events'; interface MenuOpenOpts { @@ -216,7 +215,7 @@ export class MenuTester { return; } - if (document.activeElement !== menu && !nodeContains(menu, document.activeElement)) { + if (document.activeElement !== menu && !menu.contains(document.activeElement)) { act(() => menu.focus()); } @@ -263,7 +262,7 @@ export class MenuTester { // close. In React 16, focus actually makes it all the way to the root menu's submenu trigger so we need check the root menu if (this._isSubmenu) { await waitFor(() => { - if (document.activeElement === this.trigger || nodeContains(this._rootMenu, document.activeElement)) { + if (document.activeElement === this.trigger || this._rootMenu?.contains(document.activeElement)) { throw new Error('Expected focus after selecting an submenu option to move away from the original submenu trigger.'); } else { return true; @@ -343,7 +342,7 @@ export class MenuTester { private async keyboardNavigateToOption(opts: {option: HTMLElement}) { let {option} = opts; let options = this.options(); - let targetIndex = options.findIndex(opt => (opt === option) || nodeContains(opt, option)); + let targetIndex = options.findIndex(opt => (opt === option) || opt.contains(option)); if (targetIndex === -1) { throw new Error('Option provided is not in the menu'); @@ -379,7 +378,7 @@ export class MenuTester { } }); - if (nodeContains(document, menu)) { + if (document.contains(menu)) { throw new Error('Expected the menu to not be in the document after closing it.'); } } diff --git a/packages/@react-aria/test-utils/src/radiogroup.ts b/packages/@react-aria/test-utils/src/radiogroup.ts index bdcbfce9730..6c1d0e38c9e 100644 --- a/packages/@react-aria/test-utils/src/radiogroup.ts +++ b/packages/@react-aria/test-utils/src/radiogroup.ts @@ -12,7 +12,6 @@ import {act, within} from '@testing-library/react'; import {Direction, Orientation, RadioGroupTesterOpts, UserOpts} from './types'; -import {nodeContains} from '@react-aria/utils'; import {pressElement} from './events'; interface TriggerRadioOptions { @@ -95,7 +94,7 @@ export class RadioGroupTester { throw new Error('Radio provided is not in the radio group.'); } - if (!nodeContains(this.radiogroup, document.activeElement)) { + if (!this.radiogroup.contains(document.activeElement)) { let selectedRadio = this.selectedRadio; if (selectedRadio != null) { act(() => selectedRadio.focus()); diff --git a/packages/@react-aria/test-utils/src/select.ts b/packages/@react-aria/test-utils/src/select.ts index 56a9372dfe5..4cce164f53f 100644 --- a/packages/@react-aria/test-utils/src/select.ts +++ b/packages/@react-aria/test-utils/src/select.ts @@ -11,7 +11,6 @@ */ import {act, waitFor, within} from '@testing-library/react'; -import {nodeContains} from '@react-aria/utils'; import {SelectTesterOpts, UserOpts} from './types'; interface SelectOpenOpts { @@ -111,7 +110,7 @@ export class SelectTester { } }); - if (listbox && nodeContains(document, listbox)) { + if (listbox && document.contains(listbox)) { throw new Error('Expected the select element listbox to not be in the document after closing the dropdown.'); } } @@ -192,7 +191,7 @@ export class SelectTester { return; } - if (document.activeElement !== listbox && !nodeContains(listbox, document.activeElement)) { + if (document.activeElement !== listbox && !listbox.contains(document.activeElement)) { act(() => listbox.focus()); } await this.keyboardNavigateToOption({option}); @@ -215,7 +214,7 @@ export class SelectTester { } }); - if (nodeContains(document, listbox)) { + if (document.contains(listbox)) { throw new Error('Expected select element listbox to not be in the document after selecting an option'); } } diff --git a/packages/@react-aria/test-utils/src/table.ts b/packages/@react-aria/test-utils/src/table.ts index 24071fd3b90..95d4e6fe184 100644 --- a/packages/@react-aria/test-utils/src/table.ts +++ b/packages/@react-aria/test-utils/src/table.ts @@ -13,7 +13,6 @@ import {act, waitFor, within} from '@testing-library/react'; import {getAltKey, getMetaKey, pressElement, triggerLongPress} from './events'; import {GridRowActionOpts, TableTesterOpts, ToggleGridRowOpts, UserOpts} from './types'; -import {nodeContains} from '@react-aria/utils'; interface TableToggleRowOpts extends ToggleGridRowOpts {} interface TableToggleSortOpts { @@ -66,7 +65,7 @@ export class TableTester { } // Move focus into the table - if (document.activeElement !== this._table && !nodeContains(this._table, document.activeElement)) { + if (document.activeElement !== this._table && !this._table.contains(document.activeElement)) { act(() => this._table.focus()); } @@ -75,14 +74,14 @@ export class TableTester { } // If focus is currently somewhere in the first row group (aka on a column), we want to keyboard navigate downwards till we reach the rows - if (nodeContains(this.rowGroups[0], document.activeElement)) { + if (this.rowGroups[0].contains(document.activeElement)) { do { await this.user.keyboard('[ArrowDown]'); - } while (!nodeContains(this.rowGroups[1], document.activeElement)); + } while (!this.rowGroups[1].contains(document.activeElement)); } // Move focus onto the row itself - if (nodeContains(this.rowGroups[1], document.activeElement) && document.activeElement!.getAttribute('role') !== 'row') { + if (this.rowGroups[1].contains(document.activeElement) && document.activeElement!.getAttribute('role') !== 'row') { do { await this.user.keyboard('[ArrowLeft]'); } while (document.activeElement!.getAttribute('role') !== 'row'); @@ -223,7 +222,7 @@ export class TableTester { } await waitFor(() => { - if (nodeContains(document, menu)) { + if (document.contains(menu)) { throw new Error('Expected table column menu listbox to not be in the document after selecting an option'); } else { return true; @@ -309,7 +308,7 @@ export class TableTester { await pressElement(this.user, within(menu).getAllByRole('menuitem')[action], interactionType); await waitFor(() => { - if (nodeContains(document, menu)) { + if (document.contains(menu)) { throw new Error('Expected table column menu listbox to not be in the document after selecting an option'); } else { return true; diff --git a/packages/@react-aria/test-utils/src/tabs.ts b/packages/@react-aria/test-utils/src/tabs.ts index f87a2d9afd2..c26da3e7656 100644 --- a/packages/@react-aria/test-utils/src/tabs.ts +++ b/packages/@react-aria/test-utils/src/tabs.ts @@ -12,7 +12,6 @@ import {act, within} from '@testing-library/react'; import {Direction, Orientation, TabsTesterOpts, UserOpts} from './types'; -import {nodeContains} from '@react-aria/utils'; import {pressElement} from './events'; interface TriggerTabOptions { @@ -90,7 +89,7 @@ export class TabsTester { throw new Error('Tab provided is not in the tablist'); } - if (!nodeContains(this._tablist, document.activeElement)) { + if (!this._tablist.contains(document.activeElement)) { let selectedTab = this.selectedTab; if (selectedTab != null) { act(() => selectedTab.focus()); @@ -143,7 +142,7 @@ export class TabsTester { } if (interactionType === 'keyboard') { - if (document.activeElement !== this._tablist && !nodeContains(this._tablist, document.activeElement)) { + if (document.activeElement !== this._tablist && !this._tablist.contains(document.activeElement)) { act(() => this._tablist.focus()); } diff --git a/packages/@react-aria/test-utils/src/tree.ts b/packages/@react-aria/test-utils/src/tree.ts index 28a566d59ec..cadcf52b72a 100644 --- a/packages/@react-aria/test-utils/src/tree.ts +++ b/packages/@react-aria/test-utils/src/tree.ts @@ -13,7 +13,6 @@ import {act, within} from '@testing-library/react'; import {BaseGridRowInteractionOpts, GridRowActionOpts, ToggleGridRowOpts, TreeTesterOpts, UserOpts} from './types'; import {getAltKey, getMetaKey, pressElement, triggerLongPress} from './events'; -import {nodeContains} from '@react-aria/utils'; interface TreeToggleExpansionOpts extends BaseGridRowInteractionOpts {} interface TreeToggleRowOpts extends ToggleGridRowOpts {} @@ -74,13 +73,13 @@ export class TreeTester { throw new Error('Option provided is not in the tree'); } - if (document.activeElement !== this._tree && !nodeContains(this._tree, document.activeElement)) { + if (document.activeElement !== this._tree && !this._tree.contains(document.activeElement)) { act(() => this._tree.focus()); } if (document.activeElement === this.tree) { await this.user.keyboard(`${selectionOnNav === 'none' ? `[${altKey}>]` : ''}[ArrowDown]${selectionOnNav === 'none' ? `[/${altKey}]` : ''}`); - } else if (nodeContains(this._tree, document.activeElement) && document.activeElement!.getAttribute('role') !== 'row') { + } else if (this._tree.contains(document.activeElement) && document.activeElement!.getAttribute('role') !== 'row') { do { await this.user.keyboard('[ArrowLeft]'); } while (document.activeElement!.getAttribute('role') !== 'row'); @@ -179,7 +178,7 @@ export class TreeTester { row, interactionType = this._interactionType } = opts; - if (!nodeContains(this.tree, document.activeElement)) { + if (!this.tree.contains(document.activeElement)) { await act(async () => { this.tree.focus(); }); diff --git a/packages/@react-aria/utils/src/useResizeObserver.ts b/packages/@react-aria/utils/src/useResizeObserver.ts index 0d33aa60a2d..ab0a1d5ae3c 100644 --- a/packages/@react-aria/utils/src/useResizeObserver.ts +++ b/packages/@react-aria/utils/src/useResizeObserver.ts @@ -37,7 +37,7 @@ export function useResizeObserver(options: useResizeObserverO return; } - requestAnimationFrame(() => onResizeEvent()); + onResizeEvent(); }); resizeObserverInstance.observe(element, {box}); diff --git a/packages/@react-spectrum/s2/src/ComboBox.tsx b/packages/@react-spectrum/s2/src/ComboBox.tsx index d3cd25f882f..e6178185891 100644 --- a/packages/@react-spectrum/s2/src/ComboBox.tsx +++ b/packages/@react-spectrum/s2/src/ComboBox.tsx @@ -79,7 +79,7 @@ export interface ComboboxStyleProps { size?: 'S' | 'M' | 'L' | 'XL' } export interface ComboBoxProps extends - Omit, 'children' | 'style' | 'className' | 'render' | 'defaultFilter' | 'allowsEmptyCollection' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>, + Omit, 'children' | 'style' | 'className' | 'render' | 'defaultFilter' | 'allowsEmptyCollection' | keyof GlobalDOMAttributes>, ComboboxStyleProps, StyleProps, SpectrumLabelableProps, @@ -354,7 +354,6 @@ export const ComboBox = /*#__PURE__*/ (forwardRef as forwardRefType)(function Co return ( pressScale(buttonRef)(renderProps)} className={renderProps => inputButton({ ...renderProps, diff --git a/packages/@react-spectrum/s2/src/DatePicker.tsx b/packages/@react-spectrum/s2/src/DatePicker.tsx index ab44172d92c..c5e1ee8ca40 100644 --- a/packages/@react-spectrum/s2/src/DatePicker.tsx +++ b/packages/@react-spectrum/s2/src/DatePicker.tsx @@ -41,7 +41,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface DatePickerProps extends - Omit, 'children' | 'className' | 'style' | 'render' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>, + Omit, 'children' | 'className' | 'style' | 'render' | keyof GlobalDOMAttributes>, Pick, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable'>, Pick, StyleProps, @@ -155,7 +155,6 @@ export const DatePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(function ref={ref} isRequired={isRequired} {...dateFieldProps} - isTriggerUpWhenOpen style={UNSAFE_style} className={(UNSAFE_className || '') + style(field(), getAllowedOverrides())({ isInForm: !!formContext, @@ -278,6 +277,9 @@ export function CalendarButton(props: {isOpen: boolean, size: 'S' | 'M' | 'L' | return ( - + } + }], + [InsideSelectValueContext, true] + ]}> + {defaultChildren} + + ); + }} + + + ``` - + Client-side routing Due to [HTML spec limitations](https://github.com/w3c/html-aria/issues/473), GridListItems cannot be rendered as `` elements. React Aria handles link clicks with JavaScript and triggers native navigation. When using a client-side router, use the `onAction` event to programmatically trigger navigation instead of the `href` prop. diff --git a/packages/dev/s2-docs/pages/react-aria/Table.mdx b/packages/dev/s2-docs/pages/react-aria/Table.mdx index 424dc7ecd01..b84ae1716a4 100644 --- a/packages/dev/s2-docs/pages/react-aria/Table.mdx +++ b/packages/dev/s2-docs/pages/react-aria/Table.mdx @@ -295,7 +295,7 @@ import {Table, TableHeader, Column, Row, TableBody, Cell} from 'vanilla-starter/ ``` - + Client-side routing Due to [HTML spec limitations](https://github.com/w3c/html-aria/issues/473), table rows cannot be rendered as `` elements. React Aria handles link clicks with JavaScript and triggers native navigation. When using a client-side router, use the `onAction` event to programmatically trigger navigation instead of the `href` prop. diff --git a/packages/dev/s2-docs/pages/react-aria/Tree.mdx b/packages/dev/s2-docs/pages/react-aria/Tree.mdx index 92555e74f77..0cfb27d58c4 100644 --- a/packages/dev/s2-docs/pages/react-aria/Tree.mdx +++ b/packages/dev/s2-docs/pages/react-aria/Tree.mdx @@ -219,7 +219,7 @@ import {Tree, TreeItem} from 'vanilla-starter/Tree'; ``` - + Client-side routing Due to [HTML spec limitations](https://github.com/w3c/html-aria/issues/473), TreeItems cannot be rendered as `` elements. React Aria handles link clicks with JavaScript and triggers native navigation. When using a client-side router, use the `onAction` event to programmatically trigger navigation instead of the `href` prop. diff --git a/packages/dev/s2-docs/pages/s2/forms.mdx b/packages/dev/s2-docs/pages/s2/forms.mdx index 47fbfef6c9e..1da75e033d1 100644 --- a/packages/dev/s2-docs/pages/s2/forms.mdx +++ b/packages/dev/s2-docs/pages/s2/forms.mdx @@ -131,6 +131,7 @@ Well-designed form validation assists the user with specific, helpful error mess All React Spectrum form components integrate with native HTML [constraint validation](https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation). This allows you to define constraints on each field such as required, minimum and maximum values, text formats such as email addresses, and even custom regular expression patterns. These constraints are checked by the browser when the user commits changes to the value (e.g. on blur) or submits the form. ```tsx render +'use client'; import {Form, TextField, ButtonGroup, Button} from '@react-spectrum/s2'; import {style} from '@react-spectrum/s2/style' with {type: 'macro'}; diff --git a/packages/react-aria-components/src/ComboBox.tsx b/packages/react-aria-components/src/ComboBox.tsx index 42343816a6d..91c5cfe1208 100644 --- a/packages/react-aria-components/src/ComboBox.tsx +++ b/packages/react-aria-components/src/ComboBox.tsx @@ -78,9 +78,7 @@ export interface ComboBoxProps extends Omit, HTMLDivElement>>(null); @@ -210,7 +208,7 @@ function ComboBoxInner({props, collection, comboBoxRef: ref}: values={[ [ComboBoxStateContext, state], [LabelContext, {...labelProps, ref: labelRef}], - [ButtonContext, {...buttonProps, ref: buttonRef, isPressed: !props.isTriggerUpWhenOpen && state.isOpen}], + [ButtonContext, {...buttonProps, ref: buttonRef, isPressed: state.isOpen}], [InputContext, {...inputProps, ref: inputRef}], [OverlayTriggerStateContext, state], [PopoverContext, { diff --git a/packages/react-aria-components/src/DatePicker.tsx b/packages/react-aria-components/src/DatePicker.tsx index c1b8821612d..61a50dc6ae0 100644 --- a/packages/react-aria-components/src/DatePicker.tsx +++ b/packages/react-aria-components/src/DatePicker.tsx @@ -88,18 +88,14 @@ export interface DatePickerProps extends Omit, - /** Whether the trigger is up when the overlay is open. */ - isTriggerUpWhenOpen?: boolean + className?: ClassNameOrFunction } export interface DateRangePickerProps extends Omit, 'label' | 'description' | 'errorMessage' | 'validationState' | 'validationBehavior'>, Pick, 'shouldCloseOnSelect'>, RACValidation, RenderProps, SlotProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-DateRangePicker' */ - className?: ClassNameOrFunction, - /** Whether the trigger is up when the overlay is open. */ - isTriggerUpWhenOpen?: boolean + className?: ClassNameOrFunction } export const DatePickerContext = createContext, HTMLDivElement>>(null); @@ -179,7 +175,7 @@ export const DatePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(function [DatePickerStateContext, state], [GroupContext, {...groupProps, ref: groupRef, isInvalid: state.isInvalid}], [DateFieldContext, fieldProps], - [ButtonContext, {...buttonProps, isPressed: !props.isTriggerUpWhenOpen && state.isOpen}], + [ButtonContext, {...buttonProps, isPressed: state.isOpen}], [LabelContext, {...labelProps, ref: labelRef, elementType: 'span'}], [CalendarContext, calendarProps], [OverlayTriggerStateContext, state], @@ -288,7 +284,7 @@ export const DateRangePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(func values={[ [DateRangePickerStateContext, state], [GroupContext, {...groupProps, ref: groupRef, isInvalid: state.isInvalid}], - [ButtonContext, {...buttonProps, isPressed: !props.isTriggerUpWhenOpen && state.isOpen}], + [ButtonContext, {...buttonProps, isPressed: state.isOpen}], [LabelContext, {...labelProps, ref: labelRef, elementType: 'span'}], [RangeCalendarContext, calendarProps], [OverlayTriggerStateContext, state], diff --git a/packages/react-aria-components/src/Dialog.tsx b/packages/react-aria-components/src/Dialog.tsx index c95dce96e32..2091109092a 100644 --- a/packages/react-aria-components/src/Dialog.tsx +++ b/packages/react-aria-components/src/Dialog.tsx @@ -22,8 +22,6 @@ import React, {createContext, ForwardedRef, forwardRef, JSX, ReactNode, useCallb import {RootMenuTriggerStateContext} from './Menu'; export interface DialogTriggerProps extends OverlayTriggerProps { - /** Whether the trigger is up when the overlay is open. */ - isTriggerUpWhenOpen?: boolean, children: ReactNode } @@ -88,7 +86,7 @@ export function DialogTrigger(props: DialogTriggerProps): JSX.Element { style: {'--trigger-width': buttonWidth} as React.CSSProperties }] ]}> - + {props.children} diff --git a/packages/react-aria-components/src/Menu.tsx b/packages/react-aria-components/src/Menu.tsx index 994df7d3932..91cb0727e4a 100644 --- a/packages/react-aria-components/src/Menu.tsx +++ b/packages/react-aria-components/src/Menu.tsx @@ -64,8 +64,6 @@ export const RootMenuTriggerStateContext = createContext(null); export interface MenuTriggerProps extends BaseMenuTriggerProps { - /** Whether the trigger is up when the overlay is open. */ - isTriggerUpWhenOpen?: boolean, children: ReactNode } @@ -105,7 +103,7 @@ export function MenuTrigger(props: MenuTriggerProps): JSX.Element { 'aria-labelledby': menuProps['aria-labelledby'] }] ]}> - + {props.children} diff --git a/packages/react-aria-components/src/Select.tsx b/packages/react-aria-components/src/Select.tsx index ded3a340eee..3d4e3e311bb 100644 --- a/packages/react-aria-components/src/Select.tsx +++ b/packages/react-aria-components/src/Select.tsx @@ -87,9 +87,7 @@ export interface SelectProps, HTMLDivElement>>(null); @@ -204,7 +202,7 @@ function SelectInner({props, selectRef: ref, collection}: Sele [SelectStateContext, state], [SelectValueContext, valueProps], [LabelContext, {...labelProps, ref: labelRef, elementType: 'span'}], - [ButtonContext, {...triggerProps, ref: buttonRef, isPressed: !props.isTriggerUpWhenOpen && state.isOpen, autoFocus: props.autoFocus}], + [ButtonContext, {...triggerProps, ref: buttonRef, isPressed: state.isOpen, autoFocus: props.autoFocus}], [OverlayTriggerStateContext, state], [PopoverContext, { trigger: 'Select', diff --git a/packages/react-aria-components/stories/DatePicker.stories.tsx b/packages/react-aria-components/stories/DatePicker.stories.tsx index bc9cde5a648..ae079959edf 100644 --- a/packages/react-aria-components/stories/DatePicker.stories.tsx +++ b/packages/react-aria-components/stories/DatePicker.stories.tsx @@ -47,9 +47,6 @@ export default { validationBehavior: { control: 'select', options: ['native', 'aria'] - }, - isTriggerUpWhenOpen: { - control: 'boolean' } } } as Meta; diff --git a/packages/react-aria-components/stories/Select.stories.tsx b/packages/react-aria-components/stories/Select.stories.tsx index b7bf2204137..c71374de62e 100644 --- a/packages/react-aria-components/stories/Select.stories.tsx +++ b/packages/react-aria-components/stories/Select.stories.tsx @@ -31,9 +31,6 @@ export default { selectionMode: { control: 'radio', options: ['single', 'multiple'] - }, - isTriggerUpWhenOpen: { - control: 'boolean' } } } as Meta; diff --git a/packages/react-aria-components/test/ComboBox.test.js b/packages/react-aria-components/test/ComboBox.test.js index a9cf870563c..bb17da5e894 100644 --- a/packages/react-aria-components/test/ComboBox.test.js +++ b/packages/react-aria-components/test/ComboBox.test.js @@ -115,15 +115,6 @@ describe('ComboBox', () => { expect(button).toHaveAttribute('data-pressed'); }); - it('should not apply isPressed state to button when expanded and isTriggerUpWhenOpen is true', async () => { - let {getByRole} = render(); - let button = getByRole('button'); - - expect(button).not.toHaveAttribute('data-pressed'); - await user.click(button); - expect(button).not.toHaveAttribute('data-pressed'); - }); - it('should support filtering sections', async () => { let tree = render( diff --git a/packages/react-aria-components/test/DatePicker.test.js b/packages/react-aria-components/test/DatePicker.test.js index e68afdb3be3..62d0ce8c462 100644 --- a/packages/react-aria-components/test/DatePicker.test.js +++ b/packages/react-aria-components/test/DatePicker.test.js @@ -113,15 +113,6 @@ describe('DatePicker', () => { expect(button).toHaveAttribute('data-pressed'); }); - it('should not apply isPressed state to button when expanded and isTriggerUpWhenOpen is true', async () => { - let {getByRole} = render(); - let button = getByRole('button'); - - expect(button).not.toHaveAttribute('data-pressed'); - await user.click(button); - expect(button).not.toHaveAttribute('data-pressed'); - }); - it('should support data-open state', async () => { let {getByRole} = render(); let datePicker = document.querySelector('.react-aria-DatePicker'); diff --git a/packages/react-aria-components/test/DateRangePicker.test.js b/packages/react-aria-components/test/DateRangePicker.test.js index f89cc8fee01..2dda3884105 100644 --- a/packages/react-aria-components/test/DateRangePicker.test.js +++ b/packages/react-aria-components/test/DateRangePicker.test.js @@ -134,15 +134,6 @@ describe('DateRangePicker', () => { await user.click(button); expect(button).toHaveAttribute('data-pressed'); }); - - it('should not apply isPressed state to button when expanded and isTriggerUpWhenOpen is true', async () => { - let {getByRole} = render(); - let button = getByRole('button'); - - expect(button).not.toHaveAttribute('data-pressed'); - await user.click(button); - expect(button).not.toHaveAttribute('data-pressed'); - }); it('should support data-open state', async () => { let {getByRole} = render(); diff --git a/packages/react-aria-components/test/Dialog.test.js b/packages/react-aria-components/test/Dialog.test.js index fa5a043b8d8..b9c57dc9940 100644 --- a/packages/react-aria-components/test/Dialog.test.js +++ b/packages/react-aria-components/test/Dialog.test.js @@ -56,23 +56,6 @@ describe('Dialog', () => { expect(dialog).toHaveAttribute('data-rac'); }); - it('should not apply isPressed state on trigger when expanded and isTriggerUpWhenOpen is true', async () => { - let {getByRole} = render( - - - - Title - - - ); - - let button = getByRole('button'); - expect(button).not.toHaveAttribute('data-pressed'); - - await user.click(button); - expect(button).not.toHaveAttribute('data-pressed'); - }); - it('works with modal', async () => { let {getByRole} = render( diff --git a/packages/react-aria-components/test/Menu.test.tsx b/packages/react-aria-components/test/Menu.test.tsx index aa3f48f1dbe..b46ac184faf 100644 --- a/packages/react-aria-components/test/Menu.test.tsx +++ b/packages/react-aria-components/test/Menu.test.tsx @@ -536,25 +536,6 @@ describe('Menu', () => { expect(onAction).toHaveBeenLastCalledWith('rename'); }); - it('should not apply isPressed state on trigger when expanded and isTriggerUpWhenOpen is true', async () => { - let {getByRole} = render( - - - - - Open - - - - ); - - let button = getByRole('button'); - expect(button).not.toHaveAttribute('data-pressed'); - - await user.click(button); - expect(button).not.toHaveAttribute('data-pressed'); - }); - it('should support onScroll', () => { let onScroll = jest.fn(); let {getByRole} = renderMenu({onScroll}); diff --git a/packages/react-aria-components/test/Select.test.js b/packages/react-aria-components/test/Select.test.js index 97d7cba1038..78dea4fccc1 100644 --- a/packages/react-aria-components/test/Select.test.js +++ b/packages/react-aria-components/test/Select.test.js @@ -399,15 +399,6 @@ describe('Select', () => { expect(trigger).toHaveTextContent('Kangaroo'); }); - it('should not apply isPressed state to button when expanded and isTriggerUpWhenOpen is true', async () => { - let {getByRole} = render(); - let button = getByRole('button'); - - expect(button).not.toHaveAttribute('data-pressed'); - await user.click(button); - expect(button).not.toHaveAttribute('data-pressed'); - }); - describe('typeahead', () => { beforeEach(() => { jest.useFakeTimers(); diff --git a/yarn.lock b/yarn.lock index 82f4b7eb377..d716c3117ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6179,7 +6179,6 @@ __metadata: version: 0.0.0-use.local resolution: "@react-aria/test-utils@workspace:packages/@react-aria/test-utils" dependencies: - "@react-aria/utils": "npm:^3.32.0" "@swc/helpers": "npm:^0.5.0" peerDependencies: "@testing-library/react": ^16.0.0