diff --git a/CHANGELOG.md b/CHANGELOG.md index 092dfe18e1..4c5d1afa49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Add basic animation library for Teams theme @bhamlefty @mnajdova ([#871](https://github.com/stardust-ui/react/pull/871) - Export `accept` and `urgent` SVG icons to the Teams Theme @joheredi([#929](https://github.com/stardust-ui/react/pull/929)) - Add `open`, `defaultOpen` and `onOpenChange` props for `Dropdown` component (controlled mode) @Bugaa92 ([#900](https://github.com/stardust-ui/react/pull/900)) +- Add `accessibility` prop to all components that supports it @layershifter ([#927](https://github.com/stardust-ui/react/pull/927)) ### Fixes - Display correctly images in portrait mode inside `Avatar` @layershifter ([#899](https://github.com/stardust-ui/react/pull/899)) diff --git a/packages/react/src/components/Accordion/Accordion.tsx b/packages/react/src/components/Accordion/Accordion.tsx index fc3a9667ff..2eeb6172e5 100644 --- a/packages/react/src/components/Accordion/Accordion.tsx +++ b/packages/react/src/components/Accordion/Accordion.tsx @@ -104,7 +104,6 @@ class Accordion extends AutoControlledComponent, any> }), ), ]), - accessibility: PropTypes.func, renderPanelTitle: PropTypes.func, renderPanelContent: PropTypes.func, diff --git a/packages/react/src/components/Animation/Animation.tsx b/packages/react/src/components/Animation/Animation.tsx index ad5ca9da63..affc243ebd 100644 --- a/packages/react/src/components/Animation/Animation.tsx +++ b/packages/react/src/components/Animation/Animation.tsx @@ -91,6 +91,7 @@ class Animation extends UIComponent, any> { static propTypes = { ...commonPropTypes.createCommon({ + accessibility: false, animated: false, content: false, children: 'element', diff --git a/packages/react/src/components/Attachment/Attachment.tsx b/packages/react/src/components/Attachment/Attachment.tsx index e28c8d1189..32e50bdfef 100644 --- a/packages/react/src/components/Attachment/Attachment.tsx +++ b/packages/react/src/components/Attachment/Attachment.tsx @@ -75,7 +75,6 @@ class Attachment extends UIComponent, AttachmentStat ...commonPropTypes.createCommon({ content: false, }), - accessibility: PropTypes.func, action: customPropTypes.itemShorthand, actionable: PropTypes.bool, description: customPropTypes.itemShorthand, diff --git a/packages/react/src/components/Avatar/Avatar.tsx b/packages/react/src/components/Avatar/Avatar.tsx index c1d192fd87..7e2d156439 100644 --- a/packages/react/src/components/Avatar/Avatar.tsx +++ b/packages/react/src/components/Avatar/Avatar.tsx @@ -3,6 +3,8 @@ import * as React from 'react' import Image from '../Image/Image' import Label from '../Label/Label' import Status, { StatusProps } from '../Status/Status' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ReactProps, ShorthandValue } from '../../types' import { createShorthandFactory, @@ -14,6 +16,12 @@ import { } from '../../lib' export interface AvatarProps extends UIComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** Shorthand for the image. */ image?: ShorthandValue @@ -57,6 +65,7 @@ class Avatar extends UIComponent, any> { } static defaultProps = { + accessibility: defaultBehavior, size: 'medium', getInitials(name: string) { if (!name) { @@ -81,11 +90,11 @@ class Avatar extends UIComponent, any> { }, } as AvatarProps - renderComponent({ ElementType, classes, unhandledProps, styles, variables }) { + renderComponent({ accessibility, ElementType, classes, unhandledProps, styles, variables }) { const { name, status, image, label, getInitials, size } = this.props as AvatarProps return ( - + {Image.create(image, { defaultProps: { fluid: true, diff --git a/packages/react/src/components/Button/Button.tsx b/packages/react/src/components/Button/Button.tsx index a36dd87a3d..eceb8eb765 100644 --- a/packages/react/src/components/Button/Button.tsx +++ b/packages/react/src/components/Button/Button.tsx @@ -106,7 +106,6 @@ class Button extends UIComponent, ButtonState> { primary: customPropTypes.every([customPropTypes.disallow(['secondary']), PropTypes.bool]), text: PropTypes.bool, secondary: customPropTypes.every([customPropTypes.disallow(['primary']), PropTypes.bool]), - accessibility: PropTypes.func, } public static defaultProps = { diff --git a/packages/react/src/components/Button/ButtonGroup.tsx b/packages/react/src/components/Button/ButtonGroup.tsx index 9fde67dc47..96bcf178ab 100644 --- a/packages/react/src/components/Button/ButtonGroup.tsx +++ b/packages/react/src/components/Button/ButtonGroup.tsx @@ -13,12 +13,20 @@ import { commonPropTypes, rtlTextContainer, } from '../../lib' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import Button from './Button' export interface ButtonGroupProps extends UIComponentProps, ChildrenComponentProps, ContentComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** The buttons contained inside the ButtonGroup. */ buttons?: ShorthandValue[] @@ -36,12 +44,12 @@ class ButtonGroup extends UIComponent, any> { public static propTypes = { ...commonPropTypes.createCommon(), - accessibility: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), buttons: customPropTypes.collectionShorthand, circular: PropTypes.bool, } public static defaultProps = { + accessibility: defaultBehavior, as: 'div', } diff --git a/packages/react/src/components/Chat/Chat.tsx b/packages/react/src/components/Chat/Chat.tsx index b4d167cca4..1647084c4c 100644 --- a/packages/react/src/components/Chat/Chat.tsx +++ b/packages/react/src/components/Chat/Chat.tsx @@ -39,7 +39,6 @@ class Chat extends UIComponent, any> { ...commonPropTypes.createCommon({ content: false, }), - accessibility: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), items: PropTypes.arrayOf(customPropTypes.itemShorthand), } diff --git a/packages/react/src/components/Chat/ChatItem.tsx b/packages/react/src/components/Chat/ChatItem.tsx index c06fe3f582..6d204800e6 100644 --- a/packages/react/src/components/Chat/ChatItem.tsx +++ b/packages/react/src/components/Chat/ChatItem.tsx @@ -14,6 +14,8 @@ import { rtlTextContainer, } from '../../lib' import Box from '../Box/Box' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ComponentSlotStylesPrepared } from '../../themes/types' export interface ChatItemSlotClassNames { @@ -22,6 +24,12 @@ export interface ChatItemSlotClassNames { } export interface ChatItemProps extends UIComponentProps, ChildrenComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** Controls item's relation to other chat items. */ attached?: boolean | 'top' | 'bottom' @@ -53,12 +61,14 @@ class ChatItem extends UIComponent, any> { } static defaultProps = { + accessibility: defaultBehavior, as: 'li', contentPosition: 'start', attached: false, } renderComponent({ + accessibility, ElementType, classes, unhandledProps, @@ -69,6 +79,7 @@ class ChatItem extends UIComponent, any> { return ( diff --git a/packages/react/src/components/Chat/ChatMessage.tsx b/packages/react/src/components/Chat/ChatMessage.tsx index c6e0b7c5fb..56b6281399 100644 --- a/packages/react/src/components/Chat/ChatMessage.tsx +++ b/packages/react/src/components/Chat/ChatMessage.tsx @@ -96,7 +96,6 @@ class ChatMessage extends UIComponent, ChatMessageS static propTypes = { ...commonPropTypes.createCommon({ content: 'shorthand' }), - accessibility: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), actionMenu: customPropTypes.itemShorthand, author: customPropTypes.itemShorthand, badge: customPropTypes.itemShorthand, diff --git a/packages/react/src/components/Dialog/Dialog.tsx b/packages/react/src/components/Dialog/Dialog.tsx index 10ea1e7a51..90e5eae12a 100644 --- a/packages/react/src/components/Dialog/Dialog.tsx +++ b/packages/react/src/components/Dialog/Dialog.tsx @@ -94,7 +94,6 @@ class Dialog extends AutoControlledComponent, DialogStat content: true, }), actions: customPropTypes.itemShorthand, - accessibility: PropTypes.func, cancelButton: customPropTypes.itemShorthand, confirmButton: customPropTypes.itemShorthand, defaultOpen: PropTypes.bool, diff --git a/packages/react/src/components/Divider/Divider.tsx b/packages/react/src/components/Divider/Divider.tsx index ce262ad512..0540a6a6be 100644 --- a/packages/react/src/components/Divider/Divider.tsx +++ b/packages/react/src/components/Divider/Divider.tsx @@ -12,6 +12,8 @@ import { commonPropTypes, rtlTextContainer, } from '../../lib' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ReactProps } from '../../types' export interface DividerProps @@ -19,6 +21,12 @@ export interface DividerProps ChildrenComponentProps, ColorComponentProps, ContentComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** A divider can be fitted, without any space above or below it. */ fitted?: boolean @@ -47,15 +55,17 @@ class Divider extends UIComponent, any> { } static defaultProps = { + accessibility: defaultBehavior, size: 0, } - renderComponent({ ElementType, classes, unhandledProps }) { + renderComponent({ accessibility, ElementType, classes, unhandledProps }) { const { children, content } = this.props return ( diff --git a/packages/react/src/components/Dropdown/Dropdown.tsx b/packages/react/src/components/Dropdown/Dropdown.tsx index af79faad1d..4f261b6a8c 100644 --- a/packages/react/src/components/Dropdown/Dropdown.tsx +++ b/packages/react/src/components/Dropdown/Dropdown.tsx @@ -210,6 +210,7 @@ class Dropdown extends AutoControlledComponent, Dropdo static propTypes = { ...commonPropTypes.createCommon({ + accessibility: false, children: false, content: false, }), diff --git a/packages/react/src/components/Dropdown/DropdownItem.tsx b/packages/react/src/components/Dropdown/DropdownItem.tsx index ad557a767a..504b19a0d4 100644 --- a/packages/react/src/components/Dropdown/DropdownItem.tsx +++ b/packages/react/src/components/Dropdown/DropdownItem.tsx @@ -49,6 +49,7 @@ class DropdownItem extends UIComponent, any> { static propTypes = { ...commonPropTypes.createCommon({ + accessibility: false, children: false, content: false, }), diff --git a/packages/react/src/components/Dropdown/DropdownSearchInput.tsx b/packages/react/src/components/Dropdown/DropdownSearchInput.tsx index 1e2b6658fc..56c5ceb6fc 100644 --- a/packages/react/src/components/Dropdown/DropdownSearchInput.tsx +++ b/packages/react/src/components/Dropdown/DropdownSearchInput.tsx @@ -68,6 +68,7 @@ class DropdownSearchInput extends UIComponent> { public static propTypes = { ...commonPropTypes.createCommon({ + accessibility: false, content: false, }), diff --git a/packages/react/src/components/Flex/FlexItem.tsx b/packages/react/src/components/Flex/FlexItem.tsx index 5fc3adf276..cf770e3bd6 100644 --- a/packages/react/src/components/Flex/FlexItem.tsx +++ b/packages/react/src/components/Flex/FlexItem.tsx @@ -43,6 +43,7 @@ class FlexItem extends UIComponent> { static propTypes = { ...commonPropTypes.createCommon({ + accessibility: false, content: false, }), align: PropTypes.oneOf(['auto', 'start', 'end', 'center', 'baseline', 'stretch']), diff --git a/packages/react/src/components/Form/Form.tsx b/packages/react/src/components/Form/Form.tsx index 6c7ddaf9ac..658bd77f5b 100644 --- a/packages/react/src/components/Form/Form.tsx +++ b/packages/react/src/components/Form/Form.tsx @@ -11,10 +11,18 @@ import { commonPropTypes, rtlTextContainer, } from '../../lib' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ComponentEventHandler, ReactProps, ShorthandValue } from '../../types' import FormField from './FormField' export interface FormProps extends UIComponentProps, ChildrenComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** The HTML form action. */ action?: string @@ -51,12 +59,13 @@ class Form extends UIComponent, any> { } public static defaultProps = { + accessibility: defaultBehavior, as: 'form', } public static Field = FormField - public renderComponent({ ElementType, classes, unhandledProps }): React.ReactNode { + public renderComponent({ accessibility, ElementType, classes, unhandledProps }): React.ReactNode { const { action, children } = this.props return ( , any> { action={action} onSubmit={this.handleSubmit} {...rtlTextContainer.getAttributes({ forElements: [children] })} + {...accessibility.attributes.root} {...unhandledProps} > {childrenExist(children) ? children : this.renderFields()} diff --git a/packages/react/src/components/Form/FormField.tsx b/packages/react/src/components/Form/FormField.tsx index bf4b9da7c5..3605ba6421 100644 --- a/packages/react/src/components/Form/FormField.tsx +++ b/packages/react/src/components/Form/FormField.tsx @@ -10,12 +10,20 @@ import { ChildrenComponentProps, commonPropTypes, } from '../../lib' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ReactProps, ShorthandValue } from '../../types' import Text from '../Text/Text' import Input from '../Input/Input' import Box from '../Box/Box' export interface FormFieldProps extends UIComponentProps, ChildrenComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** A control for the form field. */ control?: ShorthandValue @@ -66,6 +74,7 @@ class FormField extends UIComponent, any> { } public static defaultProps = { + accessibility: defaultBehavior, as: 'div', control: { as: Input }, } @@ -108,7 +117,7 @@ class FormField extends UIComponent, any> { ) return ( - + {childrenExist(children) ? children : content} ) diff --git a/packages/react/src/components/Grid/Grid.tsx b/packages/react/src/components/Grid/Grid.tsx index b0e28536ea..6c5e60ead9 100644 --- a/packages/react/src/components/Grid/Grid.tsx +++ b/packages/react/src/components/Grid/Grid.tsx @@ -48,7 +48,6 @@ class Grid extends UIComponent, any> { ...commonPropTypes.createCommon({ content: false, }), - accessibility: PropTypes.func, columns: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), content: customPropTypes.every([ customPropTypes.disallow(['children']), @@ -66,6 +65,7 @@ class Grid extends UIComponent, any> { } public renderComponent({ + accessibility, ElementType, classes, unhandledProps, @@ -76,6 +76,7 @@ class Grid extends UIComponent, any> { {childrenExist(children) ? children : content} diff --git a/packages/react/src/components/Header/Header.tsx b/packages/react/src/components/Header/Header.tsx index b95cd188fe..8e51d4943e 100644 --- a/packages/react/src/components/Header/Header.tsx +++ b/packages/react/src/components/Header/Header.tsx @@ -14,6 +14,8 @@ import { rtlTextContainer, } from '../../lib' import HeaderDescription from './HeaderDescription' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ReactProps, ShorthandValue } from '../../types' export interface HeaderProps @@ -21,6 +23,12 @@ export interface HeaderProps ChildrenComponentProps, ContentComponentProps, ColorComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** Shorthand for Header.Description. */ description?: ShorthandValue @@ -53,12 +61,13 @@ class Header extends UIComponent, any> { } static defaultProps = { + accessibility: defaultBehavior, as: 'h1', } static Description = HeaderDescription - renderComponent({ ElementType, classes, variables: v, unhandledProps }) { + renderComponent({ accessibility, ElementType, classes, variables: v, unhandledProps }) { const { children, description, content } = this.props const hasChildren = childrenExist(children) @@ -70,6 +79,7 @@ class Header extends UIComponent, any> { forElements: [children, content], condition: !description, })} + {...accessibility.attributes.root} {...unhandledProps} className={classes.root} > diff --git a/packages/react/src/components/Header/HeaderDescription.tsx b/packages/react/src/components/Header/HeaderDescription.tsx index 2dd5a3e411..60613c4832 100644 --- a/packages/react/src/components/Header/HeaderDescription.tsx +++ b/packages/react/src/components/Header/HeaderDescription.tsx @@ -11,13 +11,21 @@ import { ColorComponentProps, rtlTextContainer, } from '../../lib' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ReactProps } from '../../types' export interface HeaderDescriptionProps extends UIComponentProps, ChildrenComponentProps, ContentComponentProps, - ColorComponentProps {} + ColorComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility +} /** * A header's description provides more detailed information. @@ -34,14 +42,16 @@ class HeaderDescription extends UIComponent, } static defaultProps = { + accessibility: defaultBehavior, as: 'p', } - renderComponent({ ElementType, classes, unhandledProps }) { + renderComponent({ accessibility, ElementType, classes, unhandledProps }) { const { children, content } = this.props return ( diff --git a/packages/react/src/components/Icon/Icon.tsx b/packages/react/src/components/Icon/Icon.tsx index 9f40aa3cda..98ed9fc35d 100644 --- a/packages/react/src/components/Icon/Icon.tsx +++ b/packages/react/src/components/Icon/Icon.tsx @@ -63,7 +63,6 @@ class Icon extends UIComponent, any> { content: false, color: true, }), - accessibility: PropTypes.func, bordered: PropTypes.bool, circular: PropTypes.bool, disabled: PropTypes.bool, diff --git a/packages/react/src/components/Image/Image.tsx b/packages/react/src/components/Image/Image.tsx index 4a92790e58..e48aec84d3 100644 --- a/packages/react/src/components/Image/Image.tsx +++ b/packages/react/src/components/Image/Image.tsx @@ -49,7 +49,6 @@ class Image extends UIComponent, any> { children: false, content: false, }), - accessibility: PropTypes.func, avatar: PropTypes.bool, circular: PropTypes.bool, fluid: PropTypes.bool, diff --git a/packages/react/src/components/Indicator/Indicator.tsx b/packages/react/src/components/Indicator/Indicator.tsx index 63c184547b..cfbcd48177 100644 --- a/packages/react/src/components/Indicator/Indicator.tsx +++ b/packages/react/src/components/Indicator/Indicator.tsx @@ -8,10 +8,18 @@ import { commonPropTypes, customPropTypes, } from '../../lib' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ReactProps, ShorthandValue } from '../../types' import Icon from '../Icon/Icon' export interface IndicatorProps extends UIComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** The indicator can point towards different directions. */ direction?: 'start' | 'end' | 'top' | 'bottom' @@ -43,17 +51,18 @@ class Indicator extends UIComponent, any> { } static defaultProps = { + accessibility: defaultBehavior, as: 'span', direction: 'bottom', } - renderComponent({ ElementType, classes, unhandledProps, rtl }) { + renderComponent({ accessibility, ElementType, classes, unhandledProps, rtl }) { const { direction, icon, color } = this.props const hexUnicode = direction && Indicator.directionMap[this.getDirectionBasedOnRtl(rtl, direction)].unicode return ( - + {icon ? Icon.create(icon, { defaultProps: { color }, diff --git a/packages/react/src/components/Input/Input.tsx b/packages/react/src/components/Input/Input.tsx index e1e75df3a8..8f6819e24a 100644 --- a/packages/react/src/components/Input/Input.tsx +++ b/packages/react/src/components/Input/Input.tsx @@ -13,6 +13,8 @@ import { commonPropTypes, handleRef, } from '../../lib' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ReactProps, ShorthandValue, ComponentEventHandler } from '../../types' import Icon from '../Icon/Icon' import Ref from '../Ref/Ref' @@ -23,6 +25,12 @@ export interface InputSlotClassNames { } export interface InputProps extends UIComponentProps, ChildrenComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** A property that will change the icon on the input and clear the input on click on Cancel. */ clearable?: boolean @@ -105,6 +113,7 @@ class Input extends AutoControlledComponent, InputState> } static defaultProps = { + accessibility: defaultBehavior, type: 'text', wrapper: {}, iconPosition: 'end', @@ -113,6 +122,7 @@ class Input extends AutoControlledComponent, InputState> static autoControlledProps = ['value'] renderComponent({ + accessibility, ElementType, classes, unhandledProps, @@ -125,6 +135,7 @@ class Input extends AutoControlledComponent, InputState> return Box.create(wrapper, { defaultProps: { + ...accessibility.attributes.root, className: cx(Input.className, className), children: ( <> diff --git a/packages/react/src/components/ItemLayout/ItemLayout.tsx b/packages/react/src/components/ItemLayout/ItemLayout.tsx index 69caa552da..f668c80ebe 100644 --- a/packages/react/src/components/ItemLayout/ItemLayout.tsx +++ b/packages/react/src/components/ItemLayout/ItemLayout.tsx @@ -80,6 +80,7 @@ class ItemLayout extends UIComponent, any> { static propTypes = { ...commonPropTypes.createCommon({ + accessibility: false, children: false, content: false, }), diff --git a/packages/react/src/components/Label/Label.tsx b/packages/react/src/components/Label/Label.tsx index ad835f219b..3f7c14cfca 100644 --- a/packages/react/src/components/Label/Label.tsx +++ b/packages/react/src/components/Label/Label.tsx @@ -19,6 +19,7 @@ import Icon from '../Icon/Icon' import Image from '../Image/Image' import Layout from '../Layout/Layout' import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ReactProps, ShorthandValue } from '../../types' import { ComplexColorPropType, @@ -30,6 +31,10 @@ export interface LabelProps ChildrenComponentProps, ContentComponentProps, ColorComponentProps> { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ accessibility?: Accessibility /** A Label can be circular. */ @@ -72,6 +77,7 @@ class Label extends UIComponent, any> { } static defaultProps = { + accessibility: defaultBehavior, as: 'span', imagePosition: 'start', iconPosition: 'end', @@ -85,13 +91,14 @@ class Label extends UIComponent, any> { } } - renderComponent({ ElementType, classes, unhandledProps, variables, styles }) { + renderComponent({ accessibility, ElementType, classes, unhandledProps, variables, styles }) { const { children, content, icon, iconPosition, image, imagePosition } = this.props if (childrenExist(children)) { return ( @@ -123,7 +130,7 @@ class Label extends UIComponent, any> { const hasEndElement = endIcon || endImage return ( - + , any> { static propTypes = { ...commonPropTypes.createCommon({ + accessibility: false, children: false, content: false, }), diff --git a/packages/react/src/components/List/List.tsx b/packages/react/src/components/List/List.tsx index 8d56fe1b53..cd278978ae 100644 --- a/packages/react/src/components/List/List.tsx +++ b/packages/react/src/components/List/List.tsx @@ -71,7 +71,6 @@ class List extends AutoControlledComponent, ListState> { ...commonPropTypes.createCommon({ content: false, }), - accessibility: PropTypes.func, debug: PropTypes.bool, items: customPropTypes.collectionShorthand, selectable: PropTypes.bool, diff --git a/packages/react/src/components/List/ListItem.tsx b/packages/react/src/components/List/ListItem.tsx index 91040ab903..63ca1ff127 100644 --- a/packages/react/src/components/List/ListItem.tsx +++ b/packages/react/src/components/List/ListItem.tsx @@ -92,7 +92,6 @@ class ListItem extends UIComponent, ListItemState> { truncateContent: PropTypes.bool, truncateHeader: PropTypes.bool, - accessibility: PropTypes.func, onClick: PropTypes.func, onFocus: PropTypes.func, } diff --git a/packages/react/src/components/Loader/Loader.tsx b/packages/react/src/components/Loader/Loader.tsx index f988d037c9..57d79cc7c1 100644 --- a/packages/react/src/components/Loader/Loader.tsx +++ b/packages/react/src/components/Loader/Loader.tsx @@ -20,7 +20,7 @@ export type LoaderPosition = 'above' | 'below' | 'start' | 'end' export interface LoaderProps extends UIComponentProps, ColorComponentProps { /** * Accessibility behavior if overridden by the user. - * @default defaultBehavior + * @default loaderBehavior */ accessibility?: Accessibility @@ -51,7 +51,6 @@ class Loader extends UIComponent> { content: false, color: true, }), - accessibility: PropTypes.func, indicator: customPropTypes.itemShorthand, label: customPropTypes.itemShorthand, labelPosition: PropTypes.oneOf(['above', 'below', 'start', 'end']), diff --git a/packages/react/src/components/Menu/Menu.tsx b/packages/react/src/components/Menu/Menu.tsx index 3c28d74441..cdaec9f118 100644 --- a/packages/react/src/components/Menu/Menu.tsx +++ b/packages/react/src/components/Menu/Menu.tsx @@ -94,7 +94,6 @@ class Menu extends AutoControlledComponent, MenuState> { ...commonPropTypes.createCommon({ content: false, }), - accessibility: PropTypes.func, activeIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), defaultActiveIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), fluid: PropTypes.bool, diff --git a/packages/react/src/components/Menu/MenuDivider.tsx b/packages/react/src/components/Menu/MenuDivider.tsx index e31dc6c5e0..6701c77fe5 100644 --- a/packages/react/src/components/Menu/MenuDivider.tsx +++ b/packages/react/src/components/Menu/MenuDivider.tsx @@ -41,7 +41,6 @@ class MenuDivider extends UIComponent, any> { static propTypes = { ...commonPropTypes.createCommon({ content: false, children: false, color: true }), - accessibility: PropTypes.func, primary: PropTypes.bool, secondary: PropTypes.bool, vertical: PropTypes.bool, diff --git a/packages/react/src/components/Menu/MenuItem.tsx b/packages/react/src/components/Menu/MenuItem.tsx index 35c62c23fc..b08a38dee7 100644 --- a/packages/react/src/components/Menu/MenuItem.tsx +++ b/packages/react/src/components/Menu/MenuItem.tsx @@ -135,7 +135,6 @@ class MenuItem extends AutoControlledComponent, MenuIt static propTypes = { ...commonPropTypes.createCommon(), - accessibility: PropTypes.func, active: PropTypes.bool, disabled: PropTypes.bool, icon: customPropTypes.itemShorthand, diff --git a/packages/react/src/components/Popup/Popup.tsx b/packages/react/src/components/Popup/Popup.tsx index ce42881186..ea83a4f2cd 100644 --- a/packages/react/src/components/Popup/Popup.tsx +++ b/packages/react/src/components/Popup/Popup.tsx @@ -138,7 +138,6 @@ export default class Popup extends AutoControlledComponent, any> { onMouseLeave: PropTypes.func, } + static defaultProps = { + accessibility: defaultBehavior, + } + private handleMouseEnter = e => { _.invoke(this.props, 'onMouseEnter', e, this.props) } @@ -60,6 +72,7 @@ class PopupContent extends UIComponent, any> { } public renderComponent({ + accessibility, ElementType, classes, unhandledProps, @@ -70,6 +83,7 @@ class PopupContent extends UIComponent, any> { , Port public static propTypes = { ...commonPropTypes.createCommon({ + accessibility: false, animated: false, as: false, className: false, diff --git a/packages/react/src/components/Portal/PortalInner.tsx b/packages/react/src/components/Portal/PortalInner.tsx index a4bda85231..cfdeec1b2e 100644 --- a/packages/react/src/components/Portal/PortalInner.tsx +++ b/packages/react/src/components/Portal/PortalInner.tsx @@ -30,6 +30,7 @@ export interface PortalInnerProps extends ChildrenComponentProps { class PortalInner extends React.Component> { public static propTypes = { ...commonPropTypes.createCommon({ + accessibility: false, animated: false, as: false, className: false, diff --git a/packages/react/src/components/RadioGroup/RadioGroup.tsx b/packages/react/src/components/RadioGroup/RadioGroup.tsx index 0e8ba44ee1..eb85164b19 100644 --- a/packages/react/src/components/RadioGroup/RadioGroup.tsx +++ b/packages/react/src/components/RadioGroup/RadioGroup.tsx @@ -61,7 +61,6 @@ class RadioGroup extends AutoControlledComponent, an ...commonPropTypes.createCommon({ content: false, }), - accessibility: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), checkedValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), defaultCheckedValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), items: customPropTypes.collectionShorthand, diff --git a/packages/react/src/components/RadioGroup/RadioGroupItem.tsx b/packages/react/src/components/RadioGroup/RadioGroupItem.tsx index e1c3ae6426..7e81877829 100644 --- a/packages/react/src/components/RadioGroup/RadioGroupItem.tsx +++ b/packages/react/src/components/RadioGroup/RadioGroupItem.tsx @@ -108,7 +108,6 @@ class RadioGroupItem extends AutoControlledComponent< ...commonPropTypes.createCommon({ content: false, }), - accessibility: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), checked: PropTypes.bool, defaultChecked: PropTypes.bool, disabled: PropTypes.bool, diff --git a/packages/react/src/components/Segment/Segment.tsx b/packages/react/src/components/Segment/Segment.tsx index 0d6549f54f..334895aee3 100644 --- a/packages/react/src/components/Segment/Segment.tsx +++ b/packages/react/src/components/Segment/Segment.tsx @@ -9,6 +9,8 @@ import { commonPropTypes, rtlTextContainer, } from '../../lib' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ReactProps, ShorthandValue } from '../../types' import Box from '../Box/Box' @@ -16,6 +18,12 @@ export interface SegmentProps extends UIComponentProps, ChildrenComponentProps, ContentComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** A segment can have its colors inverted for contrast. */ inverted?: boolean } @@ -37,15 +45,17 @@ class Segment extends UIComponent, any> { } static defaultProps = { + accessibility: defaultBehavior, as: 'div', } - renderComponent({ ElementType, classes, unhandledProps }) { + renderComponent({ accessibility, ElementType, classes, unhandledProps }) { const { children, content } = this.props return ( diff --git a/packages/react/src/components/Status/Status.tsx b/packages/react/src/components/Status/Status.tsx index 2711a8efb5..ff3d8359e6 100644 --- a/packages/react/src/components/Status/Status.tsx +++ b/packages/react/src/components/Status/Status.tsx @@ -51,7 +51,6 @@ class Status extends UIComponent, any> { children: false, content: false, }), - accessibility: PropTypes.func, color: PropTypes.string, icon: customPropTypes.itemShorthand, size: customPropTypes.size, diff --git a/packages/react/src/components/Text/Text.tsx b/packages/react/src/components/Text/Text.tsx index 688325f744..700d23a6c0 100644 --- a/packages/react/src/components/Text/Text.tsx +++ b/packages/react/src/components/Text/Text.tsx @@ -14,7 +14,8 @@ import { rtlTextContainer, SizeValue, } from '../../lib' - +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' import { ReactProps } from '../../types' export interface TextProps @@ -22,6 +23,12 @@ export interface TextProps ContentComponentProps, ChildrenComponentProps, ColorComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + /** At mentions can be formatted to draw users' attention. Mentions for "me" can be formatted to appear differently. */ atMention?: boolean | 'me' @@ -85,16 +92,18 @@ class Text extends UIComponent, any> { } static defaultProps = { + accessibility: defaultBehavior, as: 'span', } - renderComponent({ ElementType, classes, unhandledProps }): React.ReactNode { + renderComponent({ accessibility, ElementType, classes, unhandledProps }): React.ReactNode { const { children, content } = this.props return ( {childrenExist(children) ? children : content} diff --git a/packages/react/src/components/Tree/Tree.tsx b/packages/react/src/components/Tree/Tree.tsx index a782b927d5..a607dd0f90 100644 --- a/packages/react/src/components/Tree/Tree.tsx +++ b/packages/react/src/components/Tree/Tree.tsx @@ -50,7 +50,6 @@ class Tree extends UIComponent> { ...commonPropTypes.createCommon({ content: false, }), - accessibility: PropTypes.func, items: customPropTypes.collectionShorthand, renderItemTitle: PropTypes.func, rtlAttributes: PropTypes.func, diff --git a/packages/react/src/components/Tree/TreeItem.tsx b/packages/react/src/components/Tree/TreeItem.tsx index 1120e8818d..695d4d3a35 100644 --- a/packages/react/src/components/Tree/TreeItem.tsx +++ b/packages/react/src/components/Tree/TreeItem.tsx @@ -65,7 +65,6 @@ class TreeItem extends AutoControlledComponent, TreeIt ...commonPropTypes.createCommon({ content: false, }), - accessibility: PropTypes.func, defaultOpen: PropTypes.bool, items: customPropTypes.collectionShorthand, open: PropTypes.bool, diff --git a/packages/react/src/components/Tree/TreeTitle.tsx b/packages/react/src/components/Tree/TreeTitle.tsx index d15874bf17..eace9f9f04 100644 --- a/packages/react/src/components/Tree/TreeTitle.tsx +++ b/packages/react/src/components/Tree/TreeTitle.tsx @@ -42,7 +42,6 @@ class TreeTitle extends UIComponent> { static propTypes = { ...commonPropTypes.createCommon(), - accessibility: PropTypes.func, open: PropTypes.bool, hasSubtree: PropTypes.bool, } diff --git a/packages/react/src/lib/accessibility/Behaviors/Grid/gridBehavior.ts b/packages/react/src/lib/accessibility/Behaviors/Grid/gridBehavior.ts index 5db0b4bbbe..ec7cf374b2 100644 --- a/packages/react/src/lib/accessibility/Behaviors/Grid/gridBehavior.ts +++ b/packages/react/src/lib/accessibility/Behaviors/Grid/gridBehavior.ts @@ -5,6 +5,7 @@ import { Accessibility, FocusZoneMode } from '../../types' * Embeds FocusZone into component allowing circular arrow key navigation through the children of the component. */ const gridBehavior: Accessibility = (props: any) => ({ + attributes: {}, focusZone: { mode: FocusZoneMode.Embed, props: { diff --git a/packages/react/src/lib/commonPropTypes.ts b/packages/react/src/lib/commonPropTypes.ts index 699e023cc7..e396836d95 100644 --- a/packages/react/src/lib/commonPropTypes.ts +++ b/packages/react/src/lib/commonPropTypes.ts @@ -2,6 +2,7 @@ import * as PropTypes from 'prop-types' import * as customPropTypes from './customPropTypes' export interface CreateCommonConfig { + accessibility?: boolean animated?: boolean children?: boolean | 'node' | 'element' as?: boolean @@ -40,6 +41,7 @@ export const complexColorPropType = PropTypes.oneOfType([ export const createCommon = (config: CreateCommonConfig = {}) => { const { + accessibility = true, animated = true, as = true, children = 'node', @@ -49,6 +51,9 @@ export const createCommon = (config: CreateCommonConfig = {}) => { styled = true, } = config return { + ...(accessibility && { + accessibility: customPropTypes.accessibility, + }), ...(animated && { animation: customPropTypes.animation, }), diff --git a/packages/react/src/lib/customPropTypes.tsx b/packages/react/src/lib/customPropTypes.tsx index ad8f27ba01..4e477b232f 100644 --- a/packages/react/src/lib/customPropTypes.tsx +++ b/packages/react/src/lib/customPropTypes.tsx @@ -450,6 +450,8 @@ export const deprecate = (help: string, validator: Function) => ( return error } +export const accessibility = PropTypes.oneOfType([PropTypes.func, PropTypes.object]) + export const size = PropTypes.oneOf([ 'smallest', 'smaller', diff --git a/packages/react/test/specs/commonTests/isConformant.tsx b/packages/react/test/specs/commonTests/isConformant.tsx index 3b173d4120..1f8b6e167a 100644 --- a/packages/react/test/specs/commonTests/isConformant.tsx +++ b/packages/react/test/specs/commonTests/isConformant.tsx @@ -1,3 +1,4 @@ +import * as faker from 'faker' import * as _ from 'lodash' import * as React from 'react' import { ReactWrapper } from 'enzyme' @@ -14,11 +15,13 @@ import helpers from './commonHelpers' import * as stardust from 'src/index' +import { Accessibility, AriaRole } from 'src/lib/accessibility/types' import { FocusZone } from 'src/lib/accessibility/FocusZone' import { FOCUSZONE_WRAP_ATTRIBUTE } from 'src/lib/accessibility/FocusZone/focusUtilities' export interface Conformant { eventTargets?: object + hasAccessibilityProp?: boolean nestingLevel?: number requiredProps?: object exportedAtTopLevel?: boolean @@ -40,6 +43,7 @@ export default (Component, options: Conformant = {}) => { const { eventTargets = {}, exportedAtTopLevel = true, + hasAccessibilityProp = true, nestingLevel = 0, requiredProps = {}, rendersPortal = false, @@ -305,6 +309,30 @@ export default (Component, options: Conformant = {}) => { }) }) + if (hasAccessibilityProp) { + test('defines an "accessibility" prop in Component.defaultProps', () => { + expect(Component.defaultProps).toHaveProperty('accessibility') + }) + + test('defines an "accessibility" prop in Component.handledProps', () => { + expect(Component.handledProps).toContain('accessibility') + }) + + test('spreads "attributes" on root', () => { + const role = faker.lorem.word() as AriaRole + const noopBehavior: Accessibility = () => ({ + attributes: { + root: { role }, + }, + }) + + const wrapper = mount() + const element = getComponent(wrapper) + + expect(element.prop('role')).toBe(role) + }) + } + // ---------------------------------------- // Events // ---------------------------------------- diff --git a/packages/react/test/specs/components/Animation/Animation-test.tsx b/packages/react/test/specs/components/Animation/Animation-test.tsx index 2f5774e02c..4933174e41 100644 --- a/packages/react/test/specs/components/Animation/Animation-test.tsx +++ b/packages/react/test/specs/components/Animation/Animation-test.tsx @@ -3,5 +3,5 @@ import { isConformant } from 'test/specs/commonTests' import Animation from 'src/components/Animation/Animation' describe('Animation', () => { - isConformant(Animation) + isConformant(Animation, { hasAccessibilityProp: false }) }) diff --git a/packages/react/test/specs/components/Dropdown/Dropdown-test.tsx b/packages/react/test/specs/components/Dropdown/Dropdown-test.tsx index af572790e5..0080294696 100644 --- a/packages/react/test/specs/components/Dropdown/Dropdown-test.tsx +++ b/packages/react/test/specs/components/Dropdown/Dropdown-test.tsx @@ -2,5 +2,5 @@ import { isConformant } from 'test/specs/commonTests' import Dropdown from 'src/components/Dropdown/Dropdown' describe('Dropdown', () => { - isConformant(Dropdown) + isConformant(Dropdown, { hasAccessibilityProp: false }) }) diff --git a/packages/react/test/specs/components/ItemLayout/ItemLayout-test.ts b/packages/react/test/specs/components/ItemLayout/ItemLayout-test.ts index 6065907573..0500050d52 100644 --- a/packages/react/test/specs/components/ItemLayout/ItemLayout-test.ts +++ b/packages/react/test/specs/components/ItemLayout/ItemLayout-test.ts @@ -3,5 +3,5 @@ import { isConformant } from 'test/specs/commonTests' import ItemLayout from 'src/components/ItemLayout/ItemLayout' describe('ItemLayout', () => { - isConformant(ItemLayout) + isConformant(ItemLayout, { hasAccessibilityProp: false }) }) diff --git a/packages/react/test/specs/components/Layout/Layout-test.ts b/packages/react/test/specs/components/Layout/Layout-test.ts index 20910383eb..e35dfbfb04 100644 --- a/packages/react/test/specs/components/Layout/Layout-test.ts +++ b/packages/react/test/specs/components/Layout/Layout-test.ts @@ -3,5 +3,5 @@ import { isConformant } from 'test/specs/commonTests' import Layout from 'src/components/Layout/Layout' describe('Layout', () => { - isConformant(Layout) + isConformant(Layout, { hasAccessibilityProp: false }) })