diff --git a/src/MenuItem.jsx b/src/MenuItem.jsx index 19e483a6..3a19feb7 100644 --- a/src/MenuItem.jsx +++ b/src/MenuItem.jsx @@ -11,6 +11,7 @@ import { noop, menuAllProps } from './util'; export class MenuItem extends React.Component { static propTypes = { + attribute: PropTypes.object, rootPrefixCls: PropTypes.string, eventKey: PropTypes.string, active: PropTypes.bool, @@ -145,14 +146,27 @@ export class MenuItem extends React.Component { [this.getSelectedClassName()]: props.isSelected, [this.getDisabledClassName()]: props.disabled, }); - const attrs = { + let attrs = { ...props.attribute, title: props.title, className, + // set to menuitem by default role: 'menuitem', - 'aria-selected': props.isSelected, 'aria-disabled': props.disabled, }; + + if (props.role === 'option') { + // overwrite to option + attrs = { + ...attrs, + role: 'option', + 'aria-selected': props.isSelected, + }; + } else if (props.role === null) { + // sometimes we want to specify role inside
  • element + //
  • Link
  • would be a good example + delete attrs.role; + } let mouseEvent = {}; if (!props.disabled) { mouseEvent = { @@ -181,11 +195,11 @@ export class MenuItem extends React.Component { } } +MenuItem.isMenuItem = true; + const connected = connect(({ activeKey, selectedKeys }, { eventKey, subMenuKey }) => ({ active: activeKey[subMenuKey] === eventKey, isSelected: selectedKeys.indexOf(eventKey) !== -1, }))(MenuItem); -connected.isMenuItem = true; - export default connected; diff --git a/src/SubMenu.jsx b/src/SubMenu.jsx index 951fe578..d1e81b06 100644 --- a/src/SubMenu.jsx +++ b/src/SubMenu.jsx @@ -399,7 +399,7 @@ export class SubMenu extends React.Component { component="" transitionAppear={transitionAppear} > - {children} + {children} ); } @@ -448,6 +448,17 @@ export class SubMenu extends React.Component { if (isInlineMode) { style.paddingLeft = props.inlineIndent * props.level; } + + let ariaOwns = {}; + // only set aria-owns when menu is open + // otherwise it would be an invalid aria-owns value + // since corresponding node cannot be found + if (this.props.isOpen) { + ariaOwns = { + 'aria-owns': this._menuId, + }; + } + const title = (
    @@ -479,7 +490,7 @@ export class SubMenu extends React.Component { } = props; menuAllProps.forEach(key => delete props[key]); return ( -
  • +
  • {isInlineMode && title} {isInlineMode && children} {!isInlineMode && ( diff --git a/src/SubPopupMenu.js b/src/SubPopupMenu.js index cd3c71f1..0fec13ab 100644 --- a/src/SubPopupMenu.js +++ b/src/SubPopupMenu.js @@ -316,8 +316,8 @@ export class SubPopupMenu extends React.Component { ); const domProps = { className, - role: 'menu', - 'aria-activedescendant': '', + // role could be 'select' and by default set to menu + role: props.role || 'menu', }; if (props.id) { domProps.id = props.id; diff --git a/tests/Menu.spec.js b/tests/Menu.spec.js index 764282cb..03f6dfbf 100644 --- a/tests/Menu.spec.js +++ b/tests/Menu.spec.js @@ -39,6 +39,27 @@ describe('Menu', () => { }); }); + describe('render role listbox', () => { + function createMenu() { + return ( + + 1 + 2 + 3 + + ); + } + + it(`renders menu correctly`, () => { + const wrapper = render(createMenu()); + expect(renderToJson(wrapper)).toMatchSnapshot(); + }); + }); + it('set activeKey', () => { const wrapper = mount( diff --git a/tests/MenuItem.spec.js b/tests/MenuItem.spec.js index 1e65bc5c..a66e643c 100644 --- a/tests/MenuItem.spec.js +++ b/tests/MenuItem.spec.js @@ -112,4 +112,18 @@ describe('MenuItem', () => { expect(onClick).toHaveBeenCalledTimes(3); }); }); + + describe('overwrite default role', () => { + it('should set empty role', () => { + const wrapper = shallow(test); + + expect(wrapper.render()).toMatchSnapshot(); + }); + + it('should set specific role', () => { + const wrapper = shallow(test); + + expect(wrapper.render()).toMatchSnapshot(); + }); + }); }); diff --git a/tests/__snapshots__/Menu.spec.js.snap b/tests/__snapshots__/Menu.spec.js.snap index 241f13d0..1fe60a69 100644 --- a/tests/__snapshots__/Menu.spec.js.snap +++ b/tests/__snapshots__/Menu.spec.js.snap @@ -2,7 +2,6 @@ exports[`Menu render renders horizontal menu correctly 1`] = `
  • `; + +exports[`Menu render role listbox renders menu correctly 1`] = ` + +`; diff --git a/tests/__snapshots__/MenuItem.spec.js.snap b/tests/__snapshots__/MenuItem.spec.js.snap index 3fb01614..86edeebe 100644 --- a/tests/__snapshots__/MenuItem.spec.js.snap +++ b/tests/__snapshots__/MenuItem.spec.js.snap @@ -1,14 +1,29 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`MenuItem overwrite default role should set empty role 1`] = ` +
  • + test +
  • +`; + +exports[`MenuItem overwrite default role should set specific role 1`] = ` +
  • + test +
  • +`; + exports[`MenuItem rest props can render all props to sub component 1`] = `