@procore/core-react
Version:
React library of Procore Design Guidelines
604 lines (594 loc) • 27.9 kB
JavaScript
var _excluded = ["getId", "getLabel", "qa", "value"],
_excluded2 = ["value"],
_excluded3 = ["afterHide", "afterShow", "beforeHide", "beforeShow", "block", "disabled", "emptyMessage", "error", "footer", "getId", "getLabel", "getGroup", "loading", "onChange", "onScrollBottom", "onSearch", "options", "isOptionDisabled", "optionRenderer", "optgroups", "groupHeaderRenderer", "groupRenderer", "tokenRenderer", "placeholder", "placement", "value", "tabIndex", "aria-labelledby", "aria-describedby", "qa"],
_excluded4 = ["aria-controls"];
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _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 _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
import { Clear } from '@procore/core-icons/dist';
import { useId } from '@react-aria/utils';
import { VisuallyHidden } from '@react-aria/visually-hidden';
import React from 'react';
import { Box } from '../Box';
import { MenuImperative, useMenuImperativeControlNavigation } from '../MenuImperative/MenuImperative';
import { OverlayTrigger } from '../OverlayTrigger';
import { Spinner } from '../Spinner';
import { Token } from '../Token';
import { Typography } from '../Typography';
import { isEventSource } from '../_hooks/ClickOutside';
import { useI18nContext } from '../_hooks/I18n';
import { addSubcomponents } from '../_utils/addSubcomponents';
import { StyledMultiSelectArrow, StyledMultiSelectArrowContainer, StyledMultiSelectButton, StyledMultiSelectClearIcon, StyledMultiSelectInner, StyledMultiSelectMenu, StyledMultiSelectSearch, StyledMultiSelectSearchIcon, StyledMultiSelectSearchInput, StyledMultiSelectToken, StyledMultiSelectValues } from './MultiSelect.styles';
var targetShowKeys = ['ArrowDown', 'Down'];
var targetHideKeys = ['Esc', 'Escape'];
var overlayHideKeys = targetHideKeys;
var emptyArray = [];
function noop() {}
function returnTrue() {
return true;
}
function isAlphaNumeric(str) {
return str.length === 1 && str.match(/[A-Za-z0-9 _.,!"'/$]*/i);
}
function setFocusTo(ref) {
if (ref.current) {
ref.current.focus();
}
}
function isOption(obj) {
return _typeof(obj) === 'object' && obj.type === Option;
}
function defaultIsOptionDisabled() {
return false;
}
function defaultGetId(item) {
return item.id;
}
function defaultGetLabel(item) {
return item.label;
}
function defaultGetGroup(item) {
return item.groupId;
}
function defaultIsSelectable(obj) {
_typeof(obj) === 'object' && obj.type === Option;
}
function defaultOptionRenderer(item, _ref) {
var _qa$option;
var getId = _ref.getId,
getLabel = _ref.getLabel,
qa = _ref.qa,
value = _ref.value,
props = _objectWithoutProperties(_ref, _excluded);
return /*#__PURE__*/React.createElement(Option, _extends({
key: getId(item),
value: value || item,
"data-qa": qa === null || qa === void 0 ? void 0 : (_qa$option = qa.option) === null || _qa$option === void 0 ? void 0 : _qa$option.call(qa, item)
}, props), getLabel(item));
}
function defaultGroupRenderer(group) {
return /*#__PURE__*/React.createElement(MenuImperative.Group, {
key: "group_".concat(group.id),
label: group.label
}, group.children);
}
function defaultTokenRenderer(_ref2) {
var _qa$token, _qa$tokenClear;
var focused = _ref2.focused,
disabled = _ref2.disabled,
option = _ref2.option,
removeToken = _ref2.removeToken,
getLabel = _ref2.getLabel,
qa = _ref2.qa;
return /*#__PURE__*/React.createElement(Token, {
disabled: disabled,
focused: focused,
tabIndex: -1,
"data-qa": qa === null || qa === void 0 ? void 0 : (_qa$token = qa.token) === null || _qa$token === void 0 ? void 0 : _qa$token.call(qa, option)
}, /*#__PURE__*/React.createElement(Token.Label, null, getLabel(option)), /*#__PURE__*/React.createElement(Token.Remove, {
"data-close": true,
onClick: removeToken,
tabIndex: -1,
"data-qa": qa === null || qa === void 0 ? void 0 : (_qa$tokenClear = qa.tokenClear) === null || _qa$tokenClear === void 0 ? void 0 : _qa$tokenClear.call(qa, option)
}));
}
function useMultiSelect(_ref3) {
var getId = _ref3.getId,
getLabel = _ref3.getLabel,
getGroup = _ref3.getGroup,
menuRef = _ref3.menuRef,
_ref3$onChange = _ref3.onChange,
onChange = _ref3$onChange === void 0 ? noop : _ref3$onChange,
onSearch_ = _ref3.onSearch,
options_ = _ref3.options,
value = _ref3.value,
optgroups = _ref3.optgroups;
var _React$useState = React.useState(null),
_React$useState2 = _slicedToArray(_React$useState, 2),
index = _React$useState2[0],
setIndex = _React$useState2[1];
var _React$useState3 = React.useState(''),
_React$useState4 = _slicedToArray(_React$useState3, 2),
search = _React$useState4[0],
setSearch = _React$useState4[1];
var valueIds = value.reduce(function (acc, cur) {
acc.add(getId(cur));
return acc;
}, new Set());
var count = value.length;
var options = React.useMemo(function () {
if (onSearch_) {
return options_;
}
return options_.filter(function (opt) {
return getLabel(opt).toLowerCase().includes(search.toLowerCase());
});
}, [options_, onSearch_, getLabel, search]);
var onSearch = React.useCallback(function (e) {
if (onSearch_) {
onSearch_(e);
}
setSearch(e.target.value);
// TODO: because menu highlighting is now imperative, we have to wait
// for a render to highlight the first item. Is there a better way
// to schedule this?
setTimeout(function () {
var _menuRef$current;
return (_menuRef$current = menuRef.current) === null || _menuRef$current === void 0 ? void 0 : _menuRef$current.highlightFirst();
}, 0);
}, [menuRef, onSearch_]);
var clearToken = function clearToken() {
return setIndex(null);
};
var removeSelection = React.useCallback(function (selection, selected) {
return selected.filter(function (s) {
return getId(s) !== getId(selection);
});
}, [getId]);
var onSelect = React.useCallback(function (selection) {
var newSelected = valueIds.has(getId(selection.item)) ? removeSelection(selection.item, value) : [].concat(_toConsumableArray(value), [selection.item]);
setSearch('');
onChange(newSelected);
}, [setSearch, onChange, getId, removeSelection, value, valueIds]);
var removeToken = React.useCallback(function (i) {
onChange(removeSelection(value[i], value));
}, [value, onChange, removeSelection]);
var decrementToken = React.useCallback(function () {
if (index === null) {
// index is null, set it to the last token index
setIndex(count - 1);
} else {
// decrementToken by one, don't go below 0
setIndex(Math.max(0, index - 1));
}
}, [count, index, setIndex]);
var incrementToken = React.useCallback(function () {
if (index === count - 1) {
setIndex(null);
} else if (index !== null) {
setIndex(index + 1);
}
}, [count, index, setIndex]);
var onKeyDown = React.useCallback(function (event) {
if (event.key === 'Enter') {
var _menuRef$current2;
(_menuRef$current2 = menuRef.current) === null || _menuRef$current2 === void 0 ? void 0 : _menuRef$current2.select(event);
}
if (event.key === 'ArrowUp' || event.key === 'Up') {
var _menuRef$current3;
(_menuRef$current3 = menuRef.current) === null || _menuRef$current3 === void 0 ? void 0 : _menuRef$current3.prev();
}
if (event.key === 'ArrowDown' || event.key === 'Down') {
var _menuRef$current4;
(_menuRef$current4 = menuRef.current) === null || _menuRef$current4 === void 0 ? void 0 : _menuRef$current4.next();
}
if (search === '') {
if (event.key === 'Backspace' || event.key === 'Delete') {
// to prevent accidentally deleting too many tokens, don't do anything
// on repeating key events
if (event.repeat) {
return;
}
// if we are focused on a token, remove it, otherwise remove the last token
removeToken(index !== null ? index : count - 1);
if (count >= 1) {
decrementToken();
} else {
clearToken();
}
}
if (event.key === 'ArrowLeft' || event.key === 'Left') {
decrementToken();
}
if (event.key === 'ArrowRight' || event.key === 'Right') {
incrementToken();
}
}
}, [count, decrementToken, incrementToken, index, menuRef, removeToken, search]);
React.useEffect(function () {
// if we've deleted a token and our new count is less than
// our current index, clear the index
if (count <= (index || 0)) {
clearToken();
}
}, [count, index]);
var groupedOptions = React.useMemo(function () {
if (!optgroups || !optgroups.length) {
return options;
}
var optionsByGroup = optgroups.reduce(function (acc, _ref4) {
var id = _ref4.id;
return _objectSpread(_objectSpread({}, acc), {}, _defineProperty({}, id, []));
}, {});
var orphanOptions = [];
options.forEach(function (option) {
var groupId = getGroup(option);
var groupOptions = optionsByGroup[groupId];
if (!groupId || !groupOptions) {
orphanOptions.push(option);
return;
}
optionsByGroup[groupId].push(option);
});
if (orphanOptions.length) {
console.warn("Could not find option groups for the options below. Make sure that every option has a proper \"groupId\" field or if \"getGroup\" is implemented correctly.", orphanOptions);
}
return optgroups.map(function (group) {
var groupOptions = optionsByGroup[group.id];
if (!groupOptions.length) {
return null;
}
return _objectSpread(_objectSpread({}, group), {}, {
isGroupHeader: true,
options: groupOptions
});
}, []).filter(Boolean);
}, [options, getGroup, optgroups]);
return {
ids: valueIds,
index: index,
menuRef: menuRef,
options: groupedOptions,
search: search,
clearToken: clearToken,
decrementToken: decrementToken,
incrementToken: incrementToken,
onSearch: onSearch,
onSelect: onSelect,
removeToken: removeToken,
domHandlers: {
onKeyDown: onKeyDown
}
};
}
export var Option = /*#__PURE__*/React.forwardRef(function Option(_ref5, ref) {
var value = _ref5.value,
props = _objectWithoutProperties(_ref5, _excluded2);
return /*#__PURE__*/React.createElement(MenuImperative.Item, _extends({
ref: ref
}, props, {
item: value
}));
});
function GroupedOptions(_ref6) {
var multiselect = _ref6.multiselect,
groupHeaderRenderer = _ref6.groupHeaderRenderer,
groupRenderer = _ref6.groupRenderer,
optionRenderer = _ref6.optionRenderer,
getId = _ref6.getId,
getLabel = _ref6.getLabel,
isOptionDisabled = _ref6.isOptionDisabled,
qa = _ref6.qa;
var _renderOption = function renderOption(option) {
if (option.isGroupHeader) {
var groupHeader = option;
if (groupHeaderRenderer) {
return /*#__PURE__*/React.createElement(React.Fragment, null, groupHeaderRenderer(groupHeader), groupHeader.options.map(_renderOption));
}
return groupRenderer(_objectSpread(_objectSpread({}, groupHeader), {}, {
children: groupHeader.options.map(_renderOption)
}));
}
return optionRenderer(option, {
getId: getId,
getLabel: getLabel,
// @ts-ignore
// Object literal may only specify known properties, and 'key' does not exist in type 'OptionRendererProps'.
key: getId(option),
selected: multiselect.ids.has(getId(option)),
disabled: isOptionDisabled(option),
value: option,
qa: qa
});
};
return /*#__PURE__*/React.createElement(MenuImperative.Options, null, multiselect.options.map(_renderOption));
}
/**
Multi selects allow our users to choose one to many options from a list,
presented in a dropdown. We typically see these selects on forms.
Other select components are group select, select, and tiered select.
@since 10.19.0
@see [Storybook](https://stories.core.procore.com/?path=/story/core-react_multiselect--basic)
@see [Design Guidelines](https://design.procore.com/multi-select)
*/
var MultiSelect_ = /*#__PURE__*/React.forwardRef(function MultiSelect(_ref7, ref) {
var _ref7$afterHide = _ref7.afterHide,
_afterHide = _ref7$afterHide === void 0 ? noop : _ref7$afterHide,
_ref7$afterShow = _ref7.afterShow,
_afterShow = _ref7$afterShow === void 0 ? noop : _ref7$afterShow,
_ref7$beforeHide = _ref7.beforeHide,
_beforeHide = _ref7$beforeHide === void 0 ? returnTrue : _ref7$beforeHide,
_ref7$beforeShow = _ref7.beforeShow,
_beforeShow = _ref7$beforeShow === void 0 ? returnTrue : _ref7$beforeShow,
_ref7$block = _ref7.block,
block = _ref7$block === void 0 ? false : _ref7$block,
_ref7$disabled = _ref7.disabled,
disabled = _ref7$disabled === void 0 ? false : _ref7$disabled,
emptyMessage = _ref7.emptyMessage,
_ref7$error = _ref7.error,
error = _ref7$error === void 0 ? false : _ref7$error,
footer = _ref7.footer,
_ref7$getId = _ref7.getId,
getId = _ref7$getId === void 0 ? defaultGetId : _ref7$getId,
_ref7$getLabel = _ref7.getLabel,
getLabel = _ref7$getLabel === void 0 ? defaultGetLabel : _ref7$getLabel,
_ref7$getGroup = _ref7.getGroup,
getGroup = _ref7$getGroup === void 0 ? defaultGetGroup : _ref7$getGroup,
_ref7$loading = _ref7.loading,
loading = _ref7$loading === void 0 ? false : _ref7$loading,
_ref7$onChange = _ref7.onChange,
_onChange = _ref7$onChange === void 0 ? noop : _ref7$onChange,
onScrollBottom = _ref7.onScrollBottom,
onSearch = _ref7.onSearch,
_ref7$options = _ref7.options,
options = _ref7$options === void 0 ? emptyArray : _ref7$options,
_ref7$isOptionDisable = _ref7.isOptionDisabled,
isOptionDisabled = _ref7$isOptionDisable === void 0 ? defaultIsOptionDisabled : _ref7$isOptionDisable,
_ref7$optionRenderer = _ref7.optionRenderer,
optionRenderer = _ref7$optionRenderer === void 0 ? defaultOptionRenderer : _ref7$optionRenderer,
optgroups = _ref7.optgroups,
groupHeaderRenderer = _ref7.groupHeaderRenderer,
_ref7$groupRenderer = _ref7.groupRenderer,
groupRenderer = _ref7$groupRenderer === void 0 ? defaultGroupRenderer : _ref7$groupRenderer,
_ref7$tokenRenderer = _ref7.tokenRenderer,
tokenRenderer = _ref7$tokenRenderer === void 0 ? defaultTokenRenderer : _ref7$tokenRenderer,
placeholder = _ref7.placeholder,
_ref7$placement = _ref7.placement,
placement = _ref7$placement === void 0 ? 'bottom-left' : _ref7$placement,
_ref7$value = _ref7.value,
value = _ref7$value === void 0 ? emptyArray : _ref7$value,
_ref7$tabIndex = _ref7.tabIndex,
tabIndex = _ref7$tabIndex === void 0 ? 0 : _ref7$tabIndex,
ariaLabelledBy = _ref7['aria-labelledby'],
ariaDescribedBy = _ref7['aria-describedby'],
_ref7$qa = _ref7.qa,
qa = _ref7$qa === void 0 ? {} : _ref7$qa,
props = _objectWithoutProperties(_ref7, _excluded3);
var i18n = useI18nContext();
var ownRef = React.useRef();
var targetRef = ref || ownRef;
var searchRef = React.useRef(null);
var menuRef = React.useRef(null);
var tokenListId = useId();
var tokenBaseId = useId();
var noneSelectedId = useId();
var _React$useState5 = React.useState(false),
_React$useState6 = _slicedToArray(_React$useState5, 2),
isMenuOpen = _React$useState6[0],
setIsMenuOpen = _React$useState6[1];
var _useMenuImperativeCon = useMenuImperativeControlNavigation(menuRef, isMenuOpen),
menuNavigationTriggerProps = _useMenuImperativeCon.menuNavigationTriggerProps,
menuProps = _useMenuImperativeCon.menuProps;
var menuAriaControls = menuNavigationTriggerProps['aria-controls'],
restMenuNavigationTriggerProps = _objectWithoutProperties(menuNavigationTriggerProps, _excluded4);
var I18n = useI18nContext();
var multiselect = useMultiSelect({
getId: getId,
getLabel: getLabel,
getGroup: getGroup,
menuRef: menuRef,
onSearch: onSearch,
options: options,
onChange: function onChange(value) {
_onChange(value);
setFocusTo(searchRef);
},
value: value,
optgroups: optgroups
});
var showClearIcon = value.length > 0 && !loading;
var isNavigatingTokens = multiselect.index !== null;
var activeTokenId = isNavigatingTokens ? "".concat(tokenBaseId, "-").concat(multiselect.index) : undefined;
var overlay = /*#__PURE__*/React.createElement(StyledMultiSelectMenu, {
shadowStrength: 2
}, /*#__PURE__*/React.createElement(MenuImperative, _extends({}, menuProps, {
ref: menuRef,
onScrollBottom: onScrollBottom,
onSelect: multiselect.onSelect,
"data-qa": "multi-select-menu",
role: "listbox"
}), multiselect.options.length ? /*#__PURE__*/React.createElement(GroupedOptions, {
multiselect: multiselect,
getId: getId,
getLabel: getLabel,
isOptionDisabled: isOptionDisabled,
groupHeaderRenderer: groupHeaderRenderer,
groupRenderer: groupRenderer,
optionRenderer: optionRenderer,
qa: qa
}) : /*#__PURE__*/React.createElement(Box, {
padding: "md lg"
}, /*#__PURE__*/React.createElement(Typography, {
color: "gray45",
intent: "small",
italic: true
}, emptyMessage || I18n.t('core.multiSelect.noResults'))), footer && /*#__PURE__*/React.createElement(MenuImperative.Footer, null, footer)));
return /*#__PURE__*/React.createElement(OverlayTrigger, {
canFlip: true,
afterHide: function afterHide() {
multiselect.clearToken();
setIsMenuOpen(false);
_afterHide();
},
afterShow: function afterShow() {
var _menuRef$current5;
multiselect.clearToken();
(_menuRef$current5 = menuRef.current) === null || _menuRef$current5 === void 0 ? void 0 : _menuRef$current5.highlightFirst();
setIsMenuOpen(true);
_afterShow();
},
beforeHide: function beforeHide(e) {
// if we are clicking somewhere in the target, set focus on the search
if (e instanceof MouseEvent && isEventSource(targetRef, e)) {
setFocusTo(searchRef);
}
return _beforeHide(e);
},
beforeShow: function beforeShow(e) {
setFocusTo(searchRef);
return _beforeShow(e);
},
hideKeys: {
overlay: overlayHideKeys,
target: targetHideKeys
},
overlay: overlay,
placement: placement,
ref: targetRef,
showKeys: targetShowKeys,
trigger: "click"
}, function (_ref8) {
var disable = _ref8.disable,
enable = _ref8.enable,
isVisible = _ref8.isVisible;
var ariaControls = isNavigatingTokens ? tokenListId : menuAriaControls;
return /*#__PURE__*/React.createElement(StyledMultiSelectButton, _extends({
$block: block,
$error: error,
$emptyValue: value.length === 0,
$disabled: disabled,
$loading: loading,
$open: isVisible
}, props), value.length === 0 && /*#__PURE__*/React.createElement(VisuallyHidden, null, /*#__PURE__*/React.createElement("span", {
id: noneSelectedId
}, I18n.t('core.multiSelect.noneSelected'))), /*#__PURE__*/React.createElement(StyledMultiSelectInner, null, /*#__PURE__*/React.createElement(StyledMultiSelectValues, {
id: tokenListId,
role: "list",
"aria-label": value.length > 0 ? I18n.t('core.multiSelect.selectedItems') : I18n.t('core.multiSelect.noneSelected')
}, value.map(function (selection, i) {
var tokenId = "".concat(tokenBaseId, "-").concat(i);
var tokenLabel = getLabel(selection);
return /*#__PURE__*/React.createElement(StyledMultiSelectToken, {
key: getId(selection),
id: tokenId,
role: "listitem",
"aria-label": typeof tokenLabel === 'string' ? I18n.t('core.multiSelect.selectedToken', {
tokenLabel: tokenLabel
}) : undefined
}, tokenRenderer({
option: selection,
focused: i === multiselect.index,
disabled: disabled,
getLabel: getLabel,
removeToken: function removeToken() {
multiselect.removeToken(i);
},
qa: qa
}));
})), /*#__PURE__*/React.createElement(StyledMultiSelectSearch, null, /*#__PURE__*/React.createElement(StyledMultiSelectSearchInput, _extends({
"aria-activedescendant": activeTokenId,
"aria-controls": ariaControls,
"aria-describedby": [ariaDescribedBy, value.length === 0 ? noneSelectedId : undefined].filter(Boolean).join(' ') || undefined,
"aria-expanded": isVisible,
"aria-invalid": error || undefined,
"aria-labelledby": ariaLabelledBy,
"data-qa": "core-multiselect-input",
role: "combobox",
$isNavigatingTokens: isNavigatingTokens,
disabled: disabled,
onBlur: multiselect.clearToken,
onChange: function onChange(e) {
multiselect.onSearch(e);
}
}, restMenuNavigationTriggerProps, {
onKeyDown: function onKeyDown(e) {
if (isNavigatingTokens && e.key !== 'Tab') {
// if we are navigating tokens don't do any input but allow Tab
e.preventDefault();
}
if (isVisible) {
// if the overlay is visible, close it and keep focus
if (e.key === 'Tab') {
e.preventDefault();
disable(e);
}
// if open, don't notify parents (like Modal) but still let OverlayTrigger close it and keep it focus
if (e.key === 'Esc' || e.key === 'Escape') {
e.stopPropagation();
disable(e);
}
// close dropdown when navigating tokens with arrow keys
if (multiselect.search === '' && (e.key === 'ArrowLeft' || e.key === 'Left' || e.key === 'ArrowRight' || e.key === 'Right')) {
disable(e);
}
} else {
// if we type in an alphanumeric character, show the overlay
if (isAlphaNumeric(e.key)) {
enable(e);
}
}
multiselect.domHandlers.onKeyDown(e);
},
placeholder: (value === null || value === void 0 ? void 0 : value.length) > 0 ? '' : placeholder !== null && placeholder !== void 0 ? placeholder : I18n.t('core.multiSelect.selectValues'),
ref: searchRef,
tabIndex: tabIndex,
value: multiselect.search
})))), /*#__PURE__*/React.createElement(StyledMultiSelectSearchIcon, null, /*#__PURE__*/React.createElement(StyledMultiSelectClearIcon, {
"aria-label": i18n.t('core.multiSelect.clearAll'),
"data-close": true,
"data-qa": "core-multiselect-clear",
size: "sm",
variant: "tertiary",
disabled: disabled,
icon: /*#__PURE__*/React.createElement(Clear, null),
onClick: function onClick() {
return _onChange([]);
},
tabIndex: showClearIcon ? 0 : -1,
$show: showClearIcon
}), loading ? /*#__PURE__*/React.createElement(Spinner, {
color: "blue50",
size: "xs"
}) : /*#__PURE__*/React.createElement(StyledMultiSelectArrowContainer, {
"data-qa": "multiselect-select-arrow",
onClick: function onClick(e) {
return isVisible && disable(e);
}
}, /*#__PURE__*/React.createElement(StyledMultiSelectArrow, null))));
});
});
MultiSelect_.displayName = 'MultiSelect';
/**
* @see [Storybook](https://procore.github.io/core/latest/?path=/story/demos-multiselect--demo)
* @see [Design Guidelines](https://design.procore.com/multi-select)
*/
export var MultiSelect = addSubcomponents({
Option: Option
}, MultiSelect_);
//# sourceMappingURL=MultiSelect.js.map