summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamy Pesse <samypesse@gmail.com>2016-10-13 13:35:59 +0200
committerSamy Pesse <samypesse@gmail.com>2016-10-13 13:35:59 +0200
commitda8c78b3c82bcf8c5e3dad2701fedb21fc10b0b4 (patch)
treece5c6d7086d2c3f8a96bd29ea9c72bdf336b3e08
parentc42c5897fee1841d2be0207faeda81bc42f250e2 (diff)
downloadgitbook-da8c78b3c82bcf8c5e3dad2701fedb21fc10b0b4.zip
gitbook-da8c78b3c82bcf8c5e3dad2701fedb21fc10b0b4.tar.gz
gitbook-da8c78b3c82bcf8c5e3dad2701fedb21fc10b0b4.tar.bz2
Refactor Backdrop, Hotkeys and Dropdown
-rw-r--r--packages/gitbook-core/src/components/Backdrop.js34
-rw-r--r--packages/gitbook-core/src/components/Dropdown.js57
-rw-r--r--packages/gitbook-core/src/components/HotKeys.js53
-rw-r--r--packages/gitbook-core/src/index.js2
-rw-r--r--packages/gitbook-plugin-sharing/src/components/ShareButton.js25
5 files changed, 97 insertions, 74 deletions
diff --git a/packages/gitbook-core/src/components/Backdrop.js b/packages/gitbook-core/src/components/Backdrop.js
index 18f3c4d..7b34b0d 100644
--- a/packages/gitbook-core/src/components/Backdrop.js
+++ b/packages/gitbook-core/src/components/Backdrop.js
@@ -1,17 +1,19 @@
-const React = require('react');
+const React = require('react');
+const HotKeys = require('./HotKeys');
/**
* Backdrop for modals, dropdown, etc. that covers the whole screen
- * and handles click.
+ * and handles click and pressing escape.
*
- * <Backdrop onClick={onCloseModal} />
+ * <Backdrop onClose={onCloseModal} />
*/
const Backdrop = React.createClass({
propTypes: {
- // Callback when backdrop is clicked
- onClick: React.PropTypes.func.isRequired,
+ // Callback when backdrop is closed
+ onClose: React.PropTypes.func.isRequired,
// Z-index for the backdrop
- zIndex: React.PropTypes.number
+ zIndex: React.PropTypes.number,
+ children: React.PropTypes.node
},
getDefaultProps() {
@@ -20,8 +22,17 @@ const Backdrop = React.createClass({
};
},
+ onClick(event) {
+ const { onClose } = this.props;
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ onClose();
+ },
+
render() {
- const { zIndex, onClick } = this.props;
+ const { zIndex, children, onClose } = this.props;
const style = {
zIndex,
position: 'fixed',
@@ -30,8 +41,15 @@ const Backdrop = React.createClass({
width: '100%',
height: '100%'
};
+ const keyMap = {
+ 'escape': onClose
+ };
- return <div style={style} onClick={onClick}></div>;
+ return (
+ <HotKeys keyMap={keyMap}>
+ <div style={style} onClick={this.onClick}>{children}</div>
+ </HotKeys>
+ );
}
});
diff --git a/packages/gitbook-core/src/components/Dropdown.js b/packages/gitbook-core/src/components/Dropdown.js
index f43a6fc..68fb619 100644
--- a/packages/gitbook-core/src/components/Dropdown.js
+++ b/packages/gitbook-core/src/components/Dropdown.js
@@ -1,8 +1,6 @@
const React = require('react');
const classNames = require('classnames');
-const Backdrop = require('./Backdrop');
-
/**
* Dropdown to display a menu
*
@@ -10,7 +8,7 @@ const Backdrop = require('./Backdrop');
*
* <Button />
*
- * <Dropdown.Menu open={this.state.open}>
+ * <Dropdown.Menu>
* <Dropdown.Item href={...}> ... </Dropdown.Item>
* <Dropdown.Item onClick={...}> ... </Dropdown.Item>
*
@@ -27,21 +25,22 @@ const Backdrop = require('./Backdrop');
const DropdownContainer = React.createClass({
propTypes: {
className: React.PropTypes.string,
- span: React.PropTypes.bool,
children: React.PropTypes.node
},
render() {
- let { className, span, children } = this.props;
+ let { className, children } = this.props;
className = classNames(
'GitBook-Dropdown',
className
);
- return span ?
- <span className={className}>{children}</span>
- : <div className={className}>{children}</div>;
+ return (
+ <div className={className}>
+ {children}
+ </div>
+ );
}
});
@@ -56,31 +55,34 @@ const DropdownItem = React.createClass({
href: React.PropTypes.string
},
- onClick(e) {
- if (!this.props.href) {
- e.preventDefault();
- e.stopPropagation();
+ onClick(event) {
+ const { onClick, href } = this.props;
+
+ if (href) {
+ return;
+ }
+
+ event.preventDefault();
+ event.stopPropagation();
- if (this.props.onClick) this.props.onClick();
+ if (onClick) {
+ onClick();
}
},
render() {
const {
children, href,
- onClick, // eslint-disable-line no-unused-vars
...otherProps
} = this.props;
+ delete otherProps.onCLick;
- let inner = [], submenu = [];
- submenu = filterChildren(children, isDropdownMenu);
- inner = filterChildren(children, (child) => !isDropdownMenu(child));
+ const submenu = filterChildren(children, isDropdownMenu);
+ const inner = filterChildren(children, (child) => !isDropdownMenu(child));
return (
<li className="GitBook-DropdownItem">
- <a href={href || '#'}
- onClick={this.onClick}
- {...otherProps} >
+ <a href={href || '#'} onClick={this.onClick} {...otherProps} >
{inner}
</a>
{submenu}
@@ -108,20 +110,16 @@ function filterChildren(children, predicate) {
const DropdownMenu = React.createClass({
propTypes: {
className: React.PropTypes.string,
- children: React.PropTypes.node,
- open: React.PropTypes.bool
+ children: React.PropTypes.node
},
render() {
- const { open } = this.props;
- const className = classNames(
- 'GitBook-DropdownMenu',
- { 'GitBook-DropdownMenu-open': open }
- );
+ let { className, children } = this.props;
+ className = classNames('GitBook-DropdownMenu', className);
return (
<ul className={className}>
- {this.props.children}
+ {children}
</ul>
);
}
@@ -134,8 +132,7 @@ function isDropdownMenu(child) {
const Dropdown = {
Item: DropdownItem,
Menu: DropdownMenu,
- Container: DropdownContainer,
- Backdrop
+ Container: DropdownContainer
};
module.exports = Dropdown;
diff --git a/packages/gitbook-core/src/components/HotKeys.js b/packages/gitbook-core/src/components/HotKeys.js
index c2c67c8..0d6fb8d 100644
--- a/packages/gitbook-core/src/components/HotKeys.js
+++ b/packages/gitbook-core/src/components/HotKeys.js
@@ -1,52 +1,55 @@
const React = require('react');
const Mousetrap = require('mousetrap');
-const { string, node, func, shape, arrayOf } = React.PropTypes;
-
-const bindingShape = shape({
- // A key "escape", a combination of key "mod+s", or a key sequence "ctrl+x ctrl+s"
- key: string.isRequired,
- // function (event) {}
- handler: func.isRequired
-});
+const { Map } = require('immutable');
/**
* Defines hotkeys globally when this component is mounted.
*
- * keymap = [{
- * key: 'escape',
- * handler: (e) => quit()
- * }, {
- * key: 'mod+s',
- * handler: (e) => save()
- * }]
+ * keyMap = {
+ * 'escape': (e) => quit()
+ * 'mod+s': (e) => save()
+ * }
*
- * <HotKeys keymap={keymap}>
+ * <HotKeys keyMap={keyMap}>
* < ... />
* </HotKeys>
*/
const HotKeys = React.createClass({
propTypes: {
- children: node.isRequired,
- keymap: arrayOf(bindingShape)
+ children: React.PropTypes.node.isRequired,
+ keyMap: React.PropTypes.objectOf(React.PropTypes.func)
},
getDefaultProps() {
- return { keymap: [] };
+ return { keyMap: [] };
},
- componentDidMount() {
- this.props.keymap.forEach((binding) => {
- Mousetrap.bind(binding.key, binding.handler);
+ updateBindings(keyMap) {
+ Map(keyMap).forEach((handler, key) => {
+ Mousetrap.bind(key, handler);
});
},
- componentWillUnmount() {
- this.props.keymap.forEach((binding) => {
- Mousetrap.unbind(binding.key, binding.handler);
+ clearBindings(keyMap) {
+ Map(keyMap).forEach((handler, key) => {
+ Mousetrap.unbind(key, handler);
});
},
+ componentDidMount() {
+ this.updateBindings(this.props.keyMap);
+ },
+
+ componentDidUpdate(prevProps) {
+ this.clearBindings(prevProps.keyMap);
+ this.updateBindings(this.props.keyMap);
+ },
+
+ componentWillUnmount() {
+ this.clearBindings(this.props.keyMap);
+ },
+
render() {
// Simply render the only child
return React.Children.only(this.props.children);
diff --git a/packages/gitbook-core/src/index.js b/packages/gitbook-core/src/index.js
index f820599..840fffb 100644
--- a/packages/gitbook-core/src/index.js
+++ b/packages/gitbook-core/src/index.js
@@ -16,6 +16,7 @@ const HotKeys = require('./components/HotKeys');
const Button = require('./components/Button');
const ButtonGroup = require('./components/ButtonGroup');
const Dropdown = require('./components/Dropdown');
+const Backdrop = require('./components/Backdrop');
const I18nProvider = require('./components/I18nProvider');
const ACTIONS = require('./actions/TYPES');
@@ -56,6 +57,7 @@ module.exports = {
Button,
ButtonGroup,
Dropdown,
+ Backdrop,
// Utilities
Shapes,
// Librairies
diff --git a/packages/gitbook-plugin-sharing/src/components/ShareButton.js b/packages/gitbook-plugin-sharing/src/components/ShareButton.js
index 5a6cd6e..6757d67 100644
--- a/packages/gitbook-plugin-sharing/src/components/ShareButton.js
+++ b/packages/gitbook-plugin-sharing/src/components/ShareButton.js
@@ -1,5 +1,5 @@
const GitBook = require('gitbook-core');
-const { React, Dropdown } = GitBook;
+const { React, Dropdown, Backdrop } = GitBook;
const SITES = require('../SITES');
@@ -15,17 +15,13 @@ const ShareButton = React.createClass({
},
onToggle() {
- this.setState({ open: !this.state.open });
+ const { open } = this.state;
+ this.setState({ open: !open });
},
render() {
const { siteIds, onShare } = this.props;
-
- const items = siteIds.map((id) => (
- <Dropdown.Item onClick={() => onShare(SITES[id])} key={id}>
- {SITES[id].label}
- </Dropdown.Item>
- ));
+ const { open } = this.state;
return (
<Dropdown.Container>
@@ -33,9 +29,16 @@ const ShareButton = React.createClass({
<GitBook.Icon id="share-alt" />
</GitBook.Button>
- <Dropdown.Menu open={this.state.open}>
- {items}
- </Dropdown.Menu>
+ {open ? (
+ <Backdrop onClose={this.onToggle}>
+ <Dropdown.Menu>
+ {siteIds.map((id) => (
+ <Dropdown.Item onClick={() => onShare(SITES[id])} key={id}>
+ {SITES[id].label}
+ </Dropdown.Item>
+ ))}
+ </Dropdown.Menu>
+ </Backdrop>) : null}
</Dropdown.Container>
);
}