Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8ad5ae9
editing,adding behaviours and adding acc. description for components
mituron Aug 9, 2018
65003f9
removing divider role as it was not correctly implemented
mituron Aug 9, 2018
7669fd8
returning back divider file, which deleted by mistake
mituron Aug 9, 2018
83fca4f
adding tests
mituron Aug 10, 2018
0309b1f
adding test, modify tests, change format of description
mituron Aug 10, 2018
96aa2e9
another changes in descriptions
mituron Aug 10, 2018
aa73aa5
changing description based on PR proposal
mituron Aug 17, 2018
4031a53
minor changes
Aug 17, 2018
6a08214
changes after PR, merged with latest develop
mituron Aug 21, 2018
f8e00fc
reverting back divider to origin state
mituron Aug 21, 2018
97ad26c
adding changelog
mituron Aug 21, 2018
0e4ee5a
changes after PR, added unit tests
Aug 22, 2018
9860d3f
merge latest master, solve conflicts
Aug 23, 2018
bf801d6
moving coment in changelog to correct place
mituron Aug 23, 2018
eff83f6
moving comment in changelog file
mituron Aug 23, 2018
472e747
changes after PR, renaming tests, adding tests for toggleButton behavior
mituron Aug 24, 2018
5ec91c4
merge with latest master
mituron Aug 24, 2018
e252971
changing it keyword to test
mituron Aug 24, 2018
641d61a
capital letter for behavior
mituron Aug 24, 2018
1c23a5c
changing aria disabled to aria-disabled
mituron Aug 24, 2018
237521f
Merge branch 'master' into feat/acc-behaviours-descriptions
kuzhelov Aug 24, 2018
8106bef
introduce missed dashes into test names
kuzhelov-ms Aug 24, 2018
c76637c
Merge branch 'master' into feat/acc-behaviours-descriptions
kuzhelov Aug 24, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Features
- Add basic `Radio` component @alinais ([#100](https://github.com/stardust-ui/react/pull/100))
- Add `descriptionColor` to Header @kuzhelov ([#78](https://github.com/stardust-ui/react/pull/78))
- Add accessibility behavior description @kolaps33 ([#74](https://github.com/stardust-ui/react/pull/74))

<!--------------------------------[ v0.3.0 ]------------------------------- -->
## [v0.3.0](https://github.com/stardust-ui/react/tree/v0.3.0) (2018-08-22)
Expand Down
10 changes: 8 additions & 2 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ import { Accessibility } from '../../lib/accessibility/interfaces'

/**
* A button.
* @accessibility This is example usage of the accessibility tag.
* This should be replaced with the actual description after the PR is merged
* @accessibility
* Default behavior: ButtonBehavior
* - adds role='button' if element type is other than 'button'
*
*
* Other considerations:
* - for disabled buttons, add 'disabled' attribute so that the state is properly recognized by the screen reader
* - if button includes icon only, textual representation needs to be provided by using 'title', 'aria-label', or 'aria-labelledby' attributes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are really great points. They are concise, easy to understand, and easy to implement. Before merging this, I want to make sure they get first class treatment in the code base.

Here are the thoughts that come to mind when I read the @accessibility points above:

  1. I want these to stay updated and not get overlooked with library updates.
  2. I would like to enforce a test to be written for each point.
  3. I would like these points to be accessible from other places.

Perhaps we should move these somewhere closer to the Accessibility classes? I can see having these in some kind of requirements JSON file where we could then enforce a test to be written for each one.

Alternatively, we could include these as JSDoc comments directly in the Accessibility classes themselves and parse them out like we do props for components.

I'm not sure Default behavior: ButtonBehavior makes sense to doc site users without including docs for the accessibility classes, which might be a great idea.

Conclusion
This material is too valuable to leave in component comments alone. We should make it more accessible, put it in the path of updates to keep it fresh, and use it for more cases.

Feedback?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend having the separate section on the Docs site for accessibility behaviors, the similar as we have Components section. That section should contain all behaviors and description when and how to use them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, especially once the Accessibility classes will include keyboard handling, we should document them separately.

A lot of this information is however related to the component directly, see especially the 'Other considerations' part:

  • they include additional information to the user, not something that will be implemented in the behavior.
  • they are directly related to the component, less to the behavior
  • as they are suggestions, we cannot really test them (it could be however great to come up with a way of automatically notifying user, that once he uses a button with icon only, he should provide a textual representation as well - haven't figured out yet how to do this taking the flexibility of StarDust into account)

I agree that at least big part of the documentation should be inside of the Accessibility objects code - we should generate doc pages based on that and link the component page to its default behavior page.

I would prefer this to be done in a separate PR - this PR already includes valuable information to the users. We can improve both the user facing side of it as well as the way how it is generated, but that should be a separate PR.

*/
class Button extends UIComponent<any, any> {
public static displayName = 'Button'
Expand Down
5 changes: 5 additions & 0 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import HeaderDescription from './HeaderDescription'
* @accessibility
* Headings communicate the organization of the content on the page. Web browsers, plug-ins, and assistive technologies can use them to provide in-page navigation.
* Nest headings by their rank (or level). The most important heading has the rank 1 (<h1>), the least important heading rank 6 (<h6>). Headings with an equal or higher rank start a new section, headings with a lower rank start new subsections that are part of the higher ranked section.
*
*
* Other considerations:
* - when the description property is used in header, readers will narrate both header content and description within the element.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you, please, suggest what this is about? Which case we are describing there (actually, would help if you'll be able to share HTML fragment). Thanks!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related to the case when header has description, so user would be aware that description is narrated the same way as header
screen shot 2018-08-22 at 16 42 09

* In addition to that, both will be displayed in the list of headings.
*/
class Header extends UIComponent<any, any> {
static className = 'ui-header'
Expand Down
26 changes: 19 additions & 7 deletions src/components/Icon/Icon.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import * as React from 'react'
import * as PropTypes from 'prop-types'
import { customPropTypes, UIComponent, createShorthandFactory } from '../../lib'
import { IconBehavior } from '../../lib/accessibility/'

import svgIcons from './svgIcons'

export type IconXSpacing = 'none' | 'before' | 'after' | 'both'

/**
* @accessibility
* Default behavior: IconBehavior
* - attribute "aria-hidden='true'" is applied on icon
*/

class Icon extends UIComponent<any, any> {
static create: Function

Expand Down Expand Up @@ -59,9 +66,13 @@ class Icon extends UIComponent<any, any> {

/** Adds space to the before, after or on both sides of the icon, or removes the default space around the icon ('none' value) */
xSpacing: PropTypes.oneOf(['none', 'before', 'after', 'both']),

/** Accessibility behavior if overriden by the user. */
accessibility: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
}

static handledProps = [
'accessibility',
'as',
'bordered',
'circular',
Expand All @@ -79,28 +90,29 @@ class Icon extends UIComponent<any, any> {
static defaultProps = {
as: 'span',
size: 'normal',
accessibility: IconBehavior,
}

renderFontIcon(ElementType, classes, rest): React.ReactNode {
return <ElementType className={classes.root} {...rest} />
renderFontIcon(ElementType, classes, rest, accessibility): React.ReactNode {
return <ElementType className={classes.root} {...accessibility.attributes.root} {...rest} />
}

renderSvgIcon(ElementType, classes, rest): React.ReactNode {
renderSvgIcon(ElementType, classes, rest, accessibility): React.ReactNode {
const icon = svgIcons[this.props.name]

return (
<ElementType className={classes.root} {...rest}>
<ElementType className={classes.root} {...accessibility.attributes.root} {...rest}>
<svg className={classes.svg} viewBox={icon && icon.viewBox}>
{icon && icon.element}
</svg>
</ElementType>
)
}

renderComponent({ ElementType, classes, rest }) {
renderComponent({ ElementType, classes, rest, accessibility }) {
return this.props.svg
? this.renderSvgIcon(ElementType, classes, rest)
: this.renderFontIcon(ElementType, classes, rest)
? this.renderSvgIcon(ElementType, classes, rest, accessibility)
: this.renderFontIcon(ElementType, classes, rest, accessibility)
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/components/Image/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ import { Accessibility } from '../../lib/accessibility/interfaces'

/**
* An image is a graphic representation of something.
* @accessibility
* Default behavior: ImageBehavior
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just as a matter of thought: for the future we might consider to introduce Default behavior section under @ symbol, so that it could be parsed by parsing tools and segregated from the rest of content

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, we can think about that in next PR

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a note to consider - in that case we would need to maintain the information about the default behavior in two places - in the comments and in defaultProps.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, but this is something that we have even now, so the situation won't be any different. But this is a very good point raised - probably we should utilize the fact that defaultBehavior is already defined, so that there won't be any chance for these two different places of declaring it to come out os sync at some point

* - attribute "aria-hidden='true'" is applied on img element, if there is no 'alt' property provided
*
* If image should be visible to screen readers, textual representation needs to be provided in 'alt' property.
*
* Other considerations:
* - when alt property is empty, then Narrator in scan mode navigates to image and narrates it as empty paragraph
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 very helpful

* - when image has role='presentation' then screen readers navigate to the element in scan/virtual mode. To avoid this, the attribute "aria-hidden='true'" is applied by the default image behavior
* - when alt property is used in combination with aria-label, arialabbeledby or title, additional screen readers verification is needed as each screen reader handles this combination differently.
*/
class Image extends UIComponent<any, any> {
static className = 'ui-image'
Expand Down
8 changes: 7 additions & 1 deletion src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import Icon from '../Icon'

/**
* An Input
* @accessibility This is example usage of the accessibility tag.
* @accessibility
* For good screen reader experience set aria-label or aria-labelledby attribute for input.
*
*
* Other considerations:
* - if input is search, then use "role='search'"
*
*/
class Input extends AutoControlledComponent<any, any> {
static className = 'ui-input'
Expand Down
3 changes: 1 addition & 2 deletions src/lib/accessibility/Behaviors/Button/ButtonBehavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { Accessibility } from '../../interfaces'
const ButtonBehavior: Accessibility = (props: any) => ({
attributes: {
root: {
role: 'button',
'aria-hidden': false,
role: props.as === 'button' ? undefined : 'button',
'aria-disabled': !!props['disabled'],
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Accessibility } from '../../interfaces'
const ToggleButtonBehavior: Accessibility = (props: any) => ({
attributes: {
root: {
role: 'button',
role: props.as === 'button' ? undefined : 'button',
'aria-pressed': !!props['active'],
'aria-disabled': !!props['disabled'],
},
Expand Down
11 changes: 11 additions & 0 deletions src/lib/accessibility/Behaviors/Icon/IconBehavior.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Accessibility } from '../../interfaces'

const IconBehavior: Accessibility = (props: any) => ({
attributes: {
root: {
'aria-hidden': 'true',
},
},
})

export default IconBehavior
2 changes: 1 addition & 1 deletion src/lib/accessibility/Behaviors/Image/ImageBehavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Accessibility } from '../../interfaces'
const ImageBehavior: Accessibility = (props: any) => ({
attributes: {
root: {
role: props['alt'] ? undefined : 'presentation',
'aria-hidden': props['alt'] ? undefined : 'true',
},
},
})
Expand Down
1 change: 1 addition & 0 deletions src/lib/accessibility/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export { default as InputBehavior } from './Behaviors/Input/InputBehavior'
export { default as TreeBehavior } from './Behaviors/Tree/TreeBehavior'
export { default as TreeItemBehavior } from './Behaviors/Tree/TreeItemBehavior'
export { default as GroupBehavior } from './Behaviors/Tree/GroupBehavior'
export { default as IconBehavior } from './Behaviors/Icon/IconBehavior'
14 changes: 7 additions & 7 deletions test/specs/commonTests/handlesAccessibility.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as React from 'react'
import { getTestingRenderedComponent } from 'test/utils'
import { ButtonBehavior, DefaultBehavior } from 'src/lib/accessibility'

const getProp = (renderedComponent, propName, partSelector) => {
export const getRenderedAttribute = (renderedComponent, propName, partSelector) => {
const target = partSelector
? renderedComponent.render().find(partSelector)
: renderedComponent.render()
Expand All @@ -24,15 +24,15 @@ const getProp = (renderedComponent, propName, partSelector) => {
export default (Component, options: any = {}) => {
const {
requiredProps = {},
defaultRootRole = ButtonBehavior,
defaultRootRole = undefined,
accessibilityOverride = ButtonBehavior,
overriddenRootRole = 'button',
partSelector = '',
} = options

test('gets default accessibility when no override used', () => {
const rendered = getTestingRenderedComponent(Component, <Component {...requiredProps} />)
const role = getProp(rendered, 'role', partSelector)
const role = getRenderedAttribute(rendered, 'role', partSelector)
expect(role).toBe(defaultRootRole)
})

Expand All @@ -41,7 +41,7 @@ export default (Component, options: any = {}) => {
Component,
<Component {...requiredProps} accessibility={DefaultBehavior} />,
)
const role = getProp(rendered, 'role', partSelector)
const role = getRenderedAttribute(rendered, 'role', partSelector)
expect(role).toBeFalsy()
})

Expand All @@ -52,7 +52,7 @@ export default (Component, options: any = {}) => {
Component,
<Component {...requiredProps} accessibility={accessibilityOverride} />,
)
const role = getProp(rendered, 'role', partSelector)
const role = getRenderedAttribute(rendered, 'role', partSelector)
expect(role).toBe(overriddenRootRole)
})

Expand All @@ -62,7 +62,7 @@ export default (Component, options: any = {}) => {
Component,
<Component {...requiredProps} role={testRole} />,
)
const role = getProp(rendered, 'role', partSelector)
const role = getRenderedAttribute(rendered, 'role', partSelector)
expect(role).toBe(testRole)
})

Expand All @@ -72,7 +72,7 @@ export default (Component, options: any = {}) => {
Component,
<Component {...requiredProps} accessibility={accessibilityOverride} role={testRole} />,
)
const role = getProp(rendered, 'role', partSelector)
const role = getRenderedAttribute(rendered, 'role', partSelector)
expect(role).toBe(testRole)
})
}
Expand Down
3 changes: 2 additions & 1 deletion test/specs/commonTests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './implementsClassNameProps'
export { default as implementsCreateMethod } from './implementsCreateMethod'
export { default as implementsShorthandProp } from './implementsShorthandProp'

export { default as handlesAccessibility } from './handlesAccessibility'
export { default as handlesAccessibility, getRenderedAttribute } from './handlesAccessibility'

export { default as isConformant } from './isConformant'
export { default as rendersChildren } from './rendersChildren'
Loading