Skip to content

Commit

Permalink
Merge branch 'next' into feat/prev-state
Browse files Browse the repository at this point in the history
  • Loading branch information
eunjae-lee committed Oct 12, 2020
2 parents 0079cd2 + a20887d commit 4075aab
Show file tree
Hide file tree
Showing 13 changed files with 81 additions and 61 deletions.
12 changes: 12 additions & 0 deletions packages/autocomplete-core/src/completionStateEnhancer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { getCompletion } from './getCompletion';
import { AutocompleteState, InternalAutocompleteOptions } from './types';

export function completionStateEnhancer<TItem>(
state: AutocompleteState<TItem>,
props: InternalAutocompleteOptions<TItem>
) {
return {
...state,
completion: getCompletion({ state, props }),
};
}
3 changes: 2 additions & 1 deletion packages/autocomplete-core/src/createAutocomplete.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { completionStateEnhancer } from './completionStateEnhancer';
import { createStore } from './createStore';
import { getAutocompleteSetters } from './getAutocompleteSetters';
import { getDefaultProps } from './getDefaultProps';
Expand All @@ -15,7 +16,7 @@ export function createAutocomplete<
options: AutocompleteOptions<TItem>
): AutocompleteApi<TItem, TEvent, TMouseEvent, TKeyboardEvent> {
const props = getDefaultProps(options);
const store = createStore(stateReducer, props);
const store = createStore(stateReducer, props, [completionStateEnhancer]);

const {
setHighlightedIndex,
Expand Down
42 changes: 22 additions & 20 deletions packages/autocomplete-core/src/createStore.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
import { getCompletion } from './getCompletion';
import {
InternalAutocompleteOptions,
AutocompleteState,
AutocompleteStore,
InternalAutocompleteOptions,
Reducer,
StateEnhancer,
} from './types';

export function createStore<TItem>(
reducer: Reducer,
props: InternalAutocompleteOptions<TItem>
props: InternalAutocompleteOptions<TItem>,
stateEnhancers: Array<StateEnhancer<TItem>>
): AutocompleteStore<TItem> {
function enhanceState(state: AutocompleteState<TItem>) {
return stateEnhancers.reduce(
(nextState, stateEnhancer) => stateEnhancer(nextState, props),
state
);
}

let state = enhanceState(props.initialState);

return {
state: props.initialState,
getState() {
return this.state;
return state;
},
send(action, payload) {
const prevState = { ...this.state };
this.state = withCompletion(
reducer({ type: action, value: payload }, this.state, props),
props
const prevState = { ...state };
state = enhanceState(
reducer(state, {
type: action,
props,
payload,
})
);

props.onStateChange({ state: this.state, prevState });
props.onStateChange({ state, prevState });
},
};
}

function withCompletion<TItem>(
state: AutocompleteState<TItem>,
props: InternalAutocompleteOptions<TItem>
) {
return {
...state,
completion: getCompletion({ state, props }),
};
}
2 changes: 1 addition & 1 deletion packages/autocomplete-core/src/onKeyDown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function onKeyDown<TItem>({
// Arrow down.
event.preventDefault();

store.send(event.key, { shiftKey: event.shiftKey });
store.send(event.key, null);

const nodeItem = props.environment.document.getElementById(
`${props.id}-item-${store.getState().highlightedIndex}`
Expand Down
34 changes: 18 additions & 16 deletions packages/autocomplete-core/src/stateReducer.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
import { Reducer } from './types';
import { getItemsCount, getNextHighlightedIndex } from './utils';

export const stateReducer: Reducer = (action, state, props) => {
export const stateReducer: Reducer = (state, action) => {
switch (action.type) {
case 'setHighlightedIndex': {
return {
...state,
highlightedIndex: action.value,
highlightedIndex: action.payload,
};
}

case 'setQuery': {
return {
...state,
query: action.value,
query: action.payload,
};
}

case 'setSuggestions': {
return {
...state,
suggestions: action.value,
suggestions: action.payload,
};
}

case 'setIsOpen': {
return {
...state,
isOpen: action.value,
isOpen: action.payload,
};
}

case 'setStatus': {
return {
...state,
status: action.value,
status: action.payload,
};
}

Expand All @@ -43,7 +43,7 @@ export const stateReducer: Reducer = (action, state, props) => {
...state,
context: {
...state.context,
...action.value,
...action.payload,
},
};
}
Expand All @@ -55,7 +55,7 @@ export const stateReducer: Reducer = (action, state, props) => {
1,
state.highlightedIndex,
getItemsCount(state),
props.defaultHighlightedIndex
action.props.defaultHighlightedIndex
),
};
}
Expand All @@ -67,7 +67,7 @@ export const stateReducer: Reducer = (action, state, props) => {
-1,
state.highlightedIndex,
getItemsCount(state),
props.defaultHighlightedIndex
action.props.defaultHighlightedIndex
),
};
}
Expand Down Expand Up @@ -108,8 +108,10 @@ export const stateReducer: Reducer = (action, state, props) => {

// 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.
action.props.openOnFocus === true
? action.props.defaultHighlightedIndex
: null,
isOpen: action.props.openOnFocus, // @TODO: Check with UX team if we want to close the menu on reset.
status: 'idle',
statusContext: {},
query: '',
Expand All @@ -119,13 +121,13 @@ export const stateReducer: Reducer = (action, state, props) => {
case 'focus': {
return {
...state,
highlightedIndex: props.defaultHighlightedIndex,
isOpen: props.openOnFocus || state.query.length > 0,
highlightedIndex: action.props.defaultHighlightedIndex,
isOpen: action.props.openOnFocus || state.query.length > 0,
};
}

case 'blur': {
if (props.debug) {
if (action.props.debug) {
return state;
}

Expand All @@ -139,14 +141,14 @@ export const stateReducer: Reducer = (action, state, props) => {
case 'mousemove': {
return {
...state,
highlightedIndex: action.value,
highlightedIndex: action.payload,
};
}

case 'mouseleave': {
return {
...state,
highlightedIndex: props.defaultHighlightedIndex,
highlightedIndex: action.props.defaultHighlightedIndex,
};
}

Expand Down
13 changes: 5 additions & 8 deletions packages/autocomplete-core/src/types/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AutocompleteAccessibilityGetters } from './getters';
import { AutocompleteSetters } from './setters';
import { AutocompleteState } from './state';
import { MaybePromise } from './wrappers';

export interface AutocompleteApi<
TItem,
Expand Down Expand Up @@ -92,7 +93,7 @@ export interface AutocompleteSource<TItem> {
/**
* Function called when the input changes. You can use this function to filter/search the items based on the query.
*/
getSuggestions(params: GetSourcesParams<TItem>): TItem[] | Promise<TItem[]>;
getSuggestions(params: GetSourcesParams<TItem>): MaybePromise<TItem[]>;
/**
* Function called when an item is selected.
*/
Expand Down Expand Up @@ -163,9 +164,7 @@ export type AutocompletePlugin<TItem, TData> = {
*/
getSources?(
params: GetSourcesParams<TItem>
):
| Array<AutocompleteSource<TItem>>
| Promise<Array<AutocompleteSource<TItem>>>;
): MaybePromise<Array<AutocompleteSource<TItem>>>;
/**
* The function called when the autocomplete form is submitted.
*/
Expand Down Expand Up @@ -247,9 +246,7 @@ export interface AutocompleteOptions<TItem> {
*/
getSources(
params: GetSourcesParams<TItem>
):
| Array<AutocompleteSource<TItem>>
| Promise<Array<AutocompleteSource<TItem>>>;
): MaybePromise<Array<AutocompleteSource<TItem>>>;
/**
* The environment from where your JavaScript is running.
* Useful if you're using autocomplete in a different context than
Expand All @@ -261,7 +258,7 @@ export interface AutocompleteOptions<TItem> {
/**
* Navigator API to redirect the user when a link should be opened.
*/
navigator?: Navigator<TItem>;
navigator?: Partial<Navigator<TItem>>;
/**
* The function called to determine whether the dropdown should open.
*/
Expand Down
14 changes: 9 additions & 5 deletions packages/autocomplete-core/src/types/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@ import { InternalAutocompleteOptions } from './api';
import { AutocompleteState } from './state';

export interface AutocompleteStore<TItem> {
state: AutocompleteState<TItem>;
getState(): AutocompleteState<TItem>;
send(action: ActionType, payload: any): void;
}

export type Reducer = <TItem>(
action: Action,
state: AutocompleteState<TItem>,
props: InternalAutocompleteOptions<TItem>
action: Action<TItem, any>
) => AutocompleteState<TItem>;

type Action = {
type Action<TItem, TPayload> = {
type: ActionType;
value: any;
props: InternalAutocompleteOptions<TItem>;
payload: TPayload;
};

type ActionType =
Expand All @@ -36,3 +35,8 @@ type ActionType =
| 'mousemove'
| 'mouseleave'
| 'click';

export type StateEnhancer<TItem> = (
state: AutocompleteState<TItem>,
props: InternalAutocompleteOptions<TItem>
) => AutocompleteState<TItem>;
1 change: 1 addition & 0 deletions packages/autocomplete-core/src/types/wrappers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type MaybePromise<TResolution> = Promise<TResolution> | TResolution;
1 change: 1 addition & 0 deletions packages/autocomplete-js/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export type InternalAutocompleteSource<TItem> = InternalAutocompleteCoreSource<
type GetSources<TItem> = (
params: GetSourcesParams<TItem>
) =>
// TODO: reuse MaybePromise from autocomplete-core when we find a way to share the type
| Array<AutocompleteCoreSource<TItem>>
| Promise<Array<AutocompleteCoreSource<TItem>>>;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { version } from '@algolia/autocomplete-core';
import {
MultipleQueriesResponse,
SearchResponse,
} from '@algolia/client-search';

import { version } from '../../version';
import { getAlgoliaHits } from '../getAlgoliaHits';
import { getAlgoliaResults } from '../getAlgoliaResults';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { Hit } from '@algolia/client-search';

import { search, SearchParams } from './search';

export function getAlgoliaHits<THit>({
export function getAlgoliaHits<TRecord>({
searchClient,
queries,
}: SearchParams): Promise<Array<Array<Hit<THit>>>> {
return search<THit>({ searchClient, queries }).then((response) => {
}: SearchParams): Promise<Array<Array<Hit<TRecord>>>> {
return search<TRecord>({ searchClient, queries }).then((response) => {
const results = response.results;

return results.map((result) => result.hits);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { MultipleQueriesResponse } from '@algolia/client-search';
import { SearchResponse } from '@algolia/client-search';

import { search, SearchParams } from './search';

export function getAlgoliaResults<THit>({
export function getAlgoliaResults<TRecord>({
searchClient,
queries,
}: SearchParams): Promise<MultipleQueriesResponse<THit>['results']> {
return search<THit>({ searchClient, queries }).then((response) => {
}: SearchParams): Promise<Array<SearchResponse<TRecord>>> {
return search<TRecord>({ searchClient, queries }).then((response) => {
return response.results;
});
}
4 changes: 2 additions & 2 deletions packages/autocomplete-preset-algolia/src/search/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export interface SearchParams {
queries: MultipleQueriesQuery[];
}

export function search<THit>({ searchClient, queries }: SearchParams) {
export function search<TRecord>({ searchClient, queries }: SearchParams) {
if (typeof searchClient.addAlgoliaAgent === 'function') {
searchClient.addAlgoliaAgent('autocomplete-core', version);
}

return searchClient.search<THit>(
return searchClient.search<TRecord>(
queries.map((searchParameters) => {
const { indexName, query, params } = searchParameters;

Expand Down

0 comments on commit 4075aab

Please sign in to comment.