Skip to content
This repository has been archived by the owner on Jun 11, 2021. It is now read-only.

feat: add openOnFocus and remove minLength #31

Merged
merged 9 commits into from
Feb 25, 2020
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,11 @@ Whether to show the highlighted suggestion as completion in the input.

![`showCompletion` preview](https://user-images.githubusercontent.com/6137112/68124812-7e989800-ff10-11e9-88a5-f28c1466b665.png)

#### `minLength`
#### `openOnFocus`

> `number` | defaults to `1`
> `boolean` | defaults to `false`

The minimum number of characters long the autocomplete opens.
Whether to open the dropdown on focus when there's no query.

#### `autoFocus`

Expand Down
2 changes: 1 addition & 1 deletion examples/autocomplete.js/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const searchClient = algoliasearch(
autocomplete({
container: '#autocomplete',
placeholder: 'Search…',
minLength: 0,
openOnFocus: true,
showCompletion: true,
defaultHighlightedIndex: -1,
shouldDropdownOpen({ state }) {
Expand Down
2 changes: 1 addition & 1 deletion packages/autocomplete-core/src/defaultProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function getDefaultProps<TItem>(
: {}) as typeof window;

return {
minLength: 1,
openOnFocus: false,
placeholder: '',
autoFocus: false,
defaultHighlightedIndex: null,
Expand Down
4 changes: 2 additions & 2 deletions packages/autocomplete-core/src/onInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function onInput<TItem>({
setHighlightedIndex(props.defaultHighlightedIndex);
setQuery(query);

if (query.length < props.minLength) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to keep this branch, but the condition should be query.length === 0 && props.openOnFocus === false. This makes sure to "reset" the state.

The reasoning behind this is that as opposed to InstantSearch, when there's no query, we do not want to consider any results, except when openOnFocus is true. This behavior would be easier to validate once we write integration tests.

if (query.length === 0 && props.openOnFocus === false) {
setStatus('idle');
setSuggestions(
store.getState().suggestions.map(suggestion => ({
Expand Down Expand Up @@ -117,7 +117,7 @@ export function onInput<TItem>({
setSuggestions(suggestions as any);
setIsOpen(
nextState.isOpen ??
(query.length >= props.minLength &&
((query.length === 0 && props.openOnFocus) ||
props.shouldDropdownShow({ state: store.getState() }))
);
})
Expand Down
12 changes: 5 additions & 7 deletions packages/autocomplete-core/src/propGetters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export function getPropGetters<TItem>({
onReset: event => {
event.preventDefault();

if (props.minLength === 0) {
if (props.openOnFocus) {
onInput({
query: '',
store,
Expand All @@ -130,7 +130,6 @@ export function getPropGetters<TItem>({
setContext,
});
}

store.send('reset', null);

if (providedProps.inputElement) {
Expand All @@ -143,9 +142,9 @@ export function getPropGetters<TItem>({

const getInputProps: GetInputProps = providedProps => {
function onFocus() {
// We want to trigger a query when `minLength` is reached because the
// dropdown should open with the current query.
if (store.getState().query.length >= props.minLength) {
// 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,
Expand Down Expand Up @@ -227,8 +226,7 @@ export function getPropGetters<TItem>({
if (
providedProps.inputElement ===
props.environment.document.activeElement &&
!store.getState().isOpen &&
store.getState().query.length >= props.minLength
!store.getState().isOpen
) {
onFocus();
}
Expand Down
12 changes: 9 additions & 3 deletions packages/autocomplete-core/src/stateReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,14 @@ export const stateReducer: Reducer = (action, state, props) => {
case 'reset': {
return {
...state,
highlightedIndex: null,
isOpen: false,
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: '',
Expand All @@ -115,7 +121,7 @@ export const stateReducer: Reducer = (action, state, props) => {
return {
...state,
highlightedIndex: props.defaultHighlightedIndex,
isOpen: state.query.length >= props.minLength,
isOpen: props.openOnFocus || state.query.length > 0,
};
}

Expand Down
8 changes: 4 additions & 4 deletions packages/autocomplete-core/src/types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,11 @@ export interface PublicAutocompleteOptions<TItem> {
*/
showCompletion?: boolean;
/**
* The minimum number of characters long the autocomplete opens.
* Whether to open the dropdown on focus when there's no query.
*
* @default 1
* @default false
*/
minLength?: number;
openOnFocus?: boolean;
/**
* The number of milliseconds that must elapse before the autocomplete
* experience is stalled.
Expand Down Expand Up @@ -229,7 +229,7 @@ export interface AutocompleteOptions<TItem> {
autoFocus: boolean;
defaultHighlightedIndex: number | null;
showCompletion: boolean;
minLength: number;
openOnFocus: boolean;
stallThreshold: number;
initialState: AutocompleteState<TItem>;
getSources: GetSources<TItem>;
Expand Down
40 changes: 40 additions & 0 deletions stories/react.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,46 @@ storiesOf('React', module)
container
);

return container;
})
)
.add(
'Open on focus',
withPlayground(({ container, dropdownContainer }) => {
render(
<Autocomplete
placeholder="Search items…"
showCompletion={true}
dropdownContainer={dropdownContainer}
defaultHighlightedIndex={0}
openOnFocus={true}
getSources={() => {
return [
{
getInputValue({ suggestion }) {
return suggestion.query;
},
getSuggestions({ query }) {
return getAlgoliaHits({
searchClient,
queries: [
{
indexName: 'instant_search_demo_query_suggestions',
query,
params: {
hitsPerPage: 4,
},
},
],
});
},
},
];
}}
/>,
container
);

return container;
})
);