UNPKG

calcite-react

Version:
694 lines (571 loc) 29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _reactDom = _interopRequireDefault(require("react-dom")); var _propTypes = _interopRequireDefault(require("prop-types")); var _downshift = _interopRequireDefault(require("downshift")); var _memoizeOne = _interopRequireDefault(require("memoize-one")); var _reactVirtualized = require("react-virtualized"); var _reactPopper = require("react-popper"); var _matchSorter = _interopRequireDefault(require("match-sorter")); var _helpers = require("../utils/helpers"); var _SelectStyled = require("./Select-styled"); var _SelectMenu = _interopRequireDefault(require("./SelectMenu")); var _FormControl = require("../Form/FormControl"); var _Popover = require("../Popover/Popover"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 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)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } function _typeof(obj) { 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); } 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 _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } 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 _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 _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 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 _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 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; } var Select = /*#__PURE__*/ function (_Component) { _inherits(Select, _Component); function Select() { var _getPrototypeOf2; var _this; _classCallCheck(this, Select); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Select)).call.apply(_getPrototypeOf2, [this].concat(args))); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getAnchorElement", function (_ref) { var ref = _ref.ref, getToggleButtonProps = _ref.getToggleButtonProps, getInputProps = _ref.getInputProps, openMenu = _ref.openMenu, highlightedIndex = _ref.highlightedIndex, selectHighlightedItem = _ref.selectHighlightedItem, inputValue = _ref.inputValue, getItemProps = _ref.getItemProps, menuHeight = _ref.menuHeight, selectedItem = _ref.selectedItem, other = _objectWithoutProperties(_ref, ["ref", "getToggleButtonProps", "getInputProps", "openMenu", "highlightedIndex", "selectHighlightedItem", "inputValue", "getItemProps", "menuHeight", "selectedItem"]); var _this$props = _this.props, renderValue = _this$props.renderValue, filterable = _this$props.filterable, autoSelect = _this$props.autoSelect, fullWidth = _this$props.fullWidth, minimal = _this$props.minimal, style = _this$props.style, id = _this$props.id, placeholder = _this$props.placeholder, disabled = _this$props.disabled, field = _this$props.field, form = _this$props.form; var onKeyDown = function onKeyDown(event) { if (!event) return; if (event.key === 'Enter') { if (filterable) { event.preventDefault(); } } else if (event.key === ' ') { if (filterable && autoSelect) return; if (highlightedIndex === null) { openMenu(); } else { event.nativeEvent.preventDefault(); // Avoids an extra space after value selectHighlightedItem(); } } }; if (filterable) { return _react.default.createElement(_FormControl.FormControlContext.Consumer, null, function (formControlContext) { return _react.default.createElement(_SelectStyled.StyledSelectInput, _extends({ as: "input", onClick: function onClick(e) { e.target.select(0, e.target.value.length); getToggleButtonProps().onClick(e); }, success: _this.isSuccess({ formControlContext: formControlContext, field: field, form: form }), error: _this.isError({ formControlContext: formControlContext, field: field, form: form }), disabled: _this.isDisabled({ field: field, form: form, disabled: disabled }) }, getInputProps(_objectSpread({ placeholder: placeholder, id: id || formControlContext._generatedId, fullWidth: fullWidth, minimal: minimal, style: style, onKeyDown: onKeyDown, onBlur: _this.handleBlur }, other)), { ref: ref })); }); } return _react.default.createElement(_FormControl.FormControlContext.Consumer, null, function (formControlContext) { return _react.default.createElement(_SelectStyled.StyledSelectButton, _extends({}, getToggleButtonProps(), getInputProps({ onKeyDown: onKeyDown, onBlur: _this.handleBlur }), { as: "button", fullWidth: fullWidth, minimal: minimal, ref: ref, id: id || formControlContext._generatedId, style: style, success: _this.isSuccess({ formControlContext: formControlContext, field: field, form: form }), error: _this.isError({ formControlContext: formControlContext, field: field, form: form }), disabled: _this.isDisabled({ field: field, form: form, disabled: disabled }) }, other), _this.downshiftRenderValue({ selectedItem: selectedItem, renderValue: renderValue }) ? _this.downshiftRenderValue({ selectedItem: selectedItem, renderValue: renderValue }) : placeholder); }); }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "downshiftRenderValue", function (_ref2) { var selectedItem = _ref2.selectedItem, renderValue = _ref2.renderValue; if (renderValue) return renderValue(selectedItem); return _this.itemToString(selectedItem); }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "itemToString", function (item) { var label = item; if (item && item.props) { label = item.props.label || item.props.children || item; } return label; }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "downshiftOnChange", function (params) { var selectedItem = params.selectedItem, field = params.field, form = params.form, onChange = params.onChange; // Ignore onChange if not item was selected (e.g. escape key) if (!selectedItem) return; var name, touched, setTouched, setFieldValue; if (field) { name = field.name; touched = form.touched; setTouched = form.setTouched; setFieldValue = form.setFieldValue; } var value = selectedItem.props.value; if (setFieldValue) { setTouched(_objectSpread({}, touched, _defineProperty({}, name, true))); setFieldValue(name, value); } onChange(value, selectedItem); }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "_getItemFromValue", function (children, value) { if (value === null || value === undefined) return null; return _react.Children.toArray(children).filter(function (child) { return child.props.value === value; })[0] || null; }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleBlur", function (e) { var _this$props2 = _this.props, onBlur = _this$props2.onBlur, field = _this$props2.field, autoSelect = _this$props2.autoSelect; // Ignore field blur if autoSelect // Blur behavior is handled by downshift stateReducer if (!autoSelect && field) { field.onBlur(e); } onBlur(e); }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getMenuItems", function (filteredList, virtualized, params) { var getItemProps = params.getItemProps, highlightedIndex = params.highlightedIndex, selectedItem = params.selectedItem, menuHeight = params.menuHeight, virtualizedRowHeight = params.virtualizedRowHeight, virtualizedMenuWidth = params.virtualizedMenuWidth; if (virtualized) { return _react.default.createElement(_reactVirtualized.List, { width: virtualizedMenuWidth || 9999, autoWidth: !virtualizedMenuWidth, scrollToIndex: highlightedIndex || 0, scrollToAlignment: "auto", height: filteredList.length < 7 ? filteredList.length * virtualizedRowHeight : menuHeight, rowCount: filteredList.length, rowHeight: virtualizedRowHeight, rowRenderer: function rowRenderer(_ref3) { var index = _ref3.index, rowRenderStyle = _ref3.style; return _this.getMenuItem(filteredList[index], { getItemProps: getItemProps, highlightedIndex: highlightedIndex, index: index, selectedItem: selectedItem, rowRenderStyle: rowRenderStyle }); }, style: { direction: document && document.documentElement.dir || 'ltr' } }); } return filteredList.map(function (item, index) { return _this.getMenuItem(item, { getItemProps: getItemProps, highlightedIndex: highlightedIndex, index: index, selectedItem: selectedItem }); }); }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getMenuItem", function (item, params) { var _params$getItemProps = params.getItemProps, getItemProps = _params$getItemProps === void 0 ? function (props) { return props; } : _params$getItemProps, highlightedIndex = params.highlightedIndex, index = params.index, selectedItem = params.selectedItem, rowRenderStyle = params.rowRenderStyle; return _react.default.cloneElement(item, _objectSpread({}, getItemProps({ style: _objectSpread({}, item.props.style, rowRenderStyle), item: item, index: index, active: highlightedIndex === index, selected: selectedItem && selectedItem.props.value === item.props.value, key: item.props.value }))); }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "filterItems", (0, _memoizeOne.default)(function (items, inputValue, filterable, selectedItem) { var inputMatchesSelection = inputValue === _this.itemToString(selectedItem); if (filterable && inputValue && !inputMatchesSelection) { return (0, _matchSorter.default)(items || _this.state.items, inputValue, { keys: ['props.children', 'props.value'] }); } return items; })); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getFullWidthStyle", function (fullWidth) { if (fullWidth) { return { minWidth: '100%' }; } }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getSelectedValue", function (field, selectedValue) { return field ? field.value : selectedValue; }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "isSuccess", function (params) { var formControlContext = params.formControlContext, field = params.field, form = params.form; var name, touched, errors; if (field) { name = field.name; touched = form.touched; errors = form.errors; } if (touched) { return touched[name] && !errors[name] ? true : false; } return formControlContext.success; }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "isError", function (params) { var formControlContext = params.formControlContext, field = params.field, form = params.form; var name, touched, errors; if (field) { name = field.name; touched = form.touched; errors = form.errors; } if (touched) { return touched[name] && errors[name] ? true : false; } return formControlContext.error; }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "isDisabled", function (params) { var field = params.field, form = params.form, disabled = params.disabled; var isSubmitting; if (field) { isSubmitting = form.isSubmitting; } return isSubmitting || disabled; }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "_getPopper", function (params) { var popper = params.popper, isOpen = params.isOpen, isInPopover = params.isInPopover, appendToBody = params.appendToBody; if (isOpen || isInPopover) { if (appendToBody) { return _reactDom.default.createPortal(popper, document.body); } return popper; } }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getItemIndexFromChildren", function (value) { var children = _this.props.children; return children.findIndex(function (child) { return child.props.value === value; }); }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "stateReducer", function (state, changes) { if (!_this.props.autoSelect) { return changes; } var children = _this.props.children; var selectedItemIndex; switch (changes.type) { case _downshift.default.stateChangeTypes.mouseUp: case _downshift.default.stateChangeTypes.blurInput: case _downshift.default.stateChangeTypes.blurButton: // Assumes they already collapsed the select and are now // navigating away, we shouldnt change the selection here if (!state.isOpen) { return changes; } // Get the item list so we can find the item at the highlitedIndex var _this$props3 = _this.props, filterable = _this$props3.filterable, virtualizedRowHeight = _this$props3.virtualizedRowHeight, virtualizedMenuWidth = _this$props3.virtualizedMenuWidth, menuHeight = _this$props3.menuHeight; var filteredItems = _this.filterItems(children, state.inputValue, filterable, state.selectedItem); var items = _this.getMenuItems(filteredItems, false, { highlightedIndex: state.highlightedIndex, menuHeight: menuHeight, virtualizedRowHeight: virtualizedRowHeight, virtualizedMenuWidth: virtualizedMenuWidth }); var selectedItem = items[state.highlightedIndex]; selectedItemIndex = selectedItem && _this.getItemIndexFromChildren(selectedItem.props.value); // Set the new selectedItem return _objectSpread({}, changes, { highlightedIndex: selectedItemIndex, selectedItem: selectedItem }); case _downshift.default.stateChangeTypes.changeInput: return _objectSpread({}, changes, { highlightedIndex: 0 }); case _downshift.default.stateChangeTypes.clickItem: case _downshift.default.stateChangeTypes.keyDownEnter: selectedItemIndex = changes.selectedItem && _this.getItemIndexFromChildren(changes.selectedItem.props.value); return _objectSpread({}, changes, { highlightedIndex: selectedItemIndex || changes.highlightedIndex }); default: return changes; } }); return _this; } _createClass(Select, [{ key: "render", value: function render() { var _this2 = this; var _this$props4 = this.props, children = _this$props4.children, filterable = _this$props4.filterable, virtualized = _this$props4.virtualized, fullWidth = _this$props4.fullWidth, minimal = _this$props4.minimal, style = _this$props4.style, id = _this$props4.id, placeholder = _this$props4.placeholder, selectedItem = _this$props4.selectedItem, selectedValue = _this$props4.selectedValue, menuStyle = _this$props4.menuStyle, wrapperStyle = _this$props4.wrapperStyle, horizontal = _this$props4.horizontal, label = _this$props4.label, _onChange = _this$props4.onChange, positionFixed = _this$props4.positionFixed, appendToBody = _this$props4.appendToBody, disabled = _this$props4.disabled, onBlur = _this$props4.onBlur, field = _this$props4.field, form = _this$props4.form, virtualizedRowHeight = _this$props4.virtualizedRowHeight, virtualizedMenuWidth = _this$props4.virtualizedMenuWidth, autoSelect = _this$props4.autoSelect, popperModifiers = _this$props4.popperModifiers, other = _objectWithoutProperties(_this$props4, ["children", "filterable", "virtualized", "fullWidth", "minimal", "style", "id", "placeholder", "selectedItem", "selectedValue", "menuStyle", "wrapperStyle", "horizontal", "label", "onChange", "positionFixed", "appendToBody", "disabled", "onBlur", "field", "form", "virtualizedRowHeight", "virtualizedMenuWidth", "autoSelect", "popperModifiers"]); var menuHeight = menuStyle && parseInt(menuStyle.height, 10) || menuStyle && parseInt(menuStyle.maxHeight, 10) || 300; // The selectedItem or the item with the same value as selectedValue var selectedMenuItem = selectedItem || this._getItemFromValue(children, this.getSelectedValue(field, selectedValue)); var defaultHighlightedIndex = undefined; if (autoSelect) { if (selectedMenuItem) { defaultHighlightedIndex = this.getItemIndexFromChildren(selectedMenuItem.props.value); } else { defaultHighlightedIndex = 0; } } return _react.default.createElement(_reactPopper.Manager, { style: _objectSpread({}, _SelectStyled.PopperManagerStyles, wrapperStyle) }, _react.default.createElement(_downshift.default, { itemToString: this.itemToString, onChange: function onChange(selection) { _this2.downshiftOnChange({ selectedItem: selection, field: field, form: form, onChange: _onChange }); }, selectedItem: selectedMenuItem, stateReducer: this.stateReducer, defaultHighlightedIndex: defaultHighlightedIndex }, function (_ref4) { var getRootProps = _ref4.getRootProps, getToggleButtonProps = _ref4.getToggleButtonProps, getInputProps = _ref4.getInputProps, getItemProps = _ref4.getItemProps, isOpen = _ref4.isOpen, openMenu = _ref4.openMenu, selectHighlightedItem = _ref4.selectHighlightedItem, selectedItem = _ref4.selectedItem, highlightedIndex = _ref4.highlightedIndex, inputValue = _ref4.inputValue; var filteredList = _this2.filterItems(children, inputValue, filterable, selectedItem); return _react.default.createElement(_SelectStyled.StyledSelectWrapper, _extends({ fullWidth: fullWidth }, getRootProps({}, { suppressRefError: true })), _react.default.createElement(_reactPopper.Reference, { style: { display: 'inline-block' } }, function (_ref5) { var ref = _ref5.ref; return _this2.getAnchorElement(_objectSpread({ ref: ref, getToggleButtonProps: getToggleButtonProps, getInputProps: getInputProps, openMenu: openMenu, highlightedIndex: highlightedIndex, selectHighlightedItem: selectHighlightedItem, inputValue: inputValue, getItemProps: getItemProps, menuHeight: menuHeight, selectedItem: selectedItem }, other)); }), _react.default.createElement(_Popover.PopoverContext.Consumer, null, function (popoverContext) { return _this2._getPopper({ popper: _react.default.createElement(_reactPopper.Popper, { positionFixed: positionFixed, placement: (0, _helpers.rtlPlacement)(other.placement), modifiers: _objectSpread({ preventOverflow: { boundariesElement: positionFixed || appendToBody ? 'window' : 'scrollParent' } }, popperModifiers) }, function (_ref6) { var ref = _ref6.ref, popperStyle = _ref6.style, placement = _ref6.placement, scheduleUpdate = _ref6.scheduleUpdate; return _react.default.createElement(_SelectMenu.default, { innerRef: ref, style: _objectSpread({}, popperStyle, _this2.getFullWidthStyle(), menuStyle), isOpen: isOpen, "data-placement": placement, fullWidth: fullWidth, scheduleUpdate: scheduleUpdate }, _this2.getMenuItems(filteredList, virtualized, { highlightedIndex: highlightedIndex, menuHeight: menuHeight, virtualizedRowHeight: virtualizedRowHeight, virtualizedMenuWidth: virtualizedMenuWidth, getItemProps: getItemProps, selectedItem: selectedItem })); }), isOpen: isOpen, popoverContext: popoverContext.isInPopover, appendToBody: appendToBody }); })); })); } }]); return Select; }(_react.Component); Select.propTypes = { /** Nodes to be used as options in the Select. */ children: _propTypes.default.node, /** Toggle the Select to use an input and allow filtering of the items. */ filterable: _propTypes.default.bool, /** The highlighted item will be automatically selected on blur. */ autoSelect: _propTypes.default.bool, /** Use react-virtualized to render rows as the user scrolls. */ virtualized: _propTypes.default.bool, /** Callback function fired when the value of the Select changes. */ onChange: _propTypes.default.func, /** The selected item of the Select. */ selectedItem: _propTypes.default.node, /** Value of the selected item. */ selectedValue: _propTypes.default.any, /** Function to run when determining how to display selected values in a collapsed Select. */ renderValue: _propTypes.default.func, /** Placeholder text for the input. */ placeholder: _propTypes.default.string, /** Whether or not the Select will fill its container's width. */ fullWidth: _propTypes.default.bool, /** A style variant for Select inputs. */ minimal: _propTypes.default.bool, /** HTML prop for the Select; works together with a label's `for` prop. */ id: _propTypes.default.string, /** Style prop applied to the menu wrapper. */ menuStyle: _propTypes.default.object, /** Uses `position: fixed` on the tooltip, allowing it to show up outside of containers that have `overflow: hidden`. */ positionFixed: _propTypes.default.bool, /** Specify where the menu should appear in relation to the Select element. */ placement: _propTypes.default.oneOf(['auto', 'top', 'top-start', 'top-end', 'right', 'right-start', 'right-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end']), /** (virtualized only) Row height used to calculate how many rows to render in a virtualized menu. */ virtualizedRowHeight: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.func]), /** (virtualized only) Width of the menu; unloaded rows may be wider than the initial set. */ virtualizedMenuWidth: _propTypes.default.number, /** Modifiers to be passed to the Popper element */ popperModifiers: _propTypes.default.object }; Select.defaultProps = { placeholder: 'Select...', placement: 'bottom-start', virtualizedRowHeight: 42, onChange: function onChange() {}, onBlur: function onBlur() {} }; Select.displayName = 'Select'; var _default = Select; exports.default = _default;