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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^12.1.3",
"@types/react": "^17.0.37",
"@types/react": "^18.2.7",
"@types/storybook__react": "^5.2.1",
"@typescript-eslint/eslint-plugin": "^5.40.0",
"@typescript-eslint/parser": "^5.40.0",
Expand Down
15 changes: 8 additions & 7 deletions packages/@react-aria/button/src/useButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {mergeProps} from '@react-aria/utils';
import {useFocusable} from '@react-aria/focus';
import {usePress} from '@react-aria/interactions';

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

export interface ButtonAria<T> {
/** Props for the button element. */
Expand All @@ -34,19 +35,19 @@ export interface ButtonAria<T> {
}

// Order with overrides is important: 'button' should be default
export function useButton(props: AriaButtonProps<'button'>, ref: RefObject<HTMLButtonElement>): ButtonAria<ButtonHTMLAttributes<HTMLButtonElement>>;
export function useButton(props: AriaButtonProps<'a'>, ref: RefObject<HTMLAnchorElement>): ButtonAria<AnchorHTMLAttributes<HTMLAnchorElement>>;
export function useButton(props: AriaButtonProps<'div'>, ref: RefObject<HTMLDivElement>): ButtonAria<HTMLAttributes<HTMLDivElement>>;
export function useButton(props: AriaButtonProps<'input'>, ref: RefObject<HTMLInputElement>): ButtonAria<InputHTMLAttributes<HTMLInputElement>>;
export function useButton(props: AriaButtonProps<'span'>, ref: RefObject<HTMLSpanElement>): ButtonAria<HTMLAttributes<HTMLSpanElement>>;
export function useButton(props: AriaButtonProps<ElementType>, ref: RefObject<Element>): ButtonAria<DOMAttributes>;
export function useButton(props: AriaButtonOptions<'button'>, ref: RefObject<HTMLButtonElement>): ButtonAria<ButtonHTMLAttributes<HTMLButtonElement>>;
export function useButton(props: AriaButtonOptions<'a'>, ref: RefObject<HTMLAnchorElement>): ButtonAria<AnchorHTMLAttributes<HTMLAnchorElement>>;
export function useButton(props: AriaButtonOptions<'div'>, ref: RefObject<HTMLDivElement>): ButtonAria<HTMLAttributes<HTMLDivElement>>;
export function useButton(props: AriaButtonOptions<'input'>, ref: RefObject<HTMLInputElement>): ButtonAria<InputHTMLAttributes<HTMLInputElement>>;
export function useButton(props: AriaButtonOptions<'span'>, ref: RefObject<HTMLSpanElement>): ButtonAria<HTMLAttributes<HTMLSpanElement>>;
export function useButton(props: AriaButtonOptions<ElementType>, ref: RefObject<Element>): ButtonAria<DOMAttributes>;
/**
* Provides the behavior and accessibility implementation for a button component. Handles mouse, keyboard, and touch interactions,
* focus behavior, and ARIA props for both native button elements and custom element types.
* @param props - Props to be applied to the button.
* @param ref - A ref to a DOM element for the button.
*/
export function useButton(props: AriaButtonProps<ElementType>, ref: RefObject<any>): ButtonAria<HTMLAttributes<any>> {
export function useButton(props: AriaButtonOptions<ElementType>, ref: RefObject<any>): ButtonAria<HTMLAttributes<any>> {
let {
elementType = 'button',
isDisabled,
Expand Down
16 changes: 9 additions & 7 deletions packages/@react-aria/button/src/useToggleButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,20 @@ import {DOMAttributes} from '@react-types/shared';
import {mergeProps} from '@react-aria/utils';
import {ToggleState} from '@react-stately/toggle';

export interface AriaToggleButtonOptions<E extends ElementType> extends Omit<AriaToggleButtonProps<E>, 'children'> {}

// Order with overrides is important: 'button' should be default
export function useToggleButton(props: AriaToggleButtonProps<'button'>, state: ToggleState, ref: RefObject<HTMLButtonElement>): ButtonAria<ButtonHTMLAttributes<HTMLButtonElement>>;
export function useToggleButton(props: AriaToggleButtonProps<'a'>, state: ToggleState, ref: RefObject<HTMLAnchorElement>): ButtonAria<AnchorHTMLAttributes<HTMLAnchorElement>>;
export function useToggleButton(props: AriaToggleButtonProps<'div'>, state: ToggleState, ref: RefObject<HTMLDivElement>): ButtonAria<HTMLAttributes<HTMLDivElement>>;
export function useToggleButton(props: AriaToggleButtonProps<'input'>, state: ToggleState, ref: RefObject<HTMLInputElement>): ButtonAria<InputHTMLAttributes<HTMLInputElement>>;
export function useToggleButton(props: AriaToggleButtonProps<'span'>, state: ToggleState, ref: RefObject<HTMLSpanElement>): ButtonAria<HTMLAttributes<HTMLSpanElement>>;
export function useToggleButton(props: AriaToggleButtonProps<ElementType>, state: ToggleState, ref: RefObject<Element>): ButtonAria<DOMAttributes>;
export function useToggleButton(props: AriaToggleButtonOptions<'button'>, state: ToggleState, ref: RefObject<HTMLButtonElement>): ButtonAria<ButtonHTMLAttributes<HTMLButtonElement>>;
export function useToggleButton(props: AriaToggleButtonOptions<'a'>, state: ToggleState, ref: RefObject<HTMLAnchorElement>): ButtonAria<AnchorHTMLAttributes<HTMLAnchorElement>>;
export function useToggleButton(props: AriaToggleButtonOptions<'div'>, state: ToggleState, ref: RefObject<HTMLDivElement>): ButtonAria<HTMLAttributes<HTMLDivElement>>;
export function useToggleButton(props: AriaToggleButtonOptions<'input'>, state: ToggleState, ref: RefObject<HTMLInputElement>): ButtonAria<InputHTMLAttributes<HTMLInputElement>>;
export function useToggleButton(props: AriaToggleButtonOptions<'span'>, state: ToggleState, ref: RefObject<HTMLSpanElement>): ButtonAria<HTMLAttributes<HTMLSpanElement>>;
export function useToggleButton(props: AriaToggleButtonOptions<ElementType>, state: ToggleState, ref: RefObject<Element>): ButtonAria<DOMAttributes>;
/**
* Provides the behavior and accessibility implementation for a toggle button component.
* ToggleButtons allow users to toggle a selection on or off, for example switching between two states or modes.
*/
export function useToggleButton(props: AriaToggleButtonProps<ElementType>, state: ToggleState, ref: RefObject<any>): ButtonAria<HTMLAttributes<any>> {
export function useToggleButton(props: AriaToggleButtonOptions<ElementType>, state: ToggleState, ref: RefObject<any>): ButtonAria<HTMLAttributes<any>> {
const {isSelected} = state;
const {isPressed, buttonProps} = useButton({
...props,
Expand Down
4 changes: 2 additions & 2 deletions packages/@react-aria/toast/docs/useToast.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ interface ToastRegionProps<T> extends AriaToastRegionProps {
state: ToastState<T>
}

function ToastRegion<T>({state, ...props}: ToastRegionProps<T>) {
function ToastRegion<T extends React.ReactNode>({state, ...props}: ToastRegionProps<T>) {
let ref = React.useRef(null);
let {regionProps} = useToastRegion(props, state, ref);

Expand All @@ -138,7 +138,7 @@ interface ToastProps<T> extends AriaToastProps<T> {
state: ToastState<T>
}

function Toast<T>({state, ...props}: ToastProps<T>) {
function Toast<T extends React.ReactNode>({state, ...props}: ToastProps<T>) {
let ref = React.useRef(null);
let {toastProps, titleProps, closeButtonProps} = useToast(props, state, ref);

Expand Down
10 changes: 5 additions & 5 deletions packages/@react-aria/virtualizer/src/Virtualizer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import {Collection} from '@react-types/shared';
import {getInteractionModality} from '@react-aria/interactions';
import {Layout, Rect, ReusableView, useVirtualizerState, VirtualizerState} from '@react-stately/virtualizer';
import {mergeProps, useLayoutEffect} from '@react-aria/utils';
import React, {FocusEvent, HTMLAttributes, Key, ReactElement, RefObject, useCallback, useEffect, useMemo, useRef} from 'react';
import React, {FocusEvent, HTMLAttributes, Key, ReactElement, ReactNode, RefObject, useCallback, useEffect, useMemo, useRef} from 'react';
import {ScrollView} from './ScrollView';
import {VirtualizerItem} from './VirtualizerItem';

interface VirtualizerProps<T extends object, V> extends HTMLAttributes<HTMLElement> {
interface VirtualizerProps<T extends object, V> extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
children: (type: string, content: T) => V,
renderWrapper?: (
parent: ReusableView<T, V> | null,
Expand All @@ -39,7 +39,7 @@ interface VirtualizerProps<T extends object, V> extends HTMLAttributes<HTMLEleme
autoFocus?: boolean
}

function Virtualizer<T extends object, V>(props: VirtualizerProps<T, V>, ref: RefObject<HTMLDivElement>) {
function Virtualizer<T extends object, V extends ReactNode>(props: VirtualizerProps<T, V>, ref: RefObject<HTMLDivElement>) {
let {
children: renderView,
renderWrapper,
Expand Down Expand Up @@ -105,7 +105,7 @@ interface VirtualizerOptions {
onLoadMore?: () => void
}

export function useVirtualizer<T extends object, V, W>(props: VirtualizerOptions, state: VirtualizerState<T, V, W>, ref: RefObject<HTMLElement>) {
export function useVirtualizer<T extends object, V extends ReactNode, W>(props: VirtualizerOptions, state: VirtualizerState<T, V, W>, ref: RefObject<HTMLElement>) {
let {focusedKey, scrollToItem, shouldUseVirtualFocus, isLoading, onLoadMore} = props;
let {virtualizer} = state;
// Scroll to the focusedKey when it changes. Actually focusing the focusedKey
Expand Down Expand Up @@ -240,7 +240,7 @@ export function useVirtualizer<T extends object, V, W>(props: VirtualizerOptions
const _Virtualizer = React.forwardRef(Virtualizer) as <T extends object, V>(props: VirtualizerProps<T, V> & {ref?: RefObject<HTMLDivElement>}) => ReactElement;
export {_Virtualizer as Virtualizer};

function defaultRenderWrapper<T extends object, V>(
function defaultRenderWrapper<T extends object, V extends ReactNode>(
parent: ReusableView<T, V> | null,
reusableView: ReusableView<T, V>
) {
Expand Down
4 changes: 2 additions & 2 deletions packages/@react-spectrum/card/src/CardView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {GridCollection, useGridState} from '@react-stately/grid';
import intlMessages from '../intl/*.json';
import {mergeProps} from '@react-aria/utils';
import {ProgressCircle} from '@react-spectrum/progress';
import React, {ReactElement, useCallback, useMemo, useRef} from 'react';
import React, {ReactElement, ReactNode, useCallback, useMemo, useRef} from 'react';
import {ReusableView} from '@react-stately/virtualizer';
import {SpectrumCardViewProps} from '@react-types/card';
import styles from '@adobe/spectrum-css-temp/components/card/vars.css';
Expand Down Expand Up @@ -88,7 +88,7 @@ function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef
keyboardDelegate: cardViewLayout
}, state, domRef);

type View = ReusableView<Node<T>, unknown>;
type View = ReusableView<Node<T>, ReactNode>;
let renderWrapper = (parent: View, reusableView: View) => (
<VirtualizerItem
key={reusableView.key}
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/dialog/src/DialogTrigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ function DialogTrigger(props: SpectrumDialogTriggerProps) {

// Support DialogTrigger inside components using CollectionBuilder.
DialogTrigger.getCollectionNode = function* (props: SpectrumDialogTriggerProps) {
// @ts-ignore - seems like types are wrong. Function children work fine.
let [trigger] = React.Children.toArray(props.children);
let [, content] = props.children as [ReactElement, SpectrumDialogClose];
yield {
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-spectrum/listbox/src/ListBoxBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function ListBoxBase<T>(props: ListBoxBaseProps<T>, ref: RefObject<HTMLDivElemen

// This overrides collection view's renderWrapper to support heirarchy of items in sections.
// The header is extracted from the children so it can receive ARIA labeling properties.
type View = ReusableView<Node<T>, unknown>;
type View = ReusableView<Node<T>, ReactNode>;
let renderWrapper = (parent: View, reusableView: View, children: View[], renderChildren: (views: View[]) => ReactElement[]) => {
if (reusableView.viewType === 'section') {
return (
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-spectrum/menu/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import {FocusStrategy} from '@react-types/shared';
import React, {HTMLAttributes, MutableRefObject, useContext} from 'react';

export interface MenuContextValue extends HTMLAttributes<HTMLElement> {
export interface MenuContextValue extends Omit<HTMLAttributes<HTMLElement>, 'autoFocus'> {
onClose?: () => void,
closeOnSelect?: boolean,
shouldFocusWrap?: boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {Form} from '@react-spectrum/form';
import {Heading} from '@react-spectrum/text';
import {Item, Picker} from '@react-spectrum/picker';
import {NumberField} from '../src';
import React, {useState} from 'react';
import React, {ReactNode, useState} from 'react';

export default {
title: 'NumberField',
Expand Down Expand Up @@ -484,7 +484,7 @@ function NumberFieldControlledStateReset() {
);
}

class ErrorBoundary extends React.Component<{}, {hasError: boolean}> {
class ErrorBoundary extends React.Component<{children: ReactNode}, {hasError: boolean}> {
constructor(props) {
super(props);
this.state = {hasError: false};
Expand Down
4 changes: 2 additions & 2 deletions packages/@react-spectrum/sidenav/src/SideNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import {classNames, useStyleProps} from '@react-spectrum/utils';
import {ListLayout} from '@react-stately/layout';
import {Node} from '@react-types/shared';
import React, {ReactElement, useMemo, useRef} from 'react';
import React, {ReactElement, ReactNode, useMemo, useRef} from 'react';
import {ReusableView} from '@react-stately/virtualizer';
import {SideNavContext} from './SideNavContext';
import {SideNavItem} from './SideNavItem';
Expand All @@ -38,7 +38,7 @@ export function SideNav<T extends object>(props: SpectrumSideNavProps<T>) {

// This overrides collection view's renderWrapper to support heirarchy of items in sections.
// The header is extracted from the children so it can receive ARIA labeling properties.
type View = ReusableView<Node<T>, unknown>;
type View = ReusableView<Node<T>, ReactNode>;
let renderWrapper = (parent: View, reusableView: View, children: View[], renderChildren: (views: View[]) => ReactElement[]) => {
if (reusableView.viewType === 'section') {
return (
Expand Down
4 changes: 2 additions & 2 deletions packages/@react-spectrum/story-utils/src/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
* governing permissions and limitations under the License.
*/

import React, {Component} from 'react';
import React, {Component, ReactNode} from 'react';

export class ErrorBoundary extends Component<{message: string}, {hasError: boolean}> {
export class ErrorBoundary extends Component<{message: string, children: ReactNode}, {hasError: boolean}> {
constructor(props) {
super(props);
this.state = {hasError: false};
Expand Down
6 changes: 3 additions & 3 deletions packages/@react-spectrum/table/src/TableView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {layoutInfoToStyle, ScrollView, setScrollLeft, useVirtualizer, Virtualize
import ListGripper from '@spectrum-icons/ui/ListGripper';
import {Nubbin} from './Nubbin';
import {ProgressCircle} from '@react-spectrum/progress';
import React, {DOMAttributes, HTMLAttributes, Key, ReactElement, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import React, {DOMAttributes, HTMLAttributes, Key, ReactElement, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import {Resizer} from './Resizer';
import {ReusableView, useVirtualizerState} from '@react-stately/virtualizer';
import {RootDropIndicator} from './RootDropIndicator';
Expand Down Expand Up @@ -322,7 +322,7 @@ function TableView<T extends object>(props: SpectrumTableProps<T>, ref: DOMRef<H
let [headerRowHovered, setHeaderRowHovered] = useState(false);

// This overrides collection view's renderWrapper to support DOM hierarchy.
type View = ReusableView<GridNode<T>, unknown>;
type View = ReusableView<GridNode<T>, ReactNode>;
let renderWrapper = (parent: View, reusableView: View, children: View[], renderChildren: (views: View[]) => ReactElement[]) => {
let style = layoutInfoToStyle(reusableView.layoutInfo, direction, parent && parent.layoutInfo);
if (style.overflow === 'hidden') {
Expand Down Expand Up @@ -595,7 +595,7 @@ function TableVirtualizer(props) {
// while resizing, prop changes should not cause animations
transitionDuration = 0;
}
let state = useVirtualizerState({
let state = useVirtualizerState<object, ReactNode, ReactNode>({
layout,
collection,
renderView,
Expand Down
11 changes: 8 additions & 3 deletions packages/@react-spectrum/tabs/src/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
* governing permissions and limitations under the License.
*/

import {AriaTabPanelProps, SpectrumTabListProps, SpectrumTabPanelsProps, SpectrumTabsProps} from '@react-types/tabs';
import {classNames, SlotProvider, unwrapDOMRef, useDOMRef, useStyleProps} from '@react-spectrum/utils';
import {DOMProps, DOMRef, Node, Orientation} from '@react-types/shared';
import {DOMProps, DOMRef, Node, Orientation, StyleProps} from '@react-types/shared';
import {filterDOMProps} from '@react-aria/utils';
import {FocusRing} from '@react-aria/focus';
import {Item, Picker} from '@react-spectrum/picker';
Expand All @@ -21,14 +22,14 @@ import React, {
Key,
MutableRefObject,
ReactElement,
ReactNode,
useCallback,
useContext,
useEffect,
useRef,
useState
} from 'react';
import {SpectrumPickerProps} from '@react-types/select';
import {SpectrumTabListProps, SpectrumTabPanelsProps, SpectrumTabsProps} from '@react-types/tabs';
import styles from '@adobe/spectrum-css-temp/components/tabs/vars.css';
import {TabListState, useTabListState} from '@react-stately/tabs';
import {Text} from '@react-spectrum/text';
Expand Down Expand Up @@ -348,8 +349,12 @@ export function TabPanels<T>(props: SpectrumTabPanelsProps<T>) {
);
}

interface TabPanelProps extends AriaTabPanelProps, StyleProps {
children?: ReactNode
}

// @private
function TabPanel<T>(props: SpectrumTabPanelsProps<T>) {
function TabPanel(props: TabPanelProps) {
const {tabState, tabPanelProps: ctxTabPanelProps} = useContext(TabContext);
const {tabListState} = tabState;
let ref = useRef();
Expand Down
3 changes: 1 addition & 2 deletions packages/@react-stately/collections/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
* governing permissions and limitations under the License.
*/

import {ItemRenderer} from '@react-types/shared';
import {Key, ReactElement, ReactNode} from 'react';

export interface PartialNode<T> {
Expand All @@ -23,7 +22,7 @@ export interface PartialNode<T> {
textValue?: string,
'aria-label'?: string,
index?: number,
renderer?: ItemRenderer<T>,
renderer?: (item: T) => ReactElement,
hasChildNodes?: boolean,
childNodes?: () => IterableIterator<PartialNode<T>>,
props?: any,
Expand Down
8 changes: 6 additions & 2 deletions packages/@react-stately/collections/src/useCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@

import {Collection, CollectionStateBase, Node} from '@react-types/shared';
import {CollectionBuilder} from './CollectionBuilder';
import {useMemo} from 'react';
import {ReactElement, useMemo} from 'react';

interface CollectionOptions<T, C extends Collection<Node<T>>> extends Omit<CollectionStateBase<T, C>, 'children'> {
children?: ReactElement | ReactElement[] | ((item: T) => ReactElement)
}

type CollectionFactory<T, C extends Collection<Node<T>>> = (node: Iterable<Node<T>>) => C;

export function useCollection<T extends object, C extends Collection<Node<T>> = Collection<Node<T>>>(props: CollectionStateBase<T, C>, factory: CollectionFactory<T, C>, context?: unknown): C {
export function useCollection<T extends object, C extends Collection<Node<T>> = Collection<Node<T>>>(props: CollectionOptions<T, C>, factory: CollectionFactory<T, C>, context?: unknown): C {
let builder = useMemo(() => new CollectionBuilder<T>(), []);
let {children, items, collection} = props;
let result = useMemo(() => {
Expand Down
14 changes: 10 additions & 4 deletions packages/@react-stately/table/src/useTableState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
* governing permissions and limitations under the License.
*/

import {CollectionStateBase, Node, SelectionMode, Sortable, SortDescriptor, SortDirection} from '@react-types/shared';
import {GridState, useGridState} from '@react-stately/grid';
import {TableCollection as ITableCollection} from '@react-types/table';
import {Key, useCallback, useMemo, useState} from 'react';
import {TableCollection as ITableCollection, TableBodyProps, TableHeaderProps} from '@react-types/table';
import {Key, ReactElement, useCallback, useMemo, useState} from 'react';
import {MultipleSelectionStateProps} from '@react-stately/selection';
import {Node, SelectionMode, Sortable, SortDescriptor, SortDirection} from '@react-types/shared';
import {TableCollection} from './TableCollection';
import {useCollection} from '@react-stately/collections';

Expand All @@ -40,7 +40,13 @@ export interface CollectionBuilderContext<T> {
columns: Node<T>[]
}

export interface TableStateProps<T> extends CollectionStateBase<T, ITableCollection<T>>, MultipleSelectionStateProps, Sortable {
export interface TableStateProps<T> extends MultipleSelectionStateProps, Sortable {
/** The elements that make up the table. Includes the TableHeader, TableBody, Columns, and Rows. */
children?: [ReactElement<TableHeaderProps<T>>, ReactElement<TableBodyProps<T>>],
/** A list of row keys to disable. */
disabledKeys?: Iterable<Key>,
/** A pre-constructed collection to use instead of building one from items and children. */
collection?: ITableCollection<T>,
/** Whether the row selection checkboxes should be displayed. */
showSelectionCheckboxes?: boolean,
/** Whether the row drag button should be displayed.
Expand Down
Loading