@szhsin/react-autocomplete
Advanced tools
Comparing version 0.8.8 to 0.8.9
@@ -85,5 +85,7 @@ 'use strict'; | ||
}); | ||
const autocomplete = ({ | ||
const autocompleteLite = ({ | ||
rovingText, | ||
constricted | ||
constricted, | ||
selectOnBlur = true, | ||
deselectOnBlur = true | ||
} = {}) => ({ | ||
@@ -106,2 +108,3 @@ getItemValue, | ||
const mutable = useMutableState({}); | ||
const inputValue = tmpValue || value; | ||
const updateValue = (newValue, moveCaretToEnd = true) => { | ||
@@ -111,5 +114,3 @@ setTmpValue(); | ||
moveCaretToEnd && inputRef.current.setSelectionRange(endIndex, endIndex); | ||
if (value != newValue) { | ||
onChange(newValue); | ||
} | ||
if (value != newValue) onChange(newValue); | ||
}; | ||
@@ -125,79 +126,93 @@ const updateItem = item => item !== selectedItem && setSelectedItem(item); | ||
}; | ||
const getListProps = () => ({ | ||
onMouseDown: () => { | ||
mutable.a = 1; | ||
}, | ||
onClick: () => { | ||
var _inputRef$current; | ||
(_inputRef$current = inputRef.current) == null || _inputRef$current.focus(); | ||
mutable.a = 0; | ||
} | ||
}); | ||
const getInputProps = () => ({ | ||
ref: inputRef, | ||
value: tmpValue || value, | ||
onChange: e => { | ||
setFocusItem(); | ||
setOpen(true); | ||
updateValue(e.target.value, false); | ||
}, | ||
onClick: () => setOpen(true), | ||
onBlur: () => { | ||
if (mutable.a || !open) return; | ||
if (focusItem) { | ||
updateAll(focusItem); | ||
} else if (constricted) { | ||
if (value) updateAll(selectedItem);else updateItem(); | ||
} else if (getItemValue(selectedItem) != value) { | ||
updateItem(); | ||
return { | ||
clearable: !!inputValue, | ||
getClearProps: () => ({ | ||
tabIndex: -1, | ||
onMouseDown: () => { | ||
if (document.activeElement === inputRef.current) mutable.a = 1; | ||
}, | ||
onClick: () => { | ||
var _inputRef$current; | ||
(_inputRef$current = inputRef.current) == null || _inputRef$current.focus(); | ||
updateValue(''); | ||
setFocusItem(); | ||
setOpen(true); | ||
} | ||
closeList(); | ||
}, | ||
onKeyDown: e => { | ||
switch (e.key) { | ||
case 'ArrowUp': | ||
case 'ArrowDown': | ||
e.preventDefault(); | ||
if (open) { | ||
const nextItem = traverse(e.key != 'ArrowUp'); | ||
if (rovingText) setTmpValue(getItemValue(nextItem)); | ||
} else { | ||
setOpen(true); | ||
} | ||
break; | ||
case 'Enter': | ||
if (open && focusItem) { | ||
updateAll(focusItem); | ||
closeList(); | ||
} | ||
break; | ||
case 'Escape': | ||
if (open) { | ||
if (constricted) { | ||
updateAll(selectedItem); | ||
} else if (!value || getItemValue(selectedItem) != value) { | ||
updateItem(); | ||
updateValue(value); | ||
} | ||
closeList(); | ||
} | ||
break; | ||
}), | ||
getListProps: () => ({ | ||
onMouseDown: () => { | ||
mutable.a = 1; | ||
} | ||
} | ||
}); | ||
const getItemProps = ({ | ||
item | ||
}) => ({ | ||
ref: focusItem === item ? scrollIntoView : null, | ||
onClick: () => { | ||
if (!isItemDisabled(item)) { | ||
updateAll(item); | ||
}), | ||
getItemProps: ({ | ||
item | ||
}) => ({ | ||
ref: focusItem === item ? scrollIntoView : null, | ||
onClick: () => { | ||
if (!isItemDisabled(item)) { | ||
updateAll(item); | ||
closeList(); | ||
} | ||
} | ||
}), | ||
getInputProps: () => ({ | ||
ref: inputRef, | ||
value: inputValue, | ||
onChange: e => { | ||
setFocusItem(); | ||
setOpen(true); | ||
updateValue(e.target.value, false); | ||
}, | ||
onBlur: ({ | ||
target | ||
}) => { | ||
if (mutable.a) { | ||
mutable.a = 0; | ||
target.focus(); | ||
return; | ||
} | ||
if (!open) return; | ||
if (selectOnBlur && focusItem) { | ||
updateAll(focusItem); | ||
} else if (constricted) { | ||
if (value || !deselectOnBlur) updateAll(selectedItem);else updateItem(); | ||
} else if (getItemValue(selectedItem) != value) { | ||
updateItem(); | ||
} | ||
setTmpValue(); | ||
closeList(); | ||
} | ||
} | ||
}); | ||
return { | ||
getInputProps, | ||
getItemProps, | ||
getListProps | ||
}, | ||
onKeyDown: e => { | ||
switch (e.key) { | ||
case 'ArrowUp': | ||
case 'ArrowDown': | ||
e.preventDefault(); | ||
if (open) { | ||
const nextItem = traverse(e.key != 'ArrowUp'); | ||
if (rovingText) setTmpValue(getItemValue(nextItem)); | ||
} else { | ||
setOpen(true); | ||
} | ||
break; | ||
case 'Enter': | ||
if (open && focusItem) { | ||
updateAll(focusItem); | ||
closeList(); | ||
} | ||
break; | ||
case 'Escape': | ||
if (open) { | ||
if (constricted) { | ||
updateAll(selectedItem); | ||
} else if (!value || getItemValue(selectedItem) != value) { | ||
updateItem(); | ||
updateValue(value); | ||
} | ||
closeList(); | ||
} | ||
break; | ||
} | ||
}, | ||
onClick: () => setOpen(true) | ||
}) | ||
}; | ||
@@ -229,27 +244,33 @@ }; | ||
const inline = ({ | ||
getInlineItem | ||
}) => ({ | ||
getItemValue, | ||
setTmpValue, | ||
setFocusItem | ||
const inputToggle = () => ({ | ||
inputRef, | ||
open, | ||
setOpen | ||
}) => { | ||
const mutable = useMutableState({}); | ||
return { | ||
getToggleProps: () => ({ | ||
tabIndex: -1, | ||
onMouseDown: () => { | ||
mutable.b = open; | ||
mutable.c = 1; | ||
}, | ||
onClick: () => { | ||
var _inputRef$current; | ||
if (mutable.b) { | ||
mutable.b = 0; | ||
} else { | ||
setOpen(true); | ||
} | ||
(_inputRef$current = inputRef.current) == null || _inputRef$current.focus(); | ||
} | ||
}), | ||
getInputProps: () => ({ | ||
onChange: async ({ | ||
target, | ||
nativeEvent | ||
onBlur: ({ | ||
target | ||
}) => { | ||
if (nativeEvent.inputType !== 'insertText') { | ||
return; | ||
if (mutable.c) { | ||
mutable.c = 0; | ||
target.focus(); | ||
} | ||
const nextValue = target.value; | ||
const item = await getInlineItem(nextValue); | ||
if (!item) return; | ||
setFocusItem(item); | ||
const itemValue = getItemValue(item); | ||
const start = nextValue.length; | ||
const end = itemValue.length; | ||
setTmpValue(nextValue + itemValue.slice(start)); | ||
setTimeout(() => target.setSelectionRange(start, end), 0); | ||
} | ||
@@ -260,17 +281,10 @@ }) | ||
const supercomplete = ({ | ||
constricted, | ||
getInlineItem | ||
}) => mergeFeatures(autocomplete({ | ||
constricted, | ||
rovingText: true | ||
}), inline({ | ||
getInlineItem | ||
})); | ||
const autocomplete = props => mergeFeatures(autocompleteLite(props), inputToggle()); | ||
const toggle = () => ({ | ||
const dropdownToggle = () => ({ | ||
inputRef, | ||
open, | ||
setOpen, | ||
focusItem | ||
focusItem, | ||
onChange | ||
}) => { | ||
@@ -283,2 +297,10 @@ const mutable = useMutableState({}); | ||
}, [open, inputRef]); | ||
const openList = () => { | ||
onChange(''); | ||
setOpen(true); | ||
}; | ||
const focusToggle = () => setTimeout(() => { | ||
var _toggleRef$current; | ||
return (_toggleRef$current = toggleRef.current) == null ? void 0 : _toggleRef$current.focus(); | ||
}, 0); | ||
return { | ||
@@ -294,3 +316,3 @@ getToggleProps: () => ({ | ||
} else { | ||
setOpen(true); | ||
openList(); | ||
} | ||
@@ -302,5 +324,5 @@ }, | ||
} = e; | ||
if (key === 'ArrowUp' || key === 'ArrowDown') { | ||
if (key === 'ArrowDown') { | ||
e.preventDefault(); | ||
setOpen(true); | ||
openList(); | ||
} | ||
@@ -311,11 +333,9 @@ } | ||
onKeyDown: e => { | ||
var _toggleRef$current; | ||
const { | ||
key | ||
} = e; | ||
if (key === 'Escape') (_toggleRef$current = toggleRef.current) == null || _toggleRef$current.focus(); | ||
if (key === 'Escape') focusToggle(); | ||
if (key === 'Enter' && focusItem) { | ||
var _toggleRef$current2; | ||
e.preventDefault(); | ||
(_toggleRef$current2 = toggleRef.current) == null || _toggleRef$current2.focus(); | ||
focusToggle(); | ||
} | ||
@@ -327,7 +347,49 @@ } | ||
const dropdown = props => mergeFeatures(autocomplete({ | ||
const dropdown = props => mergeFeatures(autocompleteLite({ | ||
...props, | ||
constricted: true | ||
}), toggle()); | ||
constricted: true, | ||
selectOnBlur: false, | ||
deselectOnBlur: false | ||
}), dropdownToggle()); | ||
const inline = ({ | ||
getInlineItem | ||
}) => ({ | ||
getItemValue, | ||
setTmpValue, | ||
setFocusItem | ||
}) => { | ||
return { | ||
getInputProps: () => ({ | ||
onChange: async ({ | ||
target, | ||
nativeEvent | ||
}) => { | ||
if (nativeEvent.inputType !== 'insertText') { | ||
return; | ||
} | ||
const nextValue = target.value; | ||
const item = await getInlineItem(nextValue); | ||
if (!item) return; | ||
setFocusItem(item); | ||
const itemValue = getItemValue(item); | ||
const start = nextValue.length; | ||
const end = itemValue.length; | ||
setTmpValue(nextValue + itemValue.slice(start)); | ||
setTimeout(() => target.setSelectionRange(start, end), 0); | ||
} | ||
}) | ||
}; | ||
}; | ||
const supercomplete = ({ | ||
getInlineItem, | ||
...rest | ||
}) => mergeFeatures(autocomplete({ | ||
...rest, | ||
rovingText: true | ||
}), inline({ | ||
getInlineItem | ||
})); | ||
const linearTraversal = ({ | ||
@@ -388,7 +450,9 @@ traverseInput, | ||
exports.autocomplete = autocomplete; | ||
exports.autocompleteLite = autocompleteLite; | ||
exports.dropdown = dropdown; | ||
exports.groupedTraversal = groupedTraversal; | ||
exports.linearTraversal = linearTraversal; | ||
exports.mergeFeatures = mergeFeatures; | ||
exports.supercomplete = supercomplete; | ||
exports.useAutoHeight = useAutoHeight; | ||
exports.useAutocomplete = useAutocomplete; |
export { useAutocomplete } from './hooks/useAutocomplete.js'; | ||
export { useAutoHeight } from './hooks/useAutoHeight.js'; | ||
export { autocomplete } from './features/autocomplete.js'; | ||
export { supercomplete } from './features/supercomplete.js'; | ||
export { dropdown } from './features/dropdown.js'; | ||
export { autocompleteLite } from './features/atom/autocompleteLite.js'; | ||
export { autocomplete } from './features/molecule/autocomplete.js'; | ||
export { dropdown } from './features/molecule/dropdown.js'; | ||
export { supercomplete } from './features/molecule/supercomplete.js'; | ||
export { linearTraversal } from './traversals/linearTraversal.js'; | ||
export { groupedTraversal } from './traversals/groupedTraversal.js'; | ||
export { mergeFeatures } from './utils/mergeFeatures.js'; |
{ | ||
"name": "@szhsin/react-autocomplete", | ||
"version": "0.8.8", | ||
"version": "0.8.9", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "author": "Zheng Song", |
@@ -8,2 +8,3 @@ import type { HTMLAttributes, InputHTMLAttributes, ButtonHTMLAttributes } from 'react'; | ||
getToggleProps: () => ButtonHTMLAttributes<HTMLButtonElement>; | ||
getClearProps: () => ButtonHTMLAttributes<HTMLButtonElement>; | ||
getListProps: () => HTMLAttributes<HTMLElement>; | ||
@@ -45,4 +46,7 @@ getItemProps: (option: { | ||
constricted?: boolean; | ||
selectOnBlur?: boolean; | ||
deselectOnBlur?: boolean; | ||
getInlineItem: (value: string) => T | undefined | null | void | Promise<T | undefined | null | void>; | ||
} | ||
export type AutocompleteFeatureProps<T> = Pick<FeatureProps<T>, 'rovingText' | 'constricted' | 'selectOnBlur' | 'deselectOnBlur'>; | ||
export type Feature<T, Yield extends object> = (cx: Contextual<T> & ReturnType<Traversal<T>>) => Yield; | ||
@@ -49,0 +53,0 @@ export type MergedFeatureYield<T, Features> = Features extends readonly [Feature<T, infer S>] ? S : Features extends readonly [Feature<T, infer F>, ...infer R] ? F & MergedFeatureYield<T, R> : never; |
export { useAutocomplete } from './hooks/useAutocomplete'; | ||
export { useAutoHeight } from './hooks/useAutoHeight'; | ||
export { autocomplete } from './features/autocomplete'; | ||
export { supercomplete } from './features/supercomplete'; | ||
export { dropdown } from './features/dropdown'; | ||
export { type AutocompleteLiteFeature, autocompleteLite } from './features/atom/autocompleteLite'; | ||
export { type AutocompleteFeature, autocomplete } from './features/molecule/autocomplete'; | ||
export { type DropdownFeature, dropdown } from './features/molecule/dropdown'; | ||
export { type SupercompleteFeature, supercomplete } from './features/molecule/supercomplete'; | ||
export { linearTraversal } from './traversals/linearTraversal'; | ||
export { groupedTraversal } from './traversals/groupedTraversal'; | ||
export type { AutocompleteProps, AutocompleteState, Feature } from './common'; | ||
export { mergeFeatures } from './utils/mergeFeatures'; | ||
export type { AutocompleteProps, AutocompleteState, Feature, MergedFeature, FeatureProps } from './common'; |
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
35425
1034
34