Skip to content

Commit

Permalink
Fixed #702 - Keyboard support for MegaMenu
Browse files Browse the repository at this point in the history
  • Loading branch information
cagataycivici committed Dec 24, 2018
1 parent dcb83a7 commit ab03c4b
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 53 deletions.
2 changes: 0 additions & 2 deletions src/components/megamenu/MegaMenu.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ interface MegaMenuProps {
style?: object;
className?: string;
orientation?: string;
autoZIndex?: boolean;
bazeZIndex?: number;
}

export class MegaMenu extends React.Component<MegaMenuProps,any> {}
157 changes: 118 additions & 39 deletions src/components/megamenu/MegaMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,25 @@ export class MegaMenu extends Component {
model: null,
style: null,
className: null,
orientation: 'horizontal',
autoZIndex: true,
baseZIndex: 0
orientation: 'horizontal'
};

static propTypes = {
id: PropTypes.string,
model: PropTypes.array,
style: PropTypes.object,
className: PropTypes.string,
orientation: PropTypes.string,
autoZIndex: PropTypes.bool,
baseZIndex: PropTypes.number
orientation: PropTypes.string
};

constructor(props) {
super();
super(props);
this.state = {
activeItem: null
}
this.onMenuClick = this.onMenuClick.bind(this);
this.onLeafClick = this.onLeafClick.bind(this);
}

componentDidMount() {
this.bindDocumentClickListener();
}

onMenuClick() {
this.selfClick = true;

if (this.props.autoZIndex) {
this.container.style.zIndex = String(this.props.baseZIndex + DomHandler.generateZIndex());
}
}

onLeafClick(event, item) {
if (item.disabled) {
event.preventDefault();
Expand All @@ -68,33 +51,25 @@ export class MegaMenu extends Component {
});
}

bindDocumentClickListener() {
componentDidMount() {
if (!this.documentClickListener) {
this.documentClickListener = (event) => {
if (!this.selfClick) {
this.setState({
activeItem: null
});
if (this.container && !this.container.contains(event.target)) {
this.setState({activeItem: null});
}

this.selfClick = false;
};

document.addEventListener('click', this.documentClickListener);
}
}

unbindDocumentClickListener() {
if(this.documentClickListener) {
componentWillUnmount() {
if (this.documentClickListener) {
document.removeEventListener('click', this.documentClickListener);
this.documentClickListener = null;
}
}

componentWillUnmount() {
this.unbindDocumentClickListener();
}

onCategoryMouseEnter(event, item) {
if (item.disabled) {
event.preventDefault();
Expand Down Expand Up @@ -126,7 +101,7 @@ export class MegaMenu extends Component {
}

if (item.items) {
if (this.state.activeItem) {
if (this.state.activeItem && this.state.activeItem === item) {
this.setState({
activeItem: null
});
Expand All @@ -141,6 +116,109 @@ export class MegaMenu extends Component {
event.preventDefault();
}

onCategoryKeyDown(event, item) {
let listItem = event.currentTarget.parentElement;

switch(event.which) {
//down
case 40:
if (this.isHorizontal())
this.expandMenu(item);
else
this.navigateToNextItem(listItem);

event.preventDefault();
break;

//up
case 38:
if (this.isVertical())
this.navigateToPrevItem(listItem);
else if (item.items && item === this.state.activeItem)
this.collapseMenu();

event.preventDefault();
break;

//right
case 39:
if (this.isHorizontal())
this.navigateToNextItem(listItem);
else
this.expandMenu(item);

event.preventDefault()
break;

//left
case 37:
if (this.isHorizontal())
this.navigateToPrevItem(listItem);
else if (item.items && item === this.state.activeItem)
this.collapseMenu();

event.preventDefault();
break;

default:
break;
}
}

expandMenu(item) {
if (item.items) {
this.setState({
activeItem: item
});
}
}

collapseMenu(item) {
this.setState({
activeItem: null
});
}

findNextItem(item) {
let nextItem = item.nextElementSibling;

if (nextItem)
return DomHandler.hasClass(nextItem, 'p-disabled') || !DomHandler.hasClass(nextItem, 'p-menuitem') ? this.findNextItem(nextItem) : nextItem;
else
return null;
}

findPrevItem(item) {
let prevItem = item.previousElementSibling;

if (prevItem)
return DomHandler.hasClass(prevItem, 'p-disabled') || !DomHandler.hasClass(prevItem, 'p-menuitem') ? this.findPrevItem(prevItem) : prevItem;
else
return null;
}

navigateToNextItem(listItem) {
var nextItem = this.findNextItem(listItem);
if (nextItem) {
nextItem.children[0].focus();
}
}

navigateToPrevItem(listItem) {
var prevItem = this.findPrevItem(listItem);
if (prevItem) {
prevItem.children[0].focus();
}
}

isHorizontal() {
return this.props.orientation === 'horizontal';
}

isVertical() {
return this.props.orientation === 'vertical';
}

getColumnClassName(category) {
let length = category.items ? category.items.length: 0;
let columnClass;
Expand Down Expand Up @@ -178,7 +256,7 @@ export class MegaMenu extends Component {

renderSubmenuIcon(item) {
if (item.items) {
const className = classNames('p-submenu-icon pi pi-fw', {'pi-caret-down': this.props.orientation === 'horizontal','pi-caret-right': this.props.orientation === 'vertical'});
const className = classNames('p-submenu-icon pi pi-fw', {'pi-caret-down': this.isHorizontal(),'pi-caret-right': this.isVertical()});

return (
<span className={className}></span>
Expand Down Expand Up @@ -285,8 +363,8 @@ export class MegaMenu extends Component {
const panel = this.renderCategoryPanel(category);

return (
<li key={category.label + '_' + index} className={className} style={category.style} onMouseEnter={(event) => this.onCategoryMouseEnter(event, category)}>
<a href={category.url || '#'} className="p-menuitem-link" target={category.target} onClick={(event) => this.onCategoryClick(event, category)}>
<li key={category.label + '_' + index} className={className} style={category.style} onMouseEnter={e => this.onCategoryMouseEnter(e, category)}>
<a href={category.url || '#'} className="p-menuitem-link" target={category.target} onClick={e => this.onCategoryClick(e, category)} onKeyDown={e => this.onCategoryKeyDown(e, category)}>
{icon}
<span className="p-menuitem-text">{category.label}</span>
{submenuIcon}
Expand Down Expand Up @@ -324,12 +402,13 @@ export class MegaMenu extends Component {

render() {
const className = classNames('p-megamenu p-component',
{'p-megamenu-horizontal': this.props.orientation === 'horizontal', 'p-megamenu-vertical': this.props.orientation === 'vertical'}, this.props.className);
{'p-megamenu-horizontal': this.props.orientation === 'horizontal',
'p-megamenu-vertical': this.props.orientation === 'vertical'}, this.props.className);
const menu = this.renderMenu();
const customContent = this.renderCustomContent();

return (
<div id={this.props.id} className={className} style={this.props.style} onClick={this.onMenuClick} ref={el => this.container = el}>
<div ref={el => this.container = el} id={this.props.id} className={className} style={this.props.style}>
<ul className="p-megamenu-root-list">
{menu}
</ul>
Expand Down
12 changes: 0 additions & 12 deletions src/showcase/megamenu/MegaMenuDemo.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,18 +369,6 @@ const items: [
<td>horizontal</td>
<td>Defines the orientation, valid values are horizontal and vertical.</td>
</tr>
<tr>
<td>baseZIndex</td>
<td>number</td>
<td>0</td>
<td>Base zIndex value to use in layering.</td>
</tr>
<tr>
<td>autoZIndex</td>
<td>boolean</td>
<td>true</td>
<td>Whether to automatically manage layering.</td>
</tr>
</tbody>
</table>
</div>
Expand Down

0 comments on commit ab03c4b

Please sign in to comment.