Top
Menu API - API
Menu API
Props (50)
Callback Props (4)
Styling Props (36)
Methods (2)
Object|Object[]|Number
default: {x: 0, y: 0}
Specifies the offset to which the <Menu /> will align itself in relation to the align target specified by alignTo.
It can be an object with values for the x and/or y axis, a number (in this case, this offset will be used for both x and y axis) or an array of objects/numbers that specifies offsets for each alignPosition.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'
import { Flex } from '@zippytech/react-flex'
import Icon from './icons'

const items = [
  { label: 'Refresh', icon: <Icon type="refresh" /> },
  { label: 'Back', disabled: true, icon: <Icon type="back" /> },
  '-',
  { label: 'Save file as', icon: <Icon type="save" />,
    items: [ { label: 'PDF' }, { label: 'HTML' }, { label: 'PNG' }, { label: 'Animated GIF' } ] },
  { label: 'Open' },
  { label: 'Export sheet to', items: [ { label: 'CSV' }, { label: 'Proprietary format' } ] }
];

const style = { minHeight: 400, position: 'relative' }
const alignToStyle = { width: 200, height: 150, border: '1px dashed red'}

const dataSource = [
  { id: 'br-tl', label: 'Bottom-right to top-left' },
  { id: 'bc-tc', label: 'Bottom-center to top-center' },
  { id: 'bl-tr', label: 'Bottom-left to top-right' },
  { id: 'lc-rc', label: 'Left-center to right-center' },
  { id: 'tl-br', label: 'Top-left to bottom-right' },
  { id: 'tc-bc', label: 'Top-center to bottom-center' },
  { id: 'tr-bl', label: 'Top-right to bottom-left' },
  { id: 'rc-lc', label: 'Right-center to left-center' },
  { id: 'lc-lc', label: 'Left-center to left-center' },
  { id: 'c-c', label: 'Center to Center' },
  { id: 'tr-tl', label: 'Top-right to top-left' },
  { id: 't-t', label: 'Top to top - only align on vertical axis' },
  { id: 'l-l', label: 'Left to left - only align on horizontal axis' },
  { id: 'rc-rc', label: 'Right-center to right-center' },
  { id: 'c-tl', label: 'Center to top-left' }
].map((value) => {
  return {
    id: value.id,
    label: value.label
  }
})

const offsets = [
  { id: -50, label: '-50' },
  { id: -20, label: '-20' },
  { id: 0, label: '0' },
  { id: 20, label: '20' },
  { id: 50, label: '50' },
]

class App extends React.Component {
  constructor(props) { super(props); this.state = { alignPosition: 'tl-br', offset: 0 } }
  render() {
    return <Flex justifyContent="center" style={style}>
      <Flex justifyContent="center" style={alignToStyle}><span>This is the <b>alignTo</b> target</span></Flex>
      {this.renderMenu()}
      <div style={{ position: 'absolute', top: 10, left: 10 }}>Align position:</div>
      <ComboBox
        style={{ width: 250, position: 'absolute', top: 30, left: 10 }}
        collapseOnSelect
        changeValueOnNavigation
        expandOnClick
        dataSource={dataSource}
        value={this.state.alignPosition}
        onChange={(value) => this.setState({ alignPosition: value })}
      />
      <div style={{ position: 'absolute', top: 70, left: 10 }}>Offset:</div>
      <ComboBox
        style={{ width: 100, position: 'absolute', top: 90, left: 10 }}
        collapseOnSelect
        changeValueOnNavigation
        expandOnClick
        dataSource={offsets}
        value={this.state.offset}
        onChange={(value) => this.setState({ offset: value })}
      />
    </Flex>
  }
  setOffset(event) { this.setState({ offset: event.target.value * 1 }) }
  realign(event) { this.setState({ alignPosition: event.target.value }) }
  renderMenu() {
    return <Menu
      constrainTo={false}
      alignTo={(node) => node.parentNode.firstChild }
      alignOffset={this.state.offset}
      alignPositions={[this.state.alignPosition]}
      items={items} style={{ position: 'absolute', opacity: 0.85, zIndex: 1 }}
    />
  }
}
export default () => <App />
Array[String]
default: ["tl-tr","bl-br","tr-tl","br-bl"]
Determines the position of the <Menu /> relative to the alignTo target.
You need to pass in an array, since the <Menu /> might not fit the constrainTo region for some alignments, therefore other alignments are tried in order, until one that fulfills the constrain is found and applied.
If there is no constrain specified, the first align position will be used
The align values are strings with two positions, delimited by -. The first position is the position of the <Menu />, and the second is the position of the alignTo target.
For example, "tr-bl" tells the <Menu />: align the top-right point (corner) of the menu to (overlap) the bottom-left point of the align target.
Valid values for align positions are any combination of the following:
  • tl - top-left
  • tc - top-center
  • tr - top-right
  • bl - bottom-left
  • bc - bottom-center
  • br - bottom-right
  • t - top - only align the top (alignment only on vertical axis)
  • r - right - only align the right (alignment only on horizontal axis)
  • b - bottom - only align the bottom (alignment only on vertical axis)
  • l - left - only align the left (alignment only on horizontal axis)
  • rc - right-center
  • lc - left-center
  • c - center - center alignment on both horizontal and vertical axis
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'
import { Flex } from '@zippytech/react-flex'
import Icon from './icons'

const items = [
  { label: 'Refresh', icon: <Icon type="refresh" /> },
  { label: 'Back', disabled: true, icon: <Icon type="back" /> },
  '-',
  { label: 'Save file as', icon: <Icon type="save" />,
    items: [ { label: 'PDF' }, { label: 'HTML' }, { label: 'PNG' }, { label: 'Animated GIF' } ] },
  { label: 'Open' },
  { label: 'Export sheet to', items: [ { label: 'CSV' }, { label: 'Proprietary format' } ] }
];

const style = { minHeight: 400, position: 'relative' }
const alignToStyle = { width: 200, height: 150, border: '1px dashed red'}

const dataSource = [
  { id: 'br-tl', label: 'Bottom-right to top-left' },
  { id: 'bc-tc', label: 'Bottom-center to top-center' },
  { id: 'bl-tr', label: 'Bottom-left to top-right' },
  { id: 'lc-rc', label: 'Left-center to right-center' },
  { id: 'tl-br', label: 'Top-left to bottom-right' },
  { id: 'tc-bc', label: 'Top-center to bottom-center' },
  { id: 'tr-bl', label: 'Top-right to bottom-left' },
  { id: 'rc-lc', label: 'Right-center to left-center' },
  { id: 'lc-lc', label: 'Left-center to left-center' },
  { id: 'c-c', label: 'Center to Center' },
  { id: 'tr-tl', label: 'Top-right to top-left' },
  { id: 't-t', label: 'Top to top - only align on vertical axis' },
  { id: 'l-l', label: 'Left to left - only align on horizontal axis' },
  { id: 'rc-rc', label: 'Right-center to right-center' },
  { id: 'c-tl', label: 'Center to top-left' }
].map((value) => {
  return {
    id: value.id,
    label: value.label
  }
})

class App extends React.Component {
  constructor(props) { super(props); this.state = { alignPosition: 'tl-br' } }
  render() {
    return <Flex justifyContent="center" style={style}>
      <Flex justifyContent="center" style={alignToStyle}><span>This is the <b>alignTo</b> target</span></Flex>
      {this.renderMenu()}
      <ComboBox
        style={{ width: 250, position: 'absolute', top: 10, left: 10 }}
        collapseOnSelect
        changeValueOnNavigation
        expandOnClick
        dataSource={dataSource}
        value={this.state.alignPosition}
        onChange={(value) => this.setState({ alignPosition: value })}
      />
    </Flex>
  }
  realign(event) { this.setState({ alignPosition: event.target.value }) }
  renderMenu() {
    return <Menu
      constrainTo={false}
      alignTo={(node) => node.parentNode.firstChild }
      alignPositions={[this.state.alignPosition]}
      items={items} style={{ position: 'absolute', opacity: 0.85, zIndex: 1 }}
    />
  }
}
export default () => <App />
String|HTMLElement|Fn(node)
default: undefined
Specifies the align target to use for the <Menu />. The <Menu /> will be aligned to the bounding rect specified by (or computed from) alignTo.
Valid values for are:
  • a point object with top,left - coordinates relative to the browser viewport.
  • a rect object with top,left,bottom,right (or top,left,width,height) which is relative to the browser viewport.
  • a string to be used as query selector - will be passed to document.querySelector. getBoundingClientRect will be called on the resulting HTMLElement.
  • an HTMLElement, in which case, its bounding client rect will be used.
  • A function returning any of the above.
Basically the <Menu /> will need a bounding client rect for the alignTo you are passing and there are multiple input formats being accepted. The point is that the resulting coordinates should be relative to the browser viewport.
Most often you will use alignTo in combination with alignPositions and constrainTo to adjust and/or constrain the alignment.
Below you can find a complete example aligning the <Menu /> in different ways to the alignTo target (the red-bordered rectangle):
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'
import { Flex } from '@zippytech/react-flex'
import Icon from './icons'

const items = [
  { label: 'Refresh', icon: <Icon type="refresh" /> },
  { label: 'Back', disabled: true, icon: <Icon type="back" /> },
  '-',
  { label: 'Save file as', icon: <Icon type="save" />,
    items: [ { label: 'PDF' }, { label: 'HTML' }, { label: 'PNG' }, { label: 'Animated GIF' } ] },
  { label: 'Open' },
  { label: 'Export sheet to', items: [ { label: 'CSV' }, { label: 'Proprietary format' } ] }
];

const style = { minHeight: 400, position: 'relative' }
const alignToStyle = { width: 200, height: 150, border: '1px dashed red'}

const dataSource = [
  { id: 'br-tl', label: 'Bottom-right to top-left' },
  { id: 'bc-tc', label: 'Bottom-center to top-center' },
  { id: 'bl-tr', label: 'Bottom-left to top-right' },
  { id: 'lc-rc', label: 'Left-center to right-center' },
  { id: 'tl-br', label: 'Top-left to bottom-right' },
  { id: 'tc-bc', label: 'Top-center to bottom-center' },
  { id: 'tr-bl', label: 'Top-right to bottom-left' },
  { id: 'rc-lc', label: 'Right-center to left-center' },
  { id: 'lc-lc', label: 'Left-center to left-center' },
  { id: 'c-c', label: 'Center to Center' },
  { id: 'tr-tl', label: 'Top-right to top-left' },
  { id: 't-t', label: 'Top to top - only align on vertical axis' },
  { id: 'l-l', label: 'Left to left - only align on horizontal axis' },
  { id: 'rc-rc', label: 'Right-center to right-center' },
  { id: 'c-tl', label: 'Center to top-left' }
].map((value) => {
  return {
    id: value.id,
    label: value.label
  }
})

class App extends React.Component {
  constructor(props) { super(props); this.state = { alignPosition: 'tl-br' } }
  render() {
    return <Flex justifyContent="center" style={style}>
      <Flex justifyContent="center" style={alignToStyle}><span>This is the <b>alignTo</b> target</span></Flex>
      {this.renderMenu()}
      <ComboBox
        style={{ width: 250, position: 'absolute', top: 10, left: 10 }}
        collapseOnSelect
        changeValueOnNavigation
        expandOnClick
        dataSource={dataSource}
        value={this.state.alignPosition}
        onChange={(value) => this.setState({ alignPosition: value })}
      />
    </Flex>
  }
  realign(event) { this.setState({ alignPosition: event.target.value }) }
  renderMenu() {
    return <Menu
      constrainTo={false}
      alignTo={(node) => node.parentNode.firstChild }
      alignPositions={[this.state.alignPosition]}
      items={items} style={{ position: 'absolute', opacity: 0.85, zIndex: 1 }}
    />
  }
}
export default () => <App />
Bool
default: undefined
If this is true, it will also dismiss the <Menu /> when a top-level item (that has no submenu) is clicked.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import '@zippytech/react-toolkit/Menu/index.css'

import Icon from './icons'

const items = [
  { label: 'Refresh', icon: <Icon type="refresh" /> },
  { label: 'Back', disabled: true, icon: <Icon type="back" /> },
  '-',
  { label: 'Save file as', icon: <Icon type="save" />,
    items: [ { label: 'PDF' }, { label: 'HTML' }, { label: 'PNG' }, { label: 'Animated GIF' } ] },
  { label: 'Open' },
  { label: 'Export sheet to', items: [ { label: 'CSV' }, { label: 'Proprietary format' } ] }
];

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      autoDismiss: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.autoDismiss}
          onChange={autoDismiss => this.setState({ autoDismiss })}
        >
          Auto dismiss
        </CheckBox>
      </div>
      <Menu
        autoDismiss={this.state.autoDismiss}
        items={items}
      />
    </div>
  }
}

export default () => <App />
Bool
default: false
Using this property, you can automatically focus the <Menu /> when it gets rendered. Defaults to false
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import NotificationBoard from '@zippytech/react-toolkit/Notification'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/Notification/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

class App extends React.Component {

  render() {
    return <div>
      <Menu
      autoFocus
      items={items}
      onFocus={() => zippy.notification.first.addNotification({
        title: 'autoFocus', content: 'The menu is focused!'
      })}
      />
      <NotificationBoard id="first" />
    </div>
  }
}

export default () => <App />
Bool
default: false
If true, and menu selection is enabled, instead of rendering radios/checkboxes from the Zippy React Toolkit, the <Menu /> will render browser native radios/checkboxes.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'vegetable', value: 'potato', label: 'Potatoes' },
  { name: 'vegetable', value: 'tomato', label: 'Tomatoes' },
  { name: 'vegetable', value: 'onion', label: 'Onions' },
  '-',
  { name: 'water', label: 'Water', value: 'h20' },
  { name: 'fire', label: 'Fire', value: true }
];

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      browserNativeSelectInputs: true,
      selected: { fruit: 'orange' }
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.browserNativeSelectInputs}
          onChange={(browserNativeSelectInputs) => this.setState({ browserNativeSelectInputs })}
        >
          Browser native select inputs
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <b>Selected:</b>
        <code>{JSON.stringify(this.state.selected, null, 2)}</code>
      </div>
      <Menu
        enableSelection
        defaultSelected={this.state.selected}
        nameProperty="name"
        valueProperty="value"
        items={items}
        browserNativeSelectInputs={this.state.browserNativeSelectInputs}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />
Array[Object]
default: undefined
The content of the <Menu /> its organized in multiple columns. By default, menus have only one column, which is the label column.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save' },
  '-',
  { label: 'Export as PDF' },
  { label: 'Export as HTML' },
];

export default () => <Menu
  columns={['label']}
  items={items}
/>
You can add as many columns as you wish, and they will render the matching property in every object in the items array .
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save', description: 'Saves your content' },
  '-',
  { label: 'Export as PDF', description: 'Exports to PDF format' },
  { label: 'Export as HTML', description: 'Exports to a webpage' },
];

export default () => <Menu
  columns={[
    'label',
    { name: 'description', style: { color: 'gray', paddingLeft: 10 } }
  ]}
  items={items}
/>
Columns can be configured with a number of properties. For the most basic configuration of a column, simply use the column name as a string in the columns array.
However, when you want to customize the column, you have to specify an object, with the following properties being supported:
String
default: undefined
Content align for cells in this column. Valid values are:
  • "start" - by default aligns content to the left. When rtl=true, aligns content to the right.
  • "center" - centers content horizontally in the menu cell.
  • "end" - by default aligns content to the right. When rtl=true, aligns content to the left.
  • "left" - always aligns content to the left, without accounting for rtl=true.
  • "right" - always aligns content to the right, without accounting for rtl=true.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'

const items = [
  { label: 'Save', description: 'Saves your content' },
  '-',
  { label: 'Export as PDF', description: 'Exports to PDF format' },
  { label: 'Export as HTML', description: 'Exports to a webpage' },
];

const dataSource = [
  'start', 'center', 'end' , 'left', 'right'
].map((value) => {
  return {
    id: value,
    label: value
  }
})

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      align: 'start'
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        Columns align:
        <ComboBox
          style={{ width: 200 }}
          collapseOnSelect
          changeValueOnNavigation
          dataSource={dataSource}
          value={this.state.align || 'start'}
          onChange={(value) => this.setState({ align: value })}
        />
      </div>
      <Menu
        columns={[
          'label',
          { name: 'description', align: this.state.align || 'start', style: { width: 300, paddingLeft: 10 } }
        ]}
        items={items}
      />
    </div>
  }
}

export default () => <App />
Number
default: undefined
Specifies how many columns to span.
String
default: undefined
The name to be used for the column. Column cells will render item[column.name] for every item in the <Menu />.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { description: 'Save!' },
  '-',
  { description: 'Export to PDF format' },
  { description: 'Export to a webpage' },
];

export default () => <Menu
  columns={[
    { name: 'description' }
  ]}
  items={items}
/>
Fn(item)
default: undefined
This prop is an alternative to the name prop, since it allows you to render any valid React.Node instead of the value in item[column.name]. Either name or render should be specified for every column.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { description: 'Save!' },
  '-',
  { description: 'Export to PDF format' },
  { description: 'Export to a webpage' },
];

export default () => <Menu
  columns={[
    { render: (item) => <b>{item.description}</b> }
  ]}
  items={items}
/>
String|HTMLElement|Fn(node)|Bool
default: undefined
constrainTo is used to tell the menu to always try to display itself (and its submenus) in the specified area.
Valid values for constrainTo are:
  • A string to be used with document.querySelector. In this case, it will be used to retrieve the first ancestor matching the given selector. So elements are queried upwards in the hierarchy, starting from the menu, until one matches. When one is found, the menu will be constrained to the bounding client rect of the element.
  • A reference to a HTMLElement in the page - the menu will be constrained to the bounding client rect of the element.
  • a boolean - if false, no constrain will be applied. If true, the documentElement will be used as the HTMLElement.
  • An object similar to the one returned by getBoundingClientRect (containing either top,left,bottom,right or top,left,width,height) with coordinates relative to the viewport - see getBoundingClientRect docs on MDN .
  • A function returning any of the above.
For more details on constrainTo and how it works in combination with alignTo and alignPositions see positioning menus.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'
import { Flex } from '@zippytech/react-flex'
import Icon from './icons'

const items = [
  { label: 'Refresh', icon: <Icon type="refresh" /> },
  { label: 'Back', disabled: true, icon: <Icon type="back" /> },
  '-',
  { label: 'Save file as', icon: <Icon type="save" />,
    items: [ { label: 'PDF' }, { label: 'HTML' }, { label: 'PNG' }, { label: 'Animated GIF' } ] },
  { label: 'Open' },
  { label: 'Export sheet to', items: [ { label: 'CSV' }, { label: 'Proprietary format' } ] }
];

class App extends React.Component {
  constructor(props) { super(props); this.state = {} }
  render() {
    const style = {
      border: '1px dashed blue',
      width: 500,
      height: 500,
      position: 'relative'
    }
    return <Flex justifyContent="center" className="menu-constrain-region" style={style}
      onContextMenu={this.onContextMenu.bind(this)}
    >
      <span style={{ color: 'gray', fontStyle: 'italic'}}> Right-click to show context-menu.</span>
      {this.renderMenu()}
    </Flex>
  }
  renderMenu() {
    if (!this.state.menuPosition) { return null }

    return <Menu
      autoFocus
      onDismiss={this.dismiss.bind(this)}
      constrainTo=".menu-constrain-region"
      alignTo={this.state.menuPosition}
      items={items}
      style={{ position: 'absolute' }}
    />
  }
  dismiss() { this.setState({ menuPosition: null }) }
  onContextMenu(event) {
    event.preventDefault(); // prevents the browser from displaying the default context-menu
    this.setState({
      menuPosition: { left: event.clientX, top: event.clientY }
    })
  }
}

export default () => <App />
Object
default: undefined
Determines which items are selected (when enableSelection=true).
This is the uncontrolled version of selected.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'vegetable', value: 'potato', label: 'Potatoes' },
  { name: 'vegetable', value: 'tomato', label: 'Tomatoes' },
  { name: 'vegetable', value: 'onion', label: 'Onions' },
  '-',
  { name: 'water', value: true, label: 'Water' },
  { name: 'fire', value: true, label: 'Fire' }
];

export default () => <Menu
  enableSelection
  defaultSelected={{ vegetable: 'tomato', water: true }}
  nameProperty="name"
  valueProperty="value"
  items={items}
/>
Bool
default: false
If true, will not show the scrolling arrows when there is overflowing content.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { isTitle: true, label: 'Text' },
  { label: 'Copy' },
  { label: 'Paste' },
  { label: 'Paste with formatting' },
  { label: 'Cut' },
  '-',
  { isTitle: true, label: 'Actions' },
  { label: 'Save' },
  { label: 'Save as', items: [ { label: 'HTML' }, { label: 'PDF' } ] },
  { label: 'Export' },
  { label: 'Open' }
];

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      disableScroller: false
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.disableScroller}
          onChange={(disableScroller) => this.setState({ disableScroller })}
        >
          Disable scroller
        </CheckBox>
      </div>
      <p>Current state for disableScroller is: {this.state.disableScroller ? '{true}' : '{false}'}.</p>
      <Menu
        disableScroller={this.state.disableScroller}
        scrollOnMouseEnter={false}
        maxHeight={200}
        items={items}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
When dismissOnClick=true, if the user clicks an item in a submenu, the submenu will be dismissed.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

class App extends React.Component {
  constructor(props) { super(props); this.state = { dismiss: true } }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.dismiss} style={{ margin: 5 }}
          onChange={(checked) => this.setState({ dismiss: checked })}>
          Dismiss on click
        </CheckBox>
      </div>
      <Menu items={items} dismissOnClick={this.state.dismiss} />
    </div>
  }
}
export default () => <App />
Bool
default: true
Specifies whether the menu uses animation when displaying its submenus.
For controlling fade animation duration, use fadeDuration.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      enableAnimation: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableAnimation}
          onChange={(enableAnimation) => this.setState({ enableAnimation })}
        >
          Enable animation
        </CheckBox>
      </div>
      <Menu
        enableAnimation={this.state.enableAnimation}
        items={items}
      />
    </div>
  }
}


export default () => <App />
Bool
default: true
By default, menus have keyboard navigation enabled. If you don't want this, set enableKeyboardNavigation=false
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

class App extends React.Component {
  constructor(props) { super(props); this.state = { navigation: true } }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.navigation} style={{ margin: 5 }}
          onChange={(checked) => this.setState({ navigation: checked })}>
          Keyboard navigation
        </CheckBox>
      </div>
      <Menu items={items} enableKeyboardNavigation={this.state.navigation} />
    </div>
  }
}
export default () => <App />
Bool
default: false
Specifies whether the <Menu /> root node uses animation when it is rendered.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu
  fadeDuration={500}
  enableRootAnimation={true}
  items={items}
/>
Bool
default: false
If true, enables selection on the <Menu />.
Use nameProperty to specify the keys to set on the selected object for each item, and valueProperty to specify the values.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'vegetable', value: 'potato', label: 'Potatoes' },
  { name: 'vegetable', value: 'tomato', label: 'Tomatoes' },
  { name: 'vegetable', value: 'onion', label: 'Onions' },
  '-',
  { name: 'water', label: 'Water', value: 'h20' },
  { name: 'fire', label: 'Fire', value: true }
];

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableSelection: true,
      selected: { fruit: 'orange' }
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableSelection}
          onChange={(enableSelection) => this.setState({ enableSelection })}
        >
          Enable selection
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <b>Selected:</b>
        <code>{JSON.stringify(this.state.selected, null, 2)}</code>
      </div>
      <Menu
        enableSelection={this.state.enableSelection}
        defaultSelected={this.state.selected}
        nameProperty="name"
        valueProperty="value"
        items={items}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />
Bool|React.Node|Fn
default: undefined
The expander icon to use for menu items that have submenus
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image',
  items: [ { label: 'PNG' }, { label: 'JPG' }] } ] },
  { label: 'Open' }
];

const expander = <div style={{ display: 'inline-block', padding: 5 }}>
  <svg fill="#000000" height="24" viewBox="0 0 24 24" width="24">
    <path d="M8 5v14l11-7z"/>
    <path d="M0 0h24v24H0z" fill="none"/>
  </svg>
</div>

export default () => <Menu items={items} expander={expander} />
If true or undefined, the default expander will be rendered
If specified as a function, it will be called with two params: domProps and item.
If a valid React.Node, will be rendered as given (this includes values like strings, react elements, false or null.
This property will also propagate to submenus, and they will use the same expander.
Number
default: 300
The duration (expressed in milliseconds) of the fade-in animation.
By default, animation is enabled.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

const dataSource = ['300', '500', '800', '1000', '2000'].map((value) => {
  return {
    id: value,
    label: value
  }
});

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      fadeDuration: 300
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        Fade duration:{' '}
        <ComboBox
          style={{ width: 200 }}
          collapseOnSelect
          changeValueOnNavigation
          inlineFlex
          dataSource={dataSource}
          value={this.state.fadeDuration || '300'}
          onChange={(value) => this.setState({ fadeDuration: value })}
        />
      </div>
      <Menu
        fadeDuration={this.state.fadeDuration * 1 || '300' * 1}
        items={items}
      />
    </div>
  }
}


export default () => <App />
Number
default: 150
The delay (in milliseconds) to wait until to hide a submenu.
To control the delay used when showing the submenu, see showSubMenuDelay.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

const dataSource = [
  '150', '300', '1000', '2000'
].map((value) => {
  return {
    id: value,
    label: 'Delay: ' + value
  }
})

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      hideSubMenuDelay: 150
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <ComboBox
          style={{ width: 200 }}
          collapseOnSelect
          changeValueOnNavigation
          expandOnClick
          dataSource={dataSource}
          value={this.state.hideSubMenuDelay || '150' * 1}
          onChange={(value) => this.setState({ hideSubMenuDelay: value })}
        />
      </div>
      <Menu
        hideSubMenuDelay={this.state.hideSubMenuDelay * 1 || '150' * 1}
        items={items}
      />
    </div>
  }
}


export default () => <App />
Array
default: undefined
Describes the items to show in the <Menu />.
Without any additional configuration, every item in the array should have a label property, which can be any valid React.Node (so, basically valid JSX).
Additionally, you can specify an icon property, which can be any valid React.Node (so, basically valid JSX code). Add an onClick property to intercept a click on that particular <Menu /> item.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'
import NotificationBoard from '@zippytech/react-toolkit/Notification'
import '@zippytech/react-toolkit/Notification/index.css'

const items = [
  { label: <b>Save as ...</b>, items: [
    {
      label: 'PDF',
      onClick: () => zippy.notification.first.addNotification({ title: 'onClick', content: 'save as PDF' })
    },
    { label: 'HTML' }
  ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <div>
  <p>Click on Save as.../PDF menu item to see the effect of onClick callback.</p>
  <Menu items={items} />
  <NotificationBoard id="first" />
</div>
Bool
default: undefined
Can be used to mark an item as disabled.
Disabled items do not respond to user interaction/events and are also skipped from keyboard navigation.
In CSS, they also have pointer-events: none
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const getItems = (state) => {
  return [
    { disabled: state.disabled, label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
    { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image', disabled: true } ] },
    { label: 'Open' }
  ]
};

class App extends React.Component {
  constructor(props) {
    super(props)
    this.onItemsChange = this.onItemsChange.bind(this)

    this.state = {
      disabled: false
    }

    this.state.items = getItems(this.state)
  }

  onItemsChange(value) {
    const disabled = value
    this.setState({
      items: getItems(Object.assign({}, this.state, { disabled })),
      disabled
    })
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.disabled}
          onChange={this.onItemsChange}
        >
          Make the first item disabled
        </CheckBox>
      </div>
      <Menu items={this.state.items} />
    </div>
  }
}


export default () => <App />
React.Node
default: undefined
Using expander on a specific item, you can override the global expander prop.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  {
    expander: <svg fill="#000000" height="24" viewBox="0 0 24 24" width="24">
      <path d="M8 5v14l11-7z"/>
      <path d="M0 0h24v24H0z" fill="none"/>
    </svg>,
    label: 'Save as ...',
    items: [ { label: 'PDF' }, { label: 'HTML'  } ]
  },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image', disabled: true } ] },
  { label: 'Open' }
];

export default () => <Menu items={items} />
String|React.Node
default: undefined
When menu items contain an icon property, it is transformed into a column, inserted at the beginning of the columns array .
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'
import Icon from './icons'

const items = [
  { label: 'Refresh', icon: <Icon type="refresh" /> },
  { label: 'Save', icon: <Icon type="save" /> },
  { label: 'Open' }
];

export default () => <Menu items={items} />
It's just a convention to name this column as icon - since you can render whatever you want in the column (so, any valid React.Node is valid as a value for the item icon property).
In the example above, we render an <Icon /> component, which renders a simple SVG.
The only other special column, that is injected, is secondaryLabel.
Bool
default: undefined
You can take items out of the keyboard navigation/selection flow by using isTitle: true.
You can use isTitle in combination with separator items ('-') to have titles to menu sections.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { isTitle: true, label: 'Text' },
  { label: 'Copy' },
  { label: 'Paste' },
  { label: 'Paste with formatting' },
  { label: 'Cut' },
  '-',
  { isTitle: true, label: 'Actions' },
  { label: 'Save' },
  { label: 'Save as', items: [ { label: 'HTML' }, { label: 'PDF' } ] },
  { label: 'Export' },
  { label: 'Open' }
];

export default () => <Menu items={items} />
String|React.Node
default: undefined
By default, menus are configured with columns=['label'], so this property should be used to render the contents of the menu item.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: <b>Save as ...</b> },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];
export default () => <Menu items={items} />
Object
default: undefined
Props to configure the submenu for this item. If present, it overrides the props specified by the global submenuProps.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { menuProps: { padding: 50 },
  label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu submenuProps={{ padding: 10}} items={items} />
Fn(event, itemProps, index)
default: undefined
You can specify onClick on each menu item and get that called only when that specific item is clicked.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import NotificationBoard from '@zippytech/react-toolkit/Notification'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/Notification/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  {
    label: 'Open',
    onClick: (event, { item }, index) => {
      zippy.notification.first.addNotification({ title: 'onClick', content: 'You clicked "' + item.label + '".' })
    }
  }
];

export default () => <div>
  <p>Click on Open item to see the effect.</p>
  <Menu items={items} />
  <NotificationBoard id="first" />
</div>
String|React.Node
default: undefined
secondaryLabel column is another automatically injected column, when this property is detected on menu items. Unlike the icon column, this is injected at the end of the columns array.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'
import Icon from './icons'

const items = [
  { name: 'Refresh', icon: <Icon type="refresh" />, secondaryLabel: 'Cmd + R' },
  { name: 'Save', icon: <Icon type="save" />, secondaryLabel: 'Cmd + S' },
  { name: 'Open', secondaryLabel: 'Cmd + O' }
];

export default () => <Menu columns={["name"]} items={items} />
In the example above, even though the columns prop is explicitly given a value, the icon and secondaryLabel columns are still injected, since they have a special behaviour.
Number
default: undefined
The maximum height of the <Menu />, in px
If the <Menu /> content needs more vertical space, top/bottom arrow scrollbars will be shown to allow menu content to be scrolled to.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { isTitle: true, label: 'Text' },
  { label: 'Copy' },
  { label: 'Paste' },
  { label: 'Paste with formatting' },
  { label: 'Cut' },
  '-',
  { isTitle: true, label: 'Actions' },
  { label: 'Save' },
  { label: 'Save as', items: [ { label: 'HTML' }, { label: 'PDF' } ] },
  { label: 'Export' },
  { label: 'Open' }
];

export default () => <Menu maxHeight={200} items={items} />
Object
default: undefined
An object with width,height to be used as max-width,max-height.
If the <Menu /> content needs more vertical space, top/bottom arrow scrollbars will be shown to allow <Menu /> content to be scrolled to.
See related maxHeight and minSize.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { isTitle: true, label: 'Text' },
  { label: 'Copy' },
  { label: 'Paste' },
  { label: 'Paste with formatting' },
  { label: 'Cut' },
  '-',
  { isTitle: true, label: 'Actions' },
  { label: 'Save' },
  { label: 'Save as', items: [ { label: 'HTML' }, { label: 'PDF' } ] },
  { label: 'Export' },
  { label: 'Open' }
];

export default () => <Menu maxSize={{ height: 200 }} items={items} />
Object
default: undefined
An object with width,height to be used as min-width,min-height.
See related maxHeight and maxSize.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { isTitle: true, label: 'Text' },
  { label: 'Copy' },
  { label: 'Paste with formatting' },
  '-',
  { isTitle: true, label: 'Actions' },
  { label: 'Save' }
];

export default () => <Menu minSize={{ height: 300}} items={items} />
String
default: "name"
Specifies which property from given items to use as a selection key.
For specifying the value property, see valueProperty.
If you want to have single select for a group of items, make sure they have the same value for the nameProperty.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'vegetable', value: 'potato', label: 'Potatoes' },
  { name: 'vegetable', value: 'tomato', label: 'Tomatoes' },
  { name: 'vegetable', value: 'onion', label: 'Onions' },
  '-',
  { name: 'water', label: 'Water', value: 'h20' },
  { name: 'fire', label: 'Fire', value: true }
];

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableSelection: true,
      selected: { fruit: 'orange' }
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableSelection}
          onChange={(enableSelection) => this.setState({ enableSelection })}
        >
          Enable selection
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <b>Selected:</b>
        <code>{JSON.stringify(this.state.selected, null, 2)}</code>
      </div>
      <Menu
        enableSelection={this.state.enableSelection}
        defaultSelected={this.state.selected}
        nameProperty="name"
        valueProperty="value"
        items={items}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
If this is true, when the <Menu /> needs scrolling, it will be scrollable via mouse (wheel) interaction, and not just via up/down menu arrows
Due to a flexbox bug, IE11 and Edge will have this prop set to false.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import '@zippytech/react-toolkit/Menu/index.css'

import Icon from './icons'

const items = [
  { label: 'Refresh', icon: <Icon type="refresh" /> },
  { label: 'Back', disabled: true, icon: <Icon type="back" /> },
  { label: 'Forward', disabled: true, icon: <Icon type="forward" /> },
  '-',
  { label: 'Save file as', icon: <Icon type="save" />,
    items: [ { label: 'PDF' }, { label: 'HTML' }, { label: 'PNG' }, { label: 'Animated GIF' } ] },
  { label: 'Open' },
  { label: 'Remove' },
  { label: 'Export sheet to', items: [ { label: 'CSV' }, { label: 'Proprietary format' } ] }
];

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      nativeScroll: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.nativeScroll}
          onChange={nativeScroll => this.setState({ nativeScroll })}
        >
          Native scroll
        </CheckBox>
      </div>
      <Menu
        nativeScroll={this.state.nativeScroll}
        items={items}
        maxHeight={150}
      />
    </div>
  }
}

export default () => <App />
Fn({checked:Bool,onChange:Fn,domProps:Object})
default: undefined
Can be used to customize the rendering of checkboxes for menus with multi selection.
The onChange fn passed to renderCheckInput should be called with a bool argument, denoting if the option is or not selected.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'option1', value: 'potato', label: 'Potatoes' },
  { name: 'option2', value: 'tomato', label: 'Tomatoes' },
  { name: 'option3', value: 'onion', label: 'Onions' }
];

const customCheckbox = ({ checked, onChange }) => {
  return <div onClick={() => onChange(!checked)}>
    {checked ?
      <svg fill="#000000" height="18" viewBox="0 0 24 24" width="18">
        <path d="M0 0h24v24H0z" fill="none"/>
        <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
      </svg> :
      <svg fill="#000000" height="18" viewBox="0 0 24 24" width="18">
        <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
        <path d="M0 0h24v24H0z" fill="none"/>
      </svg>
    }
  </div>
}

class App extends React.Component {
  constructor(props) {
    super(props); this.state = { selected: { fruit: 'orange' } }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <b>Selected:</b>
        <code>{JSON.stringify(this.state.selected, null, 2)}</code>
      </div>
      <Menu
        enableSelection
        defaultSelected={this.state.selected}
        nameProperty="name"
        valueProperty="value"
        items={items}
        renderCheckInput={customCheckbox}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />
Fn({checked:Bool,onChange:Fn,domProps:Object})
default: undefined
Can be used to customize the rendering of radios for menus with single selection.
The onChange fn passed to renderRadioInput should be called with a bool argument, denoting if the option is or not selected.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'option1', value: 'potato', label: 'Potatoes' },
  { name: 'option2', value: 'tomato', label: 'Tomatoes' },
  { name: 'option3', value: 'onion', label: 'Onions' }
];

const customRadio = ({ checked, onChange }) => {
  return <div onClick={() => onChange(!checked)}>
    {checked ?
      <svg fill="#000000" height="18" viewBox="0 0 24 24" width="18">
        <path d="M0 0h24v24H0z" fill="none"/>
        <path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/>
        <path d="M0 0h24v24H0z" fill="none"/>
      </svg> :
      <svg fill="#000000" height="18" viewBox="0 0 24 24" width="18">
        <path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"/>
        <path d="M0 0h24v24H0z" fill="none"/>
      </svg>
    }
  </div>
}

class App extends React.Component {
  constructor(props) {
    super(props); this.state = { selected: { fruit: 'orange' } }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <b>Selected:</b>
        <code>{JSON.stringify(this.state.selected, null, 2)}</code>
      </div>
      <Menu
        enableSelection
        defaultSelected={this.state.selected}
        nameProperty="name"
        valueProperty="value"
        items={items}
        renderRadioInput={customRadio}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />
Bool
default: false
Whether to use direction: rtl on the menu or not. Defaults to false.
Specifying this, affects , column order (columns are displayed in reverse order) and align selectionInputPosition.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { label: 'Save', description: 'Saves your content' },
  '-',
  { label: 'Export as PDF', description: 'Exports to PDF format' },
  { label: 'Export as HTML', description: 'Exports to a webpage' },
];

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      rtl: false
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.rtl}
          onChange={(rtl) => this.setState({ rtl })}
        >
          Right-to-left
        </CheckBox>
      </div>
      <Menu
        rtl={this.state.rtl}
        columns={[
          'label',
          { name: 'description', align: 'end', style: { width: 300, paddingLeft: 10 } }
        ]}
        items={items}
      />
    </div>
  }
}


export default () => <App />
Bool
default: true
If true, will scroll when the mouse enters the scroll arrow.
Otherwise, will only scroll on mousedown on the scroll arrow.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { isTitle: true, label: 'Text' },
  { label: 'Copy' },
  { label: 'Paste' },
  { label: 'Paste with formatting' },
  { label: 'Cut' },
  '-',
  { isTitle: true, label: 'Actions' },
  { label: 'Save' },
  { label: 'Save as', items: [ { label: 'HTML' }, { label: 'PDF' } ] },
  { label: 'Export' },
  { label: 'Open' }
];

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      scrollOnMouseEnter: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.scrollOnMouseEnter}
          onChange={(scrollOnMouseEnter) => this.setState({ scrollOnMouseEnter })}
        >
          Scroll on mouse enter
        </CheckBox>
      </div>
      <Menu
        scrollOnMouseEnter={this.state.scrollOnMouseEnter}
        maxHeight={200}
        items={items}
      />
    </div>
  }
}


export default () => <App />
Object
default: undefined
Determines which items are selected (when enableSelection=true).
This is a controlled prop.
For uncontrolled behavior, see defaultSelected.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'vegetable', value: 'potato', label: 'Potatoes' },
  { name: 'vegetable', value: 'tomato', label: 'Tomatoes' },
  { name: 'vegetable', value: 'onion', label: 'Onions' }
];

class App extends React.Component {
  constructor(props) {
    super(props); this.state = { selected: { fruit: 'orange' } }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <b>Selected:</b>
        <code>{JSON.stringify(this.state.selected, null, 2)}</code>
      </div>
      <Menu
        enableSelection
        selected={this.state.selected}
        nameProperty="name"
        valueProperty="value"
        items={items}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />
String
default: "start"
Determines the position of the selection inputs, when selection is enabled.
This prop takes into account the value of rtl.
Valid values are "start" and "end".
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'option1', value: true, label: 'Potatoes' },
  { name: 'option2', value: true, label: 'Tomatoes' },
  { name: 'option3', value: true, label: 'Onions' }
];

const dataSource = ['start', 'end'].map((position) => {
  return {
    id: position,
    label: position
  }
})

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      selectionInputPosition: 'start',
      selected: { fruit: 'orange' }
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        Selection input position: {' '}
        <ComboBox
          style={{ width: 200 }}
          inlineFlex
          collapseOnSelect
          changeValueOnNavigation
          dataSource={dataSource}
          value={this.state.selectionInputPosition || 'start'}
          onChange={(value) => this.setState({ selectionInputPosition: value })}
        />
      </div>
      <div style={{ marginBottom: 20 }}>
        <b>Selected:</b>
        <code>{JSON.stringify(this.state.selected, null, 2)}</code>
      </div>
      <Menu
        enableSelection
        defaultSelected={this.state.selected}
        nameProperty="name"
        valueProperty="value"
        items={items}
        selectionInputPosition={this.state.selectionInputPosition || 'start'}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Determines if the selection value can be changed via mouse clicks or not.
If this is false, the selection will only change via keyboard interaction (when spacebar key is hit on a menu item).
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'vegetable', value: 'potato', label: 'Potatoes' },
  { name: 'vegetable', value: 'tomato', label: 'Tomatoes' },
  { name: 'vegetable', value: 'onion', label: 'Onions' },
  '-',
  { name: 'water', value: true, label: 'Water' },
  { name: 'fire', value: true, label: 'Fire' }
];

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      selectOnClick: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.selectOnClick}
          onChange={(selectOnClick) => this.setState({ selectOnClick })}
        >
          Select on click
        </CheckBox>
      </div>
      <Menu
        enableSelection
        selectOnClick={this.state.selectOnClick}
        defaultSelected={{ vegetable: 'tomato', water: true }}
        nameProperty="name"
        valueProperty="value"
        items={items}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Use this prop to control whether the scroll arrows are being displayed or not
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { isTitle: true, label: 'Text' },
  { label: 'Copy' },
  { label: 'Paste' },
  { label: 'Paste with formatting' },
  { label: 'Cut' },
  '-',
  { isTitle: true, label: 'Actions' },
  { label: 'Save' },
  { label: 'Save as', items: [ { label: 'HTML' }, { label: 'PDF' } ] },
  { label: 'Export' },
  { label: 'Open' }
];

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      showScrollArrows: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.showScrollArrows}
          onChange={(showScrollArrows) => this.setState({ showScrollArrows })}
        >
          Show scroll arrows
        </CheckBox>
      </div>
      <Menu
        maxHeight={200}
        items={items}
        showScrollArrows={this.state.showScrollArrows}
      />
    </div>
  }
}


export default () => <App />
Number
default: 150
The delay (in milliseconds) to wait until to show a submenu.
To control the delay used when hiding the submenu, see hideSubMenuDelay.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

const dataSource = ['150', '300', '600', '1000', '2000'].map((value) => {
  return {
    id: value,
    label: value
  }
})

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      showSubMenuDelay: 150
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        Show sub menu delay:{' '}
        <ComboBox
          style={{ width: 200 }}
          inlineFlex
          collapseOnSelect
          changeValueOnNavigation
          dataSource={dataSource}
          value={this.state.showSubMenuDelay || '150'}
          onChange={(value) => this.setState({ showSubMenuDelay: value })}
        />
      </div>
      <Menu
        showSubMenuDelay={this.state.showSubMenuDelay * 1 || '150' * 1}
        items={items}
      />
    </div>
  }
}


export default () => <App />
Object|Object[]|Number
default: { x: -7, y: 5 }
Specifies the offset used by submenus of the current <Menu />, for alignment relative to the parent menu item. For details on possible values, see alignOffset.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'
import { Flex } from '@zippytech/react-flex'
import Icon from './icons'

const items = [
  { label: 'Refresh', icon: <Icon type="refresh" /> },
  { label: 'Back', disabled: true, icon: <Icon type="back" /> },
  '-',
  { label: 'Save file as', icon: <Icon type="save" />,
    items: [ { label: 'PDF' }, { label: 'HTML' }, { label: 'PNG' }, { label: 'Animated GIF' } ] },
  { label: 'Open' },
  { label: 'Export sheet to', items: [ { label: 'CSV' }, { label: 'Proprietary format' } ] }
];

const style = { minHeight: 400, position: 'relative' }
const alignToStyle = { width: 200, height: 150, border: '1px dashed red'}

const options = [
  { id: 'br-tl', label: 'Bottom-right to top-left' },
  { id: 'bc-tc', label: 'Bottom-center to top-center' },
  { id: 'bl-tr', label: 'Bottom-left to top-right' },
  { id: 'lc-rc', label: 'Left-center to right-center' },
  { id: 'tl-br', label: 'Top-left to bottom-right' },
  { id: 'tc-bc', label: 'Top-center to bottom-center' },
  { id: 'tr-bl', label: 'Top-right to bottom-left' },
  { id: 'rc-lc', label: 'Right-center to left-center' },
  { id: 'lc-lc', label: 'Left-center to left-center' },
  { id: 'c-c', label: 'Center to Center' },
  { id: 'tr-tl', label: 'Top-right to top-left' },
  { id: 't-t', label: 'Top to top - only align on vertical axis' },
  { id: 'l-l', label: 'Left to left - only align on horizontal axis' },
  { id: 'rc-rc', label: 'Right-center to right-center' },
  { id: 'c-tl', label: 'Center to top-left' }
]

const offsets = [
  { id: -50, label: '-50' },
  { id: -20, label: '-20' },
  { id: 0, label: '0' },
  { id: 20, label: '20' },
  { id: 50, label: '50' },
]

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      alignPosition: 'tl-br',
      offset: 0
    }
  }

  render() {
    return <Flex justifyContent="center" style={style}>
      <Flex justifyContent="center" style={alignToStyle}><span>This is the <b>alignTo</b> target</span></Flex>
      {this.renderMenu()}
      <div style={{ position: 'absolute', top: 10, left: 10 }}>
        Align position:
        <ComboBox
          style={{ width: 200 }}
          collapseOnSelect
          changeValueOnNavigation
          dataSource={options}
          value={this.state.alignPosition}
          onChange={(value) => this.setState({ alignPosition: value })}
        />
      </div>
      <div style={{position: 'absolute', top: 80, left: 10}}>
        Sub menu align offset:
        <ComboBox
          style={{ width: 200 }}
          collapseOnSelect
          changeValueOnNavigation
          dataSource={offsets}
          value={this.state.offset}
          onChange={(value) => this.setState({ offset: value })}
        />
      </div>
    </Flex>
  }

  setOffset(event) { this.setState({ offset: event.target.value * 1 }) }

  realign(event) { this.setState({ alignPosition: event.target.value }) }

  renderMenu() {
    return <Menu
      constrainTo={false}
      alignTo={(node) => node.parentNode.firstChild }
      submenuAlignOffset={this.state.offset}
      alignPositions={[this.state.alignPosition]}
      items={items} style={{ position: 'absolute', opacity: 0.85, zIndex: 1 }}
    />
  }
}

export default () => <App />
Number
default: undefined
The maximum height for sub-menus, in px
If submenus content needs more vertical space, top/bottom arrow scrollbars will be shown to allow content in submenus to be scrolled to.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  {
    label: 'Countries',
    items: [
      { isTitle: true, label: 'North America' },
      { label: 'USA' },
      { label: 'Canada' },
      { label: 'Mexico' },
      '-',
      { isTitle: true, label: 'Europe' },
      { label: 'UK' },
      { label: 'France' },
      { label: 'Italy' },
      { label: 'Spain' },
      { label: 'Germany' }
    ]
  },
  {
    label: 'Cities',
    items: [ { label: 'NY' }, { label: 'LA' } ]
  }
];

export default () => <Menu submenuMaxHeight={200} items={items} />
Object
default: undefined
Props to configure the submenus of all the items in this menu.
This can be overwritten by item.menuProps
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu submenuProps={{ padding: 30}} items={items} />
String
default: "name"
Specifies which property from given items to use as a selection value.
For specifying the name property, see nameProperty.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'vegetable', value: 'potato', label: 'Potatoes' },
  { name: 'vegetable', value: 'tomato', label: 'Tomatoes' },
  { name: 'vegetable', value: 'onion', label: 'Onions' },
  '-',
  { name: 'water', label: 'Water', value: 'h20' },
  { name: 'fire', label: 'Fire', value: true }
];

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableSelection: true,
      selected: { fruit: 'orange' }
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableSelection}
          onChange={(enableSelection) => this.setState({ enableSelection })}
        >
          Enable selection
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <b>Selected:</b>
        <code>{JSON.stringify(this.state.selected, null, 2)}</code>
      </div>
      <Menu
        enableSelection={this.state.enableSelection}
        defaultSelected={this.state.selected}
        nameProperty="name"
        valueProperty="value"
        items={items}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Controls <Menu /> visibility. If is set to false it will have the CSS visibility property set to hidden (visibility: hidden).
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

class App extends React.Component {
  constructor(props) { super(props); this.state = { visible: true } }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.visible} style={{ margin: 5 }}
          onChange={(checked) => this.setState({ visible: checked })}>
          Menu visibility
        </CheckBox>
      </div>
      <Menu items={items} visible={this.state.visible} />
    </div>
  }
}
export default () => <App />
Fn(event, props)
default: undefined
Called when any of the menu items are clicked, at any level of nesting.
If you only want to intercept clicks on items in the current menu (so without any nesting), use onClick.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'
import NotificationBoard from '@zippytech/react-toolkit/Notification'
import '@zippytech/react-toolkit/Notification/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <div>
  <Menu
    onChildClick={(event, { item }) =>
      zippy.notification.first.addNotification({
        title: item.label,
        content: 'You clicked on: ' + item.label
      })}
    items={items}
  />
  <NotificationBoard id="first" />
</div>
Fn(event, props, index)
default: undefined
Called when any of the immediate items in the current menu are clicked.
This is not called for clicks on items in a submenu of this<Menu />. To capture clicks at all levels, use onChildClick.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'
import NotificationBoard from '@zippytech/react-toolkit/Notification'
import '@zippytech/react-toolkit/Notification/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <div>
  <Menu
    onClick={(event, { item }) =>
      zippy.notification.first.addNotification({
        title: item.label,
        content: 'You clicked top-level: ' + item.label
      })}
    items={items}
  />
  <NotificationBoard id="first" />
</div>
Fn()
default: undefined
Called when the <Menu /> loses focus, so you can use this to dismiss/hide the <Menu />.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'
import { Flex } from '@zippytech/react-flex'
import Icon from './icons'

const items = [
  { label: 'Refresh', icon: <Icon type="refresh" /> },
  { label: 'Back', disabled: true, icon: <Icon type="back" /> },
  { label: 'Save file as', icon: <Icon type="save" />,
    items: [ { label: 'PDF' }, { label: 'HTML' }, { label: 'PNG' }, { label: 'Animated GIF' } ] },
  { label: 'Export sheet to', items: [ { label: 'CSV' }, { label: 'Proprietary format' } ] }
];

class App extends React.Component {
  constructor(props) { super(props); this.state = {} }
  render() {
    const style = { border: '1px dashed blue', width: 500, height: 500 }
    return <Flex justifyContent="center" style={style} onContextMenu={this.onContextMenu.bind(this)}>
      Right-click in this area to show context-menu.
      {this.renderMenu()}
    </Flex>
  }
  renderMenu() {
    if (!this.state.menuPosition) { return null }
    return <Menu
      onDismiss={this.dismiss.bind(this)}
      autoFocus constrainTo={(menuNode) => menuNode.parentNode}
      alignTo={this.state.menuPosition}
      items={items} style={{ position: 'absolute' }}
    />
  }
  dismiss() { this.setState({ menuPosition: null }) }
  onContextMenu(event) {
    event.preventDefault(); // prevents the browser from displaying the default context-menu
    this.setState({
      menuPosition: { left: event.clientX, top: event.clientY }
    })
  }
}
export default () => <App />
Fn(selection)
default: undefined
Function to be called whenever the selection changes.
The first param if the new selection object for the <Menu />.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/Menu/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'vegetable', value: 'potato', label: 'Potatoes' },
  { name: 'vegetable', value: 'tomato', label: 'Tomatoes' },
  { name: 'vegetable', value: 'onion', label: 'Onions' },
  '-',
  { name: 'water', label: 'Water', value: 'h20' },
  { name: 'fire', label: 'Fire', value: true }
];

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableSelection: true,
      selected: { fruit: 'orange' }
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableSelection}
          onChange={(enableSelection) => this.setState({ enableSelection })}
        >
          Enable selection
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <b>Selected:</b>
        <code>{JSON.stringify(this.state.selected, null, 2)}</code>
      </div>
      <Menu
        enableSelection={this.state.enableSelection}
        defaultSelected={this.state.selected}
        nameProperty="name"
        valueProperty="value"
        items={items}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />
String
default: undefined
The border CSS value to use for the <Menu />.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { disabled: true, label: 'Open' }
];

export default () => <Menu
  border="7px outset gray"
  items={items}
/>
Number
default: undefined
The border-radius to apply to the <Menu />.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { disabled: true, label: 'Open' }
];

export default () => <Menu
  border="1px solid gray"
  borderRadius={5}
  items={items}
/>
String
default: undefined
A CSS className to be appended to the <Menu /> component.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu
  className="menu-color-blue"
  items={items}
/>
String
default: undefined
A className to be added to all cells in the column
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save', description: 'Saves your content' },
  '-',
  { label: 'Export as PDF', description: 'Exports to PDF format' },
  { label: 'Export as HTML', description: 'Exports to a webpage' },
];

export default () => <Menu
  columns={[
    'label',
    { name: 'description', className: 'menu-column-color-blue' }
  ]}
  items={items}
/>
Object
default: undefined
A style object to be applied to all cells in the column
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save', description: 'Saves your content' },
  '-',
  { label: 'Export as PDF', description: 'Exports to PDF format' },
  { label: 'Export as HTML', description: 'Exports to a webpage' },
];

export default () => <Menu
  columns={[
    'label',
    { name: 'description', style: { color: 'blue', paddingLeft: 10 } }
  ]}
  items={items}
/>
Object
default: undefined
Applies the specified style to the <Menu /> item row, when the item is focused.
This overrides styles specified by itemFocusedStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open', focusedStyle: { color: 'blue'} }
];

export default () => <Menu itemFocusedStyle={{ color: 'green' }} items={items} />
String
default: undefined
Appends the specified className to the <Menu /> items, when the items are active (between mousedown and mouseup).
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu items={items} itemActiveClassName="menu-color-red" />
Object
default: undefined
Applies the specified style to <Menu /> items, when the items are active (between mousedown and mouseup).
This is overridden by items.activeStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open', activeStyle: { color: 'magenta' } }
];

export default () => <Menu itemActiveStyle={{ color: 'red' }} items={items} />
Object
default: undefined
Appends the specified className to all menu item rows in the <Menu />.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu itemClassName="menu-color-blue" items={items} />
String
default: undefined
Appends the specified className to disabled menu items.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { disabled: true, label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

class App extends React.Component {

  render() {
    return <Menu
      items={items}
      itemDisabledClassName="menu-disabled-item-color-green"
    />
  }
}

export default () => <App />
Object
default: undefined
Applies the specified style to all disabled items in the <Menu />.
This is overridden by items.disabledStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { disabled: true, label: 'Open' }
];

export default () => <Menu itemDisabledStyle={{ opacity: 0.4, color: 'red' }} items={items} />
String
default: undefined
Appends the specified className to menu items, when they are expanded.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu items={items} itemExpandedClassName="menu-color-blue" />
Object
default: undefined
Applies the specified style to menu items, when they are expanded.
This is overridden by items.expandedStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu itemExpandedStyle={{ color: 'blue' }} items={items} />
String
default: undefined
Appends the specified className to menu items, when they are focused.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu items={items} itemFocusedClassName="menu-item-focused-color-blue" />
Object
default: undefined
Applies the specified style to all items in the <Menu />, when they are focused.
This is overridden by items.focusedStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu itemFocusedStyle={{ color: 'green' }} items={items} />
Object
default: undefined
Specifies the height to use for all items in the <Menu />.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { disabled: true, label: 'Open' }
];

export default () => <Menu
  itemStyle={{ height: 20 }} // overridden by itemHeight
  itemHeight={60}
  items={items}
/>
String
default: undefined
Appends the specified className to all menu items when the mouse is over them.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu items={items} itemOverClassName="menu-item-over-color-red" />
Object
default: undefined
Applies the specified style to all items in the <Menu />, when the mouse is over the item.
This is overridden by items.overStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu itemOverStyle={{ color: 'red' }} items={items} />
String
default: undefined
Appends the specified className to the <Menu /> item row, when the item is active (between mousedown and mouseup).
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open', activeClassName: 'menu-color-red' }
];

export default () => <div>
  <p>Pres Open item to see the effect.</p>
  <Menu items={items} />
</div>
Object
default: undefined
Applies the specified style to the item, when the item is active (between mousedown and mouseup).
This overrides styles specified by itemActiveStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open', activeStyle: { color: 'magenta' } }
];

export default () => <Menu itemActiveStyle={{ color: 'red' }} items={items} />
Object
default: undefined
Specifying the className property on a <Menu /> item appends that className to the corresponding menu row.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { className: 'menu-color-blue', label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu items={items} />
String
default: undefined
Appends the specified className to the menu item row, when it is disabled.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { disabled: true, label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { disabled: true, label: 'Open', disabledClassName: 'menu-disabled-item-color-green' }
];

export default () => <Menu items={items} />
Object
default: undefined
Applies the specified style to the menu item, if it is disabled.
This overrides styles specified by itemDisabledStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { disabled: true, label: 'Open', disabledStyle: { opacity: 0.4, color: 'red' } }
];

export default () => <Menu items={items} />
String
default: undefined
Appends the specified className to the menu item row, when the item is expanded.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { expandedClassName: 'menu-color-blue', label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <div>
  <p>Press Import from item to see the effect.</p>
  <Menu items={items} />
</div>
Object
default: undefined
Applies the specified style to the menu item, when it is expanded.
This overrides styles specified by itemExpandedStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { expandedStyle: {color: 'green'}, label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <div>
  <p>Press Import from item to see the effect.</p>
  <Menu itemExpandedStyle={{ color: 'red' }} items={items} />
</div>
String
default: undefined
Appends the specified className to the menu item row, when the item receives focus.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open', focusedClassName: 'menu-item-focused-color-blue' }
];

export default () => <div>
  <p>Press on Open item to see the effect.</p>
  <Menu items={items} />
</div>
Object
default: undefined
Applies the specified style to the item, when the item receives focus.
This overrides styles specified by itemFocusedStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open', focusedStyle: { color: 'blue' } }
];

export default () => <div>
  <p>Press on Open item to see the effect.</p>
  <Menu itemFocusedStyle={{ color: 'green' }} items={items} />
</div>
String
default: undefined
Appends the specified className to the menu item row when the mouse is over the item.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open', overClassName: 'menu-item-over-color-red' }
];

export default () => <Menu items={items} />
Object
default: undefined
Applies the specified style when the mouse is over the item.
This overrides styles specified by itemOverStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open', overStyle: { color: 'red' } }
];

export default () => <Menu items={items} itemOverStyle={{ color: 'blue' }} />
Object
default: undefined
Specifying the style property on a menu item applies that style to the corresponding menu row.
This also overrides any styles specified by itemStyle.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { style: { color: 'red' }, label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu items={items} />
Object
default: undefined
Applies the specified style to all items in the <Menu />.
This is overridden by items.style.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu itemStyle={{ color: '#134175' }} items={items} />
Object
default: undefined
Style object for menu separator.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Copy' },
  { label: 'Paste' },
  { label: 'Paste with formatting' },
  { label: 'Cut' },
  '-',
  { label: 'Save' },
  { label: 'Save as', items: [ { label: 'HTML' }, { label: 'PDF' } ] },
  { label: 'Export' },
  { label: 'Open' }
];

export default () => <Menu
  items={items}
  menuSeparatorStyle={{ background: 'red', height: 2 }}
/>
String|Number
default: undefined
Inline padding to be added on the <Menu />.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu
  padding={30}
  items={items}
/>
Bool|String
default: true
Whether to apply a box-shadow to the <Menu /> or not. If a string, will be used as the value for box-shadow.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { disabled: true, label: 'Open' }
];

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      shadow: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.shadow}
          onChange={(shadow) => this.setState({ shadow })}
        >
          Shadow
        </CheckBox>
      </div>
      <Menu
        shadow={this.state.shadow}
        items={items}
      />
    </div>
  }
}

export default () => <App />
Object
default: undefined
A style object applied to the <Menu /> component.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { label: 'Open' }
];

export default () => <Menu
  style={{ color: '#134175' }}
  items={items}
/>
Object
default: undefined
A style object to apply to all submenus of the current <Menu />.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { label: 'Save as ...', items: [ { label: 'PDF' }, { label: 'HTML'  } ] },
  { label: 'Import from', items: [ { label: 'Doc' }, { label: 'Image' } ] },
  { disabled: true, label: 'Open' }
];

export default () => <Menu
  submenuStyle={{ border: '1px solid green' }}
  items={items}
/>
Fn(index: Number)
undefined
Focuses the given menu item
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import Button from '@zippytech/react-toolkit/Button'
import NumericInput from '@zippytech/react-toolkit/NumericInput'
import '@zippytech/react-toolkit/NumericInput/index.css'
import '@zippytech/react-toolkit/Button/index.css'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'vegetable', value: 'potato', label: 'Potatoes' },
  { name: 'vegetable', value: 'tomato', label: 'Tomatoes' },
  { name: 'vegetable', value: 'onion', label: 'Onions' }
];

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      index: 2,
      selected: {}
    }
  }

  focusApples() {
    this.menu.focusItem(this.state.index * 1)
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <b>Chose the index:</b>{' '}
        <NumericInput
          style={{ width: 70 }}
          minValue={0}
          maxValue={6}
          value={this.state.index}
          onChange={(index) => this.setState({ index })}
        />{' '}
        <Button
          style={{ height: 30, borderRadius: 3 }}
          onClick={this.focusApples.bind(this)}
        >
          Click to focus the chosen index
        </Button>
      </div>
      <Menu
        ref={(m) => this.menu = m}
        enableSelection
        nameProperty="name"
        valueProperty="value"
        items={items}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />
Fn(selected: Object)
undefined
Use this method to programmatically update the <Menu /> selection.
This will cause onSelectionChange to be called.
Using the controlled selected prop is preferred to using this method.
import React from 'react'
import Menu from '@zippytech/react-toolkit/Menu'
import Button from '@zippytech/react-toolkit/Button'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/ComboBox/index.css'
import '@zippytech/react-toolkit/Button/index.css'
import '@zippytech/react-toolkit/Menu/index.css'

const items = [
  { name: 'fruit', value: 'orange', label: 'Oranges' },
  { name: 'fruit', value: 'banana', label: 'Bananas' },
  { name: 'fruit', value: 'apple', label: 'Apples' },
  { name: 'fruit', value: 'strawberry', label: 'Strawberries' },
  '-',
  { name: 'vegetable', value: 'potato', label: 'Potatoes' },
  { name: 'vegetable', value: 'tomato', label: 'Tomatoes' },
  { name: 'vegetable', value: 'onion', label: 'Onions' }
];

const dataSource = [
  'orange', 'banana', 'apple', 'strawberry'
].map((item) => {
  return {
    id: item,
    label: item
  }
})

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      item: 'apple',
      selected: {}
    }
  }

  setApples() {
    this.menu.setSelected({ fruit: this.state.item })
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        Chose an item:{' '}
        <ComboBox
          style={{ width: 130 }}
          collapseOnSelect
          inlineFlex
          dataSource={dataSource}
          value={this.state.item}
          onChange={(value) => this.setState({ item: value })}
        />{' '}
        <Button
          onClick={this.setApples.bind(this)}
          style={{ height: 32, borderRadius: 3 }}
        >
          Click to check the chosen item
        </Button>
      </div>
      <p>
        <b>Selected:</b>
        <code>{JSON.stringify(this.state.selected, null, 2)}</code>
      </p>
      <Menu
        ref={(m) => this.menu = m}
        enableSelection
        nameProperty="name"
        valueProperty="value"
        items={items}
        onSelectionChange={(selected) => this.setState({ selected })}
      />
    </div>
  }
}

export default () => <App />