UNPKG

lucid-ui

Version:

A UI component library from AppNexus.

701 lines (584 loc) 29.5 kB
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } import _every from "lodash/every"; import _assign from "lodash/assign"; import _keys from "lodash/keys"; import _includes from "lodash/includes"; import _findIndex from "lodash/findIndex"; import _findLastIndex from "lodash/findLastIndex"; import _isEmpty from "lodash/isEmpty"; import _isNumber from "lodash/isNumber"; import _first from "lodash/first"; import _isNull from "lodash/isNull"; import _isNil from "lodash/isNil"; import _get from "lodash/get"; import _concat from "lodash/concat"; import _groupBy from "lodash/groupBy"; import _map from "lodash/map"; import _noop from "lodash/noop"; import _size from "lodash/size"; import _reduce from "lodash/reduce"; function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import React from 'react'; import PropTypes from 'react-peek/prop-types'; import { lucidClassNames, uniqueName } from '../../util/style-helpers'; import { getFirst, rejectTypes, findTypes, omitProps } from '../../util/component-types'; import { scrollParentTo } from '../../util/dom-helpers'; import { buildModernHybridComponent } from '../../util/state-management'; import * as KEYCODE from '../../constants/key-code'; import * as reducers from './DropMenu.reducers'; import ContextMenu from '../ContextMenu/ContextMenu'; function joinArray(array, getSeparator) { return _reduce(array, function (newArray, element, index) { newArray.push(element); if (index < _size(array) - 1) { newArray.push(getSeparator(element, index, array)); } return newArray; }, []); } function isOptionVisible(option) { return !option.optionProps.isHidden; } var cx = lucidClassNames.bind('&-DropMenu'); var any = PropTypes.any, arrayOf = PropTypes.arrayOf, bool = PropTypes.bool, func = PropTypes.func, node = PropTypes.node, number = PropTypes.number, object = PropTypes.object, oneOf = PropTypes.oneOf, string = PropTypes.string; var Header = function Header(_props) { return null; }; Header.displayName = 'DropMenu.Header'; Header.peek = { description: "\n\t\tAn optional header to be displayed within the expanded Flyout,\n\t\tabove all `Option`s.\n\t" }; Header.propName = 'Header'; Header.propTypes = {}; var Control = function Control(_props) { return null; }; Control.displayName = 'DropMenu.Control'; Control.peek = { description: "\n\t\tRenders a `<div>` that acts as the control target which the\n\t\tflyout menu is anchored to. Only one `Control` is used.\n\t" }; Control.propName = 'Control'; Control.propTypes = {}; var OptionGroup = function OptionGroup(_props) { return null; }; OptionGroup.displayName = 'DropMenu.OptionGroup'; OptionGroup.peek = { description: "\n\t\tA special kind of `Option` that is always rendered at the top of\n\t\tthe menu and has an `optionIndex` of `null`. Useful for\n\t\tunselect.\n\t" }; OptionGroup.propName = 'OptionGroup'; OptionGroup.propTypes = { isHidden: bool }; OptionGroup.defaultProps = { isHidden: false }; var Option = function Option(_props) { return null; }; Option.displayName = 'DropMenu.Option'; Option.peek = { description: "\n\t\tRenders a `<div>` that acts as an option in the menu.\n\t" }; Option.propName = 'Option'; Option.propTypes = { isDisabled: bool, isHidden: bool, isWrapped: bool }; Option.defaultProps = { isDisabled: false, isHidden: false, isWrapped: true }; var NullOption = function NullOption(_props) { return null; }; NullOption.displayName = 'DropMenu.NullOption'; NullOption.peek = { description: "\n\t\tA special kind of `Option` that is always rendered at the top of\n\t\tthe menu and has an `optionIndex` of `null` used for\n\t\tdeselecting.\n\t" }; NullOption.propName = 'NullOption'; NullOption.propTypes = {}; var FixedOption = function FixedOption(_props) { return null; }; FixedOption.displayName = 'DropMenu.FixedOption'; FixedOption.peek = { description: "\n\t\tA special kind of `Option` that is always rendered at the top of\n\t\tthe menu.\n\t" }; FixedOption.propName = 'FixedOption'; FixedOption.propTypes = { isDisabled: bool, isHidden: bool, isWrapped: bool }; FixedOption.defaultProps = { isDisabled: false, isHidden: false, isWrapped: true }; var DropMenuContextMenu = function DropMenuContextMenu(_props) { return null; }; DropMenuContextMenu.displayName = 'DropMenu.ContextMenu'; DropMenuContextMenu.peek = { description: "\n\t\tProps that are passed through to the underlying ContextMenu.\n\t" }; DropMenuContextMenu.propName = 'ContextMenu'; DropMenuContextMenu.propTypes = { children: node }; var DropMenu = /*#__PURE__*/function (_React$Component) { _inherits(DropMenu, _React$Component); var _super = _createSuper(DropMenu); function DropMenu(_props2) { var _this; _classCallCheck(this, DropMenu); _this = _super.call(this, _props2); _defineProperty(_assertThisInitialized(_this), "_header", void 0); _defineProperty(_assertThisInitialized(_this), "getPreprocessedOptionData", function (props) { return DropMenu.preprocessOptionData(props, DropMenu); }); _defineProperty(_assertThisInitialized(_this), "handleKeydown", function (event) { var _assertThisInitialize = _assertThisInitialized(_this), props = _assertThisInitialize.props, _assertThisInitialize2 = _assertThisInitialize.props, isExpanded = _assertThisInitialize2.isExpanded, focusedIndex = _assertThisInitialize2.focusedIndex, onExpand = _assertThisInitialize2.onExpand, onCollapse = _assertThisInitialize2.onCollapse, onSelect = _assertThisInitialize2.onSelect, onFocusOption = _assertThisInitialize2.onFocusOption; var _this$state = _this.state, flattenedOptionsData = _this$state.flattenedOptionsData, nullOptions = _this$state.nullOptions; _this.setState({ isMouseTriggered: false }); if (isExpanded) { if (event.keyCode === KEYCODE.Enter) { event.preventDefault(); var focusedOptionData = _get(flattenedOptionsData, _isNil(focusedIndex) ? '' : focusedIndex, null); var focusedOptionProps = _get(focusedOptionData, 'optionProps', Option.defaultProps); if (focusedOptionData && !focusedOptionProps.isDisabled) { onSelect && onSelect(focusedIndex, { props: focusedOptionProps, event: event }); } else if (_isNull(focusedIndex)) { onSelect && onSelect(null, { props: _first(nullOptions), event: event }); } } if (event.keyCode === KEYCODE.Escape) { event.preventDefault(); onCollapse && onCollapse({ props: props, event: event }); } if (event.keyCode === KEYCODE.ArrowUp) { if (_isNumber(focusedIndex) || _isNull(focusedIndex)) { if (focusedIndex === 0) { if (!_isEmpty(nullOptions)) { event.preventDefault(); onFocusOption && onFocusOption(null, { props: props, event: event }); } } if (!_isNil(focusedIndex) && focusedIndex > 0) { event.preventDefault(); onFocusOption && onFocusOption(_findLastIndex(flattenedOptionsData, isOptionVisible, focusedIndex - 1), { props: props, event: event }); } } else { event.preventDefault(); focusedIndex && onFocusOption && onFocusOption(_findLastIndex(flattenedOptionsData, isOptionVisible, focusedIndex - 1), { props: props, event: event }); } } if (event.keyCode === KEYCODE.ArrowDown) { if (_isNumber(focusedIndex)) { if (focusedIndex < _size(flattenedOptionsData) - 1) { event.preventDefault(); onFocusOption && onFocusOption(_findIndex(flattenedOptionsData, isOptionVisible, focusedIndex + 1), { props: props, event: event }); } } else { event.preventDefault(); onFocusOption && onFocusOption(_findIndex(flattenedOptionsData, isOptionVisible, !_isNil(focusedIndex) ? focusedIndex : undefined), { props: props, event: event }); } } } else { if (event.keyCode === KEYCODE.ArrowDown) { event.preventDefault(); onExpand && onExpand({ props: props, event: event }); } } }); _defineProperty(_assertThisInitialized(_this), "handleClick", function (event) { var _assertThisInitialize3 = _assertThisInitialized(_this), props = _assertThisInitialize3.props, _assertThisInitialize4 = _assertThisInitialize3.props, isExpanded = _assertThisInitialize4.isExpanded, onExpand = _assertThisInitialize4.onExpand, onCollapse = _assertThisInitialize4.onCollapse; if (isExpanded) { onCollapse && onCollapse({ props: props, event: event }); } else { onExpand && onExpand({ props: props, event: event }); } }); _defineProperty(_assertThisInitialized(_this), "handleMouseFocusOption", function (optionIndex, optionProps, event) { var _this$props = _this.props, focusedIndex = _this$props.focusedIndex, onFocusOption = _this$props.onFocusOption; _this.setState({ isMouseTriggered: true }); if (!optionProps.isDisabled && focusedIndex !== optionIndex) { onFocusOption && onFocusOption(optionIndex, { props: _this.props, event: event }); } }); _defineProperty(_assertThisInitialized(_this), "handleSelectOption", function (optionIndex, optionProps, event) { var onSelect = _this.props.onSelect; if (!optionProps.isDisabled) { onSelect && onSelect(optionIndex, { props: optionProps, event: event }); } }); _defineProperty(_assertThisInitialized(_this), "renderOption", function (optionProps, optionIndex) { var isGrouped = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var _this$props2 = _this.props, selectedIndices = _this$props2.selectedIndices, focusedIndex = _this$props2.focusedIndex; var isMouseTriggered = _this.state.isMouseTriggered; var isDisabled = optionProps.isDisabled, isHidden = optionProps.isHidden, isWrapped = optionProps.isWrapped; var isFocused = optionIndex === focusedIndex; var isSelected = _includes(selectedIndices, optionIndex); return isHidden ? null : /*#__PURE__*/React.createElement("div", _extends({ key: 'DropMenuOption' + optionIndex }, omitProps(optionProps, undefined, [].concat(_toConsumableArray(_keys(DropMenu.Option.propTypes)), ['Selection'])), { onClick: function onClick(event) { return _this.handleSelectOption(optionIndex, optionProps, event); }, onMouseMove: function onMouseMove(event) { return _this.handleMouseFocusOption(optionIndex, optionProps, event); }, className: cx('&-Option', { '&-Option-is-grouped': isGrouped, '&-Option-is-focused': isFocused, '&-Option-is-selected': isSelected, '&-Option-is-disabled': isDisabled, '&-Option-is-null': _isNull(optionIndex), '&-Option-is-wrapped': isWrapped }, optionProps.className), ref: function ref(optionHTMLElement) { if (isFocused && !isMouseTriggered) { scrollParentTo(optionHTMLElement, _this._header && _this._header.current ? _this._header.current.offsetHeight : undefined); } } })); }); _defineProperty(_assertThisInitialized(_this), "UNSAFE_componentWillReceiveProps", function (nextProps) { // only preprocess options data when it changes (via new props) - better performance than doing this each render _this.setState(_this.getPreprocessedOptionData(nextProps)); }); _this.state = _objectSpread({ optionGroups: [], flattenedOptionsData: [], ungroupedOptionData: [], optionGroupDataLookup: {}, nullOptions: [], fixedOptionData: [], isMouseTriggered: false, portalId: _this.props.portalId || uniqueName('DropMenu-Portal-'), isExpanded: false, focusedIndex: null, optionGroupIndex: null, optionProps: [], selectedIndices: [] }, _this.getPreprocessedOptionData(_props2)); _this._header = /*#__PURE__*/React.createRef(); return _this; } _createClass(DropMenu, [{ key: "render", value: function render() { var _this2 = this; var _this$props3 = this.props, className = _this$props3.className, style = _this$props3.style, isDisabled = _this$props3.isDisabled, isExpanded = _this$props3.isExpanded, direction = _this$props3.direction, alignment = _this$props3.alignment, onCollapse = _this$props3.onCollapse, flyOutStyle = _this$props3.flyOutStyle, optionContainerStyle = _this$props3.optionContainerStyle, passThroughs = _objectWithoutProperties(_this$props3, ["className", "style", "isDisabled", "isExpanded", "direction", "alignment", "onCollapse", "flyOutStyle", "optionContainerStyle"]); var _this$state2 = this.state, optionGroups = _this$state2.optionGroups, fixedOptionData = _this$state2.fixedOptionData, ungroupedOptionData = _this$state2.ungroupedOptionData, optionGroupDataLookup = _this$state2.optionGroupDataLookup, nullOptions = _this$state2.nullOptions, portalId = _this$state2.portalId; var contextMenuProps = _get(getFirst(this.props, DropMenu.ContextMenu), 'props', {}); var controlProps = _get(getFirst(this.props, DropMenu.Control), 'props', {}); var headerProps = _get(getFirst(this.props, DropMenu.Header), 'props', {}); return /*#__PURE__*/React.createElement("div", _extends({ className: cx('&', '&-base', { '&-is-expanded': isExpanded, '&-direction-down': isExpanded && direction === 'down', '&-direction-up': isExpanded && direction === 'up' }, className), style: style }, omitProps(passThroughs, undefined, _keys(DropMenu.propTypes))), /*#__PURE__*/React.createElement(ContextMenu, _extends({}, contextMenuProps, { portalId: portalId, isExpanded: isExpanded, direction: direction, alignment: alignment, onClickOut: onCollapse }), /*#__PURE__*/React.createElement(ContextMenu.Target, null, /*#__PURE__*/React.createElement("div", _extends({}, !isDisabled ? { tabIndex: 0, onClick: this.handleClick, onKeyDown: this.handleKeydown } : null, controlProps, { className: cx('&-Control', _get(controlProps, 'className')) }))), /*#__PURE__*/React.createElement(ContextMenu.FlyOut, { className: cx('&', className), style: flyOutStyle }, !_isEmpty(headerProps) && /*#__PURE__*/React.createElement("div", _extends({}, headerProps, { className: cx('&-Header', headerProps.className), onKeyDown: this.handleKeydown, ref: this._header })), /*#__PURE__*/React.createElement("div", { className: cx('&-option-container'), style: _assign({}, flyOutStyle, optionContainerStyle) }, _map(nullOptions, function (optionProps) { return _this2.renderOption(optionProps, null); }).concat(_isEmpty(nullOptions) ? [] : [/*#__PURE__*/React.createElement("div", { key: 'OptionGroup-divider-NullOption', className: cx('&-OptionGroup-divider') })]), // fixed options go first _map(fixedOptionData, function (_ref) { var optionProps = _ref.optionProps, optionIndex = _ref.optionIndex; return _this2.renderOption(optionProps, optionIndex); }), joinArray( // for each option group, _map(optionGroups, function (optionGroupProps, optionGroupIndex) { var groupedOptions = optionGroupDataLookup[optionGroupIndex]; if (optionGroupProps.isHidden || _every(groupedOptions, { optionProps: { isHidden: true } })) { return null; } var labelElements = rejectTypes(optionGroupProps.children, [DropMenu.Control, DropMenu.OptionGroup, DropMenu.Option, DropMenu.NullOption]); // render label if there is one return (_isEmpty(labelElements) ? [] : [/*#__PURE__*/React.createElement("div", _extends({}, omitProps(optionGroupProps, undefined, _keys(DropMenu.OptionGroup.propTypes)), { key: 'OptionGroup-label' + optionGroupIndex, className: cx('&-label', optionGroupProps.className) }), labelElements) // render the options in the group ]).concat(_map(optionGroupDataLookup[optionGroupIndex], function (_ref2) { var optionProps = _ref2.optionProps, optionIndex = _ref2.optionIndex; return _this2.renderOption(optionProps, optionIndex, true); })); // append all ungrouped options as another unlabeled group }).concat(_isEmpty(ungroupedOptionData) ? [] : [_map(ungroupedOptionData, function (_ref3) { var optionProps = _ref3.optionProps, optionIndex = _ref3.optionIndex; return _this2.renderOption(optionProps, optionIndex); })]), function (element, index) { return element && /*#__PURE__*/React.createElement("div", { key: "OptionGroup-divider-".concat(index), className: cx('&-OptionGroup-divider') }); } // separate each group with divider ))))); } }]); return DropMenu; }(React.Component); _defineProperty(DropMenu, "displayName", 'DropMenu'); _defineProperty(DropMenu, "ContextMenu", DropMenuContextMenu); _defineProperty(DropMenu, "FixedOption", FixedOption); _defineProperty(DropMenu, "NullOption", NullOption); _defineProperty(DropMenu, "Option", Option); _defineProperty(DropMenu, "OptionGroup", OptionGroup); _defineProperty(DropMenu, "Control", Control); _defineProperty(DropMenu, "Header", Header); _defineProperty(DropMenu, "peek", { ContextMenu: DropMenuContextMenu, description: "\n\t\t\t\t`DropMenu` is a helper component used to render a menu of options attached to\n\t\t\t\tany control. Supports option groups with and without labels as well as\n\t\t\t\tspecial options with a `null` index for unselect.\n\t\t\t", categories: ['helpers'], madeFrom: ['ContextMenu'] }); _defineProperty(DropMenu, "reducers", reducers); _defineProperty(DropMenu, "propTypes", { children: node, className: string, style: object, isDisabled: bool, isExpanded: bool, direction: oneOf(['down', 'up']), alignment: oneOf(['start', 'center', 'end']), selectedIndices: arrayOf(number), focusedIndex: number, portalId: string, flyOutStyle: object, optionContainerStyle: object, onExpand: func, onCollapse: func, onSelect: func, onFocusNext: func, onFocusPrev: func, onFocusOption: func, Control: any, Option: any, OptionGroup: any, NullOption: any, Header: any, ContextMenu: any, FixedOption: any }); _defineProperty(DropMenu, "defaultProps", { isDisabled: false, isExpanded: false, direction: 'down', alignment: 'start', selectedIndices: [], focusedIndex: null, flyOutStyle: { maxHeight: '18em' }, onExpand: _noop, onCollapse: _noop, onSelect: _noop, onFocusNext: _noop, onFocusPrev: _noop, onFocusOption: _noop, portalId: '', optionContainerStyle: {}, ContextMenu: ContextMenu.defaultProps }); _defineProperty(DropMenu, "preprocessOptionData", function (props, ParentType) { var OptionGroup = ParentType.OptionGroup, Option = ParentType.Option, NullOption = ParentType.NullOption, FixedOption = ParentType.FixedOption; var optionGroups = _map(findTypes(props, OptionGroup), 'props'); // find all OptionGroup props var fixedOptions = _map(findTypes(props, FixedOption), 'props'); // find all FixedOption props var ungroupedOptions = _map(findTypes(props, Option), 'props'); // find all ungrouped Option props var nullOptions = NullOption ? _map(findTypes(props, NullOption), 'props') : []; // find all NullOption props var fixedOptionData = _map(fixedOptions, function (optionProps, localOptionIndex) { return { localOptionIndex: localOptionIndex, optionIndex: localOptionIndex, optionGroupIndex: null, // ungrouped options have no `optionGroupIndex` optionProps: optionProps }; }); // flatten grouped options into array of objects to associate { index, group index, and props } for each option var groupedOptionData = _reduce(optionGroups, function (memo, optionGroupProps, optionGroupIndex) { var groupedOptions = _map(findTypes(optionGroupProps, Option), 'props'); // find all Option props for current group return memo.concat(_map(groupedOptions, function (optionProps, localOptionIndex) { return { localOptionIndex: localOptionIndex, optionIndex: _size(memo) + _size(fixedOptionData) + localOptionIndex, // add current index to current array length to get final option index optionGroupIndex: optionGroupIndex, // store option group index to associate option back to group optionProps: _objectSpread({ isHidden: false }, optionProps) }; })); }, []); // create lookup object for options by their group index var optionGroupDataLookup = _groupBy(groupedOptionData, 'optionGroupIndex'); // store ungrouped options into array of objects to associate { index, and props } for each option var ungroupedOptionData = _map(ungroupedOptions, function (optionProps, localOptionIndex) { return { localOptionIndex: localOptionIndex, optionIndex: _size(groupedOptionData) + _size(fixedOptionData) + localOptionIndex, // add current index to grouped options array length to get final option index (grouped options rendered first) optionGroupIndex: null, // ungrouped options have no `optionGroupIndex` optionProps: _objectSpread({ isHidden: false }, optionProps) }; }); // concatenate grouped options array with ungrouped options array to get flat list of all options var flattenedOptionsData = _concat(fixedOptionData, groupedOptionData, ungroupedOptionData); return { optionGroups: optionGroups, optionGroupDataLookup: optionGroupDataLookup, fixedOptionData: fixedOptionData, ungroupedOptionData: ungroupedOptionData, flattenedOptionsData: flattenedOptionsData, nullOptions: nullOptions }; }); export default buildModernHybridComponent(DropMenu, { reducers: reducers }); export { DropMenu as DropMenuDumb, NullOption, OptionGroup };