UNPKG

@versionone/ui

Version:

Open-source and community supported collection of common UI components built with React. As an open-sourced and community supported project, VersionOne UI is not formally supported by VersionOne.

348 lines (295 loc) 13 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _reactEventListener = require('react-event-listener'); var _reactEventListener2 = _interopRequireDefault(_reactEventListener); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _scrollIntoView = require('scroll-into-view'); var _scrollIntoView2 = _interopRequireDefault(_scrollIntoView); var _reduxUi = require('redux-ui'); var _reduxUi2 = _interopRequireDefault(_reduxUi); var _ListItem = require('./ListItem'); var _ListItem2 = _interopRequireDefault(_ListItem); var _Radium = require('./../utilities/Radium'); var _Radium2 = _interopRequireDefault(_Radium); var _SubHeader = require('./../SubHeader'); var _SubHeader2 = _interopRequireDefault(_SubHeader); var _component = require('./../utilities/component'); var _KeyCodes = require('./../utilities/KeyCodes'); var _CustomPropTypes = require('./../utilities/CustomPropTypes'); var CustomPropTypes = _interopRequireWildcard(_CustomPropTypes); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var noSelectedItemIndex = -1; var lowestSelectedItemIndex = 0; var selectedItemIndexIncrement = 1; var List = function (_Component) { _inherits(List, _Component); function List() { var _ref; _classCallCheck(this, List); for (var _len = arguments.length, rest = Array(_len), _key = 0; _key < _len; _key++) { rest[_key] = arguments[_key]; } var _this = _possibleConstructorReturn(this, (_ref = List.__proto__ || Object.getPrototypeOf(List)).call.apply(_ref, [this].concat(rest))); _this.listItemEls = {}; _this.getChildProps = _this.getChildProps.bind(_this); _this.getCurrentIndex = _this.getCurrentIndex.bind(_this); _this.getNextListItemIndex = _this.getNextListItemIndex.bind(_this); _this.getPreviousListItemIndex = _this.getPreviousListItemIndex.bind(_this); _this.highlightItem = _this.highlightItem.bind(_this); _this.scrollToHighlightedItem = _this.scrollToHighlightedItem.bind(_this); _this.handleKeyDown = _this.handleKeyDown.bind(_this); _this.handleKeyUp = _this.handleKeyUp.bind(_this); _this.handleMouseEnterItem = _this.handleMouseEnterItem.bind(_this); _this.getStyles = _this.getStyles.bind(_this); return _this; } _createClass(List, [{ key: 'componentDidMount', value: function componentDidMount() { this.scrollToHighlightedItem(); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (this.props.highlightedIndex !== nextProps.highlightedIndex || this.props.ui.highlightedIndex !== nextProps.ui.highlightedIndex) { this.scrollToHighlightedItem(); } } }, { key: 'getChildProps', value: function getChildProps(child, index) { if (child.type.displayName === 'ListItem') { var _props = this.props, highlightBackgroundColor = _props.highlightBackgroundColor, highlightColor = _props.highlightColor; var highlightedIndex = this.getCurrentIndex(); return { highlightBackgroundColor: highlightBackgroundColor, highlightColor: highlightColor, highlighted: index === highlightedIndex, key: index, onMouseEnter: this.handleMouseEnterItem(index) }; } return { key: index }; } }, { key: 'getCurrentIndex', value: function getCurrentIndex() { return this.props.ui.highlightedIndex || this.props.highlightedIndex || noSelectedItemIndex; } }, { key: 'getNextListItemIndex', value: function getNextListItemIndex() { var nextIndex = this.getCurrentIndex() + selectedItemIndexIncrement; while (nextIndex < this.props.children.length && this.props.children[nextIndex].type.displayName !== 'ListItem') { nextIndex += selectedItemIndexIncrement; } return Math.min(this.props.children.length - selectedItemIndexIncrement, nextIndex); } }, { key: 'getPreviousListItemIndex', value: function getPreviousListItemIndex() { var previousIndex = this.getCurrentIndex() - selectedItemIndexIncrement; while (previousIndex >= lowestSelectedItemIndex && this.props.children[previousIndex].type.displayName !== 'ListItem') { previousIndex -= selectedItemIndexIncrement; } return Math.max(selectedItemIndexIncrement, previousIndex); } }, { key: 'highlightItem', value: function highlightItem(evt, index) { var keyboardTriggered = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; this.props.updateUI({ highlightedIndex: index, keyboardTriggered: keyboardTriggered }); this.props.onHighlightItem(evt, index); } }, { key: 'scrollToHighlightedItem', value: function scrollToHighlightedItem() { var ui = this.props.ui; if (!ui.keyboardTriggered) { return; } var highlightedIndex = this.getCurrentIndex(); var highlightedEl = this.listItemEls[highlightedIndex]; if (!highlightedEl) { return; } (0, _scrollIntoView2.default)(highlightedEl); } }, { key: 'handleKeyDown', value: function handleKeyDown(evt) { var active = this.props.active; if (!active) { return null; } if (evt.keyCode === _KeyCodes.ArrowUp) { return this.highlightItem(evt, this.getPreviousListItemIndex(), true); } else if (evt.keyCode === _KeyCodes.ArrowDown) { return this.highlightItem(evt, this.getNextListItemIndex(), true); } return null; } }, { key: 'handleKeyUp', value: function handleKeyUp(evt) { var _props2 = this.props, active = _props2.active, onSelectItem = _props2.onSelectItem; if (!active) { return null; } if (evt.keyCode === _KeyCodes.Enter) { return onSelectItem(evt, this.getCurrentIndex(this.props)); } return null; } }, { key: 'handleMouseEnterItem', value: function handleMouseEnterItem(index) { var _this2 = this; return function (evt) { return _this2.highlightItem(evt, index); }; } }, { key: 'getStyles', value: function getStyles() { var maxHeight = this.props.maxHeight; var theme = this.context.theme; return { list: { backgroundColor: 'white', fontFamily: theme.basicFontFamily, fontSize: theme.smallFontSize, maxHeight: Boolean(maxHeight) && maxHeight + 'px', overflow: 'auto' } }; } }, { key: 'render', value: function render() { var _this3 = this; var _props3 = this.props, children = _props3.children, onMouseEnter = _props3.onMouseEnter, onMouseLeave = _props3.onMouseLeave, onSelectItem = _props3.onSelectItem; var styles = this.getStyles(); return _react2.default.createElement( 'div', { style: styles.list, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave }, _react2.default.createElement(_reactEventListener2.default, { target: 'window', onKeyDown: this.handleKeyDown, onKeyUp: this.handleKeyUp }), _react2.default.Children.map(children, function (child, index) { return Boolean(child) && _react2.default.createElement( 'div', { ref: function ref(el) { _this3.listItemEls[index] = el; }, onClick: (0, _component.createConditionalEventHandler)(child.type.displayName === 'ListItem')(onSelectItem, index) }, _react2.default.cloneElement(child, _this3.getChildProps(child, index)) ); }) ); } }]); return List; }(_react.Component); process.env.NODE_ENV !== "production" ? List.propTypes = { /** * Indicates List should respond to keyup events */ active: _react.PropTypes.bool, /** * ListItem or SubHeader components. */ children: CustomPropTypes.oneOfComponentType([_ListItem2.default, _SubHeader2.default]), /** * Background color used when list item is highlighted */ highlightBackgroundColor: _react.PropTypes.string, /** * Font color used on when list item is highlighted */ highlightColor: _react.PropTypes.string, /** * Index of the currently highlighted list item */ highlightedIndex: _react.PropTypes.number, /** * Maximum height of the list before a scroll bar */ maxHeight: _react.PropTypes.number, /** * Callback fired when an item is highlighted */ onHighlightItem: _react.PropTypes.func, /** * Callback fired when mouse enters List */ onMouseEnter: _react.PropTypes.func, /** * Callback fired when mouse leaves list */ onMouseLeave: _react.PropTypes.func, /** * Callback fired when an item is selected */ onSelectItem: _react.PropTypes.func, /** * Managed UI state props; can be overridden */ ui: _react.PropTypes.shape({ highlightedIndex: _react.PropTypes.number, keyboardTriggered: _react.PropTypes.bool }), /** * Callback fired when a ui prop related action is dispatched */ updateUI: _react.PropTypes.func } : void 0; List.defaultProps = { active: false, highlightBackgroundColor: '#262626', highlightColor: '#fff', onHighlightItem: function onHighlightItem() {}, onMouseEnter: function onMouseEnter() {}, onMouseLeave: function onMouseLeave() {}, onSelectItem: function onSelectItem() {}, updateUI: function updateUI() {} }; List.contextTypes = { theme: _react.PropTypes.object.isRequired }; List.displayName = 'List'; exports.default = (0, _Radium2.default)((0, _reduxUi2.default)({ state: { highlightedIndex: null, keyboardTriggered: false } })(List));