UNPKG

@react-aria/button

Version:
120 lines (112 loc) 4.61 kB
/* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ import { AnchorHTMLAttributes, ButtonHTMLAttributes, ElementType, HTMLAttributes, InputHTMLAttributes, RefObject } from 'react'; import {AriaButtonProps} from '@react-types/button'; import {DOMAttributes} from '@react-types/shared'; import {filterDOMProps, 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. */ buttonProps: T, /** Whether the button is currently pressed. */ isPressed: boolean } // Order with overrides is important: 'button' should be default export function useButton(props: AriaButtonOptions<'button'>, ref: RefObject<HTMLButtonElement | null>): ButtonAria<ButtonHTMLAttributes<HTMLButtonElement>>; export function useButton(props: AriaButtonOptions<'a'>, ref: RefObject<HTMLAnchorElement | null>): ButtonAria<AnchorHTMLAttributes<HTMLAnchorElement>>; export function useButton(props: AriaButtonOptions<'div'>, ref: RefObject<HTMLDivElement | null>): ButtonAria<HTMLAttributes<HTMLDivElement>>; export function useButton(props: AriaButtonOptions<'input'>, ref: RefObject<HTMLInputElement | null>): ButtonAria<InputHTMLAttributes<HTMLInputElement>>; export function useButton(props: AriaButtonOptions<'span'>, ref: RefObject<HTMLSpanElement | null>): ButtonAria<HTMLAttributes<HTMLSpanElement>>; export function useButton(props: AriaButtonOptions<ElementType>, ref: RefObject<Element | null>): 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: AriaButtonOptions<ElementType>, ref: RefObject<any>): ButtonAria<HTMLAttributes<any>> { let { elementType = 'button', isDisabled, onPress, onPressStart, onPressEnd, onPressUp, onPressChange, preventFocusOnPress, // @ts-ignore - undocumented allowFocusWhenDisabled, // @ts-ignore onClick: deprecatedOnClick, href, target, rel, type = 'button' } = props; let additionalProps; if (elementType === 'button') { additionalProps = { type, disabled: isDisabled }; } else { additionalProps = { role: 'button', tabIndex: isDisabled ? undefined : 0, href: elementType === 'a' && !isDisabled ? href : undefined, target: elementType === 'a' ? target : undefined, type: elementType === 'input' ? type : undefined, disabled: elementType === 'input' ? isDisabled : undefined, 'aria-disabled': !isDisabled || elementType === 'input' ? undefined : isDisabled, rel: elementType === 'a' ? rel : undefined }; } let {pressProps, isPressed} = usePress({ onPressStart, onPressEnd, onPressChange, onPress, onPressUp, isDisabled, preventFocusOnPress, ref }); let {focusableProps} = useFocusable(props, ref); if (allowFocusWhenDisabled) { focusableProps.tabIndex = isDisabled ? -1 : focusableProps.tabIndex; } let buttonProps = mergeProps(focusableProps, pressProps, filterDOMProps(props, {labelable: true})); return { isPressed, // Used to indicate press state for visual buttonProps: mergeProps(additionalProps, buttonProps, { 'aria-haspopup': props['aria-haspopup'], 'aria-expanded': props['aria-expanded'], 'aria-controls': props['aria-controls'], 'aria-pressed': props['aria-pressed'], onClick: (e) => { if (deprecatedOnClick) { deprecatedOnClick(e); console.warn('onClick is deprecated, please use onPress'); } } }) }; }