@szhsin/react-autocomplete
Advanced tools
Comparing version 0.1.0 to 0.2.0
@@ -6,30 +6,57 @@ 'use strict'; | ||
const useAutocomplete = ({ | ||
input, | ||
onInputChange, | ||
isOpen, | ||
onOpenChange = () => {}, | ||
onValueChange, | ||
items = [] | ||
}) => { | ||
const [inputValue, setInputValue] = react.useState(''); | ||
const [focusIndex, setfocusIndex] = react.useState(-1); | ||
const [isOpen, setOpen] = react.useState(false); | ||
const itemLength = items.length; | ||
const updateInput = itemIndex => { | ||
setfocusIndex(itemIndex); | ||
setInputValue(items[itemIndex]); | ||
}; | ||
const updateValue = value => { | ||
if (value == null) return; | ||
setInputValue(value); | ||
onValueChange == null || onValueChange(value); | ||
}; | ||
const inputProps = { | ||
value: input, | ||
onChange: e => onInputChange(e.target.value), | ||
onClick: () => onOpenChange(!isOpen), | ||
onBlur: () => onOpenChange(false), | ||
value: inputValue, | ||
onChange: e => { | ||
updateValue(e.target.value); | ||
setOpen(true); | ||
setfocusIndex(-1); | ||
}, | ||
onClick: () => setOpen(!isOpen), | ||
onBlur: () => setOpen(false), | ||
onKeyDown: ({ | ||
key | ||
}) => { | ||
let nextIndex = focusIndex; | ||
switch (key) { | ||
case 'ArrowDown': | ||
onOpenChange(true); | ||
setfocusIndex(i => i + 1); | ||
if (isOpen) { | ||
if (++nextIndex >= itemLength) nextIndex = 0; | ||
updateInput(nextIndex); | ||
} else { | ||
setOpen(true); | ||
} | ||
break; | ||
case 'ArrowUp': | ||
onOpenChange(true); | ||
setfocusIndex(i => i - 1); | ||
if (isOpen) { | ||
if (--nextIndex < 0) nextIndex = itemLength - 1; | ||
updateInput(nextIndex); | ||
} else { | ||
setOpen(true); | ||
} | ||
break; | ||
case 'Enter': | ||
onOpenChange(false); | ||
onInputChange(items[focusIndex]); | ||
if (isOpen) { | ||
setOpen(false); | ||
updateValue(items[focusIndex]); | ||
} | ||
break; | ||
case 'Escape': | ||
setOpen(false); | ||
break; | ||
} | ||
@@ -40,3 +67,7 @@ } | ||
inputProps, | ||
focusIndex | ||
state: { | ||
inputValue: [inputValue, setInputValue], | ||
focusIndex: [focusIndex, setfocusIndex], | ||
isOpen: [isOpen, setOpen] | ||
} | ||
}; | ||
@@ -43,0 +74,0 @@ }; |
import { useState } from 'react'; | ||
const useAutocomplete = ({ | ||
input, | ||
onInputChange, | ||
isOpen, | ||
onOpenChange = () => {}, | ||
onValueChange, | ||
items = [] | ||
}) => { | ||
const [inputValue, setInputValue] = useState(''); | ||
const [focusIndex, setfocusIndex] = useState(-1); | ||
const [isOpen, setOpen] = useState(false); | ||
const itemLength = items.length; | ||
const updateInput = itemIndex => { | ||
setfocusIndex(itemIndex); | ||
setInputValue(items[itemIndex]); | ||
}; | ||
const updateValue = value => { | ||
if (value == null) return; | ||
setInputValue(value); | ||
onValueChange == null || onValueChange(value); | ||
}; | ||
const inputProps = { | ||
value: input, | ||
onChange: e => onInputChange(e.target.value), | ||
onClick: () => onOpenChange(!isOpen), | ||
onBlur: () => onOpenChange(false), | ||
value: inputValue, | ||
onChange: e => { | ||
updateValue(e.target.value); | ||
setOpen(true); | ||
setfocusIndex(-1); | ||
}, | ||
onClick: () => setOpen(!isOpen), | ||
onBlur: () => setOpen(false), | ||
onKeyDown: ({ | ||
key | ||
}) => { | ||
let nextIndex = focusIndex; | ||
switch (key) { | ||
case 'ArrowDown': | ||
onOpenChange(true); | ||
setfocusIndex(i => i + 1); | ||
if (isOpen) { | ||
if (++nextIndex >= itemLength) nextIndex = 0; | ||
updateInput(nextIndex); | ||
} else { | ||
setOpen(true); | ||
} | ||
break; | ||
case 'ArrowUp': | ||
onOpenChange(true); | ||
setfocusIndex(i => i - 1); | ||
if (isOpen) { | ||
if (--nextIndex < 0) nextIndex = itemLength - 1; | ||
updateInput(nextIndex); | ||
} else { | ||
setOpen(true); | ||
} | ||
break; | ||
case 'Enter': | ||
onOpenChange(false); | ||
onInputChange(items[focusIndex]); | ||
if (isOpen) { | ||
setOpen(false); | ||
updateValue(items[focusIndex]); | ||
} | ||
break; | ||
case 'Escape': | ||
setOpen(false); | ||
break; | ||
} | ||
@@ -37,3 +64,7 @@ } | ||
inputProps, | ||
focusIndex | ||
state: { | ||
inputValue: [inputValue, setInputValue], | ||
focusIndex: [focusIndex, setfocusIndex], | ||
isOpen: [isOpen, setOpen] | ||
} | ||
}; | ||
@@ -40,0 +71,0 @@ }; |
{ | ||
"name": "@szhsin/react-autocomplete", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "", | ||
@@ -52,30 +52,30 @@ "author": "Zheng Song", | ||
"devDependencies": { | ||
"@babel/core": "^7.22.5", | ||
"@babel/preset-env": "^7.22.5", | ||
"@babel/preset-react": "^7.22.5", | ||
"@babel/preset-typescript": "^7.22.5", | ||
"@rollup/plugin-babel": "^6.0.3", | ||
"@rollup/plugin-node-resolve": "^15.1.0", | ||
"@testing-library/jest-dom": "^5.16.5", | ||
"@babel/core": "^7.23.2", | ||
"@babel/preset-env": "^7.23.2", | ||
"@babel/preset-react": "^7.22.15", | ||
"@babel/preset-typescript": "^7.23.2", | ||
"@rollup/plugin-babel": "^6.0.4", | ||
"@rollup/plugin-node-resolve": "^15.2.3", | ||
"@testing-library/jest-dom": "^6.1.4", | ||
"@testing-library/react": "^14.0.0", | ||
"@types/jest": "^29.5.2", | ||
"@types/react": "^18.2.14", | ||
"@typescript-eslint/eslint-plugin": "^5.60.1", | ||
"@typescript-eslint/parser": "^5.60.1", | ||
"@types/jest": "^29.5.7", | ||
"@types/react": "^18.2.34", | ||
"@typescript-eslint/eslint-plugin": "^6.9.1", | ||
"@typescript-eslint/parser": "^6.9.1", | ||
"babel-plugin-pure-annotations": "^0.1.2", | ||
"eslint": "^8.44.0", | ||
"eslint-config-prettier": "^8.8.0", | ||
"eslint-plugin-jest": "^27.2.2", | ||
"eslint-plugin-react": "^7.32.2", | ||
"eslint": "^8.53.0", | ||
"eslint-config-prettier": "^9.0.0", | ||
"eslint-plugin-jest": "^27.6.0", | ||
"eslint-plugin-react": "^7.33.2", | ||
"eslint-plugin-react-hooks": "^4.6.0", | ||
"eslint-plugin-react-hooks-addons": "^0.3.1", | ||
"jest": "^29.5.0", | ||
"jest-environment-jsdom": "^29.5.0", | ||
"jest": "^29.7.0", | ||
"jest-environment-jsdom": "^29.7.0", | ||
"npm-run-all": "^4.1.5", | ||
"prettier": "^2.8.8", | ||
"prettier": "^3.0.3", | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"rollup": "^3.26.0", | ||
"typescript": "^5.1.6" | ||
"rollup": "^4.3.0", | ||
"typescript": "^5.2.2" | ||
} | ||
} |
import type { InputHTMLAttributes } from 'react'; | ||
declare const useAutocomplete: ({ input, onInputChange, isOpen, onOpenChange, items }: { | ||
input?: string | undefined; | ||
onInputChange: (value: string) => void; | ||
isOpen?: boolean | undefined; | ||
onOpenChange?: ((open: boolean) => void) | undefined; | ||
declare const useAutocomplete: ({ onValueChange, items }: { | ||
onValueChange?: ((value: string) => void) | undefined; | ||
items?: string[] | undefined; | ||
}) => { | ||
inputProps: InputHTMLAttributes<HTMLInputElement>; | ||
focusIndex: number; | ||
readonly inputProps: InputHTMLAttributes<HTMLInputElement>; | ||
readonly state: { | ||
readonly inputValue: readonly [string, import("react").Dispatch<import("react").SetStateAction<string>>]; | ||
readonly focusIndex: readonly [number, import("react").Dispatch<import("react").SetStateAction<number>>]; | ||
readonly isOpen: readonly [boolean, import("react").Dispatch<import("react").SetStateAction<boolean>>]; | ||
}; | ||
}; | ||
export { useAutocomplete }; |
7587
156