diff --git a/dist/cjs/index.js b/dist/cjs/index.js index 841bc97..7d07b76 100644 --- a/dist/cjs/index.js +++ b/dist/cjs/index.js @@ -3,8 +3,10 @@ var react = require('react'); const useAutocomplete = ({ - value = '', - onChange = () => {}, + value, + onChange, + selectedItem, + onSelectedItemChange, isItemDisabled = () => false, feature: useFeature, traversal: useTraversal, @@ -14,13 +16,10 @@ const useAutocomplete = ({ const [tmpValue, setTmpValue] = react.useState(); const [open, setOpen] = react.useState(false); const [focusItem, setFocusItem] = react.useState(); - const [selectedItem, setSelectedItem] = react.useState(); - const getItemValue = react.useCallback(item => item == null ? '' : _getItemValue ? _getItemValue(item) : item.toString(), [_getItemValue]); + const getItemValue = item => item == null ? '' : _getItemValue ? _getItemValue(item) : item.toString(); const state = { focusItem, setFocusItem, - selectedItem, - setSelectedItem, open, setOpen }; @@ -30,7 +29,9 @@ const useAutocomplete = ({ getItemValue, isItemDisabled, value, - onChange, + onChange: newValue => value != newValue && (onChange == null ? void 0 : onChange(newValue)), + selectedItem, + onSelectedItemChange: newItem => newItem !== selectedItem && (onSelectedItemChange == null ? void 0 : onSelectedItemChange(newItem)), inputRef, ...state }; @@ -84,9 +85,10 @@ const scrollIntoView = element => element == null ? void 0 : element.scrollIntoV }); const autocompleteLite = ({ rovingText, - constricted, - selectOnBlur = true, - deselectOnBlur = true + select, + selectOnBlur = rovingText, + deselectOnClear = true, + deselectOnChange = true } = {}) => ({ getItemValue, isItemDisabled, @@ -96,29 +98,30 @@ const autocompleteLite = ({ tmpValue, setTmpValue, selectedItem, - setSelectedItem, + onSelectedItemChange, focusItem, setFocusItem, open, setOpen, inputRef }) => { + var _ref; const mutable = useMutableState({}); - const inputValue = tmpValue || value; - const updateValue = (newValue, moveCaretToEnd = true) => { - setTmpValue(); + const inputValue = (_ref = tmpValue || value) != null ? _ref : getItemValue(selectedItem); + const updateValue = newValue => { const endIndex = newValue.length; - moveCaretToEnd && inputRef.current.setSelectionRange(endIndex, endIndex); - if (value != newValue) onChange(newValue); + inputRef.current.setSelectionRange(endIndex, endIndex); + if (!select) onChange(newValue); }; - const updateItem = item => item !== selectedItem && setSelectedItem(item); const updateAll = item => { - updateItem(item); + onSelectedItemChange(item); updateValue(getItemValue(item)); }; const closeList = () => { setOpen(false); setFocusItem(); + setTmpValue(); + if (select) onChange(); }; return { clearable: !!inputValue, @@ -130,9 +133,11 @@ const autocompleteLite = ({ onClick: () => { var _inputRef$current; (_inputRef$current = inputRef.current) == null || _inputRef$current.focus(); - updateValue(''); - setFocusItem(); setOpen(true); + onChange(''); + setTmpValue(); + setFocusItem(); + if (deselectOnClear) onSelectedItemChange(); } }), getListProps: () => ({ @@ -155,9 +160,12 @@ const autocompleteLite = ({ ref: inputRef, value: inputValue, onChange: e => { - setFocusItem(); setOpen(true); - updateValue(e.target.value, false); + setFocusItem(); + setTmpValue(); + const newValue = e.target.value; + onChange(newValue); + if (!select && deselectOnChange || deselectOnClear && !newValue) onSelectedItemChange(); }, onBlur: ({ target @@ -170,12 +178,7 @@ const autocompleteLite = ({ 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(); }, onKeyDown: e => { @@ -197,15 +200,7 @@ const autocompleteLite = ({ } break; case 'Escape': - if (open) { - if (constricted) { - updateAll(selectedItem); - } else if (!value || getItemValue(selectedItem) != value) { - updateItem(); - updateValue(value); - } - closeList(); - } + if (open) closeList(); break; } }, @@ -280,23 +275,22 @@ const dropdownToggle = () => ({ open, setOpen, focusItem, - onChange + value, + tmpValue }) => { const mutable = useMutableState({}); const toggleRef = react.useRef(null); + const inputValue = tmpValue || value || ''; react.useEffect(() => { var _inputRef$current; if (open) (_inputRef$current = inputRef.current) == null || _inputRef$current.focus(); }, [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 { + clearable: !!inputValue, getToggleProps: () => ({ ref: toggleRef, onMouseDown: () => { @@ -306,7 +300,7 @@ const dropdownToggle = () => ({ if (mutable.a) { mutable.a = 0; } else { - openList(); + setOpen(true); } }, onKeyDown: e => { @@ -315,11 +309,12 @@ const dropdownToggle = () => ({ } = e; if (key === 'ArrowDown') { e.preventDefault(); - openList(); + setOpen(true); } } }), getInputProps: () => ({ + value: inputValue, onKeyDown: e => { const { key @@ -336,9 +331,8 @@ const dropdownToggle = () => ({ const dropdown = props => mergeFeatures(autocompleteLite({ ...props, - constricted: true, - selectOnBlur: false, - deselectOnBlur: false + select: true, + deselectOnClear: false }), dropdownToggle()); const inline = ({ diff --git a/dist/esm/features/atom/autocompleteLite.js b/dist/esm/features/atom/autocompleteLite.js index 43cfce3..f2d75ce 100644 --- a/dist/esm/features/atom/autocompleteLite.js +++ b/dist/esm/features/atom/autocompleteLite.js @@ -5,9 +5,10 @@ const scrollIntoView = element => element == null ? void 0 : element.scrollIntoV }); const autocompleteLite = ({ rovingText, - constricted, - selectOnBlur = true, - deselectOnBlur = true + select, + selectOnBlur = rovingText, + deselectOnClear = true, + deselectOnChange = true } = {}) => ({ getItemValue, isItemDisabled, @@ -17,29 +18,30 @@ const autocompleteLite = ({ tmpValue, setTmpValue, selectedItem, - setSelectedItem, + onSelectedItemChange, focusItem, setFocusItem, open, setOpen, inputRef }) => { + var _ref; const mutable = useMutableState({}); - const inputValue = tmpValue || value; - const updateValue = (newValue, moveCaretToEnd = true) => { - setTmpValue(); + const inputValue = (_ref = tmpValue || value) != null ? _ref : getItemValue(selectedItem); + const updateValue = newValue => { const endIndex = newValue.length; - moveCaretToEnd && inputRef.current.setSelectionRange(endIndex, endIndex); - if (value != newValue) onChange(newValue); + inputRef.current.setSelectionRange(endIndex, endIndex); + if (!select) onChange(newValue); }; - const updateItem = item => item !== selectedItem && setSelectedItem(item); const updateAll = item => { - updateItem(item); + onSelectedItemChange(item); updateValue(getItemValue(item)); }; const closeList = () => { setOpen(false); setFocusItem(); + setTmpValue(); + if (select) onChange(); }; return { clearable: !!inputValue, @@ -51,9 +53,11 @@ const autocompleteLite = ({ onClick: () => { var _inputRef$current; (_inputRef$current = inputRef.current) == null || _inputRef$current.focus(); - updateValue(''); - setFocusItem(); setOpen(true); + onChange(''); + setTmpValue(); + setFocusItem(); + if (deselectOnClear) onSelectedItemChange(); } }), getListProps: () => ({ @@ -76,9 +80,12 @@ const autocompleteLite = ({ ref: inputRef, value: inputValue, onChange: e => { - setFocusItem(); setOpen(true); - updateValue(e.target.value, false); + setFocusItem(); + setTmpValue(); + const newValue = e.target.value; + onChange(newValue); + if (!select && deselectOnChange || deselectOnClear && !newValue) onSelectedItemChange(); }, onBlur: ({ target @@ -91,12 +98,7 @@ const autocompleteLite = ({ 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(); }, onKeyDown: e => { @@ -118,15 +120,7 @@ const autocompleteLite = ({ } break; case 'Escape': - if (open) { - if (constricted) { - updateAll(selectedItem); - } else if (!value || getItemValue(selectedItem) != value) { - updateItem(); - updateValue(value); - } - closeList(); - } + if (open) closeList(); break; } }, diff --git a/dist/esm/features/atom/dropdownToggle.js b/dist/esm/features/atom/dropdownToggle.js index e6e51e2..0d02a5a 100644 --- a/dist/esm/features/atom/dropdownToggle.js +++ b/dist/esm/features/atom/dropdownToggle.js @@ -6,23 +6,22 @@ const dropdownToggle = () => ({ open, setOpen, focusItem, - onChange + value, + tmpValue }) => { const mutable = useMutableState({}); const toggleRef = useRef(null); + const inputValue = tmpValue || value || ''; useEffect(() => { var _inputRef$current; if (open) (_inputRef$current = inputRef.current) == null || _inputRef$current.focus(); }, [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 { + clearable: !!inputValue, getToggleProps: () => ({ ref: toggleRef, onMouseDown: () => { @@ -32,7 +31,7 @@ const dropdownToggle = () => ({ if (mutable.a) { mutable.a = 0; } else { - openList(); + setOpen(true); } }, onKeyDown: e => { @@ -41,11 +40,12 @@ const dropdownToggle = () => ({ } = e; if (key === 'ArrowDown') { e.preventDefault(); - openList(); + setOpen(true); } } }), getInputProps: () => ({ + value: inputValue, onKeyDown: e => { const { key diff --git a/dist/esm/features/molecule/dropdown.js b/dist/esm/features/molecule/dropdown.js index 1919bfb..2707303 100644 --- a/dist/esm/features/molecule/dropdown.js +++ b/dist/esm/features/molecule/dropdown.js @@ -4,9 +4,8 @@ import { dropdownToggle } from '../atom/dropdownToggle.js'; const dropdown = props => mergeFeatures(autocompleteLite({ ...props, - constricted: true, - selectOnBlur: false, - deselectOnBlur: false + select: true, + deselectOnClear: false }), dropdownToggle()); export { dropdown }; diff --git a/dist/esm/hooks/useAutocomplete.js b/dist/esm/hooks/useAutocomplete.js index 35d9a83..2970345 100644 --- a/dist/esm/hooks/useAutocomplete.js +++ b/dist/esm/hooks/useAutocomplete.js @@ -1,8 +1,10 @@ -import { useRef, useState, useCallback } from 'react'; +import { useRef, useState } from 'react'; const useAutocomplete = ({ - value = '', - onChange = () => {}, + value, + onChange, + selectedItem, + onSelectedItemChange, isItemDisabled = () => false, feature: useFeature, traversal: useTraversal, @@ -12,13 +14,10 @@ const useAutocomplete = ({ const [tmpValue, setTmpValue] = useState(); const [open, setOpen] = useState(false); const [focusItem, setFocusItem] = useState(); - const [selectedItem, setSelectedItem] = useState(); - const getItemValue = useCallback(item => item == null ? '' : _getItemValue ? _getItemValue(item) : item.toString(), [_getItemValue]); + const getItemValue = item => item == null ? '' : _getItemValue ? _getItemValue(item) : item.toString(); const state = { focusItem, setFocusItem, - selectedItem, - setSelectedItem, open, setOpen }; @@ -28,7 +27,9 @@ const useAutocomplete = ({ getItemValue, isItemDisabled, value, - onChange, + onChange: newValue => value != newValue && (onChange == null ? void 0 : onChange(newValue)), + selectedItem, + onSelectedItemChange: newItem => newItem !== selectedItem && (onSelectedItemChange == null ? void 0 : onSelectedItemChange(newItem)), inputRef, ...state }; diff --git a/examples/data.ts b/examples/data.ts index 56e6c74..0f55301 100644 --- a/examples/data.ts +++ b/examples/data.ts @@ -579,6 +579,10 @@ const LIST_GROUP = [ name: 'Alaska', abbr: 'AK' }, + { + name: 'a', + abbr: 'A' + }, { name: 'American Samoa', abbr: 'AS' diff --git a/examples/package-lock.json b/examples/package-lock.json index 7cd9825..cc60c44 100644 --- a/examples/package-lock.json +++ b/examples/package-lock.json @@ -24,7 +24,7 @@ }, "..": { "name": "@szhsin/react-autocomplete", - "version": "0.8.9", + "version": "0.8.10", "license": "MIT", "devDependencies": { "@babel/core": "^7.23.2", diff --git a/examples/pages/dropdownExample.tsx b/examples/pages/dropdownExample.tsx index 037ffc3..caad246 100644 --- a/examples/pages/dropdownExample.tsx +++ b/examples/pages/dropdownExample.tsx @@ -12,7 +12,7 @@ type Item = { name: string; abbr: string }; const getItemValue = (item: Item) => item.name; const isItemDisabled = ({ abbr }: Item) => abbr.startsWith('CO'); -const getGroupedItems = (value: string) => +const getGroupedItems = (value: string = '') => LIST_GROUP.map((group) => ({ ...group, states: group.states.filter((item) => item.name.toLowerCase().startsWith(value.toLowerCase())) @@ -20,11 +20,8 @@ const getGroupedItems = (value: string) => export default function Dropdown() { const [rovingText, setRovingText] = useState(false); - const [value, setValue] = useState(''); - // const items = US_STATES.filter((item) => item.name.toLowerCase().startsWith(value.toLowerCase())); - // const [myinput, setmyinput] = useState(''); - // const [items, setItems] = useState(US_STATES); - // const feature = supercomplete<{ name: string; abbr: string }>(); + const [value, setValue] = useState(''); + const [selectedItem, setSelectedItem] = useState(); const groupedItems = getGroupedItems(value); @@ -36,8 +33,7 @@ export default function Dropdown() { getClearProps, clearable, open, - focusItem, - selectedItem + focusItem // inlineComplete } = useAutocomplete({ // traversal: linearTraversal({ @@ -57,6 +53,8 @@ export default function Dropdown() { // const item = getGroupedItems(value)[0]?.states.find((item) => !isItemDisabled(item)); // item && inlineComplete({ item }); }, + selectedItem, + onSelectedItemChange: setSelectedItem, // feature: autocomplete({ constricted, rovingText }), feature: dropdown({ rovingText }), traversal: groupedTraversal({ @@ -66,19 +64,8 @@ export default function Dropdown() { }) }); - // useEffect(() => { - // items.length && inlineComplete({ index: 0, value: items[0] }); - // }, [items, inlineComplete]); - const inputProps = getInputProps(); - // useEffect(() => { - // if (open) { - // console.log('inputProps.ref.current useEffect', inputProps.ref.current); - // inputProps.ref.current?.focus(); - // } - // }, [open]); - const [maxHeight] = useAutoHeight({ anchorRef: inputProps.ref, show: open, margin: 30 }); return ( @@ -109,7 +96,7 @@ export default function Dropdown() { }} >
- + {clearable && (