UNPKG

@base-ui-components/react

Version:

Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.

96 lines (92 loc) 3.19 kB
'use client'; import * as React from 'react'; import { useForkRef } from '../utils/useForkRef.js'; import { extractEventHandlers } from '../utils/extractEventHandlers.js'; import { useRootElementName } from '../utils/useRootElementName.js'; export function useButton(parameters = {}) { const { disabled = false, focusableWhenDisabled, buttonRef: externalRef, tabIndex, type, elementName: elementNameProp } = parameters; const buttonRef = React.useRef(null); const [elementName, updateElementName] = useRootElementName({ rootElementName: elementNameProp, componentName: 'Button' }); const isNativeButton = () => { const button = buttonRef.current; return elementName === 'BUTTON' || elementName === 'INPUT' && ['button', 'submit', 'reset'].includes(button?.type); }; const createHandleClick = otherHandlers => event => { if (!disabled) { otherHandlers.onClick?.(event); } }; const createHandleKeyDown = otherHandlers => event => { otherHandlers.onKeyDown?.(event); if (event.defaultMuiPrevented) { return; } if (event.target === event.currentTarget && !isNativeButton() && event.key === ' ') { event.preventDefault(); } // Keyboard accessibility for non interactive elements if (event.target === event.currentTarget && !isNativeButton() && event.key === 'Enter' && !disabled) { otherHandlers.onClick?.(event); event.preventDefault(); } }; const createHandleKeyUp = otherHandlers => event => { // calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed // https://codesandbox.io/p/sandbox/button-keyup-preventdefault-dn7f0 otherHandlers.onKeyUp?.(event); // Keyboard accessibility for non interactive elements if (event.target === event.currentTarget && !isNativeButton() && !disabled && event.key === ' ' && !event.defaultMuiPrevented) { otherHandlers.onClick?.(event); } }; const handleRef = useForkRef(updateElementName, externalRef, buttonRef); const buttonProps = {}; if (tabIndex !== undefined) { buttonProps.tabIndex = tabIndex; } if (elementName === 'BUTTON' || elementName === 'INPUT') { if (focusableWhenDisabled) { buttonProps['aria-disabled'] = disabled; } else { buttonProps.disabled = disabled; } } else if (elementName !== '') { buttonProps.role = 'button'; buttonProps.tabIndex = tabIndex ?? 0; if (disabled) { buttonProps['aria-disabled'] = disabled; buttonProps.tabIndex = focusableWhenDisabled ? tabIndex ?? 0 : -1; } } const getButtonProps = externalProps => { const externalEventHandlers = { ...extractEventHandlers(parameters), ...extractEventHandlers(externalProps) }; const props = { type, ...externalEventHandlers, ...buttonProps, ...externalProps, onClick: createHandleClick(externalEventHandlers), onKeyDown: createHandleKeyDown(externalEventHandlers), onKeyUp: createHandleKeyUp(externalEventHandlers), ref: handleRef }; return props; }; return { getButtonProps, buttonRef: handleRef }; }