Skip to content

Commit

Permalink
feat: improve handling aria props
Browse files Browse the repository at this point in the history
  • Loading branch information
DanisAvko committed Nov 26, 2024
1 parent 704f53b commit cd2e988
Show file tree
Hide file tree
Showing 17 changed files with 111 additions and 90 deletions.
16 changes: 12 additions & 4 deletions src/components/ActionTooltip/ActionTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ import {Hotkey} from '../Hotkey';
import type {HotkeyProps} from '../Hotkey';
import {Popup} from '../Popup';
import type {PopupPlacement} from '../Popup';
import type {DOMProps, QAProps} from '../types';
import type {AriaLabelingProps, DOMProps, QAProps} from '../types';
import {block} from '../utils/cn';
import {filterDOMProps} from '../utils/filterDOMProps';
import {getElementRef} from '../utils/getElementRef';

import './ActionTooltip.scss';

export interface ActionTooltipProps extends QAProps, DOMProps, TooltipDelayProps {
export interface ActionTooltipProps
extends AriaLabelingProps,
QAProps,
DOMProps,
TooltipDelayProps {
id?: string;
disablePortal?: boolean;
contentClassName?: string;
Expand Down Expand Up @@ -44,15 +49,18 @@ export function ActionTooltip(props: ActionTooltipProps) {
qa,
id,
disablePortal,
...delayProps
openDelay,
closeDelay,
...otherProps
} = props;

const [anchorElement, setAnchorElement] = React.useState<HTMLElement | null>(null);
const tooltipVisible = useTooltipVisible(anchorElement, delayProps);
const tooltipVisible = useTooltipVisible(anchorElement, {openDelay, closeDelay});

const renderPopup = () => {
return (
<Popup
{...filterDOMProps(otherProps, {labelable: true})}
id={id}
disablePortal={disablePortal}
role="tooltip"
Expand Down
7 changes: 3 additions & 4 deletions src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';

import {block} from '../utils/cn';
import {filterDOMProps} from '../utils/filterDOMProps';

import {AvatarIcon} from './AvatarIcon';
import {AvatarImage} from './AvatarImage';
Expand All @@ -20,11 +21,10 @@ export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>((props, ref)
backgroundColor,
borderColor,
title,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledby,
className,
style: styleProp,
qa,
...otherProps
} = props;

const style = {backgroundColor, color: borderColor, ...styleProp};
Expand Down Expand Up @@ -72,11 +72,10 @@ export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>((props, ref)

return (
<div
{...filterDOMProps(otherProps, {labelable: true})}
className={b({size, theme, view, 'with-border': Boolean(borderColor)}, className)}
title={title}
role="img"
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
style={style}
data-qa={qa}
ref={ref}
Expand Down
11 changes: 3 additions & 8 deletions src/components/Avatar/types/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {DistributiveOmit} from '../../../types/utils';
import type {DOMProps, QAProps} from '../../types';
import type {AriaLabelingProps, DOMProps, QAProps} from '../../types';
import type {AvatarIconProps} from '../AvatarIcon';
import type {AvatarImageProps} from '../AvatarImage';
import type {AvatarTextProps} from '../AvatarText';
Expand All @@ -9,12 +9,7 @@ import type {AvatarCommonProps, AvatarSize} from './common';
export type AvatarTheme = 'normal' | 'brand';
export type AvatarView = 'filled' | 'outlined';

interface AvatarAriaProps {
'aria-label'?: string;
'aria-labelledby'?: string;
}

interface AvatarBaseProps extends DOMProps, QAProps, AvatarAriaProps {
interface AvatarBaseProps extends DOMProps, QAProps, AriaLabelingProps {
size?: AvatarSize;
theme?: AvatarTheme;
view?: AvatarView;
Expand All @@ -25,6 +20,6 @@ interface AvatarBaseProps extends DOMProps, QAProps, AvatarAriaProps {

export type AvatarProps = AvatarBaseProps &
DistributiveOmit<
AvatarImageProps | AvatarIconProps | AvatarTextProps | AvatarAriaProps,
AvatarImageProps | AvatarIconProps | AvatarTextProps | AriaLabelingProps,
keyof AvatarCommonProps
>;
3 changes: 3 additions & 0 deletions src/components/DefinitionList/DefinitionList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';

import {filterDOMProps} from '../utils/filterDOMProps';
import {isOfType} from '../utils/isOfType';
import {warnOnce} from '../utils/warn';

Expand All @@ -18,6 +19,7 @@ export function DefinitionList({
className,
children,
qa,
...otherProps
}: DefinitionListProps) {
const normalizedChildren = prepareChildren(children);
return (
Expand All @@ -27,6 +29,7 @@ export function DefinitionList({
contentMaxWidth={contentMaxWidth}
>
<dl
{...filterDOMProps(otherProps, {labelable: true})}
className={b({responsive, vertical: direction === 'vertical'}, className)}
data-qa={qa}
>
Expand Down
4 changes: 2 additions & 2 deletions src/components/DefinitionList/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type React from 'react';

import type {HelpMarkProps} from '../HelpMark';
import type {QAProps} from '../types';
import type {AriaLabelingProps, QAProps} from '../types';
export type DefinitionListItemNote = string | HelpMarkProps;

export interface DefinitionListItemProps {
Expand All @@ -13,7 +13,7 @@ export interface DefinitionListItemProps {

export type DefinitionListDirection = 'vertical' | 'horizontal';

export interface DefinitionListProps extends QAProps {
export interface DefinitionListProps extends AriaLabelingProps, QAProps {
responsive?: boolean;
direction?: DefinitionListDirection;
nameMaxWidth?: number;
Expand Down
13 changes: 5 additions & 8 deletions src/components/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import React from 'react';

import {Modal} from '../Modal';
import type {ModalCloseReason, ModalProps} from '../Modal';
import type {QAProps} from '../types';
import type {AriaLabelingProps, QAProps} from '../types';
import {block} from '../utils/cn';
import {filterDOMProps} from '../utils/filterDOMProps';

import {ButtonClose} from './ButtonClose/ButtonClose';
import {DialogBody} from './DialogBody/DialogBody';
Expand All @@ -17,7 +18,7 @@ import './Dialog.scss';

const b = block('dialog');

interface DialogOwnProps extends QAProps {
interface DialogOwnProps extends AriaLabelingProps, QAProps {
open: boolean;
children: React.ReactNode;
onEscapeKeyDown?: ModalProps['onEscapeKeyDown'];
Expand All @@ -34,8 +35,6 @@ interface DialogOwnProps extends QAProps {
className?: string;
modalClassName?: string;
size?: 's' | 'm' | 'l';
'aria-label'?: string;
'aria-labelledby'?: string;
container?: HTMLElement;
disableFocusTrap?: boolean;
disableAutoFocus?: boolean;
Expand Down Expand Up @@ -93,13 +92,13 @@ export class Dialog extends React.Component<DialogInnerProps> {
onTransitionEntered,
onTransitionExit,
onTransitionExited,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy,
qa,
...otherProps
} = this.props;

return (
<Modal
{...filterDOMProps(otherProps, {labelable: true})}
open={open}
contentOverflow={contentOverflow}
disableBodyScrollLock={disableBodyScrollLock}
Expand All @@ -118,8 +117,6 @@ export class Dialog extends React.Component<DialogInnerProps> {
onTransitionExit={onTransitionExit}
onTransitionExited={onTransitionExited}
className={b('modal', modalClassName)}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledBy}
container={container}
qa={qa}
>
Expand Down
16 changes: 13 additions & 3 deletions src/components/Divider/Divider.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React from 'react';

import type {DOMProps, QAProps} from '../types';
import type {AriaLabelingProps, DOMProps, QAProps} from '../types';
import {block} from '../utils/cn';
import {filterDOMProps} from '../utils/filterDOMProps';

import './Divider.scss';

export type DividerOrientation = 'vertical' | 'horizontal';
export type DividerAlign = 'start' | 'center' | 'end';

export interface DividerProps extends DOMProps, QAProps {
export interface DividerProps extends AriaLabelingProps, DOMProps, QAProps {
orientation?: DividerOrientation;
align?: DividerAlign;
children?: React.ReactNode;
Expand All @@ -17,10 +18,19 @@ export interface DividerProps extends DOMProps, QAProps {
const b = block('divider');

export const Divider = React.forwardRef<HTMLDivElement, DividerProps>(function Divider(props, ref) {
const {orientation = 'horizontal', className, style, qa, children, align = 'start'} = props;
const {
orientation = 'horizontal',
className,
style,
qa,
children,
align = 'start',
...otherProps
} = props;

return (
<div
{...filterDOMProps(otherProps, {labelable: true})}
className={b({orientation, align}, className)}
ref={ref}
style={style}
Expand Down
15 changes: 11 additions & 4 deletions src/components/Hotkey/Hotkey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import React from 'react';

import type {DOMProps, QAProps} from '../types';
import type {AriaLabelingProps, DOMProps, QAProps} from '../types';
import {block} from '../utils/cn';
import {filterDOMProps} from '../utils/filterDOMProps';

import {defsByPlatform} from './definitions';
import {parseKeyGroups} from './parse';
Expand All @@ -19,7 +20,7 @@ const Spaces = {
BetweenKeys: String.fromCharCode(8239), // Narrow No-Break Space
};

export interface HotkeyProps extends DOMProps, QAProps {
export interface HotkeyProps extends AriaLabelingProps, DOMProps, QAProps {
/**
* @example
* 'mod+a mod+c mod+v'
Expand All @@ -33,7 +34,7 @@ export interface HotkeyProps extends DOMProps, QAProps {
}

export const Hotkey = React.forwardRef<HTMLElement, HotkeyProps>(function Hotkey(props, ref) {
const {value, platform, view = 'light', qa, style, className} = props;
const {value, platform, view = 'light', qa, style, className, ...otherProps} = props;

const groups = parseHotkeys(value, {platform});
const content: React.ReactNode[] = [];
Expand Down Expand Up @@ -64,7 +65,13 @@ export const Hotkey = React.forwardRef<HTMLElement, HotkeyProps>(function Hotkey
if (content.length === 0) return null;

return (
<kbd ref={ref} style={style} data-qa={qa} className={b({view}, className)}>
<kbd
{...filterDOMProps(otherProps, {labelable: true})}
ref={ref}
style={style}
data-qa={qa}
className={b({view}, className)}
>
{content}
</kbd>
);
Expand Down
8 changes: 5 additions & 3 deletions src/components/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import React from 'react';

import type {DOMProps, QAProps} from '../types';
import type {AriaLabelingProps, DOMProps, QAProps} from '../types';
import {block} from '../utils/cn';
import {filterDOMProps} from '../utils/filterDOMProps';

import {MenuGroup} from './MenuGroup';
import type {MenuGroupProps} from './MenuGroup';
Expand All @@ -16,7 +17,7 @@ const b = block('menu');

export type MenuSize = 's' | 'm' | 'l' | 'xl';

export interface MenuProps extends DOMProps, QAProps {
export interface MenuProps extends AriaLabelingProps, DOMProps, QAProps {
size?: MenuSize;
children?: React.ReactNode;
}
Expand All @@ -31,11 +32,12 @@ interface MenuComponent

// TODO: keyboard navigation, Up/Down arrows and Enter
export const Menu = React.forwardRef<HTMLUListElement, MenuProps>(function Menu(
{size = 'm', children, style, className, qa},
{size = 'm', children, style, className, qa, ...otherProps},
ref,
) {
return (
<ul
{...filterDOMProps(otherProps, {labelable: true})}
ref={ref}
role="menu"
// tabIndex={0}
Expand Down
20 changes: 5 additions & 15 deletions src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ import {CSSTransition} from 'react-transition-group';
import {useBodyScrollLock} from '../../hooks';
import {useRestoreFocus} from '../../hooks/private';
import {Portal} from '../Portal';
import type {DOMProps, QAProps} from '../types';
import type {AriaLabelingProps, DOMProps, QAProps} from '../types';
import {FocusTrap} from '../utils/FocusTrap';
import {block} from '../utils/cn';
import {filterDOMProps} from '../utils/filterDOMProps';
import type {LayerCloseReason} from '../utils/layer-manager';
import {useLayer} from '../utils/layer-manager';
import type {LayerExtendableProps} from '../utils/layer-manager/LayerManager';
import {getCSSTransitionClassNames} from '../utils/transition';

import './Modal.scss';

export interface ModalProps extends DOMProps, LayerExtendableProps, QAProps {
export interface ModalProps extends DOMProps, AriaLabelingProps, LayerExtendableProps, QAProps {
open?: boolean;
keepMounted?: boolean;
disableBodyScrollLock?: boolean;
Expand All @@ -29,15 +30,6 @@ export interface ModalProps extends DOMProps, LayerExtendableProps, QAProps {
autoFocus?: boolean;
restoreFocusRef?: React.RefObject<HTMLElement>;
children?: React.ReactNode;
/**
* Id of visible `<Modal/>` caption element
*/
'aria-labelledby'?: string;
/**
* A11y text
* Prefer `aria-labelledby` in case caption is visible to user
*/
'aria-label'?: string;
container?: HTMLElement;
contentClassName?: string;
onTransitionEnter?: VoidFunction;
Expand Down Expand Up @@ -75,10 +67,9 @@ export function Modal({
contentOverflow = 'visible',
className,
contentClassName,
'aria-labelledby': ariaLabelledBy,
'aria-label': ariaLabel,
container,
qa,
...otherProps
}: ModalProps) {
const containerRef = React.useRef<HTMLDivElement>(null);
const contentRef = React.useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -138,12 +129,11 @@ export function Modal({
autoFocus={!disableAutoFocus && autoFocus}
>
<div
{...filterDOMProps(otherProps, {labelable: true})}
ref={contentRef}
tabIndex={-1}
role="dialog"
aria-modal={open}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledBy}
className={b(
'content',
{'has-scroll': contentOverflow === 'auto'},
Expand Down
Loading

0 comments on commit cd2e988

Please sign in to comment.