From 380731baa3ed75d89f2b4de617b2ed234b8ac7fe Mon Sep 17 00:00:00 2001 From: Zheng Song Date: Tue, 9 Jul 2024 22:15:55 +1000 Subject: [PATCH 1/3] Support for search scenario --- dist/cjs/index.js | 5 +- dist/esm/features/atom/autocompleteLite.js | 5 +- examples/pages/search.tsx | 93 ++++++++++++++++++++++ src/features/atom/autocompleteLite.ts | 8 +- 4 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 examples/pages/search.tsx diff --git a/dist/cjs/index.js b/dist/cjs/index.js index 740466a..7d92445 100644 --- a/dist/cjs/index.js +++ b/dist/cjs/index.js @@ -191,11 +191,11 @@ const autocompleteLite = ({ !noAction && (onAction == null ? void 0 : onAction(item)); return true; } - onSelectChange(item); const itemValue = getItemValue(item); + if (!select) onChange(itemValue); const endIndex = itemValue.length; inputRef.current.setSelectionRange(endIndex, endIndex); - if (!select) onChange(itemValue); + onSelectChange(item); }; const resetState = shouldClose => { setFocusItem(); @@ -268,6 +268,7 @@ const autocompleteLite = ({ case 'Enter': if (open) { if (focusItem) { + e.preventDefault(); resetState(selectItemOrAction(focusItem)); } else if (!select) { resetState(true); diff --git a/dist/esm/features/atom/autocompleteLite.js b/dist/esm/features/atom/autocompleteLite.js index 5255b6d..fc17266 100644 --- a/dist/esm/features/atom/autocompleteLite.js +++ b/dist/esm/features/atom/autocompleteLite.js @@ -37,11 +37,11 @@ const autocompleteLite = ({ !noAction && (onAction == null ? void 0 : onAction(item)); return true; } - onSelectChange(item); const itemValue = getItemValue(item); + if (!select) onChange(itemValue); const endIndex = itemValue.length; inputRef.current.setSelectionRange(endIndex, endIndex); - if (!select) onChange(itemValue); + onSelectChange(item); }; const resetState = shouldClose => { setFocusItem(); @@ -114,6 +114,7 @@ const autocompleteLite = ({ case 'Enter': if (open) { if (focusItem) { + e.preventDefault(); resetState(selectItemOrAction(focusItem)); } else if (!select) { resetState(true); diff --git a/examples/pages/search.tsx b/examples/pages/search.tsx new file mode 100644 index 0000000..ab1c967 --- /dev/null +++ b/examples/pages/search.tsx @@ -0,0 +1,93 @@ +import React, { useState } from 'react'; +import { useCombobox, supercomplete, linearTraversal } from '@szhsin/react-autocomplete'; +import styles from '@/styles/Home.module.css'; +import { US_STATES } from '../data'; + +type Item = { name: string; abbr: string }; +const getItemValue = (item: Item) => item.name; + +const search = (value: string | undefined) => value && console.log(`Searching for "${value}"`); + +export default function Home() { + const [value, setValue] = useState(); + const items = value + ? US_STATES.filter((item) => item.name.toLowerCase().startsWith(value.toLowerCase())) + : US_STATES; + + const { + getInputProps, + getListProps, + getItemProps, + getToggleProps, + getClearProps, + open, + focusItem, + clearable + } = useCombobox({ + onSelectChange: (selected) => search(selected?.name), + getItemValue, + value, + onChange: setValue, + feature: supercomplete({ + selectOnBlur: false, + getFocusItem: (newValue) => + US_STATES.filter((item) => + item.name.toLowerCase().startsWith(newValue.toLowerCase()) + )[0] + }), + + traversal: linearTraversal({ items, traverseInput: true }) + }); + + return ( +
+
value: {value}
+
Focus item: {focusItem?.name}
+ +
{ + e.preventDefault(); + search(value); + }} + > + + + {clearable && ( + + )} + +
+
    + {items.map((item) => ( +
  • + {item.name} +
  • + ))} +
+
+ ); +} diff --git a/src/features/atom/autocompleteLite.ts b/src/features/atom/autocompleteLite.ts index 922b6ec..acd241b 100644 --- a/src/features/atom/autocompleteLite.ts +++ b/src/features/atom/autocompleteLite.ts @@ -55,11 +55,13 @@ const autocompleteLite = return true; // Always close list on action } - onSelectChange(item); const itemValue = getItemValue(item); + if (!select) onChange(itemValue); const endIndex = itemValue.length; inputRef.current!.setSelectionRange(endIndex, endIndex); - if (!select) onChange(itemValue); + // We place onSelectChange after onChange to give user an opportunity + // to manipulate the `value` state + onSelectChange(item); }; const resetState = (shouldClose?: boolean) => { @@ -145,6 +147,8 @@ const autocompleteLite = case 'Enter': if (open) { if (focusItem) { + // Call preventDefault as we've already triggered on* events in this branch + e.preventDefault(); resetState(selectItemOrAction(focusItem)); } else if (!select) { resetState(true); From 4561eb9016152e173b2c043a35a3c181f0162f3c Mon Sep 17 00:00:00 2001 From: Zheng Song Date: Tue, 9 Jul 2024 22:27:11 +1000 Subject: [PATCH 2/3] Add `isInputEmpty` state --- dist/cjs/index.js | 4 ++-- dist/esm/features/atom/autocompleteLite.js | 2 +- dist/esm/features/atom/dropdownToggle.js | 2 +- examples/pages/dropdown.tsx | 4 ++-- examples/pages/index.tsx | 4 ++-- examples/pages/multiDropdown.tsx | 4 ++-- examples/pages/multiSelect.tsx | 4 ++-- examples/pages/multiSelectAction.tsx | 4 ++-- examples/pages/search.tsx | 4 ++-- src/common.ts | 4 ++-- src/features/atom/autocompleteLite.ts | 6 +++--- src/features/atom/dropdownToggle.ts | 6 +++--- types/common.d.ts | 4 ++-- types/features/atom/autocompleteLite.d.ts | 4 ++-- types/features/atom/dropdownToggle.d.ts | 4 ++-- 15 files changed, 30 insertions(+), 30 deletions(-) diff --git a/dist/cjs/index.js b/dist/cjs/index.js index 7d92445..61be6b7 100644 --- a/dist/cjs/index.js +++ b/dist/cjs/index.js @@ -206,7 +206,7 @@ const autocompleteLite = ({ } }; return { - clearable: !!inputValue, + isInputEmpty: !inputValue, getClearProps: () => ({ tabIndex: -1, onMouseDown: startCapture, @@ -390,7 +390,7 @@ const dropdownToggle = ({ return (_toggleRef$current = toggleRef.current) == null ? void 0 : _toggleRef$current.focus(); }, 0); return { - clearable: !!inputValue, + isInputEmpty: !inputValue, getToggleProps: () => ({ ref: toggleRef, onMouseDown: startToggle, diff --git a/dist/esm/features/atom/autocompleteLite.js b/dist/esm/features/atom/autocompleteLite.js index fc17266..1687438 100644 --- a/dist/esm/features/atom/autocompleteLite.js +++ b/dist/esm/features/atom/autocompleteLite.js @@ -52,7 +52,7 @@ const autocompleteLite = ({ } }; return { - clearable: !!inputValue, + isInputEmpty: !inputValue, getClearProps: () => ({ tabIndex: -1, onMouseDown: startCapture, diff --git a/dist/esm/features/atom/dropdownToggle.js b/dist/esm/features/atom/dropdownToggle.js index ace7332..c76f09e 100644 --- a/dist/esm/features/atom/dropdownToggle.js +++ b/dist/esm/features/atom/dropdownToggle.js @@ -23,7 +23,7 @@ const dropdownToggle = ({ return (_toggleRef$current = toggleRef.current) == null ? void 0 : _toggleRef$current.focus(); }, 0); return { - clearable: !!inputValue, + isInputEmpty: !inputValue, getToggleProps: () => ({ ref: toggleRef, onMouseDown: startToggle, diff --git a/examples/pages/dropdown.tsx b/examples/pages/dropdown.tsx index 04facb7..f39bd83 100644 --- a/examples/pages/dropdown.tsx +++ b/examples/pages/dropdown.tsx @@ -35,7 +35,7 @@ export default function Dropdown() { getItemProps, getToggleProps, getClearProps, - clearable, + isInputEmpty, open, focusItem, inputRef @@ -128,7 +128,7 @@ export default function Dropdown() { {...getInputProps()} placeholder="Search a state..." /> - {clearable && ( + {!isInputEmpty && ( diff --git a/examples/pages/multiSelect.tsx b/examples/pages/multiSelect.tsx index 20b0804..4831b6b 100644 --- a/examples/pages/multiSelect.tsx +++ b/examples/pages/multiSelect.tsx @@ -45,7 +45,7 @@ export default function Home() { getInputWrapperProps, open, focusItem, - clearable, + isInputEmpty, removeSelect, focused } = useMultiSelect({ @@ -134,7 +134,7 @@ export default function Home() {
- {clearable && ( + {!isInputEmpty && ( diff --git a/examples/pages/multiSelectAction.tsx b/examples/pages/multiSelectAction.tsx index 8d4388c..3d348b1 100644 --- a/examples/pages/multiSelectAction.tsx +++ b/examples/pages/multiSelectAction.tsx @@ -57,7 +57,7 @@ export default function Home() { getInputWrapperProps, open, focusItem, - clearable, + isInputEmpty, removeSelect, focused } = useMultiSelect({ @@ -155,7 +155,7 @@ export default function Home() {
- {clearable && ( + {!isInputEmpty && ( diff --git a/examples/pages/search.tsx b/examples/pages/search.tsx index ab1c967..72ceb64 100644 --- a/examples/pages/search.tsx +++ b/examples/pages/search.tsx @@ -22,7 +22,7 @@ export default function Home() { getClearProps, open, focusItem, - clearable + isInputEmpty } = useCombobox({ onSelectChange: (selected) => search(selected?.name), getItemValue, @@ -52,7 +52,7 @@ export default function Home() { > - {clearable && ( + {!isInputEmpty && (