Outlook_Addin_LLM/node_modules/@fluentui/react-aria/lib/button/useARIAButtonProps.js

108 lines
4.3 KiB
JavaScript

import { Enter, Space } from '@fluentui/keyboard-keys';
import { useEventCallback } from '@fluentui/react-utilities';
import * as React from 'react';
/**
* @internal
*
* Button keyboard handling, role, disabled and tabIndex implementation that ensures ARIA spec
* for multiple scenarios of non native button elements. Ensuring 1st rule of ARIA for cases
* where no attribute addition is required.
*
* @param type - the proper scenario to be interpreted by the hook.
* 1. `button` - Minimal interference from the hook, as semantic button already supports most of the states
* 2. `a` or `div` - Proper keyboard/mouse handling plus other support to ensure ARIA behavior
* @param props - the props to be passed down the line to the desired element.
* This hook will encapsulate proper properties, such as `onClick`, `onKeyDown`, `onKeyUp`, etc,.
*
* @example
* ```tsx
* const buttonProps = useARIAButtonProps('a', {
* href: './some-route'
* onClick: () => console.log('this should run both on click and Space and Enter')
* })
*
* // ...
*
* return (
* <a {...buttonProps}>This anchor will behave as a proper button</a>
* )
* ```
*/ export function useARIAButtonProps(type, props) {
const { disabled, disabledFocusable = false, ['aria-disabled']: ariaDisabled, onClick, onKeyDown, onKeyUp, ...rest } = props !== null && props !== void 0 ? props : {};
const normalizedARIADisabled = typeof ariaDisabled === 'string' ? ariaDisabled === 'true' : ariaDisabled;
const isDisabled = disabled || disabledFocusable || normalizedARIADisabled;
const handleClick = useEventCallback((ev)=>{
if (isDisabled) {
ev.preventDefault();
ev.stopPropagation();
} else {
onClick === null || onClick === void 0 ? void 0 : onClick(ev);
}
});
const handleKeyDown = useEventCallback((ev)=>{
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(ev);
if (ev.isDefaultPrevented()) {
return;
}
const key = ev.key;
if (isDisabled && (key === Enter || key === Space)) {
ev.preventDefault();
ev.stopPropagation();
return;
}
if (key === Space) {
ev.preventDefault();
return;
} else if (key === Enter) {
ev.preventDefault();
ev.currentTarget.click();
}
});
const handleKeyUp = useEventCallback((ev)=>{
onKeyUp === null || onKeyUp === void 0 ? void 0 : onKeyUp(ev);
if (ev.isDefaultPrevented()) {
return;
}
const key = ev.key;
if (isDisabled && (key === Enter || key === Space)) {
ev.preventDefault();
ev.stopPropagation();
return;
}
if (key === Space) {
ev.preventDefault();
ev.currentTarget.click();
}
});
// If a <button> tag is to be rendered we just need to set disabled and aria-disabled correctly
if (type === 'button' || type === undefined) {
return {
...rest,
disabled: disabled && !disabledFocusable,
'aria-disabled': disabledFocusable ? true : normalizedARIADisabled,
// onclick should still use internal handler to ensure prevention if disabled
// if disabledFocusable then there's no requirement for handlers as those events should not be propagated
onClick: disabledFocusable ? undefined : handleClick,
onKeyUp: disabledFocusable ? undefined : onKeyUp,
onKeyDown: disabledFocusable ? undefined : onKeyDown
};
} else {
const resultProps = {
role: 'button',
tabIndex: disabled && !disabledFocusable ? undefined : 0,
...rest,
// If it's not a <button> than listeners are required even with disabledFocusable
// Since you cannot assure the default behavior of the element
// E.g: <a> will redirect on click
onClick: handleClick,
onKeyUp: handleKeyUp,
onKeyDown: handleKeyDown,
'aria-disabled': disabled || disabledFocusable || normalizedARIADisabled
};
if (type === 'a' && isDisabled) {
resultProps.href = undefined;
}
return resultProps;
}
}