From 23ee58b1c0026d85484df3dd87314b68a46f7aa0 Mon Sep 17 00:00:00 2001 From: Ali Taheri Date: Mon, 14 Dec 2015 01:18:36 +0330 Subject: [PATCH] LeftNav: deprecate menuItems and migrate docs. --- .../components/LeftNav/ExampleOpenRight.jsx | 27 ++ .../app/components/LeftNav/ExampleSimple.jsx | 28 ++ .../components/LeftNav/ExampleUndocked.jsx | 35 +++ docs/src/app/components/LeftNav/README.md | 18 ++ .../components/pages/components/left-nav.jsx | 249 ++---------------- .../app/components/raw-code/left-nav-code.txt | 40 --- src/left-nav.jsx | 228 ++++++++++++---- 7 files changed, 311 insertions(+), 314 deletions(-) create mode 100644 docs/src/app/components/LeftNav/ExampleOpenRight.jsx create mode 100644 docs/src/app/components/LeftNav/ExampleSimple.jsx create mode 100644 docs/src/app/components/LeftNav/ExampleUndocked.jsx create mode 100644 docs/src/app/components/LeftNav/README.md delete mode 100644 docs/src/app/components/raw-code/left-nav-code.txt diff --git a/docs/src/app/components/LeftNav/ExampleOpenRight.jsx b/docs/src/app/components/LeftNav/ExampleOpenRight.jsx new file mode 100644 index 00000000000000..ca7edd6b22e01e --- /dev/null +++ b/docs/src/app/components/LeftNav/ExampleOpenRight.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import LeftNav from 'material-ui/lib/left-nav'; +import AppBar from 'material-ui/lib/app-bar'; +import RaisedButton from 'material-ui/lib/raised-button'; + +export default class LeftNavOpenRightExample extends React.Component { + + constructor(props) { + super(props); + this.state = {open: false}; + } + + handleToggle = () => this.setState({open: !this.state.open}); + + render() { + return ( +
+ + + + +
+ ); + } +} diff --git a/docs/src/app/components/LeftNav/ExampleSimple.jsx b/docs/src/app/components/LeftNav/ExampleSimple.jsx new file mode 100644 index 00000000000000..acfb49ece54bd9 --- /dev/null +++ b/docs/src/app/components/LeftNav/ExampleSimple.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import LeftNav from 'material-ui/lib/left-nav'; +import MenuItem from 'material-ui/lib/menus/menu-item'; +import RaisedButton from 'material-ui/lib/raised-button'; + +export default class LeftNavSimpleExample extends React.Component { + + constructor(props) { + super(props); + this.state = {open: false}; + } + + handleToggle = () => this.setState({open: !this.state.open}); + + render() { + return ( +
+ + + Menu Item + Menu Item 2 + +
+ ); + } +} diff --git a/docs/src/app/components/LeftNav/ExampleUndocked.jsx b/docs/src/app/components/LeftNav/ExampleUndocked.jsx new file mode 100644 index 00000000000000..a5bd95616153b7 --- /dev/null +++ b/docs/src/app/components/LeftNav/ExampleUndocked.jsx @@ -0,0 +1,35 @@ +import React from 'react'; +import LeftNav from 'material-ui/lib/left-nav'; +import MenuItem from 'material-ui/lib/menus/menu-item'; +import RaisedButton from 'material-ui/lib/raised-button'; + +export default class LeftNavUndockedExample extends React.Component { + + constructor(props) { + super(props); + this.state = {open: false}; + } + + handleToggle = () => this.setState({open: !this.state.open}); + + handleClose = () => this.setState({open: false}); + + render() { + return ( +
+ + this.setState({open})} + > + Menu Item + Menu Item 2 + +
+ ); + } +} diff --git a/docs/src/app/components/LeftNav/README.md b/docs/src/app/components/LeftNav/README.md new file mode 100644 index 00000000000000..22f34efda8b096 --- /dev/null +++ b/docs/src/app/components/LeftNav/README.md @@ -0,0 +1,18 @@ +## Left Nav + +To find out more about the `LeftNav` component please visit the Material Design's +specifications [here](https://www.google.com/design/spec/patterns/navigation-drawer.html). + +The API of `LeftNav` has been changed to be declarative and composable. +The methods `close()`, `open()` and `toggle()` have been deprecated. +In order to control the `LeftNav` use the `open` property +and handle the `onRequestChange` event. Also, as you have +noticed there are no examples for uncontrolled mode. +That is because uncontrolled `LeftNav` can only be opened +with swipe. The doc site has an uncontrolled `LeftNav`, +swipe left with a touch device to see it. +Also, `menuItems` and all related props have been deprecated too. +As a result, it is now possible to shape the contents of +`LeftNav` however you wish. + +### Examples diff --git a/docs/src/app/components/pages/components/left-nav.jsx b/docs/src/app/components/pages/components/left-nav.jsx index bc5989e849fe2d..3c7a77f73eed82 100644 --- a/docs/src/app/components/pages/components/left-nav.jsx +++ b/docs/src/app/components/pages/components/left-nav.jsx @@ -1,237 +1,32 @@ import React from 'react'; -import {LeftNav, MenuItem, RaisedButton, Paper} from 'material-ui'; -import ComponentDoc from '../../component-doc'; -import Code from 'left-nav-code'; +import MarkdownElement from '../../MarkdownElement'; import CodeExample from '../../code-example/code-example'; -import CodeBlock from '../../code-example/code-block'; +import PropTypeDescription from '../../PropTypeDescription'; +import leftNavReadmeText from '../../LeftNav/README'; +import LeftNavSimpleExample from '../../LeftNav/ExampleSimple'; +import leftNavSimpleExampleCode from '!raw!../../LeftNav/ExampleSimple'; +import LeftNavUndockedExample from '../../LeftNav/ExampleUndocked'; +import leftNavUndockedExampleCode from '!raw!../../LeftNav/ExampleUndocked'; +import LeftNavOpenRightExample from '../../LeftNav/ExampleOpenRight'; +import leftNavOpenRightExampleCode from '!raw!../../LeftNav/ExampleOpenRight'; +import leftNavCode from '!raw!material-ui/lib/left-nav'; export default class LeftNavPage extends React.Component { - - constructor() { - super(); - this._toggleLeftNavChildrenClick = this._toggleLeftNavChildrenClick.bind(this); - this._showLeftNavUndockedControlledClick = this._showLeftNavUndockedControlledClick.bind(this); - this._changeLeftNavUndockedControlledClick = this._changeLeftNavUndockedControlledClick.bind(this); - this.state = { - navWithChildrenOpen: false, - undockedNavOpen: false, - }; - } - render() { - this.desc = 'The api of Left Nav has been changed to be declarative. ' + - 'The methods close, open and toggle have been deprecated. ' + - 'In order to control the Left Nav use the open property and handle ' + - 'the onRequestChange event. Also, as you have noticed there are no examples ' + - 'for uncontrolled mode. That is because uncontrolled Left Nav can only be open ' + - 'with swipe. The doc site has an uncontrolled Left Nav, swipe left with a touch ' + - 'device to see it.'; - - let componentInfo = [ - { - name: 'Props', - infoArray: [ - { - name: 'disableSwipeToOpen', - type: 'bool', - header: 'default: false', - desc: 'Indicates whether swiping sideways when the nav is closed ' + - 'should open the nav.', - }, - { - name: 'docked', - type: 'bool', - header: 'default: true', - desc: 'Indicates that the left nav should be docked. In this state, the ' + - 'overlay won\'t show and clicking on a menu item will not close the left nav.', - }, - { - name: 'open', - type: 'bool', - header: 'default: null', - desc: 'Indicates that the left nav should be opened, closed or uncontrolled. Providing a boolean ' + - 'will turn the left nav into a controlled component.', - }, - { - name: 'header', - type: 'element', - header: 'optional', - desc: 'A react component that will be displayed above all the menu items. ' + - 'Usually, this is used for a logo or a profile image.', - }, - { - name: 'menuItems', - type: 'array', - header: 'optional', - desc: 'JSON data representing all menu items to render.', - }, - { - name: 'openRight', - type: 'bool', - header: 'default: false', - desc: 'Positions the LeftNav to open from the right side.', - }, - { - name: 'selectedIndex', - type: 'number', - header: 'optional', - desc: 'Indicates the particular item in the menuItems array that is ' + - 'currently selected.', - }, - { - name: 'style', - type: 'object', - header: 'optional', - desc: 'Override the inline-styles of LeftNav\'s root element.', - }, - { - name: 'menuItemClassName', - type: 'string', - header: 'optional', - desc: 'Class name for the menuItem.', - }, - { - name: 'menuItemClassNameSubheader', - type: 'string', - header: 'optional', - desc: 'Class name for the subheader menuItem.', - }, - { - name: 'menuItemClassNameLink', - type: 'string', - header: 'optional', - desc: 'Class name for the link menuItem.', - }, - ], - }, - { - name: 'Methods', - infoArray: [ - { - name: 'Deprecated: open', - header: 'LeftNav.open()', - desc: 'Opens the component. ' + - 'Using this method is deprecated, use the ' + - 'open property and handle onRequestChange to control the left nav.', - }, - { - name: 'Deprecated: close', - header: 'LeftNav.close()', - desc: 'Closes the component, hiding it from view. ' + - 'Using this method is deprecated, use the ' + - 'open property and handle onRequestChange to control the left nav.', - }, - { - name: 'Deprecated: toggle', - header: 'LeftNav.toggle()', - desc: 'Toggles between the open and closed states. ' + - 'Using this method is deprecated, use the ' + - 'open property and handle onRequestChange to control the left nav.', - }, - ], - }, - { - name: 'Events', - infoArray: [ - { - name: 'onChange', - header: 'function(event, selectedIndex, menuItem)', - desc: 'Fired when a menu item is clicked that is not the one currently ' + - 'selected. Note that this requires the injectTapEventPlugin component. ' + - 'See the "Get Started" section for more detail.', - }, - { - name: 'Deprecated: onNavOpen', - header: 'function()', - desc: 'Fired when the component is opened. ' + - 'Using this method is deprecated, use the ' + - 'open property and handle onRequestChange to control the left nav.', - }, - { - name: 'Deprecated: onNavClose', - header: 'function()', - desc: 'Fired when the component is closed. ' + - 'Using this method is deprecated, use the ' + - 'open property and handle onRequestChange to control the left nav.', - }, - { - name: 'onRequestChange', - header: 'function(open, reason)', - desc: 'Callback function that is fired when the ' + - 'open state of the left nav is requested to be changed. ' + - 'The provided open argument determines whether the left nav is ' + - 'requested to be opened or closed. Also, the reason argument states why the ' + - 'left nav got closed or opend. It can be either \'clickaway\' for menuItem and ' + - 'overlay clicks, \'escape\' for pressing the escape key and \'swipe\' for swiping. ' + - 'For opening the reason is always \'swipe\'.', - }, - ], - }, - ]; - return ( - - - - - { - `//Import statement: -import LeftNav from 'material-ui/lib/left-nav/'; - -//See material-ui/lib/index.js for more - ` - } - - - - -
-
- -

- -

-
- - - Menu Item - Menu Item 2 - - - Menu Item - Menu Item 2 - -
+
+ + + - + + + + + + + +
); } - - _toggleLeftNavChildrenClick() { - this.setState({ - navWithChildrenOpen: !this.state.navWithChildrenOpen, - }); - } - - _showLeftNavUndockedControlledClick() { - this.setState({ - undockedNavOpen: true, - }); - } - - _changeLeftNavUndockedControlledClick(open) { - this.setState({ - undockedNavOpen: open, - }); - } - } diff --git a/docs/src/app/components/raw-code/left-nav-code.txt b/docs/src/app/components/raw-code/left-nav-code.txt deleted file mode 100644 index 9212a9e1b12327..00000000000000 --- a/docs/src/app/components/raw-code/left-nav-code.txt +++ /dev/null @@ -1,40 +0,0 @@ -menuItems = [ - { route: 'get-started', text: 'Get Started' }, - { route: 'customization', text: 'Customization' }, - { route: 'components', text: 'Components' }, - { type: MenuItem.Types.SUBHEADER, text: 'Resources' }, - { - type: MenuItem.Types.LINK, - payload: 'https://github.com/callemall/material-ui', - text: 'GitHub' - }, - { - text: 'Disabled', - disabled: true - }, - { - type: MenuItem.Types.LINK, - payload: 'https://www.google.com', - text: 'Disabled Link', - disabled: true - }, -]; - -//Docked Left Nav - - -//Controlled and docked Left Nav. Can only be opened and close by changing the open prop. - - -//Controlled and docked Left Nav with nested children - - Menu Item - Link - - -//Controlled and undocked Left Nav. - diff --git a/src/left-nav.jsx b/src/left-nav.jsx index d5673d2f5609e3..874ab9b4789f04 100644 --- a/src/left-nav.jsx +++ b/src/left-nav.jsx @@ -2,7 +2,7 @@ import isBrowser from './utils/is-browser'; import warning from 'warning'; -let Modernizr = isBrowser ? require('./utils/modernizr.custom') : undefined; +const Modernizr = isBrowser ? require('./utils/modernizr.custom') : undefined; import React from 'react'; import ReactDOM from 'react-dom'; @@ -43,23 +43,123 @@ const LeftNav = React.createClass({ }, propTypes: { + /** + * The contents of the `LeftNav` + */ children: React.PropTypes.node, + + /** + * The css class name of the root element. + */ className: React.PropTypes.string, + + /** + * Indicates whether swiping sideways when the `LeftNav` is closed should open it. + */ disableSwipeToOpen: React.PropTypes.bool, + + /** + * Indicates that the `LeftNav` should be docked. In this state, the overlay won't + * show and clicking on a menu item will not close the `LeftNav`. + */ docked: React.PropTypes.bool, + + /** + * **DEPRECATED** A react component that will be displayed above all the menu items. + * Usually, this is used for a logo or a profile image. + */ header: React.PropTypes.element, + + /** + * **DEPRECATED** Class name for the menuItem. + */ menuItemClassName: React.PropTypes.string, + + /** + * **DEPRECATED** Class name for the link menuItem. + */ menuItemClassNameLink: React.PropTypes.string, + + /** + * **DEPRECATED** Class name for the subheader menuItem. + */ menuItemClassNameSubheader: React.PropTypes.string, + + /** + * **DEPRECATED** JSON data representing all menu items to render. + */ menuItems: React.PropTypes.array, + + /** + * **DEPRECATED** Fired when a menu item is clicked that is not the + * one currently selected. Note that this requires the `injectTapEventPlugin` + * component. See the "Get Started" section for more detail. + */ onChange: React.PropTypes.func, + + /** + * **DEPRECATED** Fired when the component is opened. + */ onNavClose: React.PropTypes.func, + + /** + * **DEPRECATED** Fired when the component is closed. + */ onNavOpen: React.PropTypes.func, + + /** + * Callback function that is fired when the open state of the `LeftNav` is + * requested to be changed. The provided open argument determines whether + * the `LeftNav` is requested to be opened or closed. Also, the reason + * argument states why the `LeftNav` got closed or opend. It can be either + * `'clickaway'` for menuItem and overlay clicks, `'escape'` for pressing the + * escape key and 'swipe' for swiping. For opening the reason is always `'swipe'`. + */ onRequestChange: React.PropTypes.func, + + /** + * Indicates that the `LeftNav` should be opened, closed or uncontrolled. + * Providing a boolean will turn the `LeftNav` into a controlled component. + */ open: React.PropTypes.bool, + + /** + * Positions the `LeftNav` to open from the right side. + */ openRight: React.PropTypes.bool, + + /** + * The `className` to add to the `Overlay` component that is rendered behind the `LeftNav`. + */ + overlayClassName: React.PropTypes.string, + + /** + * Overrides the inline-styles of the `Overlay` component that is rendered behind the `LeftNav`. + */ + overlayStyle: React.PropTypes.object, + + /** + * **DEPRECATED** Indicates the particular item in the menuItems array that is currently selected. + */ selectedIndex: React.PropTypes.number, + + /** + * Override the inline-styles of the root element. + */ style: React.PropTypes.object, + + /** + * The width of the left most (or right most) area in pixels where the `LeftNav` can be + * swiped open from. Setting this to `null` spans that area to the entire page + * (**CAUTION!** Setting this property to `null` might cause issues with sliders and + * swipeable `Tabs`, use at your own risk). + */ + swipeAreaWidth: React.PropTypes.number, + + /** + * The width of the `LeftNav` in pixels. Defaults to using the values from theme. + */ + width: React.PropTypes.number, }, windowListeners: { @@ -72,6 +172,9 @@ const LeftNav = React.createClass({ disableSwipeToOpen: false, docked: true, open: null, + openRight: false, + swipeAreaWidth: 30, + width: null, }; }, @@ -142,29 +245,22 @@ const LeftNav = React.createClass({ return this; }, - getThemePalette() { - return this.state.muiTheme.rawTheme.palette; - }, - - getTheme() { - return this.state.muiTheme.leftNav; - }, - getStyles() { + const theme = this.state.muiTheme.leftNav; const rawTheme = this.state.muiTheme.rawTheme; - let x = this._getTranslateMultiplier() * (this.state.open ? 0 : this._getMaxTranslateX()); - let styles = { + const x = this._getTranslateMultiplier() * (this.state.open ? 0 : this._getMaxTranslateX()); + const styles = { root: { height: '100%', - width: this.getTheme().width, + width: this.props.width || theme.width, position: 'fixed', zIndex: rawTheme.zIndex.leftNav, left: isBrowser && Modernizr.csstransforms3d ? 0 : x, top: 0, - transform: 'translate3d(' + x + 'px, 0, 0)', + transform: `translate3d(${x}px, 0, 0)`, transition: !this.state.swiping && Transitions.easeOut(), - backgroundColor: this.getTheme().color, + backgroundColor: theme.color, overflow: 'hidden', }, menu: { @@ -179,7 +275,7 @@ const LeftNav = React.createClass({ }, menuItem: { height: rawTheme.spacing.desktopLeftNavMenuItemHeight, - lineHeight: rawTheme.spacing.desktopLeftNavMenuItemHeight + 'px', + lineHeight: `${rawTheme.spacing.desktopLeftNavMenuItemHeight}px`, }, rootWhenOpenRight: { left: 'auto', @@ -190,7 +286,7 @@ const LeftNav = React.createClass({ styles.menuItemLink = this.mergeStyles(styles.menuItem, { display: 'block', textDecoration: 'none', - color: this.getThemePalette().textColor, + color: rawTheme.palette.textColor, }); styles.menuItemSubheader = this.mergeStyles(styles.menuItem, { overflow: 'hidden', @@ -200,22 +296,37 @@ const LeftNav = React.createClass({ }, render() { - let selectedIndex = this.props.selectedIndex; - let overlay; + const { + className, + docked, + header, + menuItemClassName, + menuItemClassNameSubheader, + menuItemClassNameLink, + menuItems, + openRight, + overlayClassName, + overlayStyle, + selectedIndex, + style, + } = this.props; + + const styles = this.getStyles(); - let styles = this.getStyles(); - if (!this.props.docked) { + let overlay; + if (!docked) { overlay = ( ); } let children; - if (this.props.menuItems === undefined) { + if (menuItems === undefined) { children = this.props.children; } else { @@ -224,30 +335,28 @@ const LeftNav = React.createClass({ ref="menuItems" style={this.mergeStyles(styles.menu)} zDepth={0} - menuItems={this.props.menuItems} + menuItems={menuItems} menuItemStyle={this.mergeStyles(styles.menuItem)} menuItemStyleLink={this.mergeStyles(styles.menuItemLink)} menuItemStyleSubheader={this.mergeStyles(styles.menuItemSubheader)} - menuItemClassName={this.props.menuItemClassName} - menuItemClassNameSubheader={this.props.menuItemClassNameSubheader} - menuItemClassNameLink={this.props.menuItemClassNameLink} + menuItemClassName={menuItemClassName} + menuItemClassNameSubheader={menuItemClassNameSubheader} + menuItemClassNameLink={menuItemClassNameLink} selectedIndex={selectedIndex} onItemTap={this._onMenuItemClick} /> ); } return ( -
+
{overlay} - {this.props.header} + className={className} + style={this.mergeStyles(styles.root, openRight && styles.rootWhenOpenRight, style)}> + {header} {children}
@@ -260,6 +369,30 @@ const LeftNav = React.createClass({ warning(!(typeof this.props.onNavOpen === 'function'), 'onNavOpen will be removed in favor of onRequestChange'); + + warning(!this.props.hasOwnProperty('header'), + 'header will be removed in favor of composability. refer to the documentation for more information'); + + warning(!this.props.hasOwnProperty('menuItems'), + 'menuItems will be removed in favor of composability. refer to the documentation for more information'); + + warning(!this.props.hasOwnProperty('menuItemClassName'), + 'menuItemClassName will be removed with menuItems.'); + + warning(!this.props.hasOwnProperty('menuItemClassName'), + 'menuItemClassName will be removed with menuItems.'); + + warning(!this.props.hasOwnProperty('menuItemClassNameLink'), + 'menuItemClassNameLink will be removed with menuItems.'); + + warning(!this.props.hasOwnProperty('menuItemClassNameSubheader'), + 'menuItemClassNameSubheader will be removed with menuItems.'); + + warning(!(typeof this.props.onChange === 'function'), + 'onChange will be removed with menuItems.'); + + warning(!this.props.hasOwnProperty('selectedIndex'), + 'selectedIndex will be removed with menuItems.'); }, _shouldShow() { @@ -313,7 +446,8 @@ const LeftNav = React.createClass({ }, _getMaxTranslateX() { - return this.getTheme().width + 10; + const width = this.props.width || this.state.muiTheme.leftNav.width; + return width + 10; }, _getTranslateMultiplier() { @@ -340,13 +474,13 @@ const LeftNav = React.createClass({ _onBodyTouchStart(e) { - const swipeAreaWidth = 30; + const swipeAreaWidth = this.props.swipeAreaWidth; - let touchStartX = e.touches[0].pageX; - let touchStartY = e.touches[0].pageY; + const touchStartX = e.touches[0].pageX; + const touchStartY = e.touches[0].pageY; // Open only if swiping from far left (or right) while closed - if (!this.state.open) { + if (swipeAreaWidth !== null && !this.state.open) { if (this.props.openRight) { // If openRight is true calculate from the far right if (touchStartX < document.body.offsetWidth - swipeAreaWidth) return; @@ -373,8 +507,8 @@ const LeftNav = React.createClass({ }, _setPosition(translateX) { - let leftNav = ReactDOM.findDOMNode(this.refs.clickAwayableElement); - let transformCSS = 'translate3d(' + (this._getTranslateMultiplier() * translateX) + 'px, 0, 0)'; + const leftNav = ReactDOM.findDOMNode(this.refs.clickAwayableElement); + const transformCSS = 'translate3d(' + (this._getTranslateMultiplier() * translateX) + 'px, 0, 0)'; this.refs.overlay.setOpacity(1 - translateX / this._getMaxTranslateX()); AutoPrefix.set(leftNav.style, 'transform', transformCSS); }, @@ -392,20 +526,20 @@ const LeftNav = React.createClass({ }, _onBodyTouchMove(e) { - let currentX = e.touches[0].pageX; - let currentY = e.touches[0].pageY; + const currentX = e.touches[0].pageX; + const currentY = e.touches[0].pageY; if (this.state.swiping) { e.preventDefault(); this._setPosition(this._getTranslateX(currentX)); } else if (this._maybeSwiping) { - let dXAbs = Math.abs(currentX - this._touchStartX); - let dYAbs = Math.abs(currentY - this._touchStartY); + const dXAbs = Math.abs(currentX - this._touchStartX); + const dYAbs = Math.abs(currentY - this._touchStartY); // If the user has moved his thumb ten pixels in either direction, // we can safely make an assumption about whether he was intending // to swipe or scroll. - let threshold = 10; + const threshold = 10; if (dXAbs > threshold && dYAbs <= threshold) { this._swipeStartX = currentX; @@ -422,11 +556,11 @@ const LeftNav = React.createClass({ _onBodyTouchEnd(e) { if (this.state.swiping) { - let currentX = e.changedTouches[0].pageX; - let translateRatio = this._getTranslateX(currentX) / this._getMaxTranslateX(); + const currentX = e.changedTouches[0].pageX; + const translateRatio = this._getTranslateX(currentX) / this._getMaxTranslateX(); this._maybeSwiping = false; - let swiping = this.state.swiping; + const swiping = this.state.swiping; this.setState({ swiping: null, });