UNPKG

downshift

Version:

A set of primitives to build simple, flexible, WAI-ARIA compliant React autocomplete components

1,414 lines (1,169 loc) 79.4 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('preact')) : typeof define === 'function' && define.amd ? define(['exports', 'preact'], factory) : (factory((global.Downshift = {}),global.preact)); }(this, (function (exports,React) { 'use strict'; var React__default = 'default' in React ? React['default'] : React; function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } function unwrapExports (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x.default : x; } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var reactIs_production_min = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: !0 }); var b = "function" === typeof Symbol && Symbol.for, c = b ? Symbol.for("react.element") : 60103, d = b ? Symbol.for("react.portal") : 60106, e = b ? Symbol.for("react.fragment") : 60107, f = b ? Symbol.for("react.strict_mode") : 60108, g = b ? Symbol.for("react.profiler") : 60114, h = b ? Symbol.for("react.provider") : 60109, k = b ? Symbol.for("react.context") : 60110, l = b ? Symbol.for("react.async_mode") : 60111, m = b ? Symbol.for("react.concurrent_mode") : 60111, n = b ? Symbol.for("react.forward_ref") : 60112, p = b ? Symbol.for("react.suspense") : 60113, q = b ? Symbol.for("react.memo") : 60115, r = b ? Symbol.for("react.lazy") : 60116; function t(a) { if ("object" === typeof a && null !== a) { var u = a.$$typeof; switch (u) { case c: switch (a = a.type, a) { case l: case m: case e: case g: case f: case p: return a; default: switch (a = a && a.$$typeof, a) { case k: case n: case h: return a; default: return u; } } case r: case q: case d: return u; } } } function v(a) { return t(a) === m; } exports.typeOf = t; exports.AsyncMode = l; exports.ConcurrentMode = m; exports.ContextConsumer = k; exports.ContextProvider = h; exports.Element = c; exports.ForwardRef = n; exports.Fragment = e; exports.Lazy = r; exports.Memo = q; exports.Portal = d; exports.Profiler = g; exports.StrictMode = f; exports.Suspense = p; exports.isValidElementType = function (a) { return "string" === typeof a || "function" === typeof a || a === e || a === m || a === g || a === f || a === p || "object" === typeof a && null !== a && (a.$$typeof === r || a.$$typeof === q || a.$$typeof === h || a.$$typeof === k || a.$$typeof === n); }; exports.isAsyncMode = function (a) { return v(a) || t(a) === l; }; exports.isConcurrentMode = v; exports.isContextConsumer = function (a) { return t(a) === k; }; exports.isContextProvider = function (a) { return t(a) === h; }; exports.isElement = function (a) { return "object" === typeof a && null !== a && a.$$typeof === c; }; exports.isForwardRef = function (a) { return t(a) === n; }; exports.isFragment = function (a) { return t(a) === e; }; exports.isLazy = function (a) { return t(a) === r; }; exports.isMemo = function (a) { return t(a) === q; }; exports.isPortal = function (a) { return t(a) === d; }; exports.isProfiler = function (a) { return t(a) === g; }; exports.isStrictMode = function (a) { return t(a) === f; }; exports.isSuspense = function (a) { return t(a) === p; }; }); unwrapExports(reactIs_production_min); var reactIs_production_min_1 = reactIs_production_min.typeOf; var reactIs_production_min_2 = reactIs_production_min.AsyncMode; var reactIs_production_min_3 = reactIs_production_min.ConcurrentMode; var reactIs_production_min_4 = reactIs_production_min.ContextConsumer; var reactIs_production_min_5 = reactIs_production_min.ContextProvider; var reactIs_production_min_6 = reactIs_production_min.Element; var reactIs_production_min_7 = reactIs_production_min.ForwardRef; var reactIs_production_min_8 = reactIs_production_min.Fragment; var reactIs_production_min_9 = reactIs_production_min.Lazy; var reactIs_production_min_10 = reactIs_production_min.Memo; var reactIs_production_min_11 = reactIs_production_min.Portal; var reactIs_production_min_12 = reactIs_production_min.Profiler; var reactIs_production_min_13 = reactIs_production_min.StrictMode; var reactIs_production_min_14 = reactIs_production_min.Suspense; var reactIs_production_min_15 = reactIs_production_min.isValidElementType; var reactIs_production_min_16 = reactIs_production_min.isAsyncMode; var reactIs_production_min_17 = reactIs_production_min.isConcurrentMode; var reactIs_production_min_18 = reactIs_production_min.isContextConsumer; var reactIs_production_min_19 = reactIs_production_min.isContextProvider; var reactIs_production_min_20 = reactIs_production_min.isElement; var reactIs_production_min_21 = reactIs_production_min.isForwardRef; var reactIs_production_min_22 = reactIs_production_min.isFragment; var reactIs_production_min_23 = reactIs_production_min.isLazy; var reactIs_production_min_24 = reactIs_production_min.isMemo; var reactIs_production_min_25 = reactIs_production_min.isPortal; var reactIs_production_min_26 = reactIs_production_min.isProfiler; var reactIs_production_min_27 = reactIs_production_min.isStrictMode; var reactIs_production_min_28 = reactIs_production_min.isSuspense; var reactIs_development = createCommonjsModule(function (module, exports) { (function () { Object.defineProperty(exports, '__esModule', { value: true }); // The Symbol used to tag the ReactElement-like types. If there is no native Symbol // nor polyfill, then a plain number is used for performance. var hasSymbol = typeof Symbol === 'function' && Symbol.for; var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for('react.async_mode') : 0xeacf; var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; /** * Forked from fbjs/warning: * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js * * Only change is we use console.warn instead of console.error, * and do nothing when 'console' is not supported. * This really simplifies the code. * --- * Similar to invariant but only logs a warning if the condition is not met. * This can be used to log issues in development environments in critical * paths. Removing the logging code for production environments will keep the * same logic and follow the same code paths. */ var lowPriorityWarning = function () {}; { var printWarning = function (format) { for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } var argIndex = 0; var message = 'Warning: ' + format.replace(/%s/g, function () { return args[argIndex++]; }); if (typeof console !== 'undefined') { console.warn(message); } try { // --- Welcome to debugging React --- // This error was thrown as a convenience so that you can use this stack // to find the callsite that caused this warning to fire. throw new Error(message); } catch (x) {} }; lowPriorityWarning = function (condition, format) { if (format === undefined) { throw new Error('`lowPriorityWarning(condition, format, ...args)` requires a warning ' + 'message argument'); } if (!condition) { for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { args[_key2 - 2] = arguments[_key2]; } printWarning.apply(undefined, [format].concat(args)); } }; } var lowPriorityWarning$1 = lowPriorityWarning; function typeOf(object) { if (typeof object === 'object' && object !== null) { var $$typeof = object.$$typeof; switch ($$typeof) { case REACT_ELEMENT_TYPE: var type = object.type; switch (type) { case REACT_ASYNC_MODE_TYPE: case REACT_CONCURRENT_MODE_TYPE: case REACT_FRAGMENT_TYPE: case REACT_PROFILER_TYPE: case REACT_STRICT_MODE_TYPE: case REACT_SUSPENSE_TYPE: return type; default: var $$typeofType = type && type.$$typeof; switch ($$typeofType) { case REACT_CONTEXT_TYPE: case REACT_FORWARD_REF_TYPE: case REACT_PROVIDER_TYPE: return $$typeofType; default: return $$typeof; } } case REACT_LAZY_TYPE: case REACT_MEMO_TYPE: case REACT_PORTAL_TYPE: return $$typeof; } } return undefined; } // AsyncMode is deprecated along with isAsyncMode var hasWarnedAboutDeprecatedIsAsyncMode = false; // AsyncMode should be deprecated function isAsyncMode(object) { { if (!hasWarnedAboutDeprecatedIsAsyncMode) { hasWarnedAboutDeprecatedIsAsyncMode = true; lowPriorityWarning$1(false, 'The ReactIs.isAsyncMode() alias has been deprecated, ' + 'and will be removed in React 17+. Update your code to use ' + 'ReactIs.isConcurrentMode() instead. It has the exact same API.'); } } return isConcurrentMode(object) || typeOf(object) === REACT_ASYNC_MODE_TYPE; } function isConcurrentMode(object) { return typeOf(object) === REACT_CONCURRENT_MODE_TYPE; } exports.typeOf = typeOf; exports.AsyncMode = REACT_ASYNC_MODE_TYPE; exports.ConcurrentMode = REACT_CONCURRENT_MODE_TYPE; exports.ContextConsumer = REACT_CONTEXT_TYPE; exports.ContextProvider = REACT_PROVIDER_TYPE; exports.Element = REACT_ELEMENT_TYPE; exports.ForwardRef = REACT_FORWARD_REF_TYPE; exports.Fragment = REACT_FRAGMENT_TYPE; exports.Lazy = REACT_LAZY_TYPE; exports.Memo = REACT_MEMO_TYPE; exports.Portal = REACT_PORTAL_TYPE; exports.Profiler = REACT_PROFILER_TYPE; exports.StrictMode = REACT_STRICT_MODE_TYPE; exports.Suspense = REACT_SUSPENSE_TYPE; exports.isValidElementType = function (type) { return typeof type === 'string' || typeof type === 'function' || // Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill. type === REACT_FRAGMENT_TYPE || type === REACT_CONCURRENT_MODE_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || typeof type === 'object' && type !== null && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE); }; exports.isAsyncMode = isAsyncMode; exports.isConcurrentMode = isConcurrentMode; exports.isContextConsumer = function (object) { return typeOf(object) === REACT_CONTEXT_TYPE; }; exports.isContextProvider = function (object) { return typeOf(object) === REACT_PROVIDER_TYPE; }; exports.isElement = function (object) { return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; }; exports.isForwardRef = function (object) { return typeOf(object) === REACT_FORWARD_REF_TYPE; }; exports.isFragment = function (object) { return typeOf(object) === REACT_FRAGMENT_TYPE; }; exports.isLazy = function (object) { return typeOf(object) === REACT_LAZY_TYPE; }; exports.isMemo = function (object) { return typeOf(object) === REACT_MEMO_TYPE; }; exports.isPortal = function (object) { return typeOf(object) === REACT_PORTAL_TYPE; }; exports.isProfiler = function (object) { return typeOf(object) === REACT_PROFILER_TYPE; }; exports.isStrictMode = function (object) { return typeOf(object) === REACT_STRICT_MODE_TYPE; }; exports.isSuspense = function (object) { return typeOf(object) === REACT_SUSPENSE_TYPE; }; })(); }); unwrapExports(reactIs_development); var reactIs_development_1 = reactIs_development.typeOf; var reactIs_development_2 = reactIs_development.AsyncMode; var reactIs_development_3 = reactIs_development.ConcurrentMode; var reactIs_development_4 = reactIs_development.ContextConsumer; var reactIs_development_5 = reactIs_development.ContextProvider; var reactIs_development_6 = reactIs_development.Element; var reactIs_development_7 = reactIs_development.ForwardRef; var reactIs_development_8 = reactIs_development.Fragment; var reactIs_development_9 = reactIs_development.Lazy; var reactIs_development_10 = reactIs_development.Memo; var reactIs_development_11 = reactIs_development.Portal; var reactIs_development_12 = reactIs_development.Profiler; var reactIs_development_13 = reactIs_development.StrictMode; var reactIs_development_14 = reactIs_development.Suspense; var reactIs_development_15 = reactIs_development.isValidElementType; var reactIs_development_16 = reactIs_development.isAsyncMode; var reactIs_development_17 = reactIs_development.isConcurrentMode; var reactIs_development_18 = reactIs_development.isContextConsumer; var reactIs_development_19 = reactIs_development.isContextProvider; var reactIs_development_20 = reactIs_development.isElement; var reactIs_development_21 = reactIs_development.isForwardRef; var reactIs_development_22 = reactIs_development.isFragment; var reactIs_development_23 = reactIs_development.isLazy; var reactIs_development_24 = reactIs_development.isMemo; var reactIs_development_25 = reactIs_development.isPortal; var reactIs_development_26 = reactIs_development.isProfiler; var reactIs_development_27 = reactIs_development.isStrictMode; var reactIs_development_28 = reactIs_development.isSuspense; var reactIs = createCommonjsModule(function (module) { module.exports = reactIs_development; }); var reactIs_1 = reactIs.isForwardRef; // istanbul ignore next var statusDiv = typeof document === 'undefined' ? null : document.getElementById('a11y-status-message'); var statuses = []; /** * @param {String} status the status message */ function setStatus(status) { var isSameAsLast = statuses[statuses.length - 1] === status; if (isSameAsLast) { statuses = [].concat(statuses, [status]); } else { statuses = [status]; } var div = getStatusDiv(); // Remove previous children while (div.lastChild) { div.removeChild(div.firstChild); } statuses.filter(Boolean).forEach(function (statusItem, index) { div.appendChild(getStatusChildDiv(statusItem, index)); }); } /** * @param {String} status the status message * @param {Number} index the index * @return {HTMLElement} the child node */ function getStatusChildDiv(status, index) { var display = index === statuses.length - 1 ? 'block' : 'none'; var childDiv = document.createElement('div'); childDiv.style.display = display; childDiv.textContent = status; return childDiv; } /** * Get the status node or create it if it does not already exist * @return {HTMLElement} the status node */ function getStatusDiv() { if (statusDiv) { return statusDiv; } statusDiv = document.createElement('div'); statusDiv.setAttribute('id', 'a11y-status-message'); statusDiv.setAttribute('role', 'status'); statusDiv.setAttribute('aria-live', 'polite'); statusDiv.setAttribute('aria-relevant', 'additions text'); Object.assign(statusDiv.style, { border: '0', clip: 'rect(0 0 0 0)', height: '1px', margin: '-1px', overflow: 'hidden', padding: '0', position: 'absolute', width: '1px' }); document.body.appendChild(statusDiv); return statusDiv; } var unknown = '__autocomplete_unknown__'; var mouseUp = '__autocomplete_mouseup__'; var itemMouseEnter = '__autocomplete_item_mouseenter__'; var keyDownArrowUp = '__autocomplete_keydown_arrow_up__'; var keyDownArrowDown = '__autocomplete_keydown_arrow_down__'; var keyDownEscape = '__autocomplete_keydown_escape__'; var keyDownEnter = '__autocomplete_keydown_enter__'; var keyDownHome = '__autocomplete_keydown_home__'; var keyDownEnd = '__autocomplete_keydown_enter__'; var clickItem = '__autocomplete_click_item__'; var blurInput = '__autocomplete_blur_input__'; var changeInput = '__autocomplete_change_input__'; var keyDownSpaceButton = '__autocomplete_keydown_space_button__'; var clickButton = '__autocomplete_click_button__'; var blurButton = '__autocomplete_blur_button__'; var controlledPropUpdatedSelectedItem = '__autocomplete_controlled_prop_updated_selected_item__'; var touchEnd = '__autocomplete_touchend__'; var stateChangeTypes = /*#__PURE__*/Object.freeze({ unknown: unknown, mouseUp: mouseUp, itemMouseEnter: itemMouseEnter, keyDownArrowUp: keyDownArrowUp, keyDownArrowDown: keyDownArrowDown, keyDownEscape: keyDownEscape, keyDownEnter: keyDownEnter, keyDownHome: keyDownHome, keyDownEnd: keyDownEnd, clickItem: clickItem, blurInput: blurInput, changeInput: changeInput, keyDownSpaceButton: keyDownSpaceButton, clickButton: clickButton, blurButton: blurButton, controlledPropUpdatedSelectedItem: controlledPropUpdatedSelectedItem, touchEnd: touchEnd }); function isElement(el) { return el != null && typeof el === 'object' && el.nodeType === 1; } function canOverflow(overflow, skipOverflowHiddenElements) { if (skipOverflowHiddenElements && overflow === 'hidden') { return false; } return overflow !== 'visible' && overflow !== 'clip'; } function isScrollable(el, skipOverflowHiddenElements) { if (el.clientHeight < el.scrollHeight || el.clientWidth < el.scrollWidth) { var style = getComputedStyle(el, null); return canOverflow(style.overflowY, skipOverflowHiddenElements) || canOverflow(style.overflowX, skipOverflowHiddenElements); } return false; } function alignNearest(scrollingEdgeStart, scrollingEdgeEnd, scrollingSize, scrollingBorderStart, scrollingBorderEnd, elementEdgeStart, elementEdgeEnd, elementSize) { if (elementEdgeStart < scrollingEdgeStart && elementEdgeEnd > scrollingEdgeEnd || elementEdgeStart > scrollingEdgeStart && elementEdgeEnd < scrollingEdgeEnd) { return 0; } if (elementEdgeStart <= scrollingEdgeStart && elementSize <= scrollingSize || elementEdgeEnd >= scrollingEdgeEnd && elementSize >= scrollingSize) { return elementEdgeStart - scrollingEdgeStart - scrollingBorderStart; } if (elementEdgeEnd > scrollingEdgeEnd && elementSize < scrollingSize || elementEdgeStart < scrollingEdgeStart && elementSize > scrollingSize) { return elementEdgeEnd - scrollingEdgeEnd + scrollingBorderEnd; } return 0; } var computeScrollIntoView = (function (target, options) { var scrollMode = options.scrollMode, block = options.block, inline = options.inline, boundary = options.boundary, skipOverflowHiddenElements = options.skipOverflowHiddenElements; var checkBoundary = typeof boundary === 'function' ? boundary : function (node) { return node !== boundary; }; if (!isElement(target)) { throw new TypeError('Invalid target'); } var scrollingElement = document.scrollingElement || document.documentElement; var frames = []; var cursor = target; while (isElement(cursor) && checkBoundary(cursor)) { cursor = cursor.parentNode; if (cursor === scrollingElement) { frames.push(cursor); break; } if (cursor === document.body && isScrollable(cursor) && !isScrollable(document.documentElement)) { continue; } if (isScrollable(cursor, skipOverflowHiddenElements)) { frames.push(cursor); } } var viewportWidth = window.visualViewport ? visualViewport.width : innerWidth; var viewportHeight = window.visualViewport ? visualViewport.height : innerHeight; var viewportX = window.scrollX || pageXOffset; var viewportY = window.scrollY || pageYOffset; var _target$getBoundingCl = target.getBoundingClientRect(), targetHeight = _target$getBoundingCl.height, targetWidth = _target$getBoundingCl.width, targetTop = _target$getBoundingCl.top, targetRight = _target$getBoundingCl.right, targetBottom = _target$getBoundingCl.bottom, targetLeft = _target$getBoundingCl.left; var targetBlock = block === 'start' || block === 'nearest' ? targetTop : block === 'end' ? targetBottom : targetTop + targetHeight / 2; var targetInline = inline === 'center' ? targetLeft + targetWidth / 2 : inline === 'end' ? targetRight : targetLeft; var computations = []; for (var index = 0; index < frames.length; index++) { var frame = frames[index]; var _frame$getBoundingCli = frame.getBoundingClientRect(), _height = _frame$getBoundingCli.height, _width = _frame$getBoundingCli.width, _top = _frame$getBoundingCli.top, right = _frame$getBoundingCli.right, bottom = _frame$getBoundingCli.bottom, _left = _frame$getBoundingCli.left; if (scrollMode === 'if-needed' && targetTop >= 0 && targetLeft >= 0 && targetBottom <= viewportHeight && targetRight <= viewportWidth && targetTop >= _top && targetBottom <= bottom && targetLeft >= _left && targetRight <= right) { return computations; } var frameStyle = getComputedStyle(frame); var borderLeft = parseInt(frameStyle.borderLeftWidth, 10); var borderTop = parseInt(frameStyle.borderTopWidth, 10); var borderRight = parseInt(frameStyle.borderRightWidth, 10); var borderBottom = parseInt(frameStyle.borderBottomWidth, 10); var blockScroll = 0; var inlineScroll = 0; var scrollbarWidth = 'offsetWidth' in frame ? frame.offsetWidth - frame.clientWidth - borderLeft - borderRight : 0; var scrollbarHeight = 'offsetHeight' in frame ? frame.offsetHeight - frame.clientHeight - borderTop - borderBottom : 0; if (scrollingElement === frame) { if (block === 'start') { blockScroll = targetBlock; } else if (block === 'end') { blockScroll = targetBlock - viewportHeight; } else if (block === 'nearest') { blockScroll = alignNearest(viewportY, viewportY + viewportHeight, viewportHeight, borderTop, borderBottom, viewportY + targetBlock, viewportY + targetBlock + targetHeight, targetHeight); } else { blockScroll = targetBlock - viewportHeight / 2; } if (inline === 'start') { inlineScroll = targetInline; } else if (inline === 'center') { inlineScroll = targetInline - viewportWidth / 2; } else if (inline === 'end') { inlineScroll = targetInline - viewportWidth; } else { inlineScroll = alignNearest(viewportX, viewportX + viewportWidth, viewportWidth, borderLeft, borderRight, viewportX + targetInline, viewportX + targetInline + targetWidth, targetWidth); } blockScroll = Math.max(0, blockScroll + viewportY); inlineScroll = Math.max(0, inlineScroll + viewportX); } else { if (block === 'start') { blockScroll = targetBlock - _top - borderTop; } else if (block === 'end') { blockScroll = targetBlock - bottom + borderBottom + scrollbarHeight; } else if (block === 'nearest') { blockScroll = alignNearest(_top, bottom, _height, borderTop, borderBottom + scrollbarHeight, targetBlock, targetBlock + targetHeight, targetHeight); } else { blockScroll = targetBlock - (_top + _height / 2) + scrollbarHeight / 2; } if (inline === 'start') { inlineScroll = targetInline - _left - borderLeft; } else if (inline === 'center') { inlineScroll = targetInline - (_left + _width / 2) + scrollbarWidth / 2; } else if (inline === 'end') { inlineScroll = targetInline - right + borderRight + scrollbarWidth; } else { inlineScroll = alignNearest(_left, right, _width, borderLeft, borderRight + scrollbarWidth, targetInline, targetInline + targetWidth, targetWidth); } var scrollLeft = frame.scrollLeft, scrollTop = frame.scrollTop; blockScroll = Math.max(0, Math.min(scrollTop + blockScroll, frame.scrollHeight - _height + scrollbarHeight)); inlineScroll = Math.max(0, Math.min(scrollLeft + inlineScroll, frame.scrollWidth - _width + scrollbarWidth)); targetBlock += scrollTop - blockScroll; targetInline += scrollLeft - inlineScroll; } computations.push({ el: frame, top: blockScroll, left: inlineScroll }); } return computations; }); var idCounter = 0; /** * Accepts a parameter and returns it if it's a function * or a noop function if it's not. This allows us to * accept a callback, but not worry about it if it's not * passed. * @param {Function} cb the callback * @return {Function} a function */ function cbToCb(cb) { return typeof cb === 'function' ? cb : noop; } function noop() {} /** * Scroll node into view if necessary * @param {HTMLElement} node the element that should scroll into view * @param {HTMLElement} menuNode the menu element of the component */ function scrollIntoView(node, menuNode) { if (node === null) { return; } var actions = computeScrollIntoView(node, { boundary: menuNode, block: 'nearest', scrollMode: 'if-needed' }); actions.forEach(function (_ref) { var el = _ref.el, top = _ref.top, left = _ref.left; el.scrollTop = top; el.scrollLeft = left; }); } /** * @param {HTMLElement} parent the parent node * @param {HTMLElement} child the child node * @return {Boolean} whether the parent is the child or the child is in the parent */ function isOrContainsNode(parent, child) { return parent === child || parent.contains && parent.contains(child); } /** * Simple debounce implementation. Will call the given * function once after the time given has passed since * it was last called. * @param {Function} fn the function to call after the time * @param {Number} time the time to wait * @return {Function} the debounced function */ function debounce(fn, time) { var timeoutId; function cancel() { if (timeoutId) { clearTimeout(timeoutId); } } function wrapper() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } cancel(); timeoutId = setTimeout(function () { timeoutId = null; fn.apply(void 0, args); }, time); } wrapper.cancel = cancel; return wrapper; } /** * This is intended to be used to compose event handlers. * They are executed in order until one of them sets * `event.preventDownshiftDefault = true`. * @param {...Function} fns the event handler functions * @return {Function} the event handler to add to an element */ function callAllEventHandlers() { for (var _len2 = arguments.length, fns = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { fns[_key2] = arguments[_key2]; } return function (event) { for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { args[_key3 - 1] = arguments[_key3]; } return fns.some(function (fn) { if (fn) { fn.apply(void 0, [event].concat(args)); } return event.preventDownshiftDefault || event.hasOwnProperty('nativeEvent') && event.nativeEvent.preventDownshiftDefault; }); }; } /** * This return a function that will call all the given functions with * the arguments with which it's called. It does a null-check before * attempting to call the functions and can take any number of functions. * @param {...Function} fns the functions to call * @return {Function} the function that calls all the functions */ function callAll() { for (var _len4 = arguments.length, fns = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { fns[_key4] = arguments[_key4]; } return function () { for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { args[_key5] = arguments[_key5]; } fns.forEach(function (fn) { if (fn) { fn.apply(void 0, args); } }); }; } /** * This generates a unique ID for an instance of Downshift * @return {String} the unique ID */ function generateId() { return String(idCounter++); } /** * Resets idCounter to 0. Used for SSR. */ function resetIdCounter() { idCounter = 0; } /** * @param {Object} param the downshift state and other relevant properties * @return {String} the a11y status message */ function getA11yStatusMessage(_ref2) { var isOpen = _ref2.isOpen, selectedItem = _ref2.selectedItem, resultCount = _ref2.resultCount, previousResultCount = _ref2.previousResultCount, itemToString = _ref2.itemToString; if (!isOpen) { return selectedItem ? itemToString(selectedItem) : ''; } if (!resultCount) { return 'No results are available.'; } if (resultCount !== previousResultCount) { return resultCount + " result" + (resultCount === 1 ? ' is' : 's are') + " available, use up and down arrow keys to navigate. Press Enter key to select."; } return ''; } /** * Takes an argument and if it's an array, returns the first item in the array * otherwise returns the argument * @param {*} arg the maybe-array * @param {*} defaultValue the value if arg is falsey not defined * @return {*} the arg or it's first item */ function unwrapArray(arg, defaultValue) { arg = Array.isArray(arg) ? /* istanbul ignore next (preact) */ arg[0] : arg; if (!arg && defaultValue) { return defaultValue; } else { return arg; } } /** * @param {Object} element (P)react element * @return {Boolean} whether it's a DOM element */ function isDOMElement(element) { // then this is preact /* istanbul ignore if */ return typeof element.nodeName === 'string'; // then we assume this is react } /** * @param {Object} element (P)react element * @return {Object} the props */ function getElementProps(element) { // props for react, attributes for preact /* istanbul ignore if */ return element.attributes; } /** * Throws a helpful error message for required properties. Useful * to be used as a default in destructuring or object params. * @param {String} fnName the function name * @param {String} propName the prop name */ function requiredProp(fnName, propName) { // eslint-disable-next-line no-console console.error("The property \"" + propName + "\" is required in \"" + fnName + "\""); } var stateKeys = ['highlightedIndex', 'inputValue', 'isOpen', 'selectedItem', 'type']; /** * @param {Object} state the state object * @return {Object} state that is relevant to downshift */ function pickState(state) { if (state === void 0) { state = {}; } var result = {}; stateKeys.forEach(function (k) { if (state.hasOwnProperty(k)) { result[k] = state[k]; } }); return result; } /** * Normalizes the 'key' property of a KeyboardEvent in IE/Edge * @param {Object} event a keyboardEvent object * @return {String} keyboard key */ function normalizeArrowKey(event) { var key = event.key, keyCode = event.keyCode; /* istanbul ignore next (ie) */ if (keyCode >= 37 && keyCode <= 40 && key.indexOf('Arrow') !== 0) { return "Arrow" + key; } return key; } /** * Simple check if the value passed is object literal * @param {*} obj any things * @return {Boolean} whether it's object literal */ function isPlainObject(obj) { return Object.prototype.toString.call(obj) === '[object Object]'; } /** * Returns the new index in the list, in a circular way. If next value is out of bonds from the total, * it will wrap to either 0 or itemCount - 1. * * @param {number} moveAmount Number of positions to move. Negative to move backwards, positive forwards. * @param {number} baseIndex The initial position to move from. * @param {number} itemCount The total number of items. * @returns {number} The new index after the move. */ function getNextWrappingIndex(moveAmount, baseIndex, itemCount) { var itemsLastIndex = itemCount - 1; if (typeof baseIndex !== 'number' || baseIndex < 0 || baseIndex >= itemCount) { baseIndex = moveAmount > 0 ? -1 : itemsLastIndex + 1; } var newIndex = baseIndex + moveAmount; if (newIndex < 0) { newIndex = itemsLastIndex; } else if (newIndex > itemsLastIndex) { newIndex = 0; } return newIndex; } var Downshift = /*#__PURE__*/ function (_Component) { _inheritsLoose(Downshift, _Component); function Downshift(_props) { var _this = _Component.call(this, _props) || this; _this.id = _this.props.id || "downshift-" + generateId(); _this.menuId = _this.props.menuId || _this.id + "-menu"; _this.labelId = _this.props.labelId || _this.id + "-label"; _this.inputId = _this.props.inputId || _this.id + "-input"; _this.getItemId = _this.props.getItemId || function (index) { return _this.id + "-item-" + index; }; _this.input = null; _this.items = []; _this.itemCount = null; _this.previousResultCount = 0; _this.timeoutIds = []; _this.internalSetTimeout = function (fn, time) { var id = setTimeout(function () { _this.timeoutIds = _this.timeoutIds.filter(function (i) { return i !== id; }); fn(); }, time); _this.timeoutIds.push(id); }; _this.setItemCount = function (count) { _this.itemCount = count; }; _this.unsetItemCount = function () { _this.itemCount = null; }; _this.setHighlightedIndex = function (highlightedIndex, otherStateToSet) { if (highlightedIndex === void 0) { highlightedIndex = _this.props.defaultHighlightedIndex; } if (otherStateToSet === void 0) { otherStateToSet = {}; } otherStateToSet = pickState(otherStateToSet); _this.internalSetState(_extends({ highlightedIndex: highlightedIndex }, otherStateToSet)); }; _this.clearSelection = function (cb) { _this.internalSetState({ selectedItem: null, inputValue: '', highlightedIndex: _this.props.defaultHighlightedIndex, isOpen: _this.props.defaultIsOpen }, cb); }; _this.selectItem = function (item, otherStateToSet, cb) { otherStateToSet = pickState(otherStateToSet); _this.internalSetState(_extends({ isOpen: _this.props.defaultIsOpen, highlightedIndex: _this.props.defaultHighlightedIndex, selectedItem: item, inputValue: _this.props.itemToString(item) }, otherStateToSet), cb); }; _this.selectItemAtIndex = function (itemIndex, otherStateToSet, cb) { var item = _this.items[itemIndex]; if (item == null) { return; } _this.selectItem(item, otherStateToSet, cb); }; _this.selectHighlightedItem = function (otherStateToSet, cb) { return _this.selectItemAtIndex(_this.getState().highlightedIndex, otherStateToSet, cb); }; _this.internalSetState = function (stateToSet, cb) { var isItemSelected, onChangeArg; var onStateChangeArg = {}; var isStateToSetFunction = typeof stateToSet === 'function'; // we want to call `onInputValueChange` before the `setState` call // so someone controlling the `inputValue` state gets notified of // the input change as soon as possible. This avoids issues with // preserving the cursor position. // See https://github.com/downshift-js/downshift/issues/217 for more info. if (!isStateToSetFunction && stateToSet.hasOwnProperty('inputValue')) { _this.props.onInputValueChange(stateToSet.inputValue, _extends({}, _this.getStateAndHelpers(), stateToSet)); } return _this.setState(function (state) { state = _this.getState(state); var newStateToSet = isStateToSetFunction ? stateToSet(state) : stateToSet; // Your own function that could modify the state that will be set. newStateToSet = _this.props.stateReducer(state, newStateToSet); // checks if an item is selected, regardless of if it's different from // what was selected before // used to determine if onSelect and onChange callbacks should be called isItemSelected = newStateToSet.hasOwnProperty('selectedItem'); // this keeps track of the object we want to call with setState var nextState = {}; // this is just used to tell whether the state changed var nextFullState = {}; // we need to call on change if the outside world is controlling any of our state // and we're trying to update that state. OR if the selection has changed and we're // trying to update the selection if (isItemSelected && newStateToSet.selectedItem !== state.selectedItem) { onChangeArg = newStateToSet.selectedItem; } newStateToSet.type = newStateToSet.type || unknown; Object.keys(newStateToSet).forEach(function (key) { // onStateChangeArg should only have the state that is // actually changing if (state[key] !== newStateToSet[key]) { onStateChangeArg[key] = newStateToSet[key]; } // the type is useful for the onStateChangeArg // but we don't actually want to set it in internal state. // this is an undocumented feature for now... Not all internalSetState // calls support it and I'm not certain we want them to yet. // But it enables users controlling the isOpen state to know when // the isOpen state changes due to mouseup events which is quite handy. if (key === 'type') { return; } nextFullState[key] = newStateToSet[key]; // if it's coming from props, then we don't care to set it internally if (!_this.isControlledProp(key)) { nextState[key] = newStateToSet[key]; } }); // if stateToSet is a function, then we weren't able to call onInputValueChange // earlier, so we'll call it now that we know what the inputValue state will be. if (isStateToSetFunction && newStateToSet.hasOwnProperty('inputValue')) { _this.props.onInputValueChange(newStateToSet.inputValue, _extends({}, _this.getStateAndHelpers(), newStateToSet)); } return nextState; }, function () { // call the provided callback if it's a function cbToCb(cb)(); // only call the onStateChange and onChange callbacks if // we have relevant information to pass them. var hasMoreStateThanType = Object.keys(onStateChangeArg).length > 1; if (hasMoreStateThanType) { _this.props.onStateChange(onStateChangeArg, _this.getStateAndHelpers()); } if (isItemSelected) { _this.props.onSelect(stateToSet.selectedItem, _this.getStateAndHelpers()); } if (onChangeArg !== undefined) { _this.props.onChange(onChangeArg, _this.getStateAndHelpers()); } // this is currently undocumented and therefore subject to change // We'll try to not break it, but just be warned. _this.props.onUserAction(onStateChangeArg, _this.getStateAndHelpers()); }); }; _this.rootRef = function (node) { return _this._rootNode = node; }; _this.getRootProps = function (_temp, _temp2) { var _extends2; var _ref = _temp === void 0 ? {} : _temp, _ref$refKey = _ref.refKey, refKey = _ref$refKey === void 0 ? 'ref' : _ref$refKey, rest = _objectWithoutPropertiesLoose(_ref, ["refKey"]); var _ref2 = _temp2 === void 0 ? {} : _temp2, _ref2$suppressRefErro = _ref2.suppressRefError, suppressRefError = _ref2$suppressRefErro === void 0 ? false : _ref2$suppressRefErro; // this is used in the render to know whether the user has called getRootProps. // It uses that to know whether to apply the props automatically _this.getRootProps.called = true; _this.getRootProps.refKey = refKey; _this.getRootProps.suppressRefError = suppressRefError; var _this$getState = _this.getState(), isOpen = _this$getState.isOpen; return _extends((_extends2 = {}, _extends2[refKey] = _this.rootRef, _extends2.role = 'combobox', _extends2['aria-expanded'] = isOpen, _extends2['aria-haspopup'] = 'listbox', _extends2['aria-owns'] = isOpen ? _this.menuId : null, _extends2['aria-labelledby'] = _this.labelId, _extends2), rest); }; _this.keyDownHandlers = { ArrowDown: function ArrowDown(event) { var _this2 = this; event.preventDefault(); if (this.getState().isOpen) { var amount = event.shiftKey ? 5 : 1; this.moveHighlightedIndex(amount, { type: keyDownArrowDown }); } else { this.internalSetState({ isOpen: true, type: keyDownArrowDown }, function () { var itemCount = _this2.getItemCount(); if (itemCount > 0) { _this2.setHighlightedIndex(getNextWrappingIndex(1, _this2.getState().highlightedIndex, itemCount), { type: keyDownArrowDown }); } }); } }, ArrowUp: function ArrowUp(event) { var _this3 = this; event.preventDefault(); if (this.getState().isOpen) { var amount = event.shiftKey ? -5 : -1; this.moveHighlightedIndex(amount, { type: keyDownArrowUp }); } else { this.internalSetState({ isOpen: true, type: keyDownArrowUp }, function () { var itemCount = _this3.getItemCount(); if (itemCount > 0) { _this3.setHighlightedIndex(getNextWrappingIndex(-1, _this3.getState().highlightedIndex, itemCount), { type: keyDownArrowDown }); } }); } }, Enter: function Enter(event) { var _this$getState2 = this.getState(), isOpen = _this$getState2.isOpen, highlightedIndex = _this$getState2.highlightedIndex; if (isOpen && highlightedIndex != null) { event.preventDefault(); var item = this.items[highlightedIndex]; var itemNode = this.getItemNodeFromIndex(highlightedIndex); if (item == null || itemNode && itemNode.hasAttribute('disabled')) { return; } this.selectHighlightedItem({ type: keyDownEnter }); } }, Escape: function Escape(event) { event.preventDefault(); this.reset({ type: keyDownEscape }); } }; _this.buttonKeyDownHandlers = _extends({}, _this.keyDownHandlers, { ' ': function _(event) { event.preventDefault(); this.toggleMenu({ type: keyDownSpaceButton }); } }); _this.inputKeyDownHandlers = _extends({}, _this.keyDownHandlers, { Home: function Home(event) { this.highlightFirstOrLastIndex(event, true, { type: keyDownHome }); }, End: function End(event) { this.highlightFirstOrLastIndex(event, false, { type: keyDownEnd }); } }); _this.getToggleButtonProps = function (_temp3) { var _ref3 = _temp3 === void 0 ? {} : _temp3, onClick = _ref3.onClick, onPress = _ref3.onPress, onKeyDown = _ref3.onKeyDown, onKeyUp = _ref3.onKeyUp, onBlur = _ref3.onBlur, rest = _objectWithoutPropertiesLoose(_ref3, ["onClick", "onPress", "onKeyDown", "onKeyUp", "onBlur"]); var _this$getState3 = _this.getState(), isOpen = _this$getState3.isOpen; var enabledEventHandlers = { onClick: callAllEventHandlers(onClick, _this.buttonHandleClick), onKeyDown: callAllEventHandlers(onKeyDown, _this.buttonHandleKeyDown), onKeyUp: callAllEventHandlers(onKeyUp, _this.buttonHandleKeyUp), onBlur: callAllEventHandlers(onBlur, _this.buttonHandleBlur) }; var eventHandlers = rest.disabled ? {} : enabledEventHandlers; return _extends({ type: 'button', role: 'button', 'aria-label': isOpen ? 'close menu' : 'open menu', 'aria-haspopup': true, 'data-toggle': true }, eventHandlers, rest); }; _this.buttonHandleKeyUp = function (event) { // Prevent click event from emitting in Firefox event.preventDefault(); }; _this.buttonHandleKeyDown = function (event) { var key = normalizeArrowKey(event); if (_this.buttonKeyDownHandlers[key]) { _this.buttonKeyDownHandlers[key].call(_assertThisInitialized(_this), event); } }; _this.buttonHandleClick = function (event) { event.preventDefault(); // handle odd case for Safari and Firefox which // don't give the button the focus properly. /* istanbul ignore if (can't reasonably test this