Skip to content

Commit

Permalink
feat: improve handling aria props (#1958)
Browse files Browse the repository at this point in the history
  • Loading branch information
DanisAvko authored Dec 28, 2024
1 parent 65b4a65 commit ca226a5
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 48 deletions.
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 * as 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 * as 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 * as 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 @@ -19,7 +20,7 @@ import './Dialog.scss';

const b = block('dialog');

export interface DialogProps extends QAProps {
export interface DialogProps extends AriaLabelingProps, QAProps {
open: boolean;
children: React.ReactNode;
onOpenChange?: ModalProps['onOpenChange'];
Expand All @@ -37,8 +38,6 @@ export interface DialogProps extends QAProps {
className?: string;
modalClassName?: string;
size?: 's' | 'm' | 'l';
'aria-label'?: string;
'aria-labelledby'?: string;
container?: HTMLElement;
// TODO: Remove from readme disableFocusTrap disableAutoFocus
initialFocus?: ModalProps['initialFocus'] | 'cancel' | 'apply';
Expand Down Expand Up @@ -75,9 +74,8 @@ export function Dialog({
onTransitionInComplete,
onTransitionOut,
onTransitionOutComplete,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy,
qa,
...otherProps
}: DialogProps) {
const handleCloseButtonClick = React.useCallback(
(event: React.MouseEvent) => {
Expand Down Expand Up @@ -114,6 +112,7 @@ export function Dialog({

return (
<Modal
{...filterDOMProps(otherProps, {labelable: true})}
open={open}
contentOverflow={contentOverflow}
disableBodyScrollLock={disableBodyScrollLock}
Expand All @@ -132,8 +131,6 @@ export function Dialog({
onTransitionOut={onTransitionOut}
onTransitionOutComplete={onTransitionOutComplete}
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 * as 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 * as 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 * as 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
21 changes: 5 additions & 16 deletions src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,17 @@ import {KeyCode} from '../../constants';
import {useForkRef} from '../../hooks';
import {usePrevious} from '../../hooks/private';
import {Portal} from '../Portal';
import type {DOMProps, QAProps} from '../types';
import type {AriaLabelingProps, DOMProps, QAProps} from '../types';
import {block} from '../utils/cn';
import {filterDOMProps} from '../utils/filterDOMProps';

import i18n from './i18n';

import './Modal.scss';

export type ModalCloseReason = 'outsideClick' | 'escapeKeyDown';

export interface ModalProps extends DOMProps, QAProps {
export interface ModalProps extends DOMProps, AriaLabelingProps, QAProps {
open?: boolean;
/** Callback for open state changes, when dismiss happens for example */
onOpenChange?: (open: boolean, event?: Event, reason?: OpenChangeReason) => void;
Expand All @@ -50,7 +51,6 @@ export interface ModalProps extends DOMProps, QAProps {
disableFocusVisuallyHiddenDismiss?: boolean;

children?: React.ReactNode;

/**
* This callback will be called when Escape key pressed on keyboard, or click outside was made
* This behaviour could be disabled with `disableEscapeKeyDown`
Expand Down Expand Up @@ -84,15 +84,6 @@ export interface ModalProps extends DOMProps, QAProps {
disableEscapeKeyDown?: boolean;
/** Do not dismiss on outside click */
disableOutsideClick?: boolean;
/**
* 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;
/** Callback called when `Modal` is opened and "in" transition is started */
Expand Down Expand Up @@ -135,11 +126,10 @@ export function Modal({
contentOverflow = 'visible',
className,
contentClassName,
'aria-labelledby': ariaLabelledBy,
'aria-label': ariaLabel,
container,
qa,
floatingRef,
...otherProps
}: ModalProps) {
const handleOpenChange = React.useCallback<NonNullable<UseFloatingOptions['onOpenChange']>>(
(isOpen, event, reason) => {
Expand Down Expand Up @@ -273,14 +263,13 @@ export function Modal({
restoreFocus={true}
>
<div
{...filterDOMProps(otherProps, {labelable: true})}
className={b(
'content',
{'has-scroll': contentOverflow === 'auto'},
contentClassName,
)}
ref={handleFloatingRef}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledBy}
{...getFloatingProps({
onTransitionEnd: handleTransitionEnd,
onKeyDown: handleKeyDown,
Expand Down
11 changes: 8 additions & 3 deletions src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import _get from 'lodash/get';
import _has from 'lodash/has';
import _isNumber from 'lodash/isNumber';

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

import i18n from './i18n';
Expand Down Expand Up @@ -95,7 +96,7 @@ export interface DescriptorType {
export type TableWidth = 'auto' | 'max';

// TODO: Replace @default in props description with defaultProps in order to work with Storybook.
export interface TableProps<I> extends QAProps {
export interface TableProps<I> extends AriaLabelingProps, QAProps {
/** Data */
data: I[];
/** Column parameters */
Expand Down Expand Up @@ -456,7 +457,11 @@ export class Table<I extends TableDataItem = Record<string, string>> extends Rea
private renderTable() {
const {width = 'auto'} = this.props;
return (
<table ref={this.tableRef} className={b('table', {width})}>
<table
{...filterDOMProps(this.props, {labelable: true})}
ref={this.tableRef}
className={b('table', {width})}
>
{this.renderHead()}
{this.renderBody()}
</table>
Expand Down
14 changes: 11 additions & 3 deletions src/components/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import * as React from 'react';

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

import {TabsContext} from './TabsContext';
import {TabsItem} from './TabsItem';
Expand All @@ -23,7 +24,7 @@ export type TabsSize = 'm' | 'l' | 'xl';
export interface TabsItemProps
extends Omit<TabsItemInternalProps, 'active' | 'direction' | 'onClick'> {}

export interface TabsProps extends QAProps {
export interface TabsProps extends AriaLabelingProps, QAProps {
/**
* Tabs direction
* @deprecated Vertical tabs are deprecated
Expand Down Expand Up @@ -78,6 +79,7 @@ const TabsComponent = React.forwardRef<HTMLDivElement, TabsProps>(
onSelectTab,
wrapTo,
qa,
...otherProps
},
ref,
) => {
Expand All @@ -104,7 +106,13 @@ const TabsComponent = React.forwardRef<HTMLDivElement, TabsProps>(
}, [items, onSelectTab, wrapTo]);

return (
<div role="tablist" className={b({direction, size}, className)} data-qa={qa} ref={ref}>
<div
{...filterDOMProps(otherProps, {labelable: true})}
role="tablist"
className={b({direction, size}, className)}
data-qa={qa}
ref={ref}
>
<TabsContext.Provider value={tabsContextValue}>
{children || tabs}
</TabsContext.Provider>
Expand Down
Loading

0 comments on commit ca226a5

Please sign in to comment.