@material-ui/lab
Version:
Material-UI Lab - Incubator for Material-UI React components.
1,091 lines (905 loc) • 34.5 kB
JavaScript
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createFilterOptions = createFilterOptions;
exports.default = useAutocomplete;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var React = _interopRequireWildcard(require("react"));
var _utils = require("@material-ui/core/utils");
/* eslint-disable no-constant-condition */
// https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript
// Give up on IE 11 support for this feature
function stripDiacritics(string) {
return typeof string.normalize !== 'undefined' ? string.normalize('NFD').replace(/[\u0300-\u036f]/g, '') : string;
}
function createFilterOptions() {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var _config$ignoreAccents = config.ignoreAccents,
ignoreAccents = _config$ignoreAccents === void 0 ? true : _config$ignoreAccents,
_config$ignoreCase = config.ignoreCase,
ignoreCase = _config$ignoreCase === void 0 ? true : _config$ignoreCase,
limit = config.limit,
_config$matchFrom = config.matchFrom,
matchFrom = _config$matchFrom === void 0 ? 'any' : _config$matchFrom,
stringify = config.stringify,
_config$trim = config.trim,
trim = _config$trim === void 0 ? false : _config$trim;
return function (options, _ref) {
var inputValue = _ref.inputValue,
getOptionLabel = _ref.getOptionLabel;
var input = trim ? inputValue.trim() : inputValue;
if (ignoreCase) {
input = input.toLowerCase();
}
if (ignoreAccents) {
input = stripDiacritics(input);
}
var filteredOptions = options.filter(function (option) {
var candidate = (stringify || getOptionLabel)(option);
if (ignoreCase) {
candidate = candidate.toLowerCase();
}
if (ignoreAccents) {
candidate = stripDiacritics(candidate);
}
return matchFrom === 'start' ? candidate.indexOf(input) === 0 : candidate.indexOf(input) > -1;
});
return typeof limit === 'number' ? filteredOptions.slice(0, limit) : filteredOptions;
};
} // To replace with .findIndex() once we stop IE 11 support.
function findIndex(array, comp) {
for (var i = 0; i < array.length; i += 1) {
if (comp(array[i])) {
return i;
}
}
return -1;
}
var defaultFilterOptions = createFilterOptions(); // Number of options to jump in list box when pageup and pagedown keys are used.
var pageSize = 5;
function useAutocomplete(props) {
var _props$autoComplete = props.autoComplete,
autoComplete = _props$autoComplete === void 0 ? false : _props$autoComplete,
_props$autoHighlight = props.autoHighlight,
autoHighlight = _props$autoHighlight === void 0 ? false : _props$autoHighlight,
_props$autoSelect = props.autoSelect,
autoSelect = _props$autoSelect === void 0 ? false : _props$autoSelect,
_props$blurOnSelect = props.blurOnSelect,
blurOnSelect = _props$blurOnSelect === void 0 ? false : _props$blurOnSelect,
_props$clearOnBlur = props.clearOnBlur,
clearOnBlur = _props$clearOnBlur === void 0 ? !props.freeSolo : _props$clearOnBlur,
_props$clearOnEscape = props.clearOnEscape,
clearOnEscape = _props$clearOnEscape === void 0 ? false : _props$clearOnEscape,
_props$componentName = props.componentName,
componentName = _props$componentName === void 0 ? 'useAutocomplete' : _props$componentName,
_props$debug = props.debug,
debug = _props$debug === void 0 ? false : _props$debug,
_props$defaultValue = props.defaultValue,
defaultValue = _props$defaultValue === void 0 ? props.multiple ? [] : null : _props$defaultValue,
_props$disableClearab = props.disableClearable,
disableClearable = _props$disableClearab === void 0 ? false : _props$disableClearab,
_props$disableCloseOn = props.disableCloseOnSelect,
disableCloseOnSelect = _props$disableCloseOn === void 0 ? false : _props$disableCloseOn,
_props$disabledItemsF = props.disabledItemsFocusable,
disabledItemsFocusable = _props$disabledItemsF === void 0 ? false : _props$disabledItemsF,
_props$disableListWra = props.disableListWrap,
disableListWrap = _props$disableListWra === void 0 ? false : _props$disableListWra,
_props$filterOptions = props.filterOptions,
filterOptions = _props$filterOptions === void 0 ? defaultFilterOptions : _props$filterOptions,
_props$filterSelected = props.filterSelectedOptions,
filterSelectedOptions = _props$filterSelected === void 0 ? false : _props$filterSelected,
_props$freeSolo = props.freeSolo,
freeSolo = _props$freeSolo === void 0 ? false : _props$freeSolo,
getOptionDisabled = props.getOptionDisabled,
_props$getOptionLabel = props.getOptionLabel,
getOptionLabelProp = _props$getOptionLabel === void 0 ? function (option) {
return option;
} : _props$getOptionLabel,
_props$getOptionSelec = props.getOptionSelected,
getOptionSelected = _props$getOptionSelec === void 0 ? function (option, value) {
return option === value;
} : _props$getOptionSelec,
groupBy = props.groupBy,
_props$handleHomeEndK = props.handleHomeEndKeys,
handleHomeEndKeys = _props$handleHomeEndK === void 0 ? !props.freeSolo : _props$handleHomeEndK,
idProp = props.id,
_props$includeInputIn = props.includeInputInList,
includeInputInList = _props$includeInputIn === void 0 ? false : _props$includeInputIn,
inputValueProp = props.inputValue,
_props$multiple = props.multiple,
multiple = _props$multiple === void 0 ? false : _props$multiple,
onChange = props.onChange,
onClose = props.onClose,
onHighlightChange = props.onHighlightChange,
onInputChange = props.onInputChange,
onOpen = props.onOpen,
openProp = props.open,
_props$openOnFocus = props.openOnFocus,
openOnFocus = _props$openOnFocus === void 0 ? false : _props$openOnFocus,
options = props.options,
_props$selectOnFocus = props.selectOnFocus,
selectOnFocus = _props$selectOnFocus === void 0 ? !props.freeSolo : _props$selectOnFocus,
valueProp = props.value;
var id = (0, _utils.unstable_useId)(idProp);
var getOptionLabel = getOptionLabelProp;
if (process.env.NODE_ENV !== 'production') {
getOptionLabel = function getOptionLabel(option) {
var optionLabel = getOptionLabelProp(option);
if (typeof optionLabel !== 'string') {
var erroneousReturn = optionLabel === undefined ? 'undefined' : "".concat((0, _typeof2.default)(optionLabel), " (").concat(optionLabel, ")");
console.error("Material-UI: The `getOptionLabel` method of ".concat(componentName, " returned ").concat(erroneousReturn, " instead of a string for ").concat(JSON.stringify(option), "."));
}
return optionLabel;
};
}
var ignoreFocus = React.useRef(false);
var firstFocus = React.useRef(true);
var inputRef = React.useRef(null);
var listboxRef = React.useRef(null);
var _React$useState = React.useState(null),
anchorEl = _React$useState[0],
setAnchorEl = _React$useState[1];
var _React$useState2 = React.useState(-1),
focusedTag = _React$useState2[0],
setFocusedTag = _React$useState2[1];
var defaultHighlighted = autoHighlight ? 0 : -1;
var highlightedIndexRef = React.useRef(defaultHighlighted);
var _useControlled = (0, _utils.useControlled)({
controlled: valueProp,
default: defaultValue,
name: componentName
}),
_useControlled2 = (0, _slicedToArray2.default)(_useControlled, 2),
value = _useControlled2[0],
setValue = _useControlled2[1];
var _useControlled3 = (0, _utils.useControlled)({
controlled: inputValueProp,
default: '',
name: componentName,
state: 'inputValue'
}),
_useControlled4 = (0, _slicedToArray2.default)(_useControlled3, 2),
inputValue = _useControlled4[0],
setInputValue = _useControlled4[1];
var _React$useState3 = React.useState(false),
focused = _React$useState3[0],
setFocused = _React$useState3[1];
var resetInputValue = (0, _utils.useEventCallback)(function (event, newValue) {
var newInputValue;
if (multiple) {
newInputValue = '';
} else if (newValue == null) {
newInputValue = '';
} else {
var optionLabel = getOptionLabel(newValue);
newInputValue = typeof optionLabel === 'string' ? optionLabel : '';
}
if (inputValue === newInputValue) {
return;
}
setInputValue(newInputValue);
if (onInputChange) {
onInputChange(event, newInputValue, 'reset');
}
});
React.useEffect(function () {
resetInputValue(null, value);
}, [value, resetInputValue]);
var _useControlled5 = (0, _utils.useControlled)({
controlled: openProp,
default: false,
name: componentName,
state: 'open'
}),
_useControlled6 = (0, _slicedToArray2.default)(_useControlled5, 2),
open = _useControlled6[0],
setOpenState = _useControlled6[1];
var inputValueIsSelectedValue = !multiple && value != null && inputValue === getOptionLabel(value);
var popupOpen = open;
var filteredOptions = popupOpen ? filterOptions(options.filter(function (option) {
if (filterSelectedOptions && (multiple ? value : [value]).some(function (value2) {
return value2 !== null && getOptionSelected(option, value2);
})) {
return false;
}
return true;
}), // we use the empty string to manipulate `filterOptions` to not filter any options
// i.e. the filter predicate always returns true
{
inputValue: inputValueIsSelectedValue ? '' : inputValue,
getOptionLabel: getOptionLabel
}) : [];
if (process.env.NODE_ENV !== 'production') {
if (value !== null && !freeSolo && options.length > 0) {
var missingValue = (multiple ? value : [value]).filter(function (value2) {
return !options.some(function (option) {
return getOptionSelected(option, value2);
});
});
if (missingValue.length > 0) {
console.warn(["Material-UI: The value provided to ".concat(componentName, " is invalid."), "None of the options match with `".concat(missingValue.length > 1 ? JSON.stringify(missingValue) : JSON.stringify(missingValue[0]), "`."), 'You can use the `getOptionSelected` prop to customize the equality test.'].join('\n'));
}
}
}
var focusTag = (0, _utils.useEventCallback)(function (tagToFocus) {
if (tagToFocus === -1) {
inputRef.current.focus();
} else {
anchorEl.querySelector("[data-tag-index=\"".concat(tagToFocus, "\"]")).focus();
}
}); // Ensure the focusedTag is never inconsistent
React.useEffect(function () {
if (multiple && focusedTag > value.length - 1) {
setFocusedTag(-1);
focusTag(-1);
}
}, [value, multiple, focusedTag, focusTag]);
function validOptionIndex(index, direction) {
if (!listboxRef.current || index === -1) {
return -1;
}
var nextFocus = index;
while (true) {
// Out of range
if (direction === 'next' && nextFocus === filteredOptions.length || direction === 'previous' && nextFocus === -1) {
return -1;
}
var option = listboxRef.current.querySelector("[data-option-index=\"".concat(nextFocus, "\"]")); // Same logic as MenuList.js
var nextFocusDisabled = disabledItemsFocusable ? false : option && (option.disabled || option.getAttribute('aria-disabled') === 'true');
if (option && !option.hasAttribute('tabindex') || nextFocusDisabled) {
// Move to the next element.
nextFocus += direction === 'next' ? 1 : -1;
} else {
return nextFocus;
}
}
}
var setHighlightedIndex = (0, _utils.useEventCallback)(function (_ref2) {
var event = _ref2.event,
index = _ref2.index,
_ref2$reason = _ref2.reason,
reason = _ref2$reason === void 0 ? 'auto' : _ref2$reason;
highlightedIndexRef.current = index; // does the index exist?
if (index === -1) {
inputRef.current.removeAttribute('aria-activedescendant');
} else {
inputRef.current.setAttribute('aria-activedescendant', "".concat(id, "-option-").concat(index));
}
if (onHighlightChange) {
onHighlightChange(event, index === -1 ? null : filteredOptions[index], reason);
}
if (!listboxRef.current) {
return;
}
var prev = listboxRef.current.querySelector('[data-focus]');
if (prev) {
prev.removeAttribute('data-focus');
}
var listboxNode = listboxRef.current.parentElement.querySelector('[role="listbox"]'); // "No results"
if (!listboxNode) {
return;
}
if (index === -1) {
listboxNode.scrollTop = 0;
return;
}
var option = listboxRef.current.querySelector("[data-option-index=\"".concat(index, "\"]"));
if (!option) {
return;
}
option.setAttribute('data-focus', 'true'); // Scroll active descendant into view.
// Logic copied from https://www.w3.org/TR/wai-aria-practices/examples/listbox/js/listbox.js
//
// Consider this API instead once it has a better browser support:
// .scrollIntoView({ scrollMode: 'if-needed', block: 'nearest' });
if (listboxNode.scrollHeight > listboxNode.clientHeight && reason !== 'mouse') {
var element = option;
var scrollBottom = listboxNode.clientHeight + listboxNode.scrollTop;
var elementBottom = element.offsetTop + element.offsetHeight;
if (elementBottom > scrollBottom) {
listboxNode.scrollTop = elementBottom - listboxNode.clientHeight;
} else if (element.offsetTop - element.offsetHeight * (groupBy ? 1.3 : 0) < listboxNode.scrollTop) {
listboxNode.scrollTop = element.offsetTop - element.offsetHeight * (groupBy ? 1.3 : 0);
}
}
});
var changeHighlightedIndex = (0, _utils.useEventCallback)(function (_ref3) {
var event = _ref3.event,
diff = _ref3.diff,
_ref3$direction = _ref3.direction,
direction = _ref3$direction === void 0 ? 'next' : _ref3$direction,
_ref3$reason = _ref3.reason,
reason = _ref3$reason === void 0 ? 'auto' : _ref3$reason;
if (!popupOpen) {
return;
}
var getNextIndex = function getNextIndex() {
var maxIndex = filteredOptions.length - 1;
if (diff === 'reset') {
return defaultHighlighted;
}
if (diff === 'start') {
return 0;
}
if (diff === 'end') {
return maxIndex;
}
var newIndex = highlightedIndexRef.current + diff;
if (newIndex < 0) {
if (newIndex === -1 && includeInputInList) {
return -1;
}
if (disableListWrap && highlightedIndexRef.current !== -1 || Math.abs(diff) > 1) {
return 0;
}
return maxIndex;
}
if (newIndex > maxIndex) {
if (newIndex === maxIndex + 1 && includeInputInList) {
return -1;
}
if (disableListWrap || Math.abs(diff) > 1) {
return maxIndex;
}
return 0;
}
return newIndex;
};
var nextIndex = validOptionIndex(getNextIndex(), direction);
setHighlightedIndex({
index: nextIndex,
reason: reason,
event: event
}); // Sync the content of the input with the highlighted option.
if (autoComplete && diff !== 'reset') {
if (nextIndex === -1) {
inputRef.current.value = inputValue;
} else {
var option = getOptionLabel(filteredOptions[nextIndex]);
inputRef.current.value = option; // The portion of the selected suggestion that has not been typed by the user,
// a completion string, appears inline after the input cursor in the textbox.
var index = option.toLowerCase().indexOf(inputValue.toLowerCase());
if (index === 0 && inputValue.length > 0) {
inputRef.current.setSelectionRange(inputValue.length, option.length);
}
}
}
});
var syncHighlightedIndex = React.useCallback(function () {
if (!popupOpen) {
return;
}
var valueItem = multiple ? value[0] : value; // The popup is empty, reset
if (filteredOptions.length === 0 || valueItem == null) {
changeHighlightedIndex({
diff: 'reset'
});
return;
}
if (!listboxRef.current) {
return;
} // Synchronize the value with the highlighted index
if (!filterSelectedOptions && valueItem != null) {
var currentOption = filteredOptions[highlightedIndexRef.current]; // Keep the current highlighted index if possible
if (multiple && currentOption && findIndex(value, function (val) {
return getOptionSelected(currentOption, val);
}) !== -1) {
return;
}
var itemIndex = findIndex(filteredOptions, function (optionItem) {
return getOptionSelected(optionItem, valueItem);
});
if (itemIndex === -1) {
changeHighlightedIndex({
diff: 'reset'
});
} else {
setHighlightedIndex({
index: itemIndex
});
}
return;
} // Prevent the highlighted index to leak outside the boundaries.
if (highlightedIndexRef.current >= filteredOptions.length - 1) {
setHighlightedIndex({
index: filteredOptions.length - 1
});
return;
} // Restore the focus to the previous index.
setHighlightedIndex({
index: highlightedIndexRef.current
}); // Ignore filteredOptions (and options, getOptionSelected, getOptionLabel) not to break the scroll position
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [// Only sync the highlighted index when the option switch between empty and not
// eslint-disable-next-line react-hooks/exhaustive-deps
filteredOptions.length === 0, // Don't sync the highlighted index with the value when multiple
// eslint-disable-next-line react-hooks/exhaustive-deps
multiple ? false : value, filterSelectedOptions, changeHighlightedIndex, setHighlightedIndex, popupOpen, inputValue, multiple]);
var handleListboxRef = (0, _utils.useEventCallback)(function (node) {
(0, _utils.setRef)(listboxRef, node);
if (!node) {
return;
}
syncHighlightedIndex();
});
React.useEffect(function () {
syncHighlightedIndex();
}, [syncHighlightedIndex]);
var handleOpen = function handleOpen(event) {
if (open) {
return;
}
setOpenState(true);
if (onOpen) {
onOpen(event);
}
};
var handleClose = function handleClose(event, reason) {
if (!open) {
return;
}
setOpenState(false);
if (onClose) {
onClose(event, reason);
}
};
var handleValue = function handleValue(event, newValue, reason, details) {
if (value === newValue) {
return;
}
if (onChange) {
onChange(event, newValue, reason, details);
}
setValue(newValue);
};
var isTouch = React.useRef(false);
var selectNewValue = function selectNewValue(event, option) {
var reasonProp = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'select-option';
var origin = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'options';
var reason = reasonProp;
var newValue = option;
if (multiple) {
newValue = Array.isArray(value) ? value.slice() : [];
if (process.env.NODE_ENV !== 'production') {
var matches = newValue.filter(function (val) {
return getOptionSelected(option, val);
});
if (matches.length > 1) {
console.error(["Material-UI: The `getOptionSelected` method of ".concat(componentName, " do not handle the arguments correctly."), "The component expects a single value to match a given option but found ".concat(matches.length, " matches.")].join('\n'));
}
}
var itemIndex = findIndex(newValue, function (valueItem) {
return getOptionSelected(option, valueItem);
});
if (itemIndex === -1) {
newValue.push(option);
} else if (origin !== 'freeSolo') {
newValue.splice(itemIndex, 1);
reason = 'remove-option';
}
}
resetInputValue(event, newValue);
handleValue(event, newValue, reason, {
option: option
});
if (!disableCloseOnSelect) {
handleClose(event, reason);
}
if (blurOnSelect === true || blurOnSelect === 'touch' && isTouch.current || blurOnSelect === 'mouse' && !isTouch.current) {
inputRef.current.blur();
}
};
function validTagIndex(index, direction) {
if (index === -1) {
return -1;
}
var nextFocus = index;
while (true) {
// Out of range
if (direction === 'next' && nextFocus === value.length || direction === 'previous' && nextFocus === -1) {
return -1;
}
var option = anchorEl.querySelector("[data-tag-index=\"".concat(nextFocus, "\"]")); // Same logic as MenuList.js
if (option && (!option.hasAttribute('tabindex') || option.disabled || option.getAttribute('aria-disabled') === 'true')) {
nextFocus += direction === 'next' ? 1 : -1;
} else {
return nextFocus;
}
}
}
var handleFocusTag = function handleFocusTag(event, direction) {
if (!multiple) {
return;
}
handleClose(event, 'toggleInput');
var nextTag = focusedTag;
if (focusedTag === -1) {
if (inputValue === '' && direction === 'previous') {
nextTag = value.length - 1;
}
} else {
nextTag += direction === 'next' ? 1 : -1;
if (nextTag < 0) {
nextTag = 0;
}
if (nextTag === value.length) {
nextTag = -1;
}
}
nextTag = validTagIndex(nextTag, direction);
setFocusedTag(nextTag);
focusTag(nextTag);
};
var handleClear = function handleClear(event) {
ignoreFocus.current = true;
setInputValue('');
if (onInputChange) {
onInputChange(event, '', 'clear');
}
handleValue(event, multiple ? [] : null, 'clear');
};
var handleKeyDown = function handleKeyDown(other) {
return function (event) {
if (focusedTag !== -1 && ['ArrowLeft', 'ArrowRight'].indexOf(event.key) === -1) {
setFocusedTag(-1);
focusTag(-1);
}
switch (event.key) {
case 'Home':
if (popupOpen && handleHomeEndKeys) {
// Prevent scroll of the page
event.preventDefault();
changeHighlightedIndex({
diff: 'start',
direction: 'next',
reason: 'keyboard',
event: event
});
}
break;
case 'End':
if (popupOpen && handleHomeEndKeys) {
// Prevent scroll of the page
event.preventDefault();
changeHighlightedIndex({
diff: 'end',
direction: 'previous',
reason: 'keyboard',
event: event
});
}
break;
case 'PageUp':
// Prevent scroll of the page
event.preventDefault();
changeHighlightedIndex({
diff: -pageSize,
direction: 'previous',
reason: 'keyboard',
event: event
});
handleOpen(event);
break;
case 'PageDown':
// Prevent scroll of the page
event.preventDefault();
changeHighlightedIndex({
diff: pageSize,
direction: 'next',
reason: 'keyboard',
event: event
});
handleOpen(event);
break;
case 'ArrowDown':
// Prevent cursor move
event.preventDefault();
changeHighlightedIndex({
diff: 1,
direction: 'next',
reason: 'keyboard',
event: event
});
handleOpen(event);
break;
case 'ArrowUp':
// Prevent cursor move
event.preventDefault();
changeHighlightedIndex({
diff: -1,
direction: 'previous',
reason: 'keyboard',
event: event
});
handleOpen(event);
break;
case 'ArrowLeft':
handleFocusTag(event, 'previous');
break;
case 'ArrowRight':
handleFocusTag(event, 'next');
break;
case 'Enter':
// Wait until IME is settled.
if (event.which === 229) {
break;
}
if (highlightedIndexRef.current !== -1 && popupOpen) {
var option = filteredOptions[highlightedIndexRef.current];
var disabled = getOptionDisabled ? getOptionDisabled(option) : false; // We don't want to validate the form.
event.preventDefault();
if (disabled) {
return;
}
selectNewValue(event, option, 'select-option'); // Move the selection to the end.
if (autoComplete) {
inputRef.current.setSelectionRange(inputRef.current.value.length, inputRef.current.value.length);
}
} else if (freeSolo && inputValue !== '' && inputValueIsSelectedValue === false) {
if (multiple) {
// Allow people to add new values before they submit the form.
event.preventDefault();
}
selectNewValue(event, inputValue, 'create-option', 'freeSolo');
}
break;
case 'Escape':
if (popupOpen) {
// Avoid Opera to exit fullscreen mode.
event.preventDefault(); // Avoid the Modal to handle the event.
event.stopPropagation();
handleClose(event, 'escape');
} else if (clearOnEscape && (inputValue !== '' || multiple && value.length > 0)) {
// Avoid Opera to exit fullscreen mode.
event.preventDefault(); // Avoid the Modal to handle the event.
event.stopPropagation();
handleClear(event);
}
break;
case 'Backspace':
if (multiple && inputValue === '' && value.length > 0) {
var index = focusedTag === -1 ? value.length - 1 : focusedTag;
var newValue = value.slice();
newValue.splice(index, 1);
handleValue(event, newValue, 'remove-option', {
option: value[index]
});
}
break;
default:
}
if (other.onKeyDown) {
other.onKeyDown(event);
}
};
};
var handleFocus = function handleFocus(event) {
setFocused(true);
if (openOnFocus && !ignoreFocus.current) {
handleOpen(event);
}
};
var handleBlur = function handleBlur(event) {
// Ignore the event when using the scrollbar with IE 11
if (listboxRef.current !== null && document.activeElement === listboxRef.current.parentElement) {
inputRef.current.focus();
return;
}
setFocused(false);
firstFocus.current = true;
ignoreFocus.current = false;
if (debug && inputValue !== '') {
return;
}
if (autoSelect && highlightedIndexRef.current !== -1 && popupOpen) {
selectNewValue(event, filteredOptions[highlightedIndexRef.current], 'blur');
} else if (autoSelect && freeSolo && inputValue !== '') {
selectNewValue(event, inputValue, 'blur', 'freeSolo');
} else if (clearOnBlur) {
resetInputValue(event, value);
}
handleClose(event, 'blur');
};
var handleInputChange = function handleInputChange(event) {
var newValue = event.target.value;
if (inputValue !== newValue) {
setInputValue(newValue);
if (onInputChange) {
onInputChange(event, newValue, 'input');
}
}
if (newValue === '') {
if (!disableClearable && !multiple) {
handleValue(event, null, 'clear');
}
} else {
handleOpen(event);
}
};
var handleOptionMouseOver = function handleOptionMouseOver(event) {
setHighlightedIndex({
event: event,
index: Number(event.currentTarget.getAttribute('data-option-index')),
reason: 'mouse'
});
};
var handleOptionTouchStart = function handleOptionTouchStart() {
isTouch.current = true;
};
var handleOptionClick = function handleOptionClick(event) {
var index = Number(event.currentTarget.getAttribute('data-option-index'));
selectNewValue(event, filteredOptions[index], 'select-option');
isTouch.current = false;
};
var handleTagDelete = function handleTagDelete(index) {
return function (event) {
var newValue = value.slice();
newValue.splice(index, 1);
handleValue(event, newValue, 'remove-option', {
option: value[index]
});
};
};
var handlePopupIndicator = function handlePopupIndicator(event) {
if (open) {
handleClose(event, 'toggleInput');
} else {
handleOpen(event);
}
}; // Prevent input blur when interacting with the combobox
var handleMouseDown = function handleMouseDown(event) {
if (event.target.getAttribute('id') !== id) {
event.preventDefault();
}
}; // Focus the input when interacting with the combobox
var handleClick = function handleClick() {
inputRef.current.focus();
if (selectOnFocus && firstFocus.current && inputRef.current.selectionEnd - inputRef.current.selectionStart === 0) {
inputRef.current.select();
}
firstFocus.current = false;
};
var handleInputMouseDown = function handleInputMouseDown(event) {
if (inputValue === '' || !open) {
handlePopupIndicator(event);
}
};
var dirty = freeSolo && inputValue.length > 0;
dirty = dirty || (multiple ? value.length > 0 : value !== null);
var groupedOptions = filteredOptions;
if (groupBy) {
// used to keep track of key and indexes in the result array
var indexBy = new Map();
var warn = false;
groupedOptions = filteredOptions.reduce(function (acc, option, index) {
var group = groupBy(option);
if (acc.length > 0 && acc[acc.length - 1].group === group) {
acc[acc.length - 1].options.push(option);
} else {
if (process.env.NODE_ENV !== 'production') {
if (indexBy.get(group) && !warn) {
console.warn("Material-UI: The options provided combined with the `groupBy` method of ".concat(componentName, " returns duplicated headers."), 'You can solve the issue by sorting the options with the output of `groupBy`.');
warn = true;
}
indexBy.set(group, true);
}
acc.push({
key: index,
index: index,
group: group,
options: [option]
});
}
return acc;
}, []);
}
return {
getRootProps: function getRootProps() {
var other = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return (0, _extends2.default)({
'aria-owns': popupOpen ? "".concat(id, "-popup") : null,
role: 'combobox',
'aria-expanded': popupOpen
}, other, {
onKeyDown: handleKeyDown(other),
onMouseDown: handleMouseDown,
onClick: handleClick
});
},
getInputLabelProps: function getInputLabelProps() {
return {
id: "".concat(id, "-label"),
htmlFor: id
};
},
getInputProps: function getInputProps() {
return {
id: id,
value: inputValue,
onBlur: handleBlur,
onFocus: handleFocus,
onChange: handleInputChange,
onMouseDown: handleInputMouseDown,
// if open then this is handled imperativeley so don't let react override
// only have an opinion about this when closed
'aria-activedescendant': popupOpen ? '' : null,
'aria-autocomplete': autoComplete ? 'both' : 'list',
'aria-controls': popupOpen ? "".concat(id, "-popup") : null,
// Disable browser's suggestion that might overlap with the popup.
// Handle autocomplete but not autofill.
autoComplete: 'off',
ref: inputRef,
autoCapitalize: 'none',
spellCheck: 'false'
};
},
getClearProps: function getClearProps() {
return {
tabIndex: -1,
onClick: handleClear
};
},
getPopupIndicatorProps: function getPopupIndicatorProps() {
return {
tabIndex: -1,
onClick: handlePopupIndicator
};
},
getTagProps: function getTagProps(_ref4) {
var index = _ref4.index;
return {
key: index,
'data-tag-index': index,
tabIndex: -1,
onDelete: handleTagDelete(index)
};
},
getListboxProps: function getListboxProps() {
return {
role: 'listbox',
id: "".concat(id, "-popup"),
'aria-labelledby': "".concat(id, "-label"),
ref: handleListboxRef,
onMouseDown: function onMouseDown(event) {
// Prevent blur
event.preventDefault();
}
};
},
getOptionProps: function getOptionProps(_ref5) {
var index = _ref5.index,
option = _ref5.option;
var selected = (multiple ? value : [value]).some(function (value2) {
return value2 != null && getOptionSelected(option, value2);
});
var disabled = getOptionDisabled ? getOptionDisabled(option) : false;
return {
key: index,
tabIndex: -1,
role: 'option',
id: "".concat(id, "-option-").concat(index),
onMouseOver: handleOptionMouseOver,
onClick: handleOptionClick,
onTouchStart: handleOptionTouchStart,
'data-option-index': index,
'aria-disabled': disabled,
'aria-selected': selected
};
},
id: id,
inputValue: inputValue,
value: value,
dirty: dirty,
popupOpen: popupOpen,
focused: focused || focusedTag !== -1,
anchorEl: anchorEl,
setAnchorEl: setAnchorEl,
focusedTag: focusedTag,
groupedOptions: groupedOptions
};
}