@commercetools-uikit/select-input
Version:
An input component getting a selection from the user.
251 lines (243 loc) • 13 kB
JavaScript
import _defineProperty from '@babel/runtime-corejs3/helpers/esm/defineProperty';
import _objectWithoutProperties from '@babel/runtime-corejs3/helpers/esm/objectWithoutProperties';
import _flatMapInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/flat-map';
import _filterInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/filter';
import _mapInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/map';
import _findInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/find';
import _Object$keys from '@babel/runtime-corejs3/core-js-stable/object/keys';
import _Object$getOwnPropertySymbols from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols';
import _Object$getOwnPropertyDescriptor from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor';
import _forEachInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/for-each';
import _Object$getOwnPropertyDescriptors from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors';
import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/object/define-properties';
import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property';
import { useIntl } from 'react-intl';
import isEmpty from 'lodash/isEmpty';
import has from 'lodash/has';
import Select, { components } from 'react-select';
import Constraints from '@commercetools-uikit/constraints';
import { warnIfMenuPortalPropsAreMissing, messages, customComponentsWithIcons, optionStyleCheckboxComponents, createSelectStyles, optionsStyleCheckboxSelectProps, DropdownIndicator, ClearIndicator, TagRemove } from '@commercetools-uikit/select-utils';
import { filterDataAttributes } from '@commercetools-uikit/utils';
import { SearchIcon } from '@commercetools-uikit/icons';
import { jsx } from '@emotion/react/jsx-runtime';
const _excluded = ["appearance", "maxMenuHeight", "menuPortalZIndex", "options", "optionStyle"];
function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, 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 _context4, _context5; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context4 = ownKeys(Object(t), !0)).call(_context4, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context5 = ownKeys(Object(t))).call(_context5, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
const customizedComponents = {
DropdownIndicator,
ClearIndicator,
MultiValueRemove: TagRemove
};
const isOptionObject = option => option.options !== undefined;
const SelectInput = _ref => {
var _context, _context2;
let _ref$appearance = _ref.appearance,
appearance = _ref$appearance === void 0 ? 'default' : _ref$appearance,
_ref$maxMenuHeight = _ref.maxMenuHeight,
maxMenuHeight = _ref$maxMenuHeight === void 0 ? 220 : _ref$maxMenuHeight,
_ref$menuPortalZIndex = _ref.menuPortalZIndex,
menuPortalZIndex = _ref$menuPortalZIndex === void 0 ? 1 : _ref$menuPortalZIndex,
_ref$options = _ref.options,
options = _ref$options === void 0 ? [] : _ref$options,
_ref$optionStyle = _ref.optionStyle,
optionStyle = _ref$optionStyle === void 0 ? 'list' : _ref$optionStyle,
props = _objectWithoutProperties(_ref, _excluded);
const intl = useIntl();
warnIfMenuPortalPropsAreMissing({
menuPortalZIndex: menuPortalZIndex,
menuPortalTarget: props.menuPortalTarget,
componentName: 'SelectInput'
});
const placeholder = appearance === 'filter' && !props.placeholder ? intl.formatMessage(messages.selectInputAsFilterPlaceholder) : props.placeholder || intl.formatMessage(messages.placeholder);
// Options can be grouped as
// const colourOptions = [{ value: 'green', label: 'Green' }];
// const flavourOptions = [{ value: 'vanilla', label: 'Vanilla' }];
// const groupedOptions = [
// { label: 'Colours', options: colourOptions },
// { label: 'Flavours', options: flavourOptions },
// ];
// So we "ungroup" the options by merging them all into one list first.
const optionsWithoutGroups = _flatMapInstanceProperty(options).call(options, option => {
if (isOptionObject(option)) {
return option.options;
}
return option;
});
const selectedOptions = props.isMulti ? _filterInstanceProperty(_context = _mapInstanceProperty(_context2 = props.value || []
// Pass the options in the order selected by the user, so that the
// sorting is not lost
).call(_context2, value => _findInstanceProperty(optionsWithoutGroups).call(optionsWithoutGroups, option => option.value === value))).call(_context, option => Boolean(option)) : _findInstanceProperty(optionsWithoutGroups).call(optionsWithoutGroups, option => has(option, 'value') && option.value === props.value) || null;
return jsx(Constraints.Horizontal, {
max: props.horizontalConstraint,
children: jsx("div", _objectSpread(_objectSpread({}, filterDataAttributes(_objectSpread({
appearance,
maxMenuHeight,
menuPortalZIndex,
optionStyle
}, props))), {}, {
children: jsx(Select, _objectSpread(_objectSpread({
"aria-label": props['aria-label'],
"aria-labelledby": props['aria-labelledby'],
"aria-invalid": props['aria-invalid'],
"aria-errormessage": props['aria-errormessage'],
autoFocus: props.isAutofocussed,
backspaceRemovesValue: props.isReadOnly ? false : props.backspaceRemovesValue,
components: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, customizedComponents), props.iconLeft && !props.isMulti ? customComponentsWithIcons : {}), props.isReadOnly ? {
Input: ownProps => jsx(components.Input, _objectSpread(_objectSpread({}, ownProps), {}, {
readOnly: true
}))
} : {}), appearance === 'filter' && {
DropdownIndicator: () => jsx(SearchIcon, {
color: "neutral60"
}),
ClearIndicator: null
}), optionStyle === 'checkbox' ? optionStyleCheckboxComponents(appearance) : {}), props.components),
menuIsOpen: props.isReadOnly ? false : appearance === 'filter' ? true : props.menuIsOpen,
styles: createSelectStyles({
hasWarning: props.hasWarning,
hasError: props.hasError,
showOptionGroupDivider: props.showOptionGroupDivider,
menuPortalZIndex: menuPortalZIndex,
appearance: appearance,
isDisabled: props.isDisabled,
isReadOnly: props.isReadOnly,
isCondensed: appearance === 'filter' ? true : props.isCondensed,
iconLeft: props.iconLeft,
isMulti: props.isMulti,
hasValue: !isEmpty(selectedOptions),
controlShouldRenderValue: props.controlShouldRenderValue,
horizontalConstraint: props.horizontalConstraint,
minMenuWidth: props.minMenuWidth,
maxMenuWidth: props.maxMenuWidth
}),
filterOption: props.filterOption
// react-select uses "id" (for the container) and "inputId" (for the input),
// but we use "id" (for the input) and "containerId" (for the container)
// instead.
// This makes it easier to less confusing to use with <label />s.
,
id: props.containerId,
inputId: props.id,
inputValue: props.inputValue,
isClearable: props.isReadOnly ? false : props.isClearable,
isDisabled: props.isDisabled,
isOptionDisabled: props.isOptionDisabled
}, optionStyle === 'checkbox' ? optionsStyleCheckboxSelectProps() : {
hideSelectedOptions: props.hideSelectedOptions
}), {}, {
// @ts-ignore
isReadOnly: props.isReadOnly,
isMulti: props.isMulti,
isSearchable: props.isSearchable,
isCondensed: props.isCondensed,
maxMenuHeight: maxMenuHeight,
menuPortalTarget: props.menuPortalTarget,
menuShouldBlockScroll: props.menuShouldBlockScroll
// @ts-expect-error: optionStyle 'checkbox' will override this property (if set)
,
closeMenuOnSelect: props.closeMenuOnSelect,
name: props.name,
noOptionsMessage: props.noOptionsMessage || (_ref2 => {
let inputValue = _ref2.inputValue;
return !inputValue || inputValue === '' ? intl.formatMessage(messages.noOptionsMessageWithoutInputValue) : intl.formatMessage(messages.noOptionsMessageWithInputValue, {
inputValue
});
}),
onBlur: typeof props.onBlur === 'function' ? () => {
const event = {
target: {
id: props.id,
name: (() => {
if (!props.isMulti) return props.name;
// We append the ".0" to make Formik set the touched
// state as an array instead of a boolean only.
// Otherwise the shapes would clash on submission, as
// Formik will create an array on submission anyways.
return props.name ? `${props.name}.0` : undefined;
})()
},
persist: () => {}
};
props.onBlur && props.onBlur(event);
} : undefined,
onChange: nextSelectedOptions => {
// nextSelectedOptions is either an array, or a single option, or null
// depending on whether we're in multi-mode or not (isMulti)
let value = null;
if (props.isMulti) {
if (nextSelectedOptions) {
var _context3;
value = _mapInstanceProperty(_context3 = nextSelectedOptions).call(_context3, option => option.value);
} else {
value = [];
}
} else if (nextSelectedOptions) {
value = nextSelectedOptions.value;
}
props.onChange && props.onChange({
target: {
id: props.id,
name: props.name,
value
},
persist: () => {}
});
},
onFocus: props.onFocus,
onInputChange: props.onInputChange,
options: options,
placeholder: placeholder,
tabIndex: props.tabIndex,
tabSelectsValue: props.tabSelectsValue,
value: selectedOptions,
iconLeft: props.iconLeft,
controlShouldRenderValue: appearance === 'filter' ? false : props.controlShouldRenderValue,
menuPlacement: "auto"
}, optionStyle === 'checkbox' ? optionsStyleCheckboxSelectProps() : {}))
}))
});
};
SelectInput.displayName = 'SelectInput';
/**
* Expose static helper methods.
*/
// Both "true" and an empty array [] represent a touched state.
SelectInput.isTouched = touched => Boolean(touched);
/**
* Expose react-select components for customization purposes.
*/
// custom
SelectInput.ClearIndicator = customizedComponents.ClearIndicator;
SelectInput.Control = components.Control;
//https://github.com/commercetools/ui-kit/pull/3054/files#r1943026570
SelectInput.CrossIcon = components.CrossIcon;
//https://github.com/commercetools/ui-kit/pull/3054/files#r1943026570
SelectInput.DownChevron = components.DownChevron;
// custom
SelectInput.DropdownIndicator = customizedComponents.DropdownIndicator;
SelectInput.Group = components.Group;
SelectInput.GroupHeading = components.GroupHeading;
SelectInput.IndicatorSeparator = components.IndicatorSeparator;
SelectInput.IndicatorsContainer = components.IndicatorsContainer;
SelectInput.Input = components.Input;
SelectInput.LoadingIndicator = components.LoadingIndicator;
SelectInput.LoadingMessage = components.LoadingMessage;
SelectInput.Menu = components.Menu;
SelectInput.MenuList = components.MenuList;
//https://github.com/commercetools/ui-kit/pull/3054/files#r1943026570
SelectInput.MenuPortal = components.MenuPortal;
SelectInput.MultiValue = components.MultiValue;
SelectInput.MultiValueContainer = components.MultiValueContainer;
SelectInput.MultiValueLabel = components.MultiValueLabel;
// custom
SelectInput.MultiValueRemove = customizedComponents.MultiValueRemove;
SelectInput.NoOptionsMessage = components.NoOptionsMessage;
SelectInput.Option = components.Option;
SelectInput.Placeholder = components.Placeholder;
SelectInput.SelectContainer = components.SelectContainer;
SelectInput.SingleValue = components.SingleValue;
SelectInput.ValueContainer = components.ValueContainer;
var SelectInput$1 = SelectInput;
// NOTE: This string will be replaced on build time with the package version.
var version = "20.2.3";
export { SelectInput$1 as default, version };