diff --git a/src/App.js b/src/App.js index af12737042..67fb8f9a0e 100644 --- a/src/App.js +++ b/src/App.js @@ -229,6 +229,7 @@ class AppMenu extends Component { ● TabMenu ● Breadcrumb ● TieredMenu + ● Menubarssss this.openMenu(event, 7)} className={classNames({ 'active-menuitem': this.state.activeMenu === 7 })}> diff --git a/src/components/menu/MenuItem.js b/src/components/menu/MenuItem.js index 87256d5433..6cd537bae1 100644 --- a/src/components/menu/MenuItem.js +++ b/src/components/menu/MenuItem.js @@ -7,14 +7,16 @@ export class MenuItem extends Component{ index:null, items:null, menu:null, - parentMenu:null + parentMenu:null, + root:false, }; static propTypes = { index:PropTypes.number, items:PropTypes.any, menu:PropTypes.any, - parentMenu:PropTypes.string + parentMenu:PropTypes.string, + root:PropTypes.bool }; constructor(props) { @@ -25,14 +27,16 @@ export class MenuItem extends Component{ } render() { - var styleClass=classNames('ui-menuitem-link ui-corner-all',{'ui-state-disabled':this.item.disabled}) - var iconClass=classNames('ui-menuitem-icon fa fa-fw',this.item.icon?this.item.icon:null) + var styleClass=classNames('ui-menuitem-link ui-corner-all',{'ui-state-disabled':this.item.disabled}); + var iconClass=classNames('ui-menuitem-icon fa fa-fw',this.item.icon?this.item.icon:null); + var rootClass=classNames('ui-submenu-icon fa fa-fw',{' fa-caret-down':this.props.root},{' fa-caret-right':!this.props.root}) if(this.item.url){ return ( this.menu.itemClick(event,this.item)}> {this.item.items && this.props.parentMenu==='TieredMenu' && } {this.item.icon && } {this.item.label} + {this.item.items && this.props.parentMenu==='Menubar' && } ); } @@ -42,6 +46,7 @@ export class MenuItem extends Component{ {this.item.items && this.props.parentMenu==='TieredMenu' && } {this.item.icon && } {this.item.label} + {this.item.items && this.props.parentMenu==='Menubar' && } ); } diff --git a/src/components/menubar/Menubar.js b/src/components/menubar/Menubar.js new file mode 100644 index 0000000000..2bf907d101 --- /dev/null +++ b/src/components/menubar/Menubar.js @@ -0,0 +1,34 @@ +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import {NestedMenu} from "../nestedmenu/NestedMenu"; + +export class Menubar extends Component{ + static defaultProps = { + model:null, + style:null, + styleClass:null, + }; + + static propTypes = { + model:PropTypes.array, + style:PropTypes.object, + styleClass:PropTypes.string, + }; + + constructor(props) { + super(props); + this.state = {}; + } + render() { + + var styleClass=classNames('ui-menubar ui-menu ui-widget ui-widget-content ui-corner-all ui-helper-clearfix', this.props.styleClass); + var ulClass=classNames('ui-menu-list ui-menubar-root-list ui-helper-clearfix'); + + return( +
+ {this.props.children} +
+ ); + } +} diff --git a/src/components/nestedmenu/NestedMenu.js b/src/components/nestedmenu/NestedMenu.js new file mode 100644 index 0000000000..4d258bd68f --- /dev/null +++ b/src/components/nestedmenu/NestedMenu.js @@ -0,0 +1,41 @@ +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import {NestedMenuItem} from './NestedMenuItem' + +export class NestedMenu extends Component{ + static defaultProps = { + styleClass:null, + style:null, + items:null, + parentMenu:null, + root:null, + index:null + }; + + static propTypes = { + styleClass:PropTypes.string, + style:PropTypes.object, + items:PropTypes.any, + parentMenu:PropTypes.string, + root:PropTypes.bool, + index:PropTypes.any + }; + + constructor(props) { + super(props); + this.state = {}; + } + render() { + return( + + ) + } +} diff --git a/src/components/nestedmenu/NestedMenuItem.css b/src/components/nestedmenu/NestedMenuItem.css new file mode 100644 index 0000000000..8bc55bfdab --- /dev/null +++ b/src/components/nestedmenu/NestedMenuItem.css @@ -0,0 +1,4 @@ +.ui-tieredmenu-item{ + left: 100%; + top:0px; +} \ No newline at end of file diff --git a/src/components/nestedmenu/NestedMenuItem.js b/src/components/nestedmenu/NestedMenuItem.js new file mode 100644 index 0000000000..3d2efa0854 --- /dev/null +++ b/src/components/nestedmenu/NestedMenuItem.js @@ -0,0 +1,87 @@ +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import {MenuItem} from "../menu/MenuItem"; +import DomHandler from '../utils/DomHandler'; +import {NestedMenu} from "./NestedMenu"; + +export class NestedMenuItem extends Component{ + static defaultProps = { + item:null, + menu:null, + parentMenu:null, + root:null, + index:null + }; + + static propTypes = { + item:PropTypes.any, + menu:PropTypes.any, + parentMenu:PropTypes.string, + root:PropTypes.bool, + index:PropTypes.any + }; + + constructor(props) { + super(props); + this.state = {activeItem:null}; + this.onItemMouseLeave=this.onItemMouseLeave.bind(this); + } + onItemMouseEnter(event, menuitem) { + this.setState({activeItem: menuitem}); + this.sublist=event.currentTarget.children[1]; + if(this.sublist){ + this.sublist.style.zIndex = DomHandler.getZindex(); + if(this.props.parentMenu==='TieredMenu' || (this.props.parentMenu==='Menubar' && !this.props.root)) + DomHandler.addClass(this.sublist,'ui-tieredmenu-item'); + this.sublist.style.display='block'; + } + } + onItemMouseLeave(event) { + this.setState({activeItem:null}); + if(this.sublist){ + DomHandler.removeClass(this.sublist,'ui-tieredmenu-item') + this.sublist.style.display='none';} + } + itemClick(event,item){ + if(item.disabled) { + event.preventDefault(); + return; + } + + if(!item.url) { + event.preventDefault(); + } + + if(item.command) { + item.command({ + originalEvent: event, + item: item + }); + } + } + render() { + + + var listClass=classNames('ui-menuitem ui-widget ui-corner-all',{'ui-menu-parent':this.props.item.items}, + {'ui-menuitem-active':this.state.activeItem===this.props.item}); + return( this.props.item.separator? +
  • : +
  • this.onItemMouseEnter(event,this.props.item)} + onMouseLeave={this.onItemMouseLeave} onClick={()=>{ + this.setState({activeItem: null}); + if(this.sublist) + this.sublist.style.display='none'; + }}> + + + + {this.props.item.items? + :null} + +
  • + ) + + } +} \ No newline at end of file diff --git a/src/components/tieredmenu/TieredMenu.js b/src/components/tieredmenu/TieredMenu.js index ca50db48dc..dc0a1f7be6 100644 --- a/src/components/tieredmenu/TieredMenu.js +++ b/src/components/tieredmenu/TieredMenu.js @@ -1,8 +1,8 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import {TieredMenuItem} from "./TieredMenuItem"; import DomHandler from '../utils/DomHandler'; +import {NestedMenu} from "../nestedmenu/NestedMenu"; export class TieredMenu extends Component{ static defaultProps = { @@ -23,24 +23,14 @@ export class TieredMenu extends Component{ super(props); this.state = {}; } - componentDidMount(){ - if(this.props.popup){ - document.body.appendChild(this.container); - this.documentClickListener=document.addEventListener('click',(event)=>{ - if(!this.preventDocumentDefault) { - this.hide(event); - } - this.preventDocumentDefault = false; - }) - } - } toggle(event){ + if(this.documentClickListener) { + this.dropdownClick = true; + } if(this.container.offsetParent) this.hide(event); else this.show(event); - - this.preventDocumentDefault = true; } show(event) { @@ -49,20 +39,46 @@ export class TieredMenu extends Component{ this.container.style.display = 'block'; DomHandler.absolutePosition(this.container, target); DomHandler.fadeIn(this.container, 250); - this.preventDocumentDefault = true; + this.bindDocumentListener(); } hide(event) { if(this.container) this.container.style.display = 'none'; + this.unbindDocumentListener(); + } + bindDocumentListener() { + if(!this.documentClickListener) { + this.documentClickListener = () => { + if(this.dropdownClick) + this.dropdownClick = false; + else + this.hide(); + }; + + document.addEventListener('click', this.documentClickListener); + } } + + unbindDocumentListener() { + if(this.documentClickListener) { + document.removeEventListener('click', this.documentClickListener); + this.documentClickListener = null; + } + } + + componentWillUnmount() { + this.unbindDocumentListener(); + } + render() { - var styleClass=classNames('ui-tieredmenu ui-menu ui-widget ui-widget-content ui-corner-all ui-helper-clearfix', + var divClass=classNames('ui-tieredmenu ui-menu ui-widget ui-widget-content ui-corner-all ui-helper-clearfix', this.props.styleClass,{'ui-menu-dynamic ui-shadow':this.props.popup}); + var ulClass=classNames('ui-menu-list ui-helper-reset'); return( -
    this.container=el}> - +
    this.container=el}> +
    ); } diff --git a/src/components/tieredmenu/TieredMenuItem.js b/src/components/tieredmenu/TieredMenuItem.js deleted file mode 100644 index 1f05dad08c..0000000000 --- a/src/components/tieredmenu/TieredMenuItem.js +++ /dev/null @@ -1,94 +0,0 @@ -import React, {Component} from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import {MenuItem} from "../menu/MenuItem"; -import DomHandler from '../utils/DomHandler'; - -export class TieredMenuItem extends Component{ - static defaultProps = { - index:0, - items:null, - menu:null, - root:false - }; - - static propTypes = { - index:PropTypes.number, - items:PropTypes.any, - menu:PropTypes.any, - root:PropTypes.bool - }; - - constructor(props) { - super(props); - this.state = {activeItem:null}; - this.listClick=this.listClick.bind(this); - this.onItemMouseLeave=this.onItemMouseLeave.bind(this); - } - onItemMouseEnter(event, menuitem) { - this.setState({activeItem: menuitem}); - this.sublist=event.currentTarget.children[1]; - if(this.sublist){ - this.sublist.style.zIndex = DomHandler.getZindex(); - this.sublist.style.top = '0px'; - this.sublist.style.display='block'; - this.sublist.style.left='100%' - } - } - onItemMouseLeave(event) { - this.setState({activeItem:null}); - if(this.sublist) - this.sublist.style.display='none'; - } - itemClick(event,item){ - if(item.disabled) { - event.preventDefault(); - return; - } - - if(!item.url) { - event.preventDefault(); - } - - if(item.command) { - item.command({ - originalEvent: event, - item: item - }); - } - } - listClick(event) { - this.setState({activeItem: null}); - if(this.sublist) - this.sublist.style.display='none'; - } - render() { - - var styleClass=classNames('ui-menu-list',{'ui-helper-reset':this.props.root}, - {'ui-widget-content ui-corner-all ui-helper-clearfix ui-menu-child ui-shadow':!this.props.root}) - var mapElement=this.props.root?this.props.items:this.props.items.items; - var childElement; - - childElement=mapElement && mapElement.map((child,index)=>{ - var listClass=classNames('ui-menuitem ui-widget ui-corner-all',{'ui-menu-parent':child.items}, - {'ui-menuitem-active':this.state.activeItem===child}) - var element=child.separator? -
  • : -
  • this.onItemMouseEnter(event,child)} - onMouseLeave={this.onItemMouseLeave}> - - - - {child.items?:null} - -
  • - return element; - }) - - return( - - ) - } -} diff --git a/src/index.js b/src/index.js index c7dfb4da54..e3b8e256be 100644 --- a/src/index.js +++ b/src/index.js @@ -70,6 +70,7 @@ import {MenuDemo} from './showcase/menu/MenuDemo'; import {TabMenuDemo} from './showcase/tabmenu/TabMenuDemo'; import {BreadcrumbDemo} from './showcase/breadcrumb/BreadcrumbDemo'; import {TieredMenuDemo} from './showcase/tieredmenu/TieredMenuDemo'; +import {MenubarDemo} from './showcase/menubar/MenubarDemo'; import {Router,Route,hashHistory} from 'react-router'; ReactDOM.render( @@ -142,6 +143,7 @@ ReactDOM.render( + diff --git a/src/showcase/menubar/MenubarDemo.js b/src/showcase/menubar/MenubarDemo.js new file mode 100644 index 0000000000..b15129a552 --- /dev/null +++ b/src/showcase/menubar/MenubarDemo.js @@ -0,0 +1,419 @@ +import React, {Component} from 'react'; +import {Link} from 'react-router'; +import {Menubar} from '../../components/menubar/Menubar'; +import {Button} from '../../components/button/Button'; +import {TabView,TabPanel} from '../../components/tabview/TabView'; +import {CodeHighlight} from '../../components/codehighlight/CodeHighlight'; +import {InputText} from "../../components/inputtext/InputText"; + +export class MenubarDemo extends Component { + + constructor() { + super(); + this.state = {}; + } + + render() { + var items=[ { + label: 'File', + icon: 'fa-file-o', + items: [{ + label: 'New', + icon: 'fa-plus', + items: [ + {label: 'Project'}, + {label: 'Other'}, + ] + }, + {label: 'Open'}, + {separator:true}, + {label: 'Quit'} + ] + }, + { + label: 'Edit', + icon: 'fa-edit', + items: [ + {label: 'Undo', icon: 'fa-mail-forward'}, + {label: 'Redo', icon: 'fa-mail-reply'} + ] + }, + { + label: 'Help', + icon: 'fa-question', + items: [ + { + label: 'Contents' + }, + { + label: 'Search', + icon: 'fa-search', + items: [ + { + label: 'Text', + items: [ + { + label: 'Workspace' + } + ] + }, + { + label: 'File' + } + ]} + ] + }, + { + label: 'Actions', + icon: 'fa-gear', + items: [ + { + label: 'Edit', + icon: 'fa-refresh', + items: [ + {label: 'Save', icon: 'fa-save'}, + {label: 'Update', icon: 'fa-save'}, + ] + }, + { + label: 'Other', + icon: 'fa-phone', + items: [ + {label: 'Delete', icon: 'fa-minus'} + ] + } + ] + }, + { + label: 'Quit', icon: 'fa-minus' + }]; + return ( +
    +
    +
    +

    Menubar

    +

    Menubar is an horizontal menu components with support for nested submenus.

    +
    +
    +
    + + +
    + + + +
    + ); + } +} + +class MenubarDoc extends Component { + render() { + return ( +
    + + +

    Import

    + + {` +import {Menubar} from 'primereact/components/menubar/Menubar'; + +`} +

    MenuItem API

    +

    Menubar uses the common menu item api to define its items, visit Menu for details.

    + +

    Getting Started

    +

    Menubar requires nested menuitems as its model.

    + + {` + + +`} + + {` +var items=[ + { + label: 'File', + icon: 'fa-file-o', + items: [{ + label: 'New', + icon: 'fa-plus', + items: [ + {label: 'Project'}, + {label: 'Other'}, + ] + }, + {label: 'Open'}, + {separator:true}, + {label: 'Quit'} + ] + }, + { + label: 'Edit', + icon: 'fa-edit', + items: [ + {label: 'Undo', icon: 'fa-mail-forward'}, + {label: 'Redo', icon: 'fa-mail-reply'} + ] + }, + { + label: 'Help', + icon: 'fa-question', + items: [ + { + label: 'Contents' + }, + { + label: 'Search', + icon: 'fa-search', + items: [ + { + label: 'Text', + items: [ + { + label: 'Workspace' + } + ] + }, + { + label: 'File' + } + ]} + ] + }, + { + label: 'Actions', + icon: 'fa-gear', + items: [ + { + label: 'Edit', + icon: 'fa-refresh', + items: [ + {label: 'Save', icon: 'fa-save'}, + {label: 'Update', icon: 'fa-save'}, + ] + }, + { + label: 'Other', + icon: 'fa-phone', + items: [ + {label: 'Delete', icon: 'fa-minus'} + ] + } + ] + }, + { + label: 'Quit', icon: 'fa-minus' + } +]; + +`} + +

    Custom Content

    +

    Custom content can be placed between Menubar tags.

    + + {` + + +
    + + + +
    + ); + } +} + `} + + + + + ) + } + +} \ No newline at end of file diff --git a/src/showcase/tieredmenu/TieredMenuDemo.js b/src/showcase/tieredmenu/TieredMenuDemo.js index 463a6ec9ee..76f45b2707 100644 --- a/src/showcase/tieredmenu/TieredMenuDemo.js +++ b/src/showcase/tieredmenu/TieredMenuDemo.js @@ -134,7 +134,7 @@ import {TieredMenu} from 'primereact/components/tieredmenu/TieredMenu'; `} -

    Attributes

    aa +

    Attributes