From 90ada34a9dd0d54a6719c83c180d4feca607e174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fatay=20=C3=87ivici?= Date: Thu, 28 Jun 2018 23:26:31 +0300 Subject: [PATCH] Fixed #469 --- public/resources/themes/omega/theme.scss | 2 +- src/components/slidemenu/SlideMenu.css | 90 +++++ src/components/slidemenu/SlideMenu.d.ts | 20 +- src/components/slidemenu/SlideMenu.js | 393 ++++++++++++------- src/resources/style/primereact.css | 2 +- src/showcase/menu/MenuDemo.js | 2 +- src/showcase/slidemenu/SlideMenuDemo.js | 474 ++++++++++++----------- 7 files changed, 594 insertions(+), 389 deletions(-) create mode 100644 src/components/slidemenu/SlideMenu.css diff --git a/public/resources/themes/omega/theme.scss b/public/resources/themes/omega/theme.scss index 1d3c221693..8c0df460b0 100644 --- a/public/resources/themes/omega/theme.scss +++ b/public/resources/themes/omega/theme.scss @@ -451,7 +451,7 @@ $inputGroupTextColor: #222222; .ui-menu, .ui-menubar, .ui-menubar .ui-submenu-list, .ui-tieredmenu, .ui-tieredmenu .ui-submenu-list, -.ui-slidemenu, .ui-slidemenu .ui-submenu-list, +.ui-slidemenu, .ui-contextmenu, .ui-contextmenu .ui-submenu-list, .ui-megamenu { color: #1b1d1f; diff --git a/src/components/slidemenu/SlideMenu.css b/src/components/slidemenu/SlideMenu.css new file mode 100644 index 0000000000..b112ba3fa1 --- /dev/null +++ b/src/components/slidemenu/SlideMenu.css @@ -0,0 +1,90 @@ +.ui-slidemenu { + width: 12.5em; + padding: .25em; +} + +.ui-slidemenu.ui-slidemenu-dynamic { + position: absolute; + display: none; +} + +.ui-slidemenu .ui-menu-separator { + border-width: 1px 0 0 0; +} + +.ui-slidemenu ul { + list-style: none; + margin: 0; + padding: 0; +} + +.ui-slidemenu .ui-slidemenu-rootlist { + position: absolute; + top: 0; +} + +.ui-slidemenu .ui-submenu-list { + display: none; + position: absolute; + top: 0; + width: 12.5em; + padding: .25em; +} + +.ui-slidemenu .ui-menuitem-link { + padding: .25em; + display: block; + position: relative; + text-decoration: none; +} + +.ui-slidemenu .ui-menuitem-icon { + margin-right: .25em; +} + +.ui-slidemenu .ui-menuitem { + position: relative; + margin: .125em 0; +} + +.ui-slidemenu .ui-menuitem-link .ui-submenu-icon { + position: absolute; + margin-top: -.5em; + right: 0; + top: 50%; +} + +.ui-slidemenu .ui-slidemenu-wrapper { + position: relative; +} + +.ui-slidemenu .ui-slidemenu-content { + overflow-x: hidden; + overflow-y: auto; + position: relative; + height: 100%; +} + +.ui-slidemenu-backward { + position: absolute; + bottom: 0; + width: 100%; + padding: 0.25em; + cursor: pointer; +} + +.ui-slidemenu-backward .ui-slidemenu-backward-icon { + vertical-align: middle; +} + +.ui-slidemenu-backward span { + vertical-align: middle; +} + +.ui-slidemenu .ui-menuitem-active { + position: static; +} + +.ui-slidemenu .ui-menuitem-active > .ui-submenu-list { + display: block; +} diff --git a/src/components/slidemenu/SlideMenu.d.ts b/src/components/slidemenu/SlideMenu.d.ts index 9f57cce0c2..07e04d4de4 100644 --- a/src/components/slidemenu/SlideMenu.d.ts +++ b/src/components/slidemenu/SlideMenu.d.ts @@ -1,21 +1,5 @@ import React = require("react"); -interface SlideMenuSubProps { - item?: any; - root?: boolean; - backLabel?: string; - menuWidth?: any; - effectDuration?: any; - easing?: string; - slideMenu?: any; - slideMenuLeft?: string; - onMenuItemClick?(): void; - isAnimating?(): void; - setAnimating?(boolean: boolean): void; -} - -export class SlideMenuSub extends React.Component {} - interface SlideMenuProps { id?: string; model?: Array; @@ -27,6 +11,10 @@ interface SlideMenuProps { backLabel?: string; menuWidth?: number; viewportHeight?: number; + autoZIndex?: boolean; + baseZIndex?: number; + onShow?(e: Event): void; + onHide?(e: Event): void; } export class SlideMenu extends React.Component {} \ No newline at end of file diff --git a/src/components/slidemenu/SlideMenu.js b/src/components/slidemenu/SlideMenu.js index 10b43f85aa..27418a3293 100644 --- a/src/components/slidemenu/SlideMenu.js +++ b/src/components/slidemenu/SlideMenu.js @@ -1,122 +1,162 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import ReactDOM from 'react-dom'; import DomHandler from '../utils/DomHandler'; export class SlideMenuSub extends Component { + static defaultProps = { - item: null, - root: false, - backLabel: 'Back', - menuWidth: null, - effectDuration: null, + model: null, + level: 0, easing: 'ease-out', - slideMenu: null, - slideMenuLeft: null, - onMenuItemClick: null, - isAnimating: null, - setAnimating: null + effectDuration: 250, + menuWidth: 190, + parentActive: false, + onForward: null } static propsTypes = { - item: PropTypes.any, - root: PropTypes.bool, - backLabel: PropTypes.string, - menuWidth: PropTypes.any, - effectDuration: PropTypes.any, + model: PropTypes.any, + level: PropTypes.number, easing: PropTypes.string, - slideMenu: PropTypes.any, - slideMenuLeft: PropTypes.string, - onMenuItemClick: PropTypes.func, - isAnimating: PropTypes.func, - setAnimating: PropTypes.func + effectDuration: PropTypes.number, + menuWidth: PropTypes.number, + parentActive: PropTypes.bool, + onForward: PropTypes.func } constructor(props) { super(props); - this.state = {activeItemIndex: null}; + this.state = { + activeItem: null + }; } - - itemClick(event, item, index) { - if(item.disabled) { + onItemClick(event, item) { + if (item.disabled) { event.preventDefault(); return; } - - if(!item.url) { + + if (!item.url) { event.preventDefault(); } - - if(item.command) { + + if (item.command) { item.command({ originalEvent: event, item: item }); } - if(item.items && !this.props.isAnimating()) { - this.props.onMenuItemClick(); - - this.setState({activeItemIndex: index}); - this.props.setAnimating(true); - setTimeout(() => this.props.setAnimating(false), this.props.effectDuration); + if (item.items) { + this.setState({ + activeItem: item + }); + this.props.onForward(); } } - render() { - var menuListClass = classNames('ui-menu-list', { - 'ui-helper-reset ui-menu-rootlist': this.props.root, - 'ui-widget-content ui-corner-all ui-helper-clearfix ui-menu-child': !this.props.root - }), - menuListStyle = { - 'width': this.props.menuWidth, - 'left': this.props.root ? this.props.slideMenuLeft : this.props.menuWidth, - 'transitionProperty': this.props.root ? 'left' : 'none', - 'transitionDuration': this.props.effectDuration + 'ms', - 'transitionTimingFunction': this.props.easing - }; + renderSeparator(index) { + return ( +
  • + ); + } + + renderIcon(item) { + const className = classNames('ui-menuitem-icon', item.icon); + if (item.icon) { + return ( + + ); + } + else { + return null; + } + } - var menuMap = this.props.root ? this.props.item : this.props.item.items; + renderSubmenuIcon(item) { + if (item.items) { + return ( + + ); + } + else { + return null; + } + } + + renderSubmenu(item) { + if(item.items) { + return ( + + ); + } + else { + return null; + } + } + + renderMenuitem(item, index) { + const className = classNames('ui-menuitem ui-widget ui-corner-all', {'ui-menuitem-active': this.state.activeItem === item}, item.className); + const icon = this.renderIcon(item); + const submenuIcon = this.renderSubmenuIcon(item); + const submenu = this.renderSubmenu(item); return ( -
      - { - menuMap && menuMap.map((child, index) => { - if(child.separator) { - return
    • ; - } - else { - var menuitemClass = classNames('ui-menuitem ui-widget ui-corner-all', { - 'ui-menu-parent': child.items, - 'ui-slidemenuitem-active': index===this.state.activeItemIndex - }), - menuLinkClass = classNames('ui-menuitem-link ui-corner-all', { - 'ui-menuitem-link-parent':child.items, - 'ui-state-disabled':child.disabled - }), - menuiconClass = classNames('ui-menuitem-icon', child.icon); - - return ( -
    • - this.itemClick(e, child, index)}> - {child.items && } - {child.icon && } - {child.label} - - {child.items && } -
    • - ); - } - }) - } -
    +
  • + this.onItemClick(event, item, index)}> + {icon} + {item.label} + {submenuIcon} + + {submenu} +
  • ); } + + renderItem(item, index) { + if (item.separator) + return this.renderSeparator(index); + else + return this.renderMenuitem(item, index); + } + + renderItems() { + if (this.props.model) { + return ( + this.props.model.map((item, index) => { + return this.renderItem(item, index); + }) + ); + } + else { + return null; + } + } + + render() { + const className = classNames({'ui-slidemenu-rootlist': this.props.root, 'ui-submenu-list': !this.props.root, 'ui-active-submenu': this.props.parentActive}); + const style = { + width: this.props.menuWidth + 'px', + left: this.props.root ? (-1 * this.props.level * this.props.menuWidth) + 'px' : this.props.menuWidth + 'px', + transitionProperty: this.props.root ? 'left' : 'none', + transitionDuration: this.props.effectDuration + 'ms', + transitionTimingFunction: this.props.easing + }; + const items = this.renderItems(); + + return ( +
      + {items} +
    + ); + } } export class SlideMenu extends Component { + static defaultProps = { id: null, model: null, @@ -127,7 +167,11 @@ export class SlideMenu extends Component { effectDuration: 250, backLabel: 'Back', menuWidth: 190, - viewportHeight: 175 + viewportHeight: 175, + autoZIndex: true, + baseZIndex: 0, + onShow: null, + onHide: null } static propsTypes = { @@ -140,106 +184,161 @@ export class SlideMenu extends Component { effectDuration: PropTypes.number, backLabel: PropTypes.string, menuWidth: PropTypes.number, - viewportHeight: PropTypes.number + viewportHeight: PropTypes.number, + autoZIndex: PropTypes.bool, + baseZIndex: PropTypes.number, + onShow: PropTypes.func, + onHide: PropTypes.func } constructor(props) { super(props); - this.left = 0; - this.animating = false; - this.onClick = this.onClick.bind(this); - this.goBack = this.goBack.bind(this); - this.onMenuItemClick = this.onMenuItemClick.bind(this); - this.isAnimating = this.isAnimating.bind(this); - this.setAnimating = this.setAnimating.bind(this); + this.state = { + level: 0 + }; + this.onMenuClick = this.onMenuClick.bind(this); + this.navigateBack = this.navigateBack.bind(this); + this.navigateForward = this.navigateForward.bind(this); } - onMenuItemClick() { - this.left -= this.props.menuWidth; - this.rootSlideMenuSub.style.left = this.left + 'px'; - this.updateBackward(); + onMenuClick(event) { + this.selfClick = true; } - toggle(event) { - if(this.container.offsetParent) - this.hide(); - else - this.show(event); + navigateForward() { + this.setState({ + level: this.state.level + 1 + }); } - - show(event) { - this.preventDocumentDefault = true; - this.container.style.display = 'block'; - DomHandler.absolutePosition(this.container, event.target); - DomHandler.fadeIn(this.container, 250); + + navigateBack() { + this.setState({ + level: this.state.level - 1 + }); } - - hide() { - this.container.style.display = 'none'; + + renderBackward() { + const className = classNames('ui-slidemenu-backward ui-widget-header ui-corner-all', {'ui-helper-hidden': this.state.level === 0}); + + return ( +
    this.backward = el} className={className} onClick={this.navigateBack}> + + {this.props.backLabel} +
    + ); } - - onClick(event) { - this.preventDocumentDefault = true; + + componentDidMount() { + if (this.props.popup) { + this.bindDocumentClickListener(); + } } - - goBack() { - this.left += this.props.menuWidth; - this.rootSlideMenuSub.style.left = this.left + 'px'; - this.updateBackward(); + + toggle(event) { + if (this.props.popup) { + this.selfClick = true; + + if (this.container.offsetParent) + this.hide(event); + else + this.show(event); + } } - updateBackward() { - this.backward.style.display = this.left ? 'block' : 'none'; + show(event) { + this.container.style.display = 'block'; + if (this.props.autoZIndex) { + this.container.style.zIndex = String(this.props.baseZIndex + DomHandler.generateZIndex()); + } + DomHandler.absolutePosition(this.container, event.currentTarget); + DomHandler.fadeIn(this.container, 250); + + this.bindDocumentResizeListener(); + + if (this.props.onShow) { + this.props.onShow(event); + } } - isAnimating() { - return this.animating; + hide(event) { + if (this.container) { + this.container.style.display = 'none'; + } + + if (this.props.onHide) { + this.props.onHide(event); + } + + this.unbindDocumentResizeListener(); } - setAnimating(_animating) { - this.animating = _animating; + bindDocumentClickListener() { + if (!this.documentClickListener) { + this.documentClickListener = (event) => { + if (!this.selfClick && this.container.offsetParent) { + this.hide(event); + } + + this.selfClick = false; + }; + + document.addEventListener('click', this.documentClickListener); + } } - componentDidMount() { - if(this.props.popup) { - this.slideMenuContent.style.height = this.props.viewportHeight - DomHandler.getHiddenElementOuterHeight(this.backward) + 'px'; + onLeafClick(event) { + this.setState({ + resetMenu: true + }); + + event.stopPropagation(); + } - this.documentClickListener = () => { - if(!this.preventDocumentDefault) { - this.hide(); + bindDocumentResizeListener() { + if (!this.documentResizeListener) { + this.documentResizeListener = (event) => { + if(this.container.offsetParent) { + this.hide(event); } - this.preventDocumentDefault = false; - } + }; - document.addEventListener('click', this.documentClickListener); - } - else { - this.slideMenuContent.style.height = this.props.viewportHeight + 'px'; + window.addEventListener('resize', this.documentResizeListener); } } - componentWillUnmount() { - if (this.documentClickListener) { + unbindDocumentClickListener() { + if(this.documentClickListener) { document.removeEventListener('click', this.documentClickListener); + this.documentClickListener = null; } } + + unbindDocumentResizeListener() { + if(this.documentResizeListener) { + window.removeEventListener('resize', this.documentResizeListener); + this.documentResizeListener = null; + } + } + + componentWillUnmount() { + this.unbindDocumentClickListener(); + this.unbindDocumentResizeListener(); + } render() { - var menuClass = classNames('ui-menu ui-slidemenu ui-widget ui-widget-content ui-corner-all', this.props.className, { - 'ui-menu-dynamic ui-shadow': this.props.popup - }); + const className = classNames('ui-slidemenu ui-widget ui-widget-content ui-corner-all', {'ui-slidemenu-dynamic ui-shadow': this.props.popup}); + const backward = this.renderBackward(); + return ( -
    this.container = el} className={menuClass} style={this.props.style} onClick={this.onClick}> -
    -
    this.slideMenuContent = el} className="ui-slidemenu-content"> - this.rootSlideMenuSub = ReactDOM.findDOMNode(el)} onMenuItemClick={this.onMenuItemClick} item={this.props.model} slideMenuLeft={0} root={true} menuWidth={this.props.menuWidth} - effectDuration={this.props.effectDuration} easing={this.props.easing} isAnimating={this.isAnimating} setAnimating={this.setAnimating}> -
    -
    this.backward = el} className="ui-slidemenu-backward ui-widget-header ui-corner-all" style={{'display': this.left ? 'block' : 'none'}} onClick={this.goBack}> - {this.props.backLabel} +
    this.container = el} onClick={this.onMenuClick}> +
    +
    this.slideMenuContent = el}> +
    -
    + {backward} +
    - ) + ); } } \ No newline at end of file diff --git a/src/resources/style/primereact.css b/src/resources/style/primereact.css index 2d74ed26f8..54ac0ceb2d 100644 --- a/src/resources/style/primereact.css +++ b/src/resources/style/primereact.css @@ -48,7 +48,7 @@ @import '../../components/scrollpanel/ScrollPanel.css'; @import '../../components/selectbutton/SelectButton.css'; @import '../../components/sidebar/Sidebar.css'; -/*@import '../../components/slidemenu/SlideMenu.css';*/ +@import '../../components/slidemenu/SlideMenu.css'; @import '../../components/slider/Slider.css'; @import '../../components/spinner/Spinner.css'; @import '../../components/splitbutton/SplitButton.css'; diff --git a/src/showcase/menu/MenuDemo.js b/src/showcase/menu/MenuDemo.js index 0788e49d55..b5becaefc7 100644 --- a/src/showcase/menu/MenuDemo.js +++ b/src/showcase/menu/MenuDemo.js @@ -77,7 +77,7 @@ import {Menu} from 'primereact/menu';

    Menu requires a collection of menuitems as its model.

    {` - + `} diff --git a/src/showcase/slidemenu/SlideMenuDemo.js b/src/showcase/slidemenu/SlideMenuDemo.js index f9fe2ed48e..80444e9aee 100644 --- a/src/showcase/slidemenu/SlideMenuDemo.js +++ b/src/showcase/slidemenu/SlideMenuDemo.js @@ -9,107 +9,103 @@ export class SlideMenuDemo extends Component { constructor() { super(); - this.onButtonClick = this.onButtonClick.bind(this); - } - - onButtonClick(e) { - this.menu.toggle(e); + this.state = { + items: [ + { + label: 'File', + icon: 'fa fa-fw fa-file-o', + items: [{ + label: 'New', + icon: 'fa fa-fw fa-plus', + items: [ + {label: 'Project'}, + {label: 'Other'}, + ] + }, + {label: 'Open'}, + {separator: true}, + {label: 'Quit'} + ] + }, + { + label: 'Edit', + icon: 'fa fa-fw fa-edit', + items: [ + {label: 'Undo', icon: 'fa fa-fw fa-mail-forward'}, + {label: 'Redo', icon: 'fa fa-fw fa-mail-reply'} + ] + }, + { + label: 'Help', + icon: 'fa fa-fw fa-question', + items: [ + { + label: 'Contents' + }, + { + label: 'Search', + icon: 'fa fa-fw fa-search', + items: [ + { + label: 'Text', + items: [ + { + label: 'Workspace' + } + ] + }, + { + label: 'File' + } + ]} + ] + }, + { + label: 'Actions', + icon: 'fa fa-fw fa-gear', + items: [ + { + label: 'Edit', + icon: 'fa fa-fw fa-refresh', + items: [ + {label: 'Save', icon: 'fa fa-fw fa-save'}, + {label: 'Update', icon: 'fa fa-fw fa-save'}, + ] + }, + { + label: 'Other', + icon: 'fa fa-fw fa-phone', + items: [ + {label: 'Delete', icon: 'fa fa-fw fa-minus'} + ] + } + ] + }, + {separator: true}, + { + label: 'Quit', icon: 'fa fa-fw fa-minus' + } + ] + } } render() { - this.items = [ - { - label: 'File', - icon: 'fa fa-fw fa-file-o', - items: [{ - label: 'New', - icon: 'fa fa-fw fa-plus', - items: [ - {label: 'Project'}, - {label: 'Other'}, - ] - }, - {label: 'Open'}, - {separator: true}, - {label: 'Quit'} - ] - }, - { - label: 'Edit', - icon: 'fa fa-fw fa-edit', - items: [ - {label: 'Undo', icon: 'fa fa-fw fa-mail-forward'}, - {label: 'Redo', icon: 'fa fa-fw fa-mail-reply'} - ] - }, - { - label: 'Help', - icon: 'fa fa-fw fa-question', - items: [ - { - label: 'Contents' - }, - { - label: 'Search', - icon: 'fa fa-fw fa-search', - items: [ - { - label: 'Text', - items: [ - { - label: 'Workspace' - } - ] - }, - { - label: 'File' - } - ]} - ] - }, - { - label: 'Actions', - icon: 'fa fa-fw fa-gear', - items: [ - { - label: 'Edit', - icon: 'fa fa-fw fa-refresh', - items: [ - {label: 'Save', icon: 'fa fa-fw fa-save'}, - {label: 'Update', icon: 'fa fa-fw fa-save'}, - ] - }, - { - label: 'Other', - icon: 'fa fa-fw fa-phone', - items: [ - {label: 'Delete', icon: 'fa fa-fw fa-minus'} - ] - } - ] - }, - {separator: true}, - { - label: 'Quit', icon: 'fa fa-fw fa-minus' - } - ]; - return (

    Slide Menu

    -

    SlideMenu displays submenus with slide animation.

    +

    SlideMenu displays submenus with a slide animation.

    Basic

    - +

    Popup

    - this.menu = el} model={this.items} popup={true}> - + this.menu = el} model={this.state.items} popup={true}> +
    @@ -138,74 +134,69 @@ import {SlideMenu} from 'primereact/slidemenu';

    MenuItem API

    -

    SlideMenu uses the common menu item api to define its items, visit MenuModel for details.

    +

    Menu uses the common menumodel api to define its items, visit MenuModel API for details.

    Getting Started

    -

    SlideMenu requires nested menuitems as its model.

    - - -{` - - -`} - +

    Menu requires a collection of menuitems as its model.

    {` -export class SlideMenuDemo extends Component { - - render() { - this.items = [ - { - label: 'File', - icon: 'fa fa-fw fa-file-o', - items: [{ - label: 'New', - icon: 'fa fa-fw fa-plus', - items: [ - {label: 'Project'}, - {label: 'Other'}, - ] - }, - {label: 'Open'}, - {separator: true}, - {label: 'Quit'} - ] - }, - { - label: 'Edit', - icon: 'fa fa-fw fa-edit', +var items = [ + { + label: 'File', + icon: 'fa fa-fw fa-file-o', + items: [{ + label: 'New', + icon: 'fa fa-fw fa-plus', items: [ - {label: 'Undo', icon: 'fa fa-fw fa-mail-forward'}, - {label: 'Redo', icon: 'fa fa-fw fa-mail-reply'} + {label: 'Project'}, + {label: 'Other'}, ] - } - ]; - - return () + }, + {label: 'Open'}, + {separator: true}, + {label: 'Quit'} + ] + }, + { + label: 'Edit', + icon: 'fa fa-fw fa-edit', + items: [ + {label: 'Undo', icon: 'fa fa-fw fa-mail-forward'}, + {label: 'Redo', icon: 'fa fa-fw fa-mail-reply'} + ] } -} +]; `} + +{` + + +`} + + +

    Popup Mode

    -

    SlideMenu is inline by default, popup mode is also supported by enabling popup property and calling toggle method by passing the event - from the anchor element.

    +

    SlideMenu is inline by default whereas popup mode is supported by enabling popup property and calling toggle method with an event of the target.

    {` - this.menu = el} model={this.items} popup={true}> - + this.menu = el} model={items} popup={true} /> + + `}

    Effects

    -

    The easing function to use is "ease-out" by default and this can be customized using easing property. +

    The easing function to use is "ease-out" by default which can be customized using easing property. See here for possible alternative values.

    + {` - + `} @@ -282,11 +273,23 @@ export class SlideMenuDemo extends Component { 175 Height of the scrollable area, a scrollbar appears if a menu height is longer than this value. + + baseZIndex + number + 0 + Base zIndex value to use in layering. + + + autoZIndex + boolean + true + Whether to automatically manage layering. +
    -

    Methods

    +

    Methods

    @@ -295,26 +298,51 @@ export class SlideMenuDemo extends Component { - + - + - + - +
    Parameters Description
    toggleevent: browser eventevent: Browser event Toggles the visibility of the popup menu.
    showevent: browser eventevent: Browser event Displays the popup menu.
    hide-event: Browser event Hides the popup menu.
    + +

    Events

    +
    + + + + + + + + + + + + + + + + + + + + +
    NameParametersDescription
    onShowevent: Browser event Callback to invoke when a popup menu is shown.
    onHideevent: Browser event Callback to invoke when a popup menu is hidden.
    +

    Styling

    Following is the list of structural style classes.

    @@ -378,111 +406,111 @@ export class SlideMenuDemo extends Component { {` +import React, {Component} from 'react'; +import {SlideMenu} from 'primereact/slidemenu'; +import {Button} from 'primereact/button'; + export class SlideMenuDemo extends Component { constructor() { super(); - this.onButtonClick = this.onButtonClick.bind(this); - } - - onButtonClick(e) { - this.menu.toggle(e); + this.state = { + items: [ + { + label: 'File', + icon: 'fa fa-fw fa-file-o', + items: [{ + label: 'New', + icon: 'fa fa-fw fa-plus', + items: [ + {label: 'Project'}, + {label: 'Other'}, + ] + }, + {label: 'Open'}, + {separator: true}, + {label: 'Quit'} + ] + }, + { + label: 'Edit', + icon: 'fa fa-fw fa-edit', + items: [ + {label: 'Undo', icon: 'fa fa-fw fa-mail-forward'}, + {label: 'Redo', icon: 'fa fa-fw fa-mail-reply'} + ] + }, + { + label: 'Help', + icon: 'fa fa-fw fa-question', + items: [ + { + label: 'Contents' + }, + { + label: 'Search', + icon: 'fa fa-fw fa-search', + items: [ + { + label: 'Text', + items: [ + { + label: 'Workspace' + } + ] + }, + { + label: 'File' + } + ]} + ] + }, + { + label: 'Actions', + icon: 'fa fa-fw fa-gear', + items: [ + { + label: 'Edit', + icon: 'fa fa-fw fa-refresh', + items: [ + {label: 'Save', icon: 'fa fa-fw fa-save'}, + {label: 'Update', icon: 'fa fa-fw fa-save'}, + ] + }, + { + label: 'Other', + icon: 'fa fa-fw fa-phone', + items: [ + {label: 'Delete', icon: 'fa fa-fw fa-minus'} + ] + } + ] + }, + {separator: true}, + { + label: 'Quit', icon: 'fa fa-fw fa-minus' + } + ] + } } render() { - this.items = [ - { - label: 'File', - icon: 'fa fa-fw fa-file-o', - items: [{ - label: 'New', - icon: 'fa fa-fw fa-plus', - items: [ - {label: 'Project'}, - {label: 'Other'}, - ] - }, - {label: 'Open'}, - {separator: true}, - {label: 'Quit'} - ] - }, - { - label: 'Edit', - icon: 'fa fa-fw fa-edit', - items: [ - {label: 'Undo', icon: 'fa fa-fw fa-mail-forward'}, - {label: 'Redo', icon: 'fa fa-fw fa-mail-reply'} - ] - }, - { - label: 'Help', - icon: 'fa fa-fw fa-question', - items: [ - { - label: 'Contents' - }, - { - label: 'Search', - icon: 'fa fa-fw fa-search', - items: [ - { - label: 'Text', - items: [ - { - label: 'Workspace' - } - ] - }, - { - label: 'File' - } - ]} - ] - }, - { - label: 'Actions', - icon: 'fa fa-fw fa-gear', - items: [ - { - label: 'Edit', - icon: 'fa fa-fw fa-refresh', - items: [ - {label: 'Save', icon: 'fa fa-fw fa-save'}, - {label: 'Update', icon: 'fa fa-fw fa-save'}, - ] - }, - { - label: 'Other', - icon: 'fa fa-fw fa-phone', - items: [ - {label: 'Delete', icon: 'fa fa-fw fa-minus'} - ] - } - ] - }, - {separator: true}, - { - label: 'Quit', icon: 'fa fa-fw fa-minus' - } - ]; - return (
    -
    +

    Slide Menu

    -

    SlideMenu displays submenus with slide animation.

    +

    SlideMenu displays submenus with a slide animation.

    Basic

    - +

    Popup

    - this.menu = el} model={this.items} popup={true}> - + this.menu = el} model={this.state.items} popup={true}> +
    )