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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion examples/rsp-next-ts-17/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {
Flex,
Grid,
View,
ColorScheme,
} from "@adobe/react-spectrum";
import { ColorScheme } from "@react-types/provider";
import { useState } from "react";
import Moon from "@spectrum-icons/workflow/Moon";
import Light from "@spectrum-icons/workflow/Light";
Expand Down
2 changes: 1 addition & 1 deletion examples/rsp-next-ts/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
Flex,
Grid,
View,
ColorScheme,
} from "@adobe/react-spectrum";
import { ColorScheme } from "@react-types/provider";
import { useState } from "react";
import Moon from "@spectrum-icons/workflow/Moon";
import Light from "@spectrum-icons/workflow/Light";
Expand Down
2 changes: 1 addition & 1 deletion packages/@adobe/react-spectrum/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export type {SpectrumMeterProps} from '@react-spectrum/meter';
export type {SpectrumNumberFieldProps} from '@react-spectrum/numberfield';
export type {SpectrumPickerProps} from '@react-spectrum/picker';
export type {SpectrumProgressBarProps, SpectrumProgressCircleProps} from '@react-spectrum/progress';
export type {ProviderContext, ProviderProps} from '@react-spectrum/provider';
export type {ProviderContext, ProviderProps, ColorScheme, Scale, Theme} from '@react-spectrum/provider';
export type {SpectrumRadioGroupProps, SpectrumRadioProps} from '@react-spectrum/radio';
export type {SpectrumRangeSliderProps, SpectrumSliderProps} from '@react-spectrum/slider';
export type {SpectrumSearchFieldProps} from '@react-spectrum/searchfield';
Expand Down
1 change: 0 additions & 1 deletion packages/@react-aria/actiongroup/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"@react-aria/interactions": "^3.27.1",
"@react-aria/utils": "^3.33.1",
"@react-stately/list": "^3.13.4",
"@react-types/actiongroup": "^3.4.23",
"@react-types/shared": "^3.33.1",
"@swc/helpers": "^0.5.0"
},
Expand Down
3 changes: 1 addition & 2 deletions packages/@react-aria/actiongroup/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
export type {ActionGroupAria} from './useActionGroup';
export type {ActionGroupProps, AriaActionGroupProps, ActionGroupAria} from './useActionGroup';
export {useActionGroup} from './useActionGroup';
export {useActionGroupItem} from './useActionGroupItem';
export type {AriaActionGroupProps} from '@react-types/actiongroup';
export type {ActionGroupItemAria, AriaActionGroupItemProps} from './useActionGroupItem';
30 changes: 28 additions & 2 deletions packages/@react-aria/actiongroup/src/useActionGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
* governing permissions and limitations under the License.
*/

import {AriaActionGroupProps} from '@react-types/actiongroup';
import {AriaLabelingProps, DOMAttributes, DOMProps, FocusableElement, ItemElement, ItemRenderer, Key, MultipleSelection, Orientation, RefObject} from '@react-types/shared';
import {createFocusManager} from '@react-aria/focus';
import {DOMAttributes, FocusableElement, Orientation, RefObject} from '@react-types/shared';
import {filterDOMProps, getEventTarget, nodeContains, useLayoutEffect} from '@react-aria/utils';
import {KeyboardEventHandler, useState} from 'react';
import {ListState} from '@react-stately/list';
Expand All @@ -24,6 +23,33 @@ const BUTTON_GROUP_ROLES = {
'multiple': 'toolbar'
};

// Not extending CollectionBase to avoid async loading props
export interface ActionGroupProps<T> extends MultipleSelection {
/**
* The axis the ActionGroup should align with.
* @default 'horizontal'
*/
orientation?: Orientation,
/** An list of `Item` elements or a function. If the latter, a list of items must be provided using the `items` prop. */
children: ItemElement<T> | ItemElement<T>[] | ItemRenderer<T>,
/** A list of items to display as children. Must be used with a function as the sole child. */
items?: Iterable<T>,
/** A list of keys to disable. */
disabledKeys?: Iterable<Key>,
/**
* Whether the ActionGroup is disabled.
* Shows that a selection exists, but is not available in that circumstance.
*/
isDisabled?: boolean,
/**
* Invoked when an action is taken on a child. Especially useful when `selectionMode` is none.
* The sole argument `key` is the key for the item.
*/
onAction?: (key: Key) => void
}

export interface AriaActionGroupProps<T> extends ActionGroupProps<T>, DOMProps, AriaLabelingProps {}

export interface ActionGroupAria {
actionGroupProps: DOMAttributes
}
Expand Down
4 changes: 2 additions & 2 deletions packages/@react-aria/autocomplete/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"url": "https://github.com/adobe/react-spectrum"
},
"dependencies": {
"@react-aria/button": "^3.14.5",
"@react-aria/combobox": "^3.15.0",
"@react-aria/focus": "^3.21.5",
"@react-aria/i18n": "^3.12.16",
Expand All @@ -36,8 +37,7 @@
"@react-aria/utils": "^3.33.1",
"@react-stately/autocomplete": "3.0.0-beta.4",
"@react-stately/combobox": "^3.13.0",
"@react-types/autocomplete": "3.0.0-alpha.38",
"@react-types/button": "^3.15.1",
"@react-stately/searchfield": "^3.5.19",
"@react-types/shared": "^3.33.1",
"@swc/helpers": "^0.5.0"
},
Expand Down
3 changes: 1 addition & 2 deletions packages/@react-aria/autocomplete/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,5 @@
export {useSearchAutocomplete} from './useSearchAutocomplete';
export {useAutocomplete} from './useAutocomplete';

export type {AriaSearchAutocompleteOptions, SearchAutocompleteAria} from './useSearchAutocomplete';
export type {AriaSearchAutocompleteProps} from '@react-types/autocomplete';
export type {SearchAutocompleteProps, AriaSearchAutocompleteProps, AriaSearchAutocompleteOptions, SearchAutocompleteAria} from './useSearchAutocomplete';
export type {AriaAutocompleteProps, AriaAutocompleteOptions, AutocompleteAria, CollectionOptions, InputProps} from './useAutocomplete';
19 changes: 17 additions & 2 deletions packages/@react-aria/autocomplete/src/useAutocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {dispatchVirtualBlur, dispatchVirtualFocus, getVirtuallyFocusedElement, m
import {getInteractionModality, getPointerType} from '@react-aria/interactions';
// @ts-ignore
import intlMessages from '../intl/*.json';
import {FocusEvent as ReactFocusEvent, KeyboardEvent as ReactKeyboardEvent, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {FocusEvent as ReactFocusEvent, KeyboardEvent as ReactKeyboardEvent, PointerEvent as ReactPointerEvent, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {useLocalizedStringFormatter} from '@react-aria/i18n';

export interface CollectionOptions extends DOMProps, AriaLabelingProps {
Expand Down Expand Up @@ -420,6 +420,20 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
}
};

// Clicking back into the input can happen after focus moved elsewhere in the dialog, while
// virtual focus is still on an option. Clear virtual focus on pointer down so mouse
// interactions restore the input state before the click's focus handling runs.
// Touch is excluded because touch interactions should not move focus back to the input.
let onPointerDown = (e: ReactPointerEvent) => {
if (e.button !== 0 || e.pointerType === 'touch' || queuedActiveDescendant.current == null || inputRef.current == null) {
return;
}

if (getEventTarget(e) === inputRef.current) {
clearVirtualFocus();
}
};

// Only apply the autocomplete specific behaviors if the collection component wrapped by it is actually
// being filtered/allows filtering by the Autocomplete.
let inputProps = {
Expand All @@ -431,7 +445,8 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
onKeyDown,
'aria-activedescendant': state.focusedNodeId ?? undefined,
onBlur,
onFocus
onFocus,
onPointerDown
};

if (hasCollection) {
Expand Down
41 changes: 36 additions & 5 deletions packages/@react-aria/autocomplete/src/useSearchAutocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,46 @@
* governing permissions and limitations under the License.
*/

import {AriaButtonProps} from '@react-types/button';
import {AriaButtonProps} from '@react-aria/button';
import {AriaLabelingProps, CollectionBase, DOMAttributes, DOMProps, Key, KeyboardDelegate, LayoutDelegate, RefObject, ValidationResult} from '@react-types/shared';
import {AriaListBoxOptions} from '@react-aria/listbox';
import {AriaSearchAutocompleteProps} from '@react-types/autocomplete';
import {ComboBoxState} from '@react-stately/combobox';
import {DOMAttributes, KeyboardDelegate, LayoutDelegate, RefObject, ValidationResult} from '@react-types/shared';
import {AriaSearchFieldProps, useSearchField} from '@react-aria/searchfield';
import {ComboBoxState, MenuTriggerAction} from '@react-stately/combobox';
import {InputHTMLAttributes} from 'react';
import {mergeProps} from '@react-aria/utils';
import {SearchFieldProps} from '@react-stately/searchfield';
import {useComboBox} from '@react-aria/combobox';
import {useSearchField} from '@react-aria/searchfield';

export interface SearchAutocompleteProps<T> extends CollectionBase<T>, Omit<SearchFieldProps, 'onChange' | 'onSubmit' | 'defaultValue' | 'value'> {
/** The list of SearchAutocomplete items (uncontrolled). */
defaultItems?: Iterable<T>,
/** The list of SearchAutocomplete items (controlled). */
items?: Iterable<T>,
/** Method that is called when the open state of the menu changes. Returns the new open state and the action that caused the opening of the menu. */
onOpenChange?: (isOpen: boolean, menuTrigger?: MenuTriggerAction) => void,
/** The value of the SearchAutocomplete input (controlled). */
inputValue?: string,
/** The default value of the SearchAutocomplete input (uncontrolled). */
defaultInputValue?: string,
/** Handler that is called when the SearchAutocomplete input value changes. */
onInputChange?: (value: string) => void,
/**
* The interaction required to display the SearchAutocomplete menu.
* @default 'input'
*/
menuTrigger?: MenuTriggerAction,
/** Handler that is called when the SearchAutocomplete is submitted.
*
* A `value` will be passed if the submission is a custom value (e.g. a user types then presses enter).
* If the input is a selected item, `value` will be null.
*
* A `key` will be passed if the submission is a selected item (e.g. a user clicks or presses enter on an option).
* If the input is a custom value, `key` will be null.
*/
onSubmit?: (value: string | null, key: Key | null) => void
}

export interface AriaSearchAutocompleteProps<T> extends SearchAutocompleteProps<T>, Omit<AriaSearchFieldProps, 'onChange' | 'onSubmit' | 'defaultValue' | 'value'>, DOMProps, AriaLabelingProps {}

export interface SearchAutocompleteAria<T> extends ValidationResult {
/** Props for the label element. */
Expand Down
1 change: 0 additions & 1 deletion packages/@react-aria/breadcrumbs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
"@react-aria/i18n": "^3.12.16",
"@react-aria/link": "^3.8.9",
"@react-aria/utils": "^3.33.1",
"@react-types/breadcrumbs": "^3.7.19",
"@react-types/shared": "^3.33.1",
"@swc/helpers": "^0.5.0"
},
Expand Down
5 changes: 2 additions & 3 deletions packages/@react-aria/breadcrumbs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@
*/
export {useBreadcrumbItem} from './useBreadcrumbItem';
export {useBreadcrumbs} from './useBreadcrumbs';
export type {AriaBreadcrumbItemProps, AriaBreadcrumbsProps} from '@react-types/breadcrumbs';
export type {BreadcrumbItemAria} from './useBreadcrumbItem';
export type {BreadcrumbsAria} from './useBreadcrumbs';
export type {BreadcrumbItemProps, AriaBreadcrumbItemProps, BreadcrumbItemAria} from './useBreadcrumbItem';
export type {AriaBreadcrumbsProps, BreadcrumbsAria} from './useBreadcrumbs';
28 changes: 25 additions & 3 deletions packages/@react-aria/breadcrumbs/src/useBreadcrumbItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,31 @@
* governing permissions and limitations under the License.
*/

import {AriaBreadcrumbItemProps} from '@react-types/breadcrumbs';
import {DOMAttributes, FocusableElement, RefObject} from '@react-types/shared';
import {useLink} from '@react-aria/link';
import {AriaLinkProps, useLink} from '@react-aria/link';
import {DOMAttributes, DOMProps, FocusableElement, LinkDOMProps, RefObject} from '@react-types/shared';
import {ReactNode} from 'react';

export interface BreadcrumbItemProps extends AriaLinkProps, LinkDOMProps {
/** Whether the breadcrumb item represents the current page. */
isCurrent?: boolean,
/**
* The type of current location the breadcrumb item represents, if `isCurrent` is true.
* @default 'page'
*/
'aria-current'?: 'page' | 'step' | 'location' | 'date' | 'time' | boolean | 'true' | 'false',
/** Whether the breadcrumb item is disabled. */
isDisabled?: boolean,
/** The contents of the breadcrumb item. */
children: ReactNode
}

export interface AriaBreadcrumbItemProps extends BreadcrumbItemProps, DOMProps {
/**
* The HTML element used to render the breadcrumb link, e.g. 'a', or 'span'.
* @default 'a'
*/
elementType?: string
}

export interface BreadcrumbItemAria {
/** Props for the breadcrumb item link element. */
Expand Down
5 changes: 3 additions & 2 deletions packages/@react-aria/breadcrumbs/src/useBreadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
* governing permissions and limitations under the License.
*/

import {AriaBreadcrumbsProps} from '@react-types/breadcrumbs';
import {DOMAttributes} from '@react-types/shared';
import {AriaLabelingProps, DOMAttributes, DOMProps} from '@react-types/shared';
import {filterDOMProps} from '@react-aria/utils';
// @ts-ignore
import intlMessages from '../intl/*.json';
import {useLocalizedStringFormatter} from '@react-aria/i18n';

export interface AriaBreadcrumbsProps extends DOMProps, AriaLabelingProps {}

export interface BreadcrumbsAria {
/** Props for the breadcrumbs navigation element. */
navProps: DOMAttributes
Expand Down
1 change: 0 additions & 1 deletion packages/@react-aria/button/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"@react-aria/toolbar": "3.0.0-beta.24",
"@react-aria/utils": "^3.33.1",
"@react-stately/toggle": "^3.9.5",
"@react-types/button": "^3.15.1",
"@react-types/shared": "^3.33.1",
"@swc/helpers": "^0.5.0"
},
Expand Down
4 changes: 2 additions & 2 deletions packages/@react-aria/button/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
export {useButton} from './useButton';
export {useToggleButton} from './useToggleButton';
export {useToggleButtonGroup, useToggleButtonGroupItem} from './useToggleButtonGroup';
export type {AriaButtonOptions, ButtonAria} from './useButton';
export type {AriaButtonProps, AriaToggleButtonProps} from '@react-types/button';
export type {ButtonProps, LinkButtonProps, AriaBaseButtonProps, AriaButtonProps, AriaButtonOptions, ButtonAria} from './useButton';
export type {ToggleButtonProps, AriaToggleButtonProps} from './useToggleButton';
export type {AriaToggleButtonGroupProps, ToggleButtonGroupAria, AriaToggleButtonGroupItemProps} from './useToggleButtonGroup';
81 changes: 79 additions & 2 deletions packages/@react-aria/button/src/useButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,90 @@ import {
ElementType,
HTMLAttributes,
InputHTMLAttributes,
JSXElementConstructor,
ReactNode,
RefObject
} from 'react';
import {AriaButtonProps} from '@react-types/button';
import {DOMAttributes} from '@react-types/shared';
import {AriaLabelingProps, DOMAttributes, FocusableDOMProps, FocusableProps, PressEvents} from '@react-types/shared';
import {filterDOMProps, mergeProps} from '@react-aria/utils';
import {useFocusable, usePress} from '@react-aria/interactions';

export interface ButtonProps extends PressEvents, FocusableProps {
/** Whether the button is disabled. */
isDisabled?: boolean,
/** The content to display in the button. */
children?: ReactNode
}

export interface AriaBaseButtonProps extends FocusableDOMProps, AriaLabelingProps {
/** Indicates whether the element is disabled to users of assistive technology. */
'aria-disabled'?: boolean | 'true' | 'false',
/** Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed. */
'aria-expanded'?: boolean | 'true' | 'false',
/** Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element. */
'aria-haspopup'?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | 'true' | 'false',
/** Identifies the element (or elements) whose contents or presence are controlled by the current element. */
'aria-controls'?: string,
/** Indicates the current "pressed" state of toggle buttons. */
'aria-pressed'?: boolean | 'true' | 'false' | 'mixed',
/** Indicates whether this element represents the current item within a container or set of related elements. */
'aria-current'?: boolean | 'true' | 'false' | 'page' | 'step' | 'location' | 'date' | 'time',
/**
* The behavior of the button when used in an HTML form.
* @default 'button'
*/
type?: 'button' | 'submit' | 'reset',
/**
* Whether to prevent focus from moving to the button when pressing it.
*
* Caution, this can make the button inaccessible and should only be used when alternative keyboard interaction is provided,
* such as ComboBox's MenuTrigger or a NumberField's increment/decrement control.
*/
preventFocusOnPress?: boolean,
/**
* The `<form>` element to associate the button with.
* The value of this attribute must be the id of a `<form>` in the same document.
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button#form).
*/
form?: string,
/**
* The URL that processes the information submitted by the button.
* Overrides the action attribute of the button's form owner.
*/
formAction?: ButtonHTMLAttributes<HTMLButtonElement>['formAction'],
/** Indicates how to encode the form data that is submitted. */
formEncType?: string,
/** Indicates the HTTP method used to submit the form. */
formMethod?: string,
/** Indicates that the form is not to be validated when it is submitted. */
formNoValidate?: boolean,
/** Overrides the target attribute of the button's form owner. */
formTarget?: string,
/** Submitted as a pair with the button's value as part of the form data. */
name?: string,
/** The value associated with the button's name when it's submitted with the form data. */
value?: string
}

export interface AriaButtonElementTypeProps<T extends ElementType = 'button'> {
/**
* The HTML element or React element used to render the button, e.g. 'div', 'a', or `RouterLink`.
* @default 'button'
*/
elementType?: T | JSXElementConstructor<any>
}

export interface LinkButtonProps<T extends ElementType = 'button'> extends AriaButtonElementTypeProps<T> {
/** A URL to link to if elementType="a". */
href?: string,
/** The target window for the link. */
target?: string,
/** The relationship between the linked resource and the current page. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel). */
rel?: string
}

export interface AriaButtonProps<T extends ElementType = 'button'> extends ButtonProps, LinkButtonProps<T>, AriaBaseButtonProps {}

export interface AriaButtonOptions<E extends ElementType> extends Omit<AriaButtonProps<E>, 'children'> {}

export interface ButtonAria<T> {
Expand Down
Loading
Loading