@helpscout/hsds-react
Version:
React component library for Help Scout's Design System
388 lines (289 loc) • 12.5 kB
JavaScript
"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;