downshift
Version:
A set of primitives to build simple, flexible, WAI-ARIA compliant React autocomplete components
1,374 lines (1,137 loc) • 143 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('preact'), require('prop-types')) :
typeof define === 'function' && define.amd ? define(['exports', 'preact', 'prop-types'], factory) :
(global = global || self, factory(global.Downshift = {}, global.preact, global.PropTypes));
}(this, (function (exports, preact, PropTypes) { 'use strict';
PropTypes = PropTypes && PropTypes.hasOwnProperty('default') ? PropTypes['default'] : PropTypes;
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.suspense_list") : 60120,
r = b ? Symbol.for("react.memo") : 60115,
t = b ? Symbol.for("react.lazy") : 60116,
v = b ? Symbol.for("react.fundamental") : 60117,
w = b ? Symbol.for("react.responder") : 60118;
function x(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 t:
case r:
case d:
return u;
}
}
}
function y(a) {
return x(a) === m;
}
exports.typeOf = x;
exports.AsyncMode = l;
exports.ConcurrentMode = m;
exports.ContextConsumer = k;
exports.ContextProvider = h;
exports.Element = c;
exports.ForwardRef = n;
exports.Fragment = e;
exports.Lazy = t;
exports.Memo = r;
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 || a === q || "object" === typeof a && null !== a && (a.$$typeof === t || a.$$typeof === r || a.$$typeof === h || a.$$typeof === k || a.$$typeof === n || a.$$typeof === v || a.$$typeof === w);
};
exports.isAsyncMode = function (a) {
return y(a) || x(a) === l;
};
exports.isConcurrentMode = y;
exports.isContextConsumer = function (a) {
return x(a) === k;
};
exports.isContextProvider = function (a) {
return x(a) === h;
};
exports.isElement = function (a) {
return "object" === typeof a && null !== a && a.$$typeof === c;
};
exports.isForwardRef = function (a) {
return x(a) === n;
};
exports.isFragment = function (a) {
return x(a) === e;
};
exports.isLazy = function (a) {
return x(a) === t;
};
exports.isMemo = function (a) {
return x(a) === r;
};
exports.isPortal = function (a) {
return x(a) === d;
};
exports.isProfiler = function (a) {
return x(a) === g;
};
exports.isStrictMode = function (a) {
return x(a) === f;
};
exports.isSuspense = function (a) {
return x(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; // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary
// (unstable) APIs that have been removed. Can we remove the symbols?
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_SUSPENSE_LIST_TYPE = hasSymbol ? Symbol.for('react.suspense_list') : 0xead8;
var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4;
var REACT_FUNDAMENTAL_TYPE = hasSymbol ? Symbol.for('react.fundamental') : 0xead5;
var REACT_RESPONDER_TYPE = hasSymbol ? Symbol.for('react.responder') : 0xead6;
function isValidElementType(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 || type === REACT_SUSPENSE_LIST_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 || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_RESPONDER_TYPE);
}
/**
* 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 AsyncMode = REACT_ASYNC_MODE_TYPE;
var ConcurrentMode = REACT_CONCURRENT_MODE_TYPE;
var ContextConsumer = REACT_CONTEXT_TYPE;
var ContextProvider = REACT_PROVIDER_TYPE;
var Element = REACT_ELEMENT_TYPE;
var ForwardRef = REACT_FORWARD_REF_TYPE;
var Fragment = REACT_FRAGMENT_TYPE;
var Lazy = REACT_LAZY_TYPE;
var Memo = REACT_MEMO_TYPE;
var Portal = REACT_PORTAL_TYPE;
var Profiler = REACT_PROFILER_TYPE;
var StrictMode = REACT_STRICT_MODE_TYPE;
var Suspense = REACT_SUSPENSE_TYPE;
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;
}
function isContextConsumer(object) {
return typeOf(object) === REACT_CONTEXT_TYPE;
}
function isContextProvider(object) {
return typeOf(object) === REACT_PROVIDER_TYPE;
}
function isElement(object) {
return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
}
function isForwardRef(object) {
return typeOf(object) === REACT_FORWARD_REF_TYPE;
}
function isFragment(object) {
return typeOf(object) === REACT_FRAGMENT_TYPE;
}
function isLazy(object) {
return typeOf(object) === REACT_LAZY_TYPE;
}
function isMemo(object) {
return typeOf(object) === REACT_MEMO_TYPE;
}
function isPortal(object) {
return typeOf(object) === REACT_PORTAL_TYPE;
}
function isProfiler(object) {
return typeOf(object) === REACT_PROFILER_TYPE;
}
function isStrictMode(object) {
return typeOf(object) === REACT_STRICT_MODE_TYPE;
}
function isSuspense(object) {
return typeOf(object) === REACT_SUSPENSE_TYPE;
}
exports.typeOf = typeOf;
exports.AsyncMode = AsyncMode;
exports.ConcurrentMode = ConcurrentMode;
exports.ContextConsumer = ContextConsumer;
exports.ContextProvider = ContextProvider;
exports.Element = Element;
exports.ForwardRef = ForwardRef;
exports.Fragment = Fragment;
exports.Lazy = Lazy;
exports.Memo = Memo;
exports.Portal = Portal;
exports.Profiler = Profiler;
exports.StrictMode = StrictMode;
exports.Suspense = Suspense;
exports.isValidElementType = isValidElementType;
exports.isAsyncMode = isAsyncMode;
exports.isConcurrentMode = isConcurrentMode;
exports.isContextConsumer = isContextConsumer;
exports.isContextProvider = isContextProvider;
exports.isElement = isElement;
exports.isForwardRef = isForwardRef;
exports.isFragment = isFragment;
exports.isLazy = isLazy;
exports.isMemo = isMemo;
exports.isPortal = isPortal;
exports.isProfiler = isProfiler;
exports.isStrictMode = isStrictMode;
exports.isSuspense = isSuspense;
})();
}
});
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;
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;
});
};
}
function handleRefs() {
for (var _len4 = arguments.length, refs = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
refs[_key4] = arguments[_key4];
}
return function (node) {
refs.forEach(function (ref) {
if (typeof ref === 'function') {
ref(node);
} else if (ref) {
ref.current = node;
}
});
};
}
/**
* 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 or preact X
/* istanbul ignore if */
return typeof element.nodeName === 'string' || typeof element.type === '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 || element.props;
}
/**
* 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;
}
/**
* This will perform a shallow merge of the given state object
* with the state coming from props
* (for the controlled component scenario)
* This is used in state updater functions so they're referencing
* the right state regardless of where it comes from.
*
* @param {Object} state The state of the component/hook.
* @param {Object} props The props that may contain controlled values.
* @returns {Object} The merged controlled state.
*/
function getState(state, props) {
return Object.keys(state).reduce(function (prevState, key) {
prevState[key] = isControlledProp(props, key) ? props[key] : state[key];
return prevState;
}, {});
}
/**
* This determines whether a prop is a "controlled prop" meaning it is
* state which is controlled by the outside of this component rather
* than within this component.
*
* @param {Object} props The props that may contain controlled values.
* @param {String} key the key to check
* @return {Boolean} whether it is a controlled controlled prop
*/
function isControlledProp(props, key) {
return props[key] !== undefined;
}
/**
* 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.
* @param {Function} getItemNodeFromIndex Used to check if item is disabled.
* @param {boolean} circular Specify if navigation is circular. Default is true.
* @returns {number} The new index after the move.
*/
function getNextWrappingIndex(moveAmount, baseIndex, itemCount, getItemNodeFromIndex, circular) {
if (circular === void 0) {
circular = true;
}
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 = circular ? itemsLastIndex : 0;
} else if (newIndex > itemsLastIndex) {
newIndex = circular ? 0 : itemsLastIndex;
}
var nonDisabledNewIndex = getNextNonDisabledIndex(moveAmount, newIndex, itemCount, getItemNodeFromIndex, circular);
return nonDisabledNewIndex === -1 ? baseIndex : nonDisabledNewIndex;
}
/**
* Returns the next index in the list of an item that is not disabled.
*
* @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.
* @param {Function} getItemNodeFromIndex Used to check if item is disabled.
* @param {boolean} circular Specify if navigation is circular. Default is true.
* @returns {number} The new index. Returns baseIndex if item is not disabled. Returns next non-disabled item otherwise. If no non-disabled found it will return -1.
*/
function getNextNonDisabledIndex(moveAmount, baseIndex, itemCount, getItemNodeFromIndex, circular) {
var currentElementNode = getItemNodeFromIndex(baseIndex);
if (!currentElementNode || !currentElementNode.hasAttribute('disabled')) {
return baseIndex;
}
if (moveAmount > 0) {
for (var index = baseIndex + 1; index < itemCount; index++) {
if (!getItemNodeFromIndex(index).hasAttribute('disabled')) {
return index;
}
}
} else {
for (var _index = baseIndex - 1; _index >= 0; _index--) {
if (!getItemNodeFromIndex(_index).hasAttribute('disabled')) {
return _index;
}
}
}
if (circular) {
return moveAmount > 0 ? getNextNonDisabledIndex(1, 0, itemCount, getItemNodeFromIndex, false) : getNextNonDisabledIndex(-1, itemCount - 1, itemCount, getItemNodeFromIndex, false);
}
return -1;
}
/**
* Checks if event target is within the downshift elements.
*
* @param {EventTarget} target Target to check.
* @param {HTMLElement} rootNode The element with combobox role.
* @param {HTMLElement} menuNode The elements list with listbox role.
* @param {Document} document The document.
* @param {boolean} checkActiveElement Whether to also check activeElement.
*
* @returns {boolean} Whether or not the target is within downshift elements.
*/
function targetWithinDownshift(target, rootNode, menuNode, document, checkActiveElement) {
if (checkActiveElement === void 0) {
checkActiveElement = true;
}
return [rootNode, menuNode].some(function (contextNode) {
return contextNode && (isOrContainsNode(contextNode, target) || checkActiveElement && isOrContainsNode(contextNode, document.activeElement));
});
}
var cleanupStatus = debounce(function () {
getStatusDiv().textContent = '';
}, 500);
/**
* @param {String} status the status message
* @param {Object} documentProp document passed by the user.
*/
function setStatus(status, documentProp) {
var div = getStatusDiv(documentProp);
if (!status) {
return;
}
div.textContent = status;
cleanupStatus();
}
/**
* Get the status node or create it if it does not already exist.
* @param {Object} documentProp document passed by the user.
* @return {HTMLElement} the status node.
*/
function getStatusDiv(documentProp) {
if (documentProp === void 0) {
documentProp = document;
}
var statusDiv = documentProp.getElementById('a11y-status-message');
if (statusDiv) {
return statusDiv;
}
statusDiv = documentProp.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'
});
documentProp.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_end__';
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({
__proto__: null,
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
});
var Downshift =
/*#__PURE__*/
function () {
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 (!isControlledProp(_this.props, 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,
ref = _ref.ref,
rest = _objectWithoutPropertiesLoose(_ref, ["refKey", "ref"]);