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 21, 2024
1 parent 11dd537 commit cb6c66b
Show file tree
Hide file tree
Showing 22 changed files with 129 additions and 95 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
4 changes: 4 additions & 0 deletions src/components/Alert/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Card} from '../Card';
import {Icon} from '../Icon';
import {colorText} from '../Text';
import {Flex, spacing} from '../layout';
import {filterDOMProps} from '../utils/filterDOMProps';

import {AlertAction} from './AlertAction';
import {AlertActions} from './AlertActions';
Expand All @@ -29,16 +30,19 @@ export const Alert = (props: AlertProps) => {
onClose,
align,
qa,
...otherProps
} = props;

return (
<AlertContextProvider layout={layout} view={view}>
<Card
{...filterDOMProps(otherProps, {labelable: true})}
style={style}
className={bAlert({corners}, spacing({py: 4, px: 5}, className))}
theme={theme}
view={view}
qa={qa}
role="alert"
>
<Flex gap="3" alignItems={align}>
{typeof props.icon === 'undefined' ? (
Expand Down
1 change: 1 addition & 0 deletions src/components/Alert/__snapshots__/Alert.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ exports[`Alert has predicted styles if inline layout rendered 1`] = `
<div>
<div
class="g-box g-card g-card_theme_danger g-card_view_filled g-card_type_container g-card_size_m g-alert g-s__py_4 g-s__px_5"
role="alert"
>
<div
class="g-box g-flex"
Expand Down
4 changes: 2 additions & 2 deletions src/components/Alert/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type React from 'react';

import type {ButtonProps} from '../Button';
import type {QAProps} from '../types';
import type {AriaLabelingProps, QAProps} from '../types';

export type AlertTheme = 'normal' | 'info' | 'success' | 'warning' | 'danger' | 'utility';
export type AlertView = 'filled' | 'outlined';
Expand All @@ -22,7 +22,7 @@ export type AlertContextType = {

export type AlertContextProviderProps = React.PropsWithChildren<AlertContextType>;

export interface AlertProps extends QAProps, Partial<AlertContextType> {
export interface AlertProps extends AriaLabelingProps, QAProps, Partial<AlertContextType> {
title?: React.ReactNode;
message?: React.ReactNode;
theme?: AlertTheme;
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
Loading

0 comments on commit cb6c66b

Please sign in to comment.