@francoischalifour/autocomplete-core
Advanced tools
Comparing version 1.0.0-alpha.22 to 1.0.0-alpha.23
@@ -1,3 +0,3 @@ | ||
import { PublicAutocompleteOptions, AutocompleteApi } from './types'; | ||
import { AutocompleteApi, PublicAutocompleteOptions } from './types'; | ||
declare function createAutocomplete<TItem extends {}, TEvent = Event, TMouseEvent = MouseEvent, TKeyboardEvent = KeyboardEvent>(options: PublicAutocompleteOptions<TItem>): AutocompleteApi<TItem, TEvent, TMouseEvent, TKeyboardEvent>; | ||
export { createAutocomplete }; |
@@ -1,7 +0,7 @@ | ||
import { stateReducer } from './stateReducer'; | ||
import { getDefaultProps } from './defaultProps'; | ||
import { createStore } from './store'; | ||
import { onInput } from './onInput'; | ||
import { getPropGetters } from './propGetters'; | ||
import { getAutocompleteSetters } from './setters'; | ||
import { onInput } from './onInput'; | ||
import { stateReducer } from './stateReducer'; | ||
import { createStore } from './store'; | ||
@@ -8,0 +8,0 @@ function createAutocomplete(options) { |
@@ -1,2 +0,2 @@ | ||
import { AutocompleteState, AutocompleteOptions } from './types'; | ||
import { AutocompleteOptions, AutocompleteState } from './types'; | ||
interface GetCompletionProps<TItem> { | ||
@@ -3,0 +3,0 @@ state: AutocompleteState<TItem>; |
@@ -1,2 +0,2 @@ | ||
import { PublicAutocompleteOptions, AutocompleteOptions } from './types'; | ||
import { AutocompleteOptions, PublicAutocompleteOptions } from './types'; | ||
export declare function getDefaultProps<TItem>(props: PublicAutocompleteOptions<TItem>): AutocompleteOptions<TItem>; |
@@ -7,3 +7,3 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
import { generateAutocompleteId, getItemsCount, normalizeGetSources, noop } from './utils'; | ||
import { generateAutocompleteId, getItemsCount, noop, normalizeGetSources } from './utils'; | ||
export function getDefaultProps(props) { | ||
@@ -10,0 +10,0 @@ var _props$id; |
@@ -1,2 +0,2 @@ | ||
import { AutocompleteOptions, AutocompleteSetters, AutocompleteStore, AutocompleteState } from './types'; | ||
import { AutocompleteOptions, AutocompleteSetters, AutocompleteState, AutocompleteStore } from './types'; | ||
interface OnInputParams<TItem> extends AutocompleteSetters<TItem> { | ||
@@ -3,0 +3,0 @@ query: string; |
@@ -1,2 +0,2 @@ | ||
import { AutocompleteStore, AutocompleteOptions, AutocompleteSetters } from './types'; | ||
import { AutocompleteOptions, AutocompleteSetters, AutocompleteStore } from './types'; | ||
interface OnKeyDownOptions<TItem> extends AutocompleteSetters<TItem> { | ||
@@ -3,0 +3,0 @@ event: KeyboardEvent; |
@@ -0,3 +1,3 @@ | ||
import { getCompletion } from './completion'; | ||
import { onInput } from './onInput'; | ||
import { getCompletion } from './completion'; | ||
import { getHighlightedItem } from './utils'; | ||
@@ -4,0 +4,0 @@ export function onKeyDown(_ref) { |
@@ -1,2 +0,2 @@ | ||
import { GetEnvironmentProps, GetRootProps, GetFormProps, GetLabelProps, GetInputProps, GetDropdownProps, GetMenuProps, GetItemProps, AutocompleteStore, AutocompleteOptions, AutocompleteSetters } from './types'; | ||
import { AutocompleteOptions, AutocompleteSetters, AutocompleteStore, GetDropdownProps, GetEnvironmentProps, GetFormProps, GetInputProps, GetItemProps, GetLabelProps, GetMenuProps, GetRootProps } from './types'; | ||
interface GetPropGettersOptions<TItem> extends AutocompleteSetters<TItem> { | ||
@@ -3,0 +3,0 @@ store: AutocompleteStore<TItem>; |
@@ -13,3 +13,3 @@ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } | ||
import { onKeyDown as _onKeyDown } from './onKeyDown'; | ||
import { isSpecialClick, getHighlightedItem, isOrContainsNode } from './utils'; | ||
import { getHighlightedItem, isOrContainsNode, isSpecialClick } from './utils'; | ||
export function getPropGetters(_ref) { | ||
@@ -16,0 +16,0 @@ var store = _ref.store, |
@@ -1,2 +0,2 @@ | ||
import { AutocompleteState, PublicAutocompleteOptions, AutocompleteSource, GetSources, AutocompleteOptions } from './types'; | ||
import { AutocompleteOptions, AutocompleteSource, AutocompleteState, GetSources, PublicAutocompleteOptions } from './types'; | ||
export declare const noop: () => void; | ||
@@ -3,0 +3,0 @@ export declare function generateAutocompleteId(): string; |
@@ -1,1210 +0,2 @@ | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
typeof define === 'function' && define.amd ? define(['exports'], factory) : | ||
(global = global || self, factory(global['@francoischalifour/autocomplete-core'] = {})); | ||
}(this, (function (exports) { 'use strict'; | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function ownKeys(object, enumerableOnly) { | ||
var keys = Object.keys(object); | ||
if (Object.getOwnPropertySymbols) { | ||
var symbols = Object.getOwnPropertySymbols(object); | ||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | ||
}); | ||
keys.push.apply(keys, symbols); | ||
} | ||
return keys; | ||
} | ||
function _objectSpread2(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
if (i % 2) { | ||
ownKeys(Object(source), true).forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} else if (Object.getOwnPropertyDescriptors) { | ||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | ||
} else { | ||
ownKeys(Object(source)).forEach(function (key) { | ||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | ||
}); | ||
} | ||
} | ||
return target; | ||
} | ||
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 _objectWithoutProperties(source, excluded) { | ||
if (source == null) return {}; | ||
var target = _objectWithoutPropertiesLoose(source, excluded); | ||
var key, i; | ||
if (Object.getOwnPropertySymbols) { | ||
var sourceSymbolKeys = Object.getOwnPropertySymbols(source); | ||
for (i = 0; i < sourceSymbolKeys.length; i++) { | ||
key = sourceSymbolKeys[i]; | ||
if (excluded.indexOf(key) >= 0) continue; | ||
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; | ||
target[key] = source[key]; | ||
} | ||
} | ||
return target; | ||
} | ||
var noop = function noop() {}; | ||
var autocompleteId = 0; | ||
function generateAutocompleteId() { | ||
return "autocomplete-".concat(autocompleteId++); | ||
} | ||
function getItemsCount(state) { | ||
if (state.suggestions.length === 0) { | ||
return 0; | ||
} | ||
return state.suggestions.reduce(function (sum, suggestion) { | ||
return sum + suggestion.items.length; | ||
}, 0); | ||
} | ||
function isSpecialClick(event) { | ||
var isMiddleClick = event.button === 1; | ||
return isMiddleClick || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; | ||
} | ||
function normalizeSource(source) { | ||
return _objectSpread2({ | ||
getInputValue: function getInputValue(_ref) { | ||
var state = _ref.state; | ||
return state.query; | ||
}, | ||
getSuggestionUrl: function getSuggestionUrl() { | ||
return undefined; | ||
}, | ||
onSelect: function onSelect(_ref2) { | ||
var setIsOpen = _ref2.setIsOpen; | ||
setIsOpen(false); | ||
}, | ||
onHighlight: noop | ||
}, source); | ||
} | ||
function normalizeGetSources(getSources) { | ||
return function (options) { | ||
return Promise.resolve(getSources(options)).then(function (sources) { | ||
return Promise.all(sources.filter(Boolean).map(function (source) { | ||
return Promise.resolve(normalizeSource(source)); | ||
})); | ||
}); | ||
}; | ||
} | ||
function getNextHighlightedIndex(moveAmount, baseIndex, itemCount, defaultHighlightedIndex) { | ||
// We allow circular keyboard navigation from the base index. | ||
// The base index can either be `null` (nothing is highlighted) or `0` | ||
// (the first item is highlighted). | ||
// The base index is allowed to get assigned `null` only if | ||
// `props.defaultHighlightedIndex` is `null`. This pattern allows to "stop" | ||
// by the actual query before navigating to other suggestions as seen on | ||
// Google or Amazon. | ||
if (baseIndex === null && moveAmount < 0) { | ||
return itemCount - 1; | ||
} | ||
if (defaultHighlightedIndex !== null && baseIndex === 0 && moveAmount < 0) { | ||
return itemCount - 1; | ||
} | ||
var numericIndex = (baseIndex === null ? -1 : baseIndex) + moveAmount; | ||
if (numericIndex <= -1 || numericIndex >= itemCount) { | ||
return defaultHighlightedIndex === null ? null : 0; | ||
} | ||
return numericIndex; | ||
} // We don't have access to the autocomplete source when we call `onKeyDown` | ||
// or `onClick` because those are native browser events. | ||
// However, we can get the source from the suggestion index. | ||
function getSuggestionFromHighlightedIndex(_ref3) { | ||
var state = _ref3.state; | ||
// Given 3 sources with respectively 1, 2 and 3 suggestions: [1, 2, 3] | ||
// We want to get the accumulated counts: | ||
// [1, 1 + 2, 1 + 2 + 3] = [1, 3, 3 + 3] = [1, 3, 6] | ||
var accumulatedSuggestionsCount = state.suggestions.map(function (suggestion) { | ||
return suggestion.items.length; | ||
}).reduce(function (acc, suggestionCount, index) { | ||
var previousValue = acc[index - 1] || 0; | ||
var nextValue = previousValue + suggestionCount; | ||
acc.push(nextValue); | ||
return acc; | ||
}, []); // Based on the accumulated counts, we can infer the index of the suggestion. | ||
var suggestionIndex = accumulatedSuggestionsCount.reduce(function (acc, current) { | ||
if (current <= state.highlightedIndex) { | ||
return acc + 1; | ||
} | ||
return acc; | ||
}, 0); | ||
return state.suggestions[suggestionIndex]; | ||
} | ||
/** | ||
* Gets the highlighted index relative to a suggestion object (not the absolute | ||
* highlighted index). | ||
* | ||
* Example: | ||
* [['a', 'b'], ['c', 'd', 'e'], ['f']] | ||
* ↑ | ||
* (absolute: 3, relative: 1) | ||
* @param param0 | ||
*/ | ||
function getRelativeHighlightedIndex(_ref4) { | ||
var state = _ref4.state, | ||
suggestion = _ref4.suggestion; | ||
var isOffsetFound = false; | ||
var counter = 0; | ||
var previousItemsOffset = 0; | ||
while (isOffsetFound === false) { | ||
var currentSuggestion = state.suggestions[counter]; | ||
if (currentSuggestion === suggestion) { | ||
isOffsetFound = true; | ||
break; | ||
} | ||
previousItemsOffset += currentSuggestion.items.length; | ||
counter++; | ||
} | ||
return state.highlightedIndex - previousItemsOffset; | ||
} | ||
function getHighlightedItem(_ref5) { | ||
var state = _ref5.state; | ||
var suggestion = getSuggestionFromHighlightedIndex({ | ||
state: state | ||
}); | ||
if (!suggestion) { | ||
return null; | ||
} | ||
var item = suggestion.items[getRelativeHighlightedIndex({ | ||
state: state, | ||
suggestion: suggestion | ||
})]; | ||
var source = suggestion.source; | ||
var itemValue = source.getInputValue({ | ||
suggestion: item, | ||
state: state | ||
}); | ||
var itemUrl = source.getSuggestionUrl({ | ||
suggestion: item, | ||
state: state | ||
}); | ||
return { | ||
item: item, | ||
itemValue: itemValue, | ||
itemUrl: itemUrl, | ||
source: source | ||
}; | ||
} | ||
function isOrContainsNode(parent, child) { | ||
return parent === child || parent.contains && parent.contains(child); | ||
} | ||
var stateReducer = function stateReducer(action, state, props) { | ||
switch (action.type) { | ||
case 'setHighlightedIndex': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
highlightedIndex: action.value | ||
}); | ||
} | ||
case 'setQuery': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
query: action.value | ||
}); | ||
} | ||
case 'setSuggestions': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
suggestions: action.value | ||
}); | ||
} | ||
case 'setIsOpen': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
isOpen: action.value | ||
}); | ||
} | ||
case 'setStatus': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
status: action.value | ||
}); | ||
} | ||
case 'setContext': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
context: _objectSpread2(_objectSpread2({}, state.context), action.value) | ||
}); | ||
} | ||
case 'ArrowDown': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
highlightedIndex: getNextHighlightedIndex(1, state.highlightedIndex, getItemsCount(state), props.defaultHighlightedIndex) | ||
}); | ||
} | ||
case 'ArrowUp': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
highlightedIndex: getNextHighlightedIndex(-1, state.highlightedIndex, getItemsCount(state), props.defaultHighlightedIndex) | ||
}); | ||
} | ||
case 'Escape': | ||
{ | ||
if (state.isOpen) { | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
isOpen: false | ||
}); | ||
} | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
query: '', | ||
status: 'idle', | ||
statusContext: {}, | ||
suggestions: [] | ||
}); | ||
} | ||
case 'submit': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
highlightedIndex: null, | ||
isOpen: false, | ||
status: 'idle', | ||
statusContext: {} | ||
}); | ||
} | ||
case 'reset': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
highlightedIndex: // Since we open the menu on reset when openOnFocus=true | ||
// we need to restore the highlighted index to the defaultHighlightedIndex. (DocSearch use-case) | ||
// Since we close the menu when openOnFocus=false | ||
// we lose track of the highlighted index. (Query-suggestions use-case) | ||
props.openOnFocus === true ? props.defaultHighlightedIndex : null, | ||
isOpen: props.openOnFocus, | ||
// @TODO: Check with UX team if we want to close the menu on reset. | ||
status: 'idle', | ||
statusContext: {}, | ||
query: '' | ||
}); | ||
} | ||
case 'focus': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
highlightedIndex: props.defaultHighlightedIndex, | ||
isOpen: props.openOnFocus || state.query.length > 0 | ||
}); | ||
} | ||
case 'blur': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
isOpen: false, | ||
highlightedIndex: null | ||
}); | ||
} | ||
case 'mousemove': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
highlightedIndex: action.value | ||
}); | ||
} | ||
case 'mouseleave': | ||
{ | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
highlightedIndex: props.defaultHighlightedIndex | ||
}); | ||
} | ||
default: | ||
return state; | ||
} | ||
}; | ||
function getDefaultProps(props) { | ||
var _props$id; | ||
var environment = typeof window !== 'undefined' ? window : {}; | ||
return _objectSpread2(_objectSpread2({ | ||
openOnFocus: false, | ||
placeholder: '', | ||
autoFocus: false, | ||
defaultHighlightedIndex: null, | ||
showCompletion: false, | ||
stallThreshold: 300, | ||
environment: environment, | ||
shouldDropdownShow: function shouldDropdownShow(_ref) { | ||
var state = _ref.state; | ||
return getItemsCount(state) > 0; | ||
}, | ||
onStateChange: noop, | ||
onSubmit: noop | ||
}, props), {}, { | ||
// Since `generateAutocompleteId` triggers a side effect (it increments | ||
// and internal counter), we don't want to execute it if unnecessary. | ||
id: (_props$id = props.id) !== null && _props$id !== void 0 ? _props$id : generateAutocompleteId(), | ||
// The following props need to be deeply defaulted. | ||
initialState: _objectSpread2({ | ||
highlightedIndex: null, | ||
query: '', | ||
completion: null, | ||
suggestions: [], | ||
isOpen: false, | ||
status: 'idle', | ||
statusContext: {}, | ||
context: {} | ||
}, props.initialState), | ||
getSources: normalizeGetSources(props.getSources), | ||
navigator: _objectSpread2({ | ||
navigate: function navigate(_ref2) { | ||
var suggestionUrl = _ref2.suggestionUrl; | ||
environment.location.assign(suggestionUrl); | ||
}, | ||
navigateNewTab: function navigateNewTab(_ref3) { | ||
var suggestionUrl = _ref3.suggestionUrl; | ||
var windowReference = environment.open(suggestionUrl, '_blank', 'noopener'); | ||
if (windowReference) { | ||
windowReference.focus(); | ||
} | ||
}, | ||
navigateNewWindow: function navigateNewWindow(_ref4) { | ||
var suggestionUrl = _ref4.suggestionUrl; | ||
environment.open(suggestionUrl, '_blank', 'noopener'); | ||
} | ||
}, props.navigator) | ||
}); | ||
} | ||
function getCompletion(_ref) { | ||
var state = _ref.state, | ||
props = _ref.props; | ||
if (props.showCompletion === false || state.isOpen === false || state.highlightedIndex === null || state.status === 'stalled') { | ||
return null; | ||
} | ||
var _ref2 = getHighlightedItem({ | ||
state: state | ||
}), | ||
itemValue = _ref2.itemValue; // The completion should appear only if the _first_ characters of the query | ||
// match with the suggestion. | ||
if (state.query.length > 0 && itemValue.toLocaleLowerCase().indexOf(state.query.toLocaleLowerCase()) === 0) { | ||
// If the query typed has a different case than the suggestion, we want | ||
// to show the completion matching the case of the query. This makes both | ||
// strings overlap correctly. | ||
// Example: | ||
// - query: 'Gui' | ||
// - suggestion: 'guitar' | ||
// => completion: 'Guitar' | ||
var completion = state.query + itemValue.slice(state.query.length); | ||
if (completion === state.query) { | ||
return null; | ||
} | ||
return completion; | ||
} | ||
return null; | ||
} | ||
function createStore(reducer, props) { | ||
return { | ||
state: props.initialState, | ||
getState: function getState() { | ||
return this.state; | ||
}, | ||
send: function send(action, payload) { | ||
this.state = withCompletion(reducer({ | ||
type: action, | ||
value: payload | ||
}, this.state, props), props); | ||
props.onStateChange({ | ||
state: this.state | ||
}); | ||
} | ||
}; | ||
} | ||
function withCompletion(state, props) { | ||
return _objectSpread2(_objectSpread2({}, state), {}, { | ||
completion: getCompletion({ | ||
state: state, | ||
props: props | ||
}) | ||
}); | ||
} | ||
var lastStalledId = null; | ||
function onInput(_ref) { | ||
var query = _ref.query, | ||
store = _ref.store, | ||
props = _ref.props, | ||
setHighlightedIndex = _ref.setHighlightedIndex, | ||
setQuery = _ref.setQuery, | ||
setSuggestions = _ref.setSuggestions, | ||
setIsOpen = _ref.setIsOpen, | ||
setStatus = _ref.setStatus, | ||
setContext = _ref.setContext, | ||
_ref$nextState = _ref.nextState, | ||
nextState = _ref$nextState === void 0 ? {} : _ref$nextState; | ||
if (props.onInput) { | ||
return Promise.resolve(props.onInput({ | ||
query: query, | ||
state: store.getState(), | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
})); | ||
} | ||
if (lastStalledId) { | ||
clearTimeout(lastStalledId); | ||
} | ||
setHighlightedIndex(props.defaultHighlightedIndex); | ||
setQuery(query); | ||
if (query.length === 0 && props.openOnFocus === false) { | ||
var _nextState$isOpen; | ||
setStatus('idle'); | ||
setSuggestions(store.getState().suggestions.map(function (suggestion) { | ||
return _objectSpread2(_objectSpread2({}, suggestion), {}, { | ||
items: [] | ||
}); | ||
})); | ||
setIsOpen((_nextState$isOpen = nextState.isOpen) !== null && _nextState$isOpen !== void 0 ? _nextState$isOpen : props.shouldDropdownShow({ | ||
state: store.getState() | ||
})); | ||
return Promise.resolve(); | ||
} | ||
setStatus('loading'); | ||
lastStalledId = props.environment.setTimeout(function () { | ||
setStatus('stalled'); | ||
}, props.stallThreshold); | ||
return props.getSources({ | ||
query: query, | ||
state: store.getState(), | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
}).then(function (sources) { | ||
setStatus('loading'); // @TODO: convert `Promise.all` to fetching strategy. | ||
return Promise.all(sources.map(function (source) { | ||
return Promise.resolve(source.getSuggestions({ | ||
query: query, | ||
state: store.getState(), | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
})).then(function (items) { | ||
return { | ||
source: source, | ||
items: items | ||
}; | ||
}); | ||
})).then(function (suggestions) { | ||
var _nextState$isOpen2; | ||
setStatus('idle'); | ||
setSuggestions(suggestions); | ||
setIsOpen((_nextState$isOpen2 = nextState.isOpen) !== null && _nextState$isOpen2 !== void 0 ? _nextState$isOpen2 : query.length === 0 && props.openOnFocus || props.shouldDropdownShow({ | ||
state: store.getState() | ||
})); | ||
}).catch(function (error) { | ||
setStatus('error'); | ||
throw error; | ||
}).finally(function () { | ||
if (lastStalledId) { | ||
clearTimeout(lastStalledId); | ||
} | ||
}); | ||
}); | ||
} | ||
function onKeyDown(_ref) { | ||
var event = _ref.event, | ||
store = _ref.store, | ||
props = _ref.props, | ||
setHighlightedIndex = _ref.setHighlightedIndex, | ||
setQuery = _ref.setQuery, | ||
setSuggestions = _ref.setSuggestions, | ||
setIsOpen = _ref.setIsOpen, | ||
setStatus = _ref.setStatus, | ||
setContext = _ref.setContext; | ||
if (event.key === 'ArrowUp' || event.key === 'ArrowDown') { | ||
// Default browser behavior changes the caret placement on ArrowUp and | ||
// Arrow down. | ||
event.preventDefault(); | ||
store.send(event.key, { | ||
shiftKey: event.shiftKey | ||
}); | ||
var nodeItem = props.environment.document.getElementById("".concat(props.id, "-item-").concat(store.getState().highlightedIndex)); | ||
nodeItem === null || nodeItem === void 0 ? void 0 : nodeItem.scrollIntoView(false); | ||
var highlightedItem = getHighlightedItem({ | ||
state: store.getState() | ||
}); | ||
if (store.getState().highlightedIndex !== null && highlightedItem) { | ||
var item = highlightedItem.item, | ||
itemValue = highlightedItem.itemValue, | ||
itemUrl = highlightedItem.itemUrl, | ||
source = highlightedItem.source; | ||
source.onHighlight({ | ||
suggestion: item, | ||
suggestionValue: itemValue, | ||
suggestionUrl: itemUrl, | ||
source: source, | ||
state: store.getState(), | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext, | ||
event: event | ||
}); | ||
} | ||
} else if ((event.key === 'Tab' || // When the user hits the right arrow and is at the end of the input | ||
// query, we validate the completion. | ||
event.key === 'ArrowRight' && event.target.selectionStart === store.getState().query.length) && props.showCompletion && store.getState().highlightedIndex !== null) { | ||
event.preventDefault(); | ||
var query = getCompletion({ | ||
state: store.getState(), | ||
props: props | ||
}); | ||
if (query) { | ||
onInput({ | ||
query: query, | ||
store: store, | ||
props: props, | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
}); | ||
} | ||
} else if (event.key === 'Escape') { | ||
// This prevents the default browser behavior on `input[type="search"]` | ||
// to remove the query right away because we first want to close the | ||
// dropdown. | ||
event.preventDefault(); | ||
store.send(event.key, null); | ||
} else if (event.key === 'Enter') { | ||
// No item is selected, so we let the browser handle the native `onSubmit` | ||
// form event. | ||
if (store.getState().highlightedIndex === null || store.getState().suggestions.every(function (suggestion) { | ||
return suggestion.items.length === 0; | ||
})) { | ||
return; | ||
} // This prevents the `onSubmit` event to be sent because an item is | ||
// highlighted. | ||
event.preventDefault(); | ||
var _ref2 = getHighlightedItem({ | ||
state: store.getState() | ||
}), | ||
_item = _ref2.item, | ||
_itemValue = _ref2.itemValue, | ||
_itemUrl = _ref2.itemUrl, | ||
_source = _ref2.source; | ||
if (event.metaKey || event.ctrlKey) { | ||
if (_itemUrl !== undefined) { | ||
props.navigator.navigateNewTab({ | ||
suggestionUrl: _itemUrl, | ||
suggestion: _item, | ||
state: store.getState() | ||
}); | ||
} | ||
} else if (event.shiftKey) { | ||
if (_itemUrl !== undefined) { | ||
props.navigator.navigateNewWindow({ | ||
suggestionUrl: _itemUrl, | ||
suggestion: _item, | ||
state: store.getState() | ||
}); | ||
} | ||
} else if (event.altKey) ; else { | ||
onInput({ | ||
query: _itemValue, | ||
store: store, | ||
props: props, | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext, | ||
nextState: { | ||
isOpen: false | ||
} | ||
}).then(function () { | ||
_source.onSelect({ | ||
suggestion: _item, | ||
suggestionValue: _itemValue, | ||
suggestionUrl: _itemUrl, | ||
source: _source, | ||
state: store.getState(), | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext, | ||
event: event | ||
}); | ||
}); | ||
if (_itemUrl !== undefined) { | ||
props.navigator.navigate({ | ||
suggestionUrl: _itemUrl, | ||
suggestion: _item, | ||
state: store.getState() | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
function getPropGetters(_ref) { | ||
var store = _ref.store, | ||
props = _ref.props, | ||
setHighlightedIndex = _ref.setHighlightedIndex, | ||
setQuery = _ref.setQuery, | ||
setSuggestions = _ref.setSuggestions, | ||
setIsOpen = _ref.setIsOpen, | ||
setStatus = _ref.setStatus, | ||
setContext = _ref.setContext; | ||
var getEnvironmentProps = function getEnvironmentProps(getterProps) { | ||
return { | ||
// On touch devices, we do not rely on the native `blur` event of the | ||
// input to close the dropdown, but rather on a custom `touchstart` event | ||
// outside of the autocomplete elements. | ||
// This ensures a working experience on mobile because we blur the input | ||
// on touch devices when the user starts scrolling (`touchmove`). | ||
onTouchStart: function onTouchStart(event) { | ||
if (store.getState().isOpen === false || event.target === getterProps.inputElement) { | ||
return; | ||
} | ||
var isTargetWithinAutocomplete = [getterProps.searchBoxElement, getterProps.dropdownElement].some(function (contextNode) { | ||
return contextNode && (isOrContainsNode(contextNode, event.target) || isOrContainsNode(contextNode, props.environment.document.activeElement)); | ||
}); | ||
if (isTargetWithinAutocomplete === false) { | ||
store.send('blur', null); | ||
} | ||
}, | ||
// When scrolling on touch devices (mobiles, tablets, etc.), we want to | ||
// mimic the native platform behavior where the input is blurred to | ||
// hide the virtual keyboard. This gives more vertical space to | ||
// discover all the suggestions showing up in the dropdown. | ||
onTouchMove: function onTouchMove(event) { | ||
if (store.getState().isOpen === false || getterProps.inputElement !== props.environment.document.activeElement || event.target === getterProps.inputElement) { | ||
return; | ||
} | ||
getterProps.inputElement.blur(); | ||
} | ||
}; | ||
}; | ||
var getRootProps = function getRootProps(rest) { | ||
return _objectSpread2({ | ||
role: 'combobox', | ||
'aria-expanded': store.getState().isOpen, | ||
'aria-haspopup': 'listbox', | ||
'aria-owns': store.getState().isOpen ? "".concat(props.id, "-menu") : undefined, | ||
'aria-labelledby': "".concat(props.id, "-label") | ||
}, rest); | ||
}; | ||
var getFormProps = function getFormProps(providedProps) { | ||
var inputElement = providedProps.inputElement, | ||
rest = _objectWithoutProperties(providedProps, ["inputElement"]); | ||
return _objectSpread2({ | ||
onSubmit: function onSubmit(event) { | ||
event.preventDefault(); | ||
props.onSubmit({ | ||
state: store.getState(), | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext, | ||
event: event | ||
}); | ||
store.send('submit', null); | ||
if (providedProps.inputElement) { | ||
providedProps.inputElement.blur(); | ||
} | ||
}, | ||
onReset: function onReset(event) { | ||
event.preventDefault(); | ||
if (props.openOnFocus) { | ||
onInput({ | ||
query: '', | ||
store: store, | ||
props: props, | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
}); | ||
} | ||
store.send('reset', null); | ||
if (providedProps.inputElement) { | ||
providedProps.inputElement.focus(); | ||
} | ||
} | ||
}, rest); | ||
}; | ||
var getInputProps = function getInputProps(providedProps) { | ||
function onFocus() { | ||
// We want to trigger a query when `openOnFocus` is true | ||
// because the dropdown should open with the current query. | ||
if (props.openOnFocus || store.getState().query.length > 0) { | ||
onInput({ | ||
query: store.getState().query, | ||
store: store, | ||
props: props, | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
}); | ||
} | ||
store.send('focus', null); | ||
} | ||
var isTouchDevice = ('ontouchstart' in props.environment); | ||
var inputElement = providedProps.inputElement, | ||
_providedProps$maxLen = providedProps.maxLength, | ||
maxLength = _providedProps$maxLen === void 0 ? 512 : _providedProps$maxLen, | ||
rest = _objectWithoutProperties(providedProps, ["inputElement", "maxLength"]); | ||
return _objectSpread2({ | ||
'aria-autocomplete': props.showCompletion ? 'both' : 'list', | ||
'aria-activedescendant': store.getState().isOpen && store.getState().highlightedIndex !== null ? "".concat(props.id, "-item-").concat(store.getState().highlightedIndex) : undefined, | ||
'aria-controls': store.getState().isOpen ? "".concat(props.id, "-menu") : undefined, | ||
'aria-labelledby': "".concat(props.id, "-label"), | ||
value: store.getState().query, | ||
id: "".concat(props.id, "-input"), | ||
autoComplete: 'off', | ||
autoCorrect: 'off', | ||
autoCapitalize: 'off', | ||
spellCheck: false, | ||
autoFocus: props.autoFocus, | ||
placeholder: props.placeholder, | ||
maxLength: maxLength, | ||
onChange: function onChange(event) { | ||
onInput({ | ||
query: event.currentTarget.value.slice(0, maxLength), | ||
store: store, | ||
props: props, | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
}); | ||
}, | ||
onKeyDown: function onKeyDown$1(event) { | ||
onKeyDown({ | ||
event: event, | ||
store: store, | ||
props: props, | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
}); | ||
}, | ||
onFocus: onFocus, | ||
onBlur: function onBlur() { | ||
// We do rely on the `blur` event on touch devices. | ||
// See explanation in `onTouchStart`. | ||
if (!isTouchDevice) { | ||
store.send('blur', null); | ||
} | ||
}, | ||
onClick: function onClick() { | ||
// When the dropdown is closed and you click on the input while | ||
// the input is focused, the `onFocus` event is not triggered | ||
// (default browser behavior). | ||
// In an autocomplete context, it makes sense to open the menu in this | ||
// case. | ||
// We mimic this event by catching the `onClick` event which | ||
// triggers the `onFocus` for the dropdown to open. | ||
if (providedProps.inputElement === props.environment.document.activeElement && !store.getState().isOpen) { | ||
onFocus(); | ||
} | ||
} | ||
}, rest); | ||
}; | ||
var getLabelProps = function getLabelProps(rest) { | ||
return _objectSpread2({ | ||
htmlFor: "".concat(props.id, "-input"), | ||
id: "".concat(props.id, "-label") | ||
}, rest); | ||
}; | ||
var getMenuProps = function getMenuProps(rest) { | ||
return _objectSpread2({ | ||
role: 'listbox', | ||
'aria-labelledby': "".concat(props.id, "-label"), | ||
id: "".concat(props.id, "-menu") | ||
}, rest); | ||
}; | ||
var getDropdownProps = function getDropdownProps(rest) { | ||
return _objectSpread2({ | ||
onMouseLeave: function onMouseLeave() { | ||
store.send('mouseleave', null); | ||
} | ||
}, rest); | ||
}; | ||
var getItemProps = function getItemProps(providedProps) { | ||
var item = providedProps.item, | ||
source = providedProps.source, | ||
rest = _objectWithoutProperties(providedProps, ["item", "source"]); | ||
return _objectSpread2({ | ||
id: "".concat(props.id, "-item-").concat(item.__autocomplete_id), | ||
role: 'option', | ||
'aria-selected': store.getState().highlightedIndex === item.__autocomplete_id, | ||
onMouseMove: function onMouseMove(event) { | ||
if (item.__autocomplete_id === store.getState().highlightedIndex) { | ||
return; | ||
} | ||
store.send('mousemove', item.__autocomplete_id); | ||
var highlightedItem = getHighlightedItem({ | ||
state: store.getState() | ||
}); | ||
if (store.getState().highlightedIndex !== null && highlightedItem) { | ||
var _item = highlightedItem.item, | ||
itemValue = highlightedItem.itemValue, | ||
itemUrl = highlightedItem.itemUrl, | ||
_source = highlightedItem.source; | ||
_source.onHighlight({ | ||
suggestion: _item, | ||
suggestionValue: itemValue, | ||
suggestionUrl: itemUrl, | ||
source: _source, | ||
state: store.getState(), | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext, | ||
event: event | ||
}); | ||
} | ||
}, | ||
onMouseDown: function onMouseDown(event) { | ||
// Prevents the `activeElement` from being changed to the item so it | ||
// can remain with the current `activeElement`. | ||
event.preventDefault(); | ||
}, | ||
onClick: function onClick(event) { | ||
// If `getSuggestionUrl` is provided, it means that the suggestion | ||
// is a link, not plain text that aims at updating the query. | ||
// We can therefore skip the state change because it will update | ||
// the `highlightedIndex`, resulting in a UI flash, especially | ||
// noticeable on mobile. | ||
if (source.getSuggestionUrl({ | ||
suggestion: item, | ||
state: store.getState() | ||
}) !== undefined) { | ||
return; | ||
} // We ignore all modified clicks to support default browsers' behavior. | ||
if (isSpecialClick(event)) { | ||
return; | ||
} | ||
var inputValue = source.getInputValue({ | ||
suggestion: item, | ||
state: store.getState() | ||
}); | ||
onInput({ | ||
query: inputValue, | ||
store: store, | ||
props: props, | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext, | ||
nextState: { | ||
isOpen: false | ||
} | ||
}).then(function () { | ||
source.onSelect({ | ||
suggestion: item, | ||
suggestionValue: inputValue, | ||
suggestionUrl: source.getSuggestionUrl({ | ||
suggestion: item, | ||
state: store.getState() | ||
}), | ||
source: source, | ||
state: store.getState(), | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext, | ||
event: event | ||
}); | ||
}); | ||
} | ||
}, rest); | ||
}; | ||
return { | ||
getEnvironmentProps: getEnvironmentProps, | ||
getRootProps: getRootProps, | ||
getFormProps: getFormProps, | ||
getLabelProps: getLabelProps, | ||
getInputProps: getInputProps, | ||
getDropdownProps: getDropdownProps, | ||
getMenuProps: getMenuProps, | ||
getItemProps: getItemProps | ||
}; | ||
} | ||
function getAutocompleteSetters(_ref) { | ||
var store = _ref.store; | ||
var setHighlightedIndex = function setHighlightedIndex(value) { | ||
store.send('setHighlightedIndex', value); | ||
}; | ||
var setQuery = function setQuery(value) { | ||
store.send('setQuery', value); | ||
}; | ||
var setSuggestions = function setSuggestions(rawValue) { | ||
var baseItemId = 0; | ||
var value = rawValue.map(function (suggestion) { | ||
return _objectSpread2(_objectSpread2({}, suggestion), {}, { | ||
items: suggestion.items.map(function (item) { | ||
return _objectSpread2(_objectSpread2({}, item), {}, { | ||
__autocomplete_id: baseItemId++ | ||
}); | ||
}) | ||
}); | ||
}); | ||
store.send('setSuggestions', value); | ||
}; | ||
var setIsOpen = function setIsOpen(value) { | ||
store.send('setIsOpen', value); | ||
}; | ||
var setStatus = function setStatus(value) { | ||
store.send('setStatus', value); | ||
}; | ||
var setContext = function setContext(value) { | ||
store.send('setContext', value); | ||
}; | ||
return { | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
}; | ||
} | ||
function createAutocomplete(options) { | ||
var props = getDefaultProps(options); | ||
var store = createStore(stateReducer, props); | ||
var _getAutocompleteSette = getAutocompleteSetters({ | ||
store: store | ||
}), | ||
setHighlightedIndex = _getAutocompleteSette.setHighlightedIndex, | ||
setQuery = _getAutocompleteSette.setQuery, | ||
setSuggestions = _getAutocompleteSette.setSuggestions, | ||
setIsOpen = _getAutocompleteSette.setIsOpen, | ||
setStatus = _getAutocompleteSette.setStatus, | ||
setContext = _getAutocompleteSette.setContext; | ||
var _getPropGetters = getPropGetters({ | ||
store: store, | ||
props: props, | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
}), | ||
getEnvironmentProps = _getPropGetters.getEnvironmentProps, | ||
getRootProps = _getPropGetters.getRootProps, | ||
getFormProps = _getPropGetters.getFormProps, | ||
getLabelProps = _getPropGetters.getLabelProps, | ||
getInputProps = _getPropGetters.getInputProps, | ||
getDropdownProps = _getPropGetters.getDropdownProps, | ||
getMenuProps = _getPropGetters.getMenuProps, | ||
getItemProps = _getPropGetters.getItemProps; | ||
function refresh() { | ||
return onInput({ | ||
query: store.getState().query, | ||
store: store, | ||
props: props, | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext | ||
}); | ||
} | ||
return { | ||
setHighlightedIndex: setHighlightedIndex, | ||
setQuery: setQuery, | ||
setSuggestions: setSuggestions, | ||
setIsOpen: setIsOpen, | ||
setStatus: setStatus, | ||
setContext: setContext, | ||
getEnvironmentProps: getEnvironmentProps, | ||
getRootProps: getRootProps, | ||
getFormProps: getFormProps, | ||
getInputProps: getInputProps, | ||
getLabelProps: getLabelProps, | ||
getDropdownProps: getDropdownProps, | ||
getMenuProps: getMenuProps, | ||
getItemProps: getItemProps, | ||
refresh: refresh | ||
}; | ||
} | ||
exports.createAutocomplete = createAutocomplete; | ||
exports.getDefaultProps = getDefaultProps; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
}))); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self)["@francoischalifour/autocomplete-core"]={})}(this,(function(e){"use strict";function t(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function n(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);t&&(s=s.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,s)}return n}function s(e){for(var s=1;s<arguments.length;s++){var o=null!=arguments[s]?arguments[s]:{};s%2?n(Object(o),!0).forEach((function(n){t(e,n,o[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(o)):n(Object(o)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(o,t))}))}return e}function o(e,t){if(null==e)return{};var n,s,o=function(e,t){if(null==e)return{};var n,s,o={},i=Object.keys(e);for(s=0;s<i.length;s++)n=i[s],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(s=0;s<i.length;s++)n=i[s],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=function(){},u=0;function r(e){return 0===e.suggestions.length?0:e.suggestions.reduce((function(e,t){return e+t.items.length}),0)}function a(e){return function(t){return Promise.resolve(e(t)).then((function(e){return Promise.all(e.filter(Boolean).map((function(e){return Promise.resolve(function(e){return s({getInputValue:function(e){return e.state.query},getSuggestionUrl:function(){},onSelect:function(e){(0,e.setIsOpen)(!1)},onHighlight:i},e)}(e))})))}))}}function g(e,t,n,s){if(null===t&&e<0)return n-1;if(null!==s&&0===t&&e<0)return n-1;var o=(null===t?-1:t)+e;return o<=-1||o>=n?null===s?null:0:o}function l(e){var t=e.state,n=function(e){var t=e.state,n=t.suggestions.map((function(e){return e.items.length})).reduce((function(e,t,n){var s=(e[n-1]||0)+t;return e.push(s),e}),[]).reduce((function(e,n){return n<=t.highlightedIndex?e+1:e}),0);return t.suggestions[n]}({state:t});if(!n)return null;var s=n.items[function(e){for(var t=e.state,n=e.suggestion,s=!1,o=0,i=0;!1===s;){var u=t.suggestions[o];if(u===n){s=!0;break}i+=u.items.length,o++}return t.highlightedIndex-i}({state:t,suggestion:n})],o=n.source;return{item:s,itemValue:o.getInputValue({suggestion:s,state:t}),itemUrl:o.getSuggestionUrl({suggestion:s,state:t}),source:o}}function c(e,t){return e===t||e.contains&&e.contains(t)}function d(e){var t,n="undefined"!=typeof window?window:{};return s(s({openOnFocus:!1,placeholder:"",autoFocus:!1,defaultHighlightedIndex:null,showCompletion:!1,stallThreshold:300,environment:n,shouldDropdownShow:function(e){return r(e.state)>0},onStateChange:i,onSubmit:i},e),{},{id:null!==(t=e.id)&&void 0!==t?t:"autocomplete-".concat(u++),initialState:s({highlightedIndex:null,query:"",completion:null,suggestions:[],isOpen:!1,status:"idle",statusContext:{},context:{}},e.initialState),getSources:a(e.getSources),navigator:s({navigate:function(e){var t=e.suggestionUrl;n.location.assign(t)},navigateNewTab:function(e){var t=e.suggestionUrl,s=n.open(t,"_blank","noopener");s&&s.focus()},navigateNewWindow:function(e){var t=e.suggestionUrl;n.open(t,"_blank","noopener")}},e.navigator)})}var p=null;function h(e){var t,n=e.query,o=e.store,i=e.props,u=e.setHighlightedIndex,r=e.setQuery,a=e.setSuggestions,g=e.setIsOpen,l=e.setStatus,c=e.setContext,d=e.nextState,h=void 0===d?{}:d;return i.onInput?Promise.resolve(i.onInput({query:n,state:o.getState(),setHighlightedIndex:u,setQuery:r,setSuggestions:a,setIsOpen:g,setStatus:l,setContext:c})):(p&&clearTimeout(p),u(i.defaultHighlightedIndex),r(n),0===n.length&&!1===i.openOnFocus?(l("idle"),a(o.getState().suggestions.map((function(e){return s(s({},e),{},{items:[]})}))),g(null!==(t=h.isOpen)&&void 0!==t?t:i.shouldDropdownShow({state:o.getState()})),Promise.resolve()):(l("loading"),p=i.environment.setTimeout((function(){l("stalled")}),i.stallThreshold),i.getSources({query:n,state:o.getState(),setHighlightedIndex:u,setQuery:r,setSuggestions:a,setIsOpen:g,setStatus:l,setContext:c}).then((function(e){return l("loading"),Promise.all(e.map((function(e){return Promise.resolve(e.getSuggestions({query:n,state:o.getState(),setHighlightedIndex:u,setQuery:r,setSuggestions:a,setIsOpen:g,setStatus:l,setContext:c})).then((function(t){return{source:e,items:t}}))}))).then((function(e){var t;l("idle"),a(e),g(null!==(t=h.isOpen)&&void 0!==t?t:0===n.length&&i.openOnFocus||i.shouldDropdownShow({state:o.getState()}))})).catch((function(e){throw l("error"),e})).finally((function(){p&&clearTimeout(p)}))}))))}function f(e){var t=e.state;if(!1===e.props.showCompletion||!1===t.isOpen||null===t.highlightedIndex||"stalled"===t.status)return null;var n=l({state:t}).itemValue;if(t.query.length>0&&0===n.toLocaleLowerCase().indexOf(t.query.toLocaleLowerCase())){var s=t.query+n.slice(t.query.length);return s===t.query?null:s}return null}function m(e){var t=e.store,n=e.props,i=e.setHighlightedIndex,u=e.setQuery,r=e.setSuggestions,a=e.setIsOpen,g=e.setStatus,d=e.setContext;return{getEnvironmentProps:function(e){return{onTouchStart:function(s){!1!==t.getState().isOpen&&s.target!==e.inputElement&&(!1===[e.searchBoxElement,e.dropdownElement].some((function(e){return e&&(c(e,s.target)||c(e,n.environment.document.activeElement))}))&&t.send("blur",null))},onTouchMove:function(s){!1!==t.getState().isOpen&&e.inputElement===n.environment.document.activeElement&&s.target!==e.inputElement&&e.inputElement.blur()}}},getRootProps:function(e){return s({role:"combobox","aria-expanded":t.getState().isOpen,"aria-haspopup":"listbox","aria-owns":t.getState().isOpen?"".concat(n.id,"-menu"):void 0,"aria-labelledby":"".concat(n.id,"-label")},e)},getFormProps:function(e){e.inputElement;return s({onSubmit:function(s){s.preventDefault(),n.onSubmit({state:t.getState(),setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:d,event:s}),t.send("submit",null),e.inputElement&&e.inputElement.blur()},onReset:function(s){s.preventDefault(),n.openOnFocus&&h({query:"",store:t,props:n,setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:d}),t.send("reset",null),e.inputElement&&e.inputElement.focus()}},o(e,["inputElement"]))},getLabelProps:function(e){return s({htmlFor:"".concat(n.id,"-input"),id:"".concat(n.id,"-label")},e)},getInputProps:function(e){function c(){(n.openOnFocus||t.getState().query.length>0)&&h({query:t.getState().query,store:t,props:n,setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:d}),t.send("focus",null)}var p="ontouchstart"in n.environment,m=(e.inputElement,e.maxLength),S=void 0===m?512:m,v=o(e,["inputElement","maxLength"]);return s({"aria-autocomplete":n.showCompletion?"both":"list","aria-activedescendant":t.getState().isOpen&&null!==t.getState().highlightedIndex?"".concat(n.id,"-item-").concat(t.getState().highlightedIndex):void 0,"aria-controls":t.getState().isOpen?"".concat(n.id,"-menu"):void 0,"aria-labelledby":"".concat(n.id,"-label"),value:t.getState().query,id:"".concat(n.id,"-input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",spellCheck:!1,autoFocus:n.autoFocus,placeholder:n.placeholder,maxLength:S,onChange:function(e){h({query:e.currentTarget.value.slice(0,S),store:t,props:n,setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:d})},onKeyDown:function(e){!function(e){var t=e.event,n=e.store,s=e.props,o=e.setHighlightedIndex,i=e.setQuery,u=e.setSuggestions,r=e.setIsOpen,a=e.setStatus,g=e.setContext;if("ArrowUp"===t.key||"ArrowDown"===t.key){t.preventDefault(),n.send(t.key,{shiftKey:t.shiftKey});var c=s.environment.document.getElementById("".concat(s.id,"-item-").concat(n.getState().highlightedIndex));null==c||c.scrollIntoView(!1);var d=l({state:n.getState()});if(null!==n.getState().highlightedIndex&&d){var p=d.item,m=d.itemValue,S=d.itemUrl,v=d.source;v.onHighlight({suggestion:p,suggestionValue:m,suggestionUrl:S,source:v,state:n.getState(),setHighlightedIndex:o,setQuery:i,setSuggestions:u,setIsOpen:r,setStatus:a,setContext:g,event:t})}}else if(("Tab"===t.key||"ArrowRight"===t.key&&t.target.selectionStart===n.getState().query.length)&&s.showCompletion&&null!==n.getState().highlightedIndex){t.preventDefault();var x=f({state:n.getState(),props:s});x&&h({query:x,store:n,props:s,setHighlightedIndex:o,setQuery:i,setSuggestions:u,setIsOpen:r,setStatus:a,setContext:g})}else if("Escape"===t.key)t.preventDefault(),n.send(t.key,null);else if("Enter"===t.key){if(null===n.getState().highlightedIndex||n.getState().suggestions.every((function(e){return 0===e.items.length})))return;t.preventDefault();var y=l({state:n.getState()}),I=y.item,O=y.itemValue,b=y.itemUrl,w=y.source;t.metaKey||t.ctrlKey?void 0!==b&&s.navigator.navigateNewTab({suggestionUrl:b,suggestion:I,state:n.getState()}):t.shiftKey?void 0!==b&&s.navigator.navigateNewWindow({suggestionUrl:b,suggestion:I,state:n.getState()}):t.altKey||(h({query:O,store:n,props:s,setHighlightedIndex:o,setQuery:i,setSuggestions:u,setIsOpen:r,setStatus:a,setContext:g,nextState:{isOpen:!1}}).then((function(){w.onSelect({suggestion:I,suggestionValue:O,suggestionUrl:b,source:w,state:n.getState(),setHighlightedIndex:o,setQuery:i,setSuggestions:u,setIsOpen:r,setStatus:a,setContext:g,event:t})})),void 0!==b&&s.navigator.navigate({suggestionUrl:b,suggestion:I,state:n.getState()}))}}({event:e,store:t,props:n,setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:d})},onFocus:c,onBlur:function(){p||t.send("blur",null)},onClick:function(){e.inputElement!==n.environment.document.activeElement||t.getState().isOpen||c()}},v)},getDropdownProps:function(e){return s({onMouseLeave:function(){t.send("mouseleave",null)}},e)},getMenuProps:function(e){return s({role:"listbox","aria-labelledby":"".concat(n.id,"-label"),id:"".concat(n.id,"-menu")},e)},getItemProps:function(e){var c=e.item,p=e.source,f=o(e,["item","source"]);return s({id:"".concat(n.id,"-item-").concat(c.__autocomplete_id),role:"option","aria-selected":t.getState().highlightedIndex===c.__autocomplete_id,onMouseMove:function(e){if(c.__autocomplete_id!==t.getState().highlightedIndex){t.send("mousemove",c.__autocomplete_id);var n=l({state:t.getState()});if(null!==t.getState().highlightedIndex&&n){var s=n.item,o=n.itemValue,p=n.itemUrl,h=n.source;h.onHighlight({suggestion:s,suggestionValue:o,suggestionUrl:p,source:h,state:t.getState(),setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:d,event:e})}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){if(void 0===p.getSuggestionUrl({suggestion:c,state:t.getState()})&&!function(e){return 1===e.button||e.altKey||e.ctrlKey||e.metaKey||e.shiftKey}(e)){var s=p.getInputValue({suggestion:c,state:t.getState()});h({query:s,store:t,props:n,setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:d,nextState:{isOpen:!1}}).then((function(){p.onSelect({suggestion:c,suggestionValue:s,suggestionUrl:p.getSuggestionUrl({suggestion:c,state:t.getState()}),source:p,state:t.getState(),setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:d,event:e})}))}}},f)}}}var S=function(e,t,n){switch(e.type){case"setHighlightedIndex":return s(s({},t),{},{highlightedIndex:e.value});case"setQuery":return s(s({},t),{},{query:e.value});case"setSuggestions":return s(s({},t),{},{suggestions:e.value});case"setIsOpen":return s(s({},t),{},{isOpen:e.value});case"setStatus":return s(s({},t),{},{status:e.value});case"setContext":return s(s({},t),{},{context:s(s({},t.context),e.value)});case"ArrowDown":return s(s({},t),{},{highlightedIndex:g(1,t.highlightedIndex,r(t),n.defaultHighlightedIndex)});case"ArrowUp":return s(s({},t),{},{highlightedIndex:g(-1,t.highlightedIndex,r(t),n.defaultHighlightedIndex)});case"Escape":return t.isOpen?s(s({},t),{},{isOpen:!1}):s(s({},t),{},{query:"",status:"idle",statusContext:{},suggestions:[]});case"submit":return s(s({},t),{},{highlightedIndex:null,isOpen:!1,status:"idle",statusContext:{}});case"reset":return s(s({},t),{},{highlightedIndex:!0===n.openOnFocus?n.defaultHighlightedIndex:null,isOpen:n.openOnFocus,status:"idle",statusContext:{},query:""});case"focus":return s(s({},t),{},{highlightedIndex:n.defaultHighlightedIndex,isOpen:n.openOnFocus||t.query.length>0});case"blur":return s(s({},t),{},{isOpen:!1,highlightedIndex:null});case"mousemove":return s(s({},t),{},{highlightedIndex:e.value});case"mouseleave":return s(s({},t),{},{highlightedIndex:n.defaultHighlightedIndex});default:return t}};function v(e,t){return{state:t.initialState,getState:function(){return this.state},send:function(n,o){this.state=function(e,t){return s(s({},e),{},{completion:f({state:e,props:t})})}(e({type:n,value:o},this.state,t),t),t.onStateChange({state:this.state})}}}e.createAutocomplete=function(e){var t=d(e),n=v(S,t),o=function(e){var t=e.store;return{setHighlightedIndex:function(e){t.send("setHighlightedIndex",e)},setQuery:function(e){t.send("setQuery",e)},setSuggestions:function(e){var n=0,o=e.map((function(e){return s(s({},e),{},{items:e.items.map((function(e){return s(s({},e),{},{__autocomplete_id:n++})}))})}));t.send("setSuggestions",o)},setIsOpen:function(e){t.send("setIsOpen",e)},setStatus:function(e){t.send("setStatus",e)},setContext:function(e){t.send("setContext",e)}}}({store:n}),i=o.setHighlightedIndex,u=o.setQuery,r=o.setSuggestions,a=o.setIsOpen,g=o.setStatus,l=o.setContext,c=m({store:n,props:t,setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:l}),p=c.getEnvironmentProps,f=c.getRootProps,x=c.getFormProps,y=c.getLabelProps,I=c.getInputProps,O=c.getDropdownProps,b=c.getMenuProps,w=c.getItemProps;return{setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:l,getEnvironmentProps:p,getRootProps:f,getFormProps:x,getInputProps:I,getLabelProps:y,getDropdownProps:O,getMenuProps:b,getItemProps:w,refresh:function(){return h({query:n.getState().query,store:n,props:t,setHighlightedIndex:i,setQuery:u,setSuggestions:r,setIsOpen:a,setStatus:g,setContext:l})}}},e.getDefaultProps=d,Object.defineProperty(e,"__esModule",{value:!0})})); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@francoischalifour/autocomplete-core", | ||
"description": "Core primitives for building autocomplete experiences.", | ||
"version": "1.0.0-alpha.22", | ||
"version": "1.0.0-alpha.23", | ||
"license": "MIT", | ||
@@ -6,0 +6,0 @@ "source": "src/index.ts", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
130043
1701