UNPKG

38.5 kBSource Map (JSON)View Raw
1{"version":3,"file":"downshift.preact.umd.min.js","sources":["../src/set-a11y-status.js","../src/utils.js","../src/downshift.js"],"sourcesContent":["// istanbul ignore next\nlet statusDiv =\n typeof document === 'undefined' ?\n null :\n document.getElementById('a11y-status-message')\n\nlet statuses = []\n\nfunction setStatus(status) {\n const isSameAsLast = statuses[statuses.length - 1] === status\n if (isSameAsLast) {\n statuses = [...statuses, status]\n } else {\n statuses = [status]\n }\n const div = getStatusDiv()\n div.innerHTML = `${statuses.filter(Boolean).map(getStatusHtml).join('')}`\n}\n\nfunction getStatusHtml(status, index) {\n const display = index === statuses.length - 1 ? 'block' : 'none'\n return `<div style=\"display:${display};\">${status}</div>`\n}\n\nfunction getStatusDiv() {\n if (statusDiv) {\n return statusDiv\n }\n statusDiv = document.createElement('div')\n statusDiv.setAttribute('id', 'a11y-status-message')\n statusDiv.setAttribute('role', 'status')\n statusDiv.setAttribute('aria-live', 'assertive')\n statusDiv.setAttribute('aria-relevant', 'additions text')\n Object.assign(statusDiv.style, {\n border: '0',\n clip: 'rect(0 0 0 0)',\n height: '1px',\n margin: '-1px',\n overflow: 'hidden',\n padding: '0',\n position: 'absolute',\n width: '1px',\n })\n document.body.appendChild(statusDiv)\n return statusDiv\n}\n\nexport default setStatus\n","let idCounter = 1\n\n/**\n * Accepts a parameter and returns it if it's a function\n * or a noop function if it's not. This allows us to\n * accept a callback, but not worry about it if it's not\n * passed.\n * @param {Function} cb the callback\n * @return {Function} a function\n */\nfunction cbToCb(cb) {\n return typeof cb === 'function' ? cb : noop\n}\nfunction noop() {}\n\nfunction findParent(finder, node, rootNode) {\n if (node !== null && node !== rootNode.parentNode) {\n if (finder(node)) {\n return node\n } else {\n return findParent(finder, node.parentNode, rootNode)\n }\n } else {\n return null\n }\n}\n\n/**\n* Get the closest element that scrolls\n* @param {HTMLElement} node - the child element to start searching for scroll parent at\n* @param {HTMLElement} rootNode - the root element of the component\n* @return {HTMLElement} the closest parentNode that scrolls\n*/\nconst getClosestScrollParent = findParent.bind(\n null,\n node => node.scrollHeight > node.clientHeight,\n)\n\n/**\n * Scroll node into view if necessary\n * @param {HTMLElement} node - the element that should scroll into view\n * @param {HTMLElement} rootNode - the root element of the component\n * @param {Boolean} alignToTop - align element to the top of the visible area of the scrollable ancestor\n */\nfunction scrollIntoView(node, rootNode) {\n const scrollParent = getClosestScrollParent(node, rootNode)\n if (scrollParent === null) {\n return\n }\n const scrollParentStyles = getComputedStyle(scrollParent)\n const scrollParentRect = scrollParent.getBoundingClientRect()\n const scrollParentBorderTopWidth = parseInt(\n scrollParentStyles.borderTopWidth,\n 10,\n )\n const scrollParentTop = scrollParentRect.top + scrollParentBorderTopWidth\n const nodeRect = node.getBoundingClientRect()\n const nodeOffsetTop = nodeRect.top + scrollParent.scrollTop\n const nodeTop = nodeOffsetTop - scrollParentTop\n if (nodeTop < scrollParent.scrollTop) {\n // the item is above the scrollable area\n scrollParent.scrollTop = nodeTop\n } else if (\n nodeTop + nodeRect.height >\n scrollParent.scrollTop + scrollParentRect.height\n ) {\n // the item is below the scrollable area\n scrollParent.scrollTop = nodeTop + nodeRect.height - scrollParentRect.height\n }\n // the item is within the scrollable area (do nothing)\n}\n\n/**\n * Simple debounce implementation. Will call the given\n * function once after the time given has passed since\n * it was last called.\n * @param {Function} fn the function to call after the time\n * @param {Number} time the time to wait\n * @return {Function} the debounced function\n */\nfunction debounce(fn, time) {\n let timeoutId\n return wrapper\n function wrapper(...args) {\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n timeoutId = setTimeout(() => {\n timeoutId = null\n fn(...args)\n }, time)\n }\n}\n\n/**\n * This is intended to be used to compose event handlers\n * They are executed in order until one of them calls\n * `event.preventDefault()`. Not sure this is the best\n * way to do this, but it seems legit...\n * @param {Function} fns the event hanlder functions\n * @return {Function} the event handler to add to an element\n */\nfunction composeEventHandlers(...fns) {\n return (event, ...args) =>\n fns.some(fn => {\n fn && fn(event, ...args)\n return event.defaultPrevented\n })\n}\n\n/**\n * This generates a unique ID for all autocomplete inputs\n * @param {String} prefix the prefix for the id\n * @return {String} the unique ID\n */\nfunction generateId(prefix) {\n return `${prefix}-${idCounter++}`\n}\n\n/**\n * Returns the first argument that is not undefined\n * @param {...*} args the arguments\n * @return {*} the defined value\n */\nfunction firstDefined(...args) {\n return args.find(a => typeof a !== 'undefined')\n}\n\nfunction isNumber(thing) {\n // not NaN and is a number type\n // eslint-disable-next-line no-self-compare\n return thing === thing && typeof thing === 'number'\n}\n\n// eslint-disable-next-line complexity\nfunction getA11yStatusMessage({\n isOpen,\n highlightedItem,\n selectedItem,\n resultCount,\n previousResultCount,\n itemToString,\n}) {\n if (!isOpen) {\n if (selectedItem) {\n return itemToString(selectedItem)\n } else {\n return ''\n }\n }\n const resultCountChanged = resultCount !== previousResultCount\n if (!resultCount) {\n return 'No results.'\n } else if (!highlightedItem || resultCountChanged) {\n return `${resultCount} ${resultCount === 1 ?\n 'result is' :\n 'results are'} available, use up and down arrow keys to navigate.`\n }\n return itemToString(highlightedItem)\n}\n\n/**\n * Takes an argument and if it's an array, returns the first item in the array\n * otherwise returns the argument\n * @param {*} arg the maybe-array\n * @param {*} defaultValue the value if arg is falsey not defined\n * @return {*} the arg or it's first item\n */\nfunction unwrapArray(arg, defaultValue) {\n arg = Array.isArray(arg) ? /* istanbul ignore next (preact) */ arg[0] : arg\n if (!arg && defaultValue) {\n return defaultValue\n } else {\n return arg\n }\n}\n\n/**\n * @param {Object} element (P)react element\n * @return {Boolean} whether it's a DOM element\n */\nfunction isDOMElement(element) {\n /* istanbul ignore if */\n if (element.nodeName) {\n // then this is preact\n return typeof element.nodeName === 'string'\n } else {\n // then we assume this is react\n return typeof element.type === 'string'\n }\n}\n\n/**\n * @param {Object} element (P)react element\n * @return {Object} the props\n */\nfunction getElementProps(element) {\n // props for react, attributes for preact\n return element.props || /* istanbul ignore next (preact) */ element.attributes\n}\n\nexport {\n cbToCb,\n findParent,\n composeEventHandlers,\n debounce,\n scrollIntoView,\n generateId,\n firstDefined,\n isNumber,\n getA11yStatusMessage,\n unwrapArray,\n isDOMElement,\n getElementProps,\n noop,\n}\n","/* eslint camelcase:0 */\n\nimport React, {Component} from 'react'\nimport PropTypes from 'prop-types'\nimport setA11yStatus from './set-a11y-status'\nimport {\n cbToCb,\n findParent,\n composeEventHandlers,\n debounce,\n scrollIntoView,\n generateId,\n firstDefined,\n isNumber,\n getA11yStatusMessage,\n unwrapArray,\n isDOMElement,\n getElementProps,\n noop,\n} from './utils'\n\nclass Downshift extends Component {\n static propTypes = {\n children: PropTypes.func,\n defaultHighlightedIndex: PropTypes.number,\n defaultSelectedItem: PropTypes.any,\n defaultInputValue: PropTypes.string,\n defaultIsOpen: PropTypes.bool,\n getA11yStatusMessage: PropTypes.func,\n itemToString: PropTypes.func,\n onChange: PropTypes.func,\n onStateChange: PropTypes.func,\n onClick: PropTypes.func,\n itemCount: PropTypes.number,\n // things we keep in state for uncontrolled components\n // but can accept as props for controlled components\n /* eslint-disable react/no-unused-prop-types */\n selectedItem: PropTypes.any,\n isOpen: PropTypes.bool,\n inputValue: PropTypes.string,\n highlightedIndex: PropTypes.number,\n /* eslint-enable */\n }\n\n static defaultProps = {\n defaultHighlightedIndex: null,\n defaultSelectedItem: null,\n defaultInputValue: '',\n defaultIsOpen: false,\n getA11yStatusMessage,\n itemToString: i => (i == null ? '' : String(i)),\n onStateChange: () => {},\n onChange: () => {},\n }\n\n // this is an experimental feature\n // so we're not going to document this yet\n static stateChangeTypes = {\n mouseUp: '__autocomplete_mouseup__',\n }\n\n constructor(...args) {\n super(...args)\n this.id = generateId('downshift')\n const state = this.getState({\n highlightedIndex: this.props.defaultHighlightedIndex,\n isOpen: this.props.defaultIsOpen,\n inputValue: this.props.defaultInputValue,\n selectedItem: this.props.defaultSelectedItem,\n })\n if (state.selectedItem) {\n state.inputValue = this.props.itemToString(state.selectedItem)\n }\n this.state = state\n this.root_handleClick = composeEventHandlers(\n this.props.onClick,\n this.root_handleClick,\n )\n }\n\n input = null\n items = []\n previousResultCount = 0\n\n /**\n * Gets the state based on internal state or props\n * If a state value is passed via props, then that\n * is the value given, otherwise it's retrieved from\n * stateToMerge\n *\n * This will perform a shallow merge of the given state object\n * with the state coming from props\n * (for the controlled component scenario)\n * This is used in state updater functions so they're referencing\n * the right state regardless of where it comes from.\n *\n * @param {Object} stateToMerge defaults to this.state\n * @return {Object} the state\n */\n getState(stateToMerge = this.state) {\n return Object.keys(stateToMerge).reduce((state, key) => {\n state[key] = this.isStateProp(key) ? this.props[key] : stateToMerge[key]\n return state\n }, {})\n }\n\n /**\n * This determines whether a prop is a \"controlled prop\" meaning it is\n * state which is controlled by the outside of this component rather\n * than within this component.\n * @param {String} key the key to check\n * @return {Boolean} whether it is a controlled controlled prop\n */\n isStateProp(key) {\n return this.props[key] !== undefined\n }\n\n getItemCount() {\n if (this.props.itemCount === undefined) {\n return this.items.length\n } else {\n return this.props.itemCount\n }\n }\n\n getItemNodeFromIndex = index => {\n return document.getElementById(this.getItemId(index))\n }\n\n setHighlightedIndex = (\n highlightedIndex = this.props.defaultHighlightedIndex,\n ) => {\n this.internalSetState({highlightedIndex}, () => {\n const node = this.getItemNodeFromIndex(this.getState().highlightedIndex)\n const rootNode = this._rootNode\n scrollIntoView(node, rootNode)\n })\n }\n\n highlightIndex = index => {\n this.openMenu(() => {\n this.setHighlightedIndex(index)\n })\n }\n\n moveHighlightedIndex = amount => {\n if (this.getState().isOpen) {\n this.changeHighlighedIndex(amount)\n } else {\n this.highlightIndex()\n }\n }\n\n // eslint-disable-next-line complexity\n changeHighlighedIndex = moveAmount => {\n const itemsLastIndex = this.getItemCount() - 1\n if (itemsLastIndex < 0) {\n return\n }\n const {highlightedIndex} = this.getState()\n let baseIndex = highlightedIndex\n if (baseIndex === null) {\n baseIndex = moveAmount > 0 ? -1 : itemsLastIndex + 1\n }\n let newIndex = baseIndex + moveAmount\n if (newIndex < 0) {\n newIndex = itemsLastIndex\n } else if (newIndex > itemsLastIndex) {\n newIndex = 0\n }\n this.setHighlightedIndex(newIndex)\n }\n\n clearSelection = () => {\n this.internalSetState(\n {\n selectedItem: null,\n inputValue: '',\n isOpen: false,\n },\n () => {\n const inputNode = this._rootNode.querySelector(`#${this.inputId}`)\n inputNode && inputNode.focus && inputNode.focus()\n },\n )\n }\n\n selectItem = item => {\n this.internalSetState({\n isOpen: false,\n highlightedIndex: null,\n selectedItem: item,\n inputValue: this.props.itemToString(item),\n })\n }\n\n selectItemAtIndex = itemIndex => {\n const item = this.items[itemIndex]\n if (!item) {\n return\n }\n this.selectItem(item)\n }\n\n selectHighlightedItem = () => {\n return this.selectItemAtIndex(this.getState().highlightedIndex)\n }\n\n // any piece of our state can live in two places:\n // 1. Uncontrolled: it's internal (this.state)\n // We will call this.setState to update that state\n // 2. Controlled: it's external (this.props)\n // We will call this.props.onStateChange to update that state\n //\n // In addition, we'll call this.props.onChange if the\n // selectedItem is changed.\n internalSetState(stateToSet, cb) {\n let onChangeArg\n const onStateChangeArg = {}\n return this.setState(\n state => {\n state = this.getState(state)\n stateToSet =\n typeof stateToSet === 'function' ? stateToSet(state) : stateToSet\n // this keeps track of the object we want to call with setState\n const nextState = {}\n // this is just used to tell whether the state changed\n const nextFullState = {}\n // we need to call on change if the outside world is controlling any of our state\n // and we're trying to update that state. OR if the selection has changed and we're\n // trying to update the selection\n if (\n stateToSet.hasOwnProperty('selectedItem') &&\n stateToSet.selectedItem !== state.selectedItem\n ) {\n onChangeArg = stateToSet.selectedItem\n }\n Object.keys(stateToSet).forEach(key => {\n // the type is useful for the onStateChangeArg\n // but we don't actually want to set it in internal state.\n // this is an undocumented feature for now... Not all internalSetState\n // calls support it and I'm not certain we want them to yet.\n // But it enables users controlling the isOpen state to know when\n // the isOpen state changes due to mouseup events which is quite handy.\n if (key === 'type') {\n return\n }\n // onStateChangeArg should only have the state that is\n // actually changing\n if (state[key] !== stateToSet[key]) {\n onStateChangeArg[key] = stateToSet[key]\n }\n nextFullState[key] = stateToSet[key]\n // if it's coming from props, then we don't care to set it internally\n if (!this.isStateProp(key)) {\n nextState[key] = stateToSet[key]\n }\n })\n return nextState\n },\n () => {\n // call the provided callback if it's a callback\n cbToCb(cb)()\n\n // only call the onStateChange and onChange callbacks if\n // we have relevant information to pass them.\n if (Object.keys(onStateChangeArg).length) {\n this.props.onStateChange(onStateChangeArg, this.getState())\n }\n if (onChangeArg !== undefined) {\n this.props.onChange(onChangeArg, this.getState())\n }\n },\n )\n }\n\n getControllerStateAndHelpers() {\n const {highlightedIndex, inputValue, selectedItem, isOpen} = this.getState()\n const {\n getRootProps,\n getButtonProps,\n getLabelProps,\n getInputProps,\n getItemProps,\n openMenu,\n closeMenu,\n toggleMenu,\n selectItem,\n selectItemAtIndex,\n selectHighlightedItem,\n setHighlightedIndex,\n clearSelection,\n } = this\n return {\n // prop getters\n getRootProps,\n getButtonProps,\n getLabelProps,\n getInputProps,\n getItemProps,\n\n // actions\n openMenu,\n closeMenu,\n toggleMenu,\n selectItem,\n selectItemAtIndex,\n selectHighlightedItem,\n setHighlightedIndex,\n clearSelection,\n\n // state\n highlightedIndex,\n inputValue,\n isOpen,\n selectedItem,\n }\n }\n\n //////////////////////////// ROOT\n\n rootRef = node => (this._rootNode = node)\n\n getRootProps = ({refKey = 'ref', onClick, ...rest} = {}) => {\n // this is used in the render to know whether the user has called getRootProps.\n // It uses that to know whether to apply the props automatically\n this.getRootProps.called = true\n this.getRootProps.refKey = refKey\n return {\n [refKey]: this.rootRef,\n onClick: composeEventHandlers(onClick, this.root_handleClick),\n ...rest,\n }\n }\n\n root_handleClick = event => {\n event.preventDefault()\n const itemParent = findParent(\n node => {\n const index = this.getItemIndexFromId(node.getAttribute('id'))\n return isNumber(index)\n },\n event.target,\n this._rootNode,\n )\n if (itemParent) {\n this.selectItemAtIndex(\n this.getItemIndexFromId(itemParent.getAttribute('id')),\n )\n }\n }\n\n //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ROOT\n\n keyDownHandlers = {\n ArrowDown(event) {\n event.preventDefault()\n const amount = event.shiftKey ? 5 : 1\n this.moveHighlightedIndex(amount)\n },\n\n ArrowUp(event) {\n event.preventDefault()\n const amount = event.shiftKey ? -5 : -1\n this.moveHighlightedIndex(amount)\n },\n\n Enter(event) {\n event.preventDefault()\n if (this.getState().isOpen) {\n this.selectHighlightedItem()\n }\n },\n\n Escape(event) {\n event.preventDefault()\n this.reset()\n },\n }\n\n //////////////////////////// BUTTON\n\n buttonKeyDownHandlers = {\n ...this.keyDownHandlers,\n\n ' '(event) {\n event.preventDefault()\n this.toggleMenu()\n },\n }\n\n getButtonProps = ({onClick, onKeyDown, ...rest} = {}) => {\n const {isOpen} = this.getState()\n return {\n role: 'button',\n 'aria-label': isOpen ? 'close menu' : 'open menu',\n 'aria-expanded': isOpen,\n 'aria-haspopup': true,\n onClick: composeEventHandlers(onClick, this.button_handleClick),\n onKeyDown: composeEventHandlers(onKeyDown, this.button_handleKeyDown),\n ...rest,\n }\n }\n\n button_handleKeyDown = event => {\n if (this.buttonKeyDownHandlers[event.key]) {\n this.buttonKeyDownHandlers[event.key].call(this, event)\n }\n }\n\n button_handleClick = event => {\n event.preventDefault()\n this.toggleMenu()\n }\n\n //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ BUTTON\n\n /////////////////////////////// LABEL\n\n getLabelProps = (props = {}) => {\n this.getLabelProps.called = true\n if (\n this.getInputProps.called &&\n props.htmlFor &&\n props.htmlFor !== this.inputId\n ) {\n throw new Error(\n `downshift: You provided the htmlFor of \"${props.htmlFor}\" for your label, but the id of your input is \"${this\n .inputId}\". You must either remove the id from your input or set the htmlFor of the label equal to the input id.`,\n )\n }\n this.inputId = firstDefined(\n this.inputId,\n props.htmlFor,\n generateId('downshift-input'),\n )\n return {\n ...props,\n htmlFor: this.inputId,\n }\n }\n\n //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ LABEL\n\n /////////////////////////////// INPUT\n\n getInputProps = ({onKeyDown, onBlur, onChange, onInput, ...rest} = {}) => {\n this.getInputProps.called = true\n if (this.getLabelProps.called && rest.id && rest.id !== this.inputId) {\n throw new Error(\n `downshift: You provided the id of \"${rest.id}\" for your input, but the htmlFor of your label is \"${this\n .inputId}\". You must either remove the id from your input or set the htmlFor of the label equal to the input id.`,\n )\n }\n this.inputId = firstDefined(\n this.inputId,\n rest.id,\n generateId('downshift-input'),\n )\n const onChangeKey =\n process.env.LIBRARY === 'preact' ? /* istanbul ignore next (preact) */\n 'onInput' :\n 'onChange'\n const {inputValue, isOpen, highlightedIndex} = this.getState()\n return {\n role: 'combobox',\n 'aria-autocomplete': 'list',\n 'aria-expanded': isOpen,\n 'aria-activedescendant':\n typeof highlightedIndex === 'number' && highlightedIndex >= 0 ?\n this.getItemId(highlightedIndex) :\n null,\n autoComplete: 'off',\n value: inputValue,\n // preact compatibility\n [onChangeKey]: composeEventHandlers(\n onChange,\n onInput,\n this.input_handleChange,\n ),\n onKeyDown: composeEventHandlers(onKeyDown, this.input_handleKeyDown),\n onBlur: composeEventHandlers(onBlur, this.input_handleBlur),\n ...rest,\n id: this.inputId,\n }\n }\n\n input_handleKeyDown = event => {\n if (event.key && this.keyDownHandlers[event.key]) {\n this.keyDownHandlers[event.key].call(this, event)\n }\n }\n\n input_handleChange = event => {\n this.internalSetState({isOpen: true, inputValue: event.target.value})\n }\n\n input_handleBlur = () => {\n if (!this.isMouseDown) {\n this.reset()\n }\n }\n //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ INPUT\n\n /////////////////////////////// ITEM\n getItemId(index) {\n return `${this.id}-item-${index}`\n }\n\n getItemIndexFromId(id) {\n if (id) {\n return Number(id.split(`${this.id}-item-`)[1])\n } else {\n return null\n }\n }\n\n getItemProps = ({onMouseEnter, item, index, ...rest} = {}) => {\n this.items[index] = item\n return {\n id: this.getItemId(index),\n onMouseEnter: composeEventHandlers(onMouseEnter, () => {\n this.setHighlightedIndex(index)\n }),\n ...rest,\n }\n }\n //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ITEM\n\n reset = type => {\n this.internalSetState(({selectedItem}) => ({\n type,\n isOpen: false,\n highlightedIndex: null,\n inputValue: this.props.itemToString(selectedItem),\n }))\n }\n\n toggleMenu = (newState, cb) => {\n this.internalSetState(\n ({isOpen}) => {\n let nextIsOpen = !isOpen\n if (typeof newState === 'boolean') {\n nextIsOpen = newState\n }\n return {isOpen: nextIsOpen}\n },\n () => {\n const {isOpen} = this.getState()\n if (isOpen) {\n this.setHighlightedIndex()\n }\n cbToCb(cb)()\n },\n )\n }\n\n openMenu = cb => {\n this.toggleMenu(true, cb)\n }\n\n closeMenu = cb => {\n this.toggleMenu(false, cb)\n }\n\n updateStatus = debounce(() => {\n if (!this._isMounted) {\n return\n }\n const state = this.getState()\n const item = this.items[state.highlightedIndex] || {}\n const resultCount = this.getItemCount()\n const status = this.props.getA11yStatusMessage({\n itemToString: this.props.itemToString,\n previousResultCount: this.previousResultCount,\n resultCount,\n highlightedItem: item,\n ...state,\n })\n this.previousResultCount = resultCount\n setA11yStatus(status)\n }, 200)\n\n componentDidMount() {\n // the _isMounted property is because we have `updateStatus` in a `debounce`\n // and we don't want to update the status if the component has been umounted\n this._isMounted = true\n // this.isMouseDown helps us track whether the mouse is currently held down.\n // This is useful when the user clicks on an item in the list, but holds the mouse\n // down long enough for the list to disappear (because the blur event fires on the input)\n // this.isMouseDown is used in the blur handler on the input to determine whether the blur event should\n // trigger hiding the menu.\n const onMouseDown = () => {\n this.isMouseDown = true\n }\n const onMouseUp = event => {\n this.isMouseDown = false\n if (\n (event.target === this._rootNode ||\n !this._rootNode.contains(event.target)) &&\n this.getState().isOpen\n ) {\n this.reset(Downshift.stateChangeTypes.mouseUp)\n }\n }\n window.addEventListener('mousedown', onMouseDown)\n window.addEventListener('mouseup', onMouseUp)\n\n this.cleanup = () => {\n this._isMounted = false\n window.removeEventListener('mousedown', onMouseDown)\n window.removeEventListener('mouseup', onMouseUp)\n }\n }\n\n componentDidUpdate(prevProps) {\n if (\n this.isStateProp('selectedItem') &&\n this.props.selectedItem !== prevProps.selectedItem\n ) {\n this.internalSetState({\n inputValue: this.props.itemToString(this.props.selectedItem),\n })\n }\n this.updateStatus()\n }\n\n componentWillUnmount() {\n this.cleanup() // avoids memory leak\n }\n\n render() {\n const children = unwrapArray(this.props.children, noop)\n // because the items are rerendered every time we call the children\n // we clear this out each render and\n this.items = []\n // we reset this so we know whether the user calls getRootProps during\n // this render. If they do then we don't need to do anything,\n // if they don't then we need to clone the element they return and\n // apply the props for them.\n this.getRootProps.called = false\n this.getRootProps.refKey = undefined\n // we do something similar for getLabelProps\n this.getLabelProps.called = false\n // and something similar for getInputProps\n this.getInputProps.called = false\n const element = unwrapArray(children(this.getControllerStateAndHelpers()))\n if (!element) {\n return null\n }\n if (this.getRootProps.called) {\n validateGetRootPropsCalledCorrectly(element, this.getRootProps)\n return element\n } else if (isDOMElement(element)) {\n // they didn't apply the root props, but we can clone\n // this and apply the props ourselves\n return React.cloneElement(\n element,\n this.getRootProps(getElementProps(element)),\n )\n } else {\n // they didn't apply the root props, but they need to\n // otherwise we can't query around the autocomplete\n throw new Error(\n 'downshift: If you return a non-DOM element, you must use apply the getRootProps function',\n )\n }\n }\n}\n\nexport default Downshift\n\nfunction validateGetRootPropsCalledCorrectly(element, {refKey}) {\n const refKeySpecified = refKey !== 'ref'\n const isComposite = !isDOMElement(element)\n if (isComposite && !refKeySpecified) {\n throw new Error(\n 'downshift: You returned a non-DOM element. You must specify a refKey in getRootProps',\n )\n } else if (!isComposite && refKeySpecified) {\n throw new Error(\n `downshift: You returned a DOM element. You should not specify a refKey in getRootProps. You specified \"${refKey}\"`,\n )\n }\n if (!getElementProps(element).hasOwnProperty(refKey)) {\n throw new Error(\n `downshift: You must apply the ref prop \"${refKey}\" from getRootProps onto your root element.`,\n )\n }\n if (!getElementProps(element).hasOwnProperty('onClick')) {\n throw new Error(\n `downshift: You must apply the \"onClick\" prop from getRootProps onto your root element.`,\n )\n }\n}\n"],"names":["setStatus","status","isSameAsLast","statuses","length","getStatusDiv","innerHTML","filter","Boolean","map","getStatusHtml","join","index","statusDiv","document","createElement","setAttribute","assign","style","body","appendChild","cbToCb","cb","noop","findParent","finder","node","rootNode","parentNode","scrollIntoView","scrollParent","getClosestScrollParent","scrollParentStyles","getComputedStyle","scrollParentRect","getBoundingClientRect","scrollParentBorderTopWidth","parseInt","borderTopWidth","scrollParentTop","top","nodeRect","nodeTop","scrollTop","height","debounce","fn","time","timeoutId","args","setTimeout","composeEventHandlers","fns","event","some","defaultPrevented","generateId","prefix","idCounter","firstDefined","find","a","isNumber","thing","unwrapArray","arg","defaultValue","Array","isArray","isDOMElement","element","nodeName","type","getElementProps","props","attributes","validateGetRootPropsCalledCorrectly","refKey","refKeySpecified","isComposite","Error","hasOwnProperty","getElementById","bind","scrollHeight","clientHeight","Downshift","id","state","_this","getState","defaultHighlightedIndex","defaultIsOpen","defaultInputValue","defaultSelectedItem","selectedItem","inputValue","itemToString","root_handleClick","onClick","stateToMerge","this","Object","keys","reduce","key","_this2","isStateProp","undefined","itemCount","items","stateToSet","onChangeArg","onStateChangeArg","setState","_this3","nextState","nextFullState","forEach","onStateChange","onChange","highlightedIndex","isOpen","getRootProps","getButtonProps","getLabelProps","getInputProps","getItemProps","openMenu","closeMenu","toggleMenu","selectItem","selectItemAtIndex","selectHighlightedItem","setHighlightedIndex","clearSelection","Number","split","_isMounted","onMouseDown","isMouseDown","onMouseUp","target","_this4","_rootNode","contains","reset","stateChangeTypes","mouseUp","addEventListener","cleanup","removeEventListener","prevProps","internalSetState","updateStatus","children","called","getControllerStateAndHelpers","React","cloneElement","Component","defaultProps","highlightedItem","resultCount","previousResultCount","resultCountChanged","i","String","input","getItemNodeFromIndex","_this5","getItemId","highlightIndex","moveHighlightedIndex","changeHighlighedIndex","amount","itemsLastIndex","getItemCount","baseIndex","moveAmount","newIndex","inputNode","querySelector","inputId","focus","item","itemIndex","rootRef","rest","preventDefault","itemParent","getItemIndexFromId","getAttribute","keyDownHandlers","shiftKey","buttonKeyDownHandlers","onKeyDown","button_handleClick","button_handleKeyDown","call","htmlFor","onBlur","onInput","input_handleChange","input_handleKeyDown","input_handleBlur","value","onMouseEnter","newState","nextIsOpen","getA11yStatusMessage"],"mappings":"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"}
\No newline at end of file