UNPKG

@helpscout/hsds-react

Version:

React component library for Help Scout's Design System

388 lines (289 loc) 12.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = exports.Dropdown = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _wedux = require("@helpscout/wedux"); var _Dropdown = require("./Dropdown.store"); var _Dropdown2 = require("./Dropdown.actions"); var _EventListener = _interopRequireDefault(require("../EventListener")); var _Dropdown3 = _interopRequireDefault(require("./Dropdown.MenuContainer")); var _Dropdown4 = _interopRequireDefault(require("./Dropdown.Trigger")); var _VisuallyHidden = _interopRequireDefault(require("../VisuallyHidden")); var _DropdownCss = require("./Dropdown.css.js"); var _classnames = _interopRequireDefault(require("classnames")); var _Dropdown5 = require("./Dropdown.utils"); var _jsxRuntime = require("react/jsx-runtime"); // Deprecated /* istanbul ignore file */ function noop() {} var Dropdown = /*#__PURE__*/function (_React$PureComponent) { (0, _inheritsLoose2.default)(Dropdown, _React$PureComponent); function Dropdown() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _React$PureComponent.call.apply(_React$PureComponent, [this].concat(args)) || this; _this.node = void 0; _this.triggerNode = void 0; _this.menuNode = void 0; _this.handleOnDocumentBodyClick = function (event) { if (!event) return; if (!_this.menuNode) return; var targetNode = event.target; // When the component is displayed in an `iframe` (e.g. Beacon) we need // to do an instanceof check based on the `iframe`#Element class type, // using the `contentWindow` prop. https://stackoverflow.com/a/26251098 if (targetNode instanceof _this.props.contentWindow.Element) { if (_this.menuNode.contains(targetNode) || targetNode === _this.triggerNode) { return; } _this.closeMenu(); } }; _this.setNodeRef = function (node) { _this.node = node; _this.props.innerRef(node); }; _this.setMenuNodeRef = function (node) { _this.menuNode = node; _this.props.menuRef(node); // Internally, for store if (_this.props.getState().menuNode) return; _this.props.setMenuNode(node); }; _this.setTriggerNodeRef = function (node) { if (!node) return; _this.triggerNode = node; _this.props.triggerRef(node); // Internally, for store if (_this.props.getState().triggerNode === node) return; _this.props.setTriggerNode(node); }; return _this; } var _proto = Dropdown.prototype; _proto.closeMenu = function closeMenu() { if (!this.props.isOpen) return; // Store calls onClose() callback this.props.closeDropdown(); }; _proto.getTriggerProps = function getTriggerProps() { var _this2 = this; var _this$props = this.props, disabled = _this$props.disabled, onBlur = _this$props.onBlur, onFocus = _this$props.onFocus; return { disabled: disabled, onBlur: onBlur, onFocus: onFocus, triggerRef: function triggerRef(node) { return _this2.setTriggerNodeRef(node); } }; }; _proto.renderTrigger = function renderTrigger() { var _this$props2 = this.props, trigger = _this$props2.trigger, renderTrigger = _this$props2.renderTrigger; var triggerComponent = renderTrigger ? (0, _Dropdown5.renderRenderPropComponent)(renderTrigger) : trigger; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Dropdown4.default, (0, _extends2.default)({}, this.getTriggerProps(), { children: triggerComponent })); }; _proto.renderMenu = function renderMenu() { var _this$props3 = this.props, children = _this$props3.children, allowMultipleSelection = _this$props3.allowMultipleSelection; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Dropdown3.default, { children: children, menuRef: this.setMenuNodeRef, allowMultipleSelection: allowMultipleSelection }); }; _proto.renderAriaLive = function renderAriaLive() { var _this$props4 = this.props, id = _this$props4.id, label = _this$props4.label, isOpen = _this$props4.isOpen; var dropdownName = this.props['aria-label'] || label || id; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_VisuallyHidden.default, { "data-cy": "DropdownAriaLive", role: "region", "aria-live": "polite", children: isOpen ? dropdownName + " is opened" : dropdownName + " is closed" }); }; _proto.render = function render() { var _this$props5 = this.props, className = _this$props5.className, envNode = _this$props5.envNode, id = _this$props5.id, dataCy = _this$props5['data-cy']; var componentClassName = (0, _classnames.default)(className, 'c-Dropdown'); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_DropdownCss.DropdownUI, { className: componentClassName, ref: this.setNodeRef, id: id, "data-cy": dataCy, children: [this.renderAriaLive(), /*#__PURE__*/(0, _jsxRuntime.jsx)(_EventListener.default, { event: "click", handler: this.handleOnDocumentBodyClick, scope: envNode }), this.renderTrigger(), this.renderMenu()] }); }; return Dropdown; }(_react.default.PureComponent); exports.Dropdown = Dropdown; Dropdown.defaultProps = (0, _extends2.default)({}, _Dropdown.initialState, { allowMultipleSelection: false, contentWindow: window, 'data-cy': 'Dropdown', disabled: false, innerRef: noop, menuRef: noop, setMenuNode: noop, setTriggerNode: noop, triggerRef: noop }); Dropdown.propTypes = { /** Maximum height for the menu. */ maxHeight: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), /** Maximum width for the menu. */ maxWidth: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), /** Minimum height for the menu. */ minHeight: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), /** Minimum width for the menu. */ minWidth: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), /** Width for the menu. */ width: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), className: _propTypes.default.string, closeDropdown: _propTypes.default.func, enableLeftRightArrowNavigation: _propTypes.default.bool, getState: _propTypes.default.func, /** ClassName for an active item. */ activeClassName: _propTypes.default.string, /** Allows selection of multiple items from the dropdown (when stateful) */ allowMultipleSelection: _propTypes.default.bool, /** Customize the Dropdown Card border color. */ cardBorderColor: _propTypes.default.string, /** Render prop to customize the Dropdown contents. */ children: _propTypes.default.func, /** Removes selected item on select. */ clearOnSelect: _propTypes.default.bool, /** Closes Dropdown on select. */ closeOnSelect: _propTypes.default.bool, /** Custom window object (e.g. iframe window object) */ contentWindow: _propTypes.default.any, /** Preferred drop direction for the menu. */ direction: _propTypes.default.oneOf(['left', 'right', 'up', 'down']), /** Disable the dropdown trigger so it can't be clicked. */ disabled: _propTypes.default.bool, /** Changes the dropdown to drop upwards. */ dropUp: _propTypes.default.bool, /** Enables Tab keypresses to navigate through items. */ enableTabNavigation: _propTypes.default.bool, /** Node to bind global events. */ envNode: _propTypes.default.any, /** ClassName for a focused item. */ focusClassName: _propTypes.default.string, /** Forces the dropdown to always drop downwards. Overrides `dropUp`. */ forceDropDown: _propTypes.default.bool, /** Current selected item index. */ index: _propTypes.default.string, /** Used when constructing a filterable Dropdown. */ inputValue: _propTypes.default.string, /** ID of the component. */ id: _propTypes.default.string, /** Retrieves the Dropdown DOM node. */ innerRef: _propTypes.default.func, /** Items to render. */ items: _propTypes.default.arrayOf(_propTypes.default.any), /** Renders the loading UI. */ isLoading: _propTypes.default.bool, /** Focuses the selected item when the dropdown opens. */ isFocusSelectedItemOnOpen: _propTypes.default.bool, /** Selects the first item when the dropdown opens. */ isSelectFirstItemOnOpen: _propTypes.default.bool, /** Callback when the Trigger blurs. */ onBlur: _propTypes.default.func, /** Callback when the Trigger focuses. */ onFocus: _propTypes.default.func, /** Callback when the dropdown opens. */ onOpen: _propTypes.default.func, /** Callback when the dropdown closes. */ onClose: _propTypes.default.func, /** Callback when an item is selected/deselected. */ onSelect: _propTypes.default.func, /** Retrieves the Dropdown Menu DOM node. */ menuRef: _propTypes.default.func, /** ClassName for an open item (with a sub menu). */ openClassName: _propTypes.default.string, /** Renders menu as position `fixed`. Otherwise, it's `absolute`. */ positionFixed: _propTypes.default.bool, /** Callback to render the empty UI. */ renderEmpty: _propTypes.default.any, /** Callback to render the loading UI. */ renderLoading: _propTypes.default.any, /** Callback to customize how an item renders. */ renderItem: _propTypes.default.any, /** Callback to customize how an trigger renders. */ renderTrigger: _propTypes.default.any, /** Controls the dropdown and sets the "active" item. */ selectedItem: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object, _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]))]), /** Callback to determine if the dropdown should update it's `up`/`down` drop direction. Default returns `true`. */ shouldDropDirectionUpdate: _propTypes.default.func, /** Callback to determine if the dropdown refocus the trigger on close. Default returns `true`. */ shouldRefocusOnClose: _propTypes.default.func, /** Callback when the store state changes. Can be used to customize Dropdown state. */ stateReducer: _propTypes.default.func, /** Subscribes to internal Dropdown state changes. */ subscribe: _propTypes.default.func, /** The text to render into the trigger. */ trigger: _propTypes.default.any, /** Retrieves the Dropdown Trigger DOM node. */ triggerRef: _propTypes.default.func, /** Inline styles for the Trigger wrapper. */ triggerStyle: _propTypes.default.any, /** Scroll locks the Dropdown menu. */ withScrollLock: _propTypes.default.bool, /** CSS `z-index` for the menu. */ zIndex: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]), isOpen: _propTypes.default.bool, label: _propTypes.default.string, menuId: _propTypes.default.string, menuOffsetTop: _propTypes.default.number, onMenuMount: _propTypes.default.func, onMenuUnmount: _propTypes.default.func, previousIndex: _propTypes.default.any, selectionClearer: _propTypes.default.string, setMenuNode: _propTypes.default.func, setTriggerNode: _propTypes.default.func, /** Data attr for Cypress tests. */ 'data-cy': _propTypes.default.string }; var ConnectedDropdown = (0, _wedux.connect)( // mapStateToProps function (state) { var contentWindow = state.contentWindow, envNode = state.envNode, id = state.id, isOpen = state.isOpen, getState = state.getState; return { contentWindow: contentWindow, envNode: envNode, id: id, isOpen: isOpen, getState: getState }; }, // mapDispatchToProps { closeDropdown: _Dropdown2.closeDropdown, setMenuNode: _Dropdown2.setMenuNode, setTriggerNode: _Dropdown2.setTriggerNode })(Dropdown); ConnectedDropdown.propTypes = Dropdown.propTypes; var _default = ConnectedDropdown; exports.default = _default;