Skip to content

Commit

Permalink
Merge ed16607 into 35e2153
Browse files Browse the repository at this point in the history
  • Loading branch information
igorarkhipenko committed Jun 19, 2020
2 parents 35e2153 + ed16607 commit 2925f10
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 15 deletions.
10 changes: 10 additions & 0 deletions src/components/Select/AutosuggestMulti/AutosuggestMulti.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ import { BACKSPACE_KEY, ESCAPE_KEY, ENTER_KEY } from '../../../constants';
interface Props<S> extends CommonPropsWithClear<S> {
/** define id for input element */
id?: string;
/** makes a key to be used for a suggestion item */
suggestionToKey?: (suggestions: S) => string;
/** array of already selected suggestions */
selectedSuggestions: S[];
/** number of visible tags in blur mode */
numberOfVisibleTags: number;
/** to be shown in the input field when no value is typed */
inputPlaceholder: string;
/** Defines if the first item of suggestions list is always visible */
isFirstItemAlwaysVisible?: boolean;
/** Enable ListOptimizer component for decreasing render time */
useOptimizeListRender?: boolean;
/** onSelectionChange() called when a suggestion is removed */
Expand All @@ -37,12 +41,14 @@ export function AutosuggestMulti<S>(props: Props<S>) {
onSelectionChange,
selectedSuggestions,
suggestionToString,
suggestionToKey,
suggestionItemRenderer,
inputPlaceholder,
useOptimizeListRender,
suggestions,
isLoading,
numberOfVisibleTags,
isFirstItemAlwaysVisible,
onFocus,
onBlur,
onSubmit,
Expand Down Expand Up @@ -164,8 +170,10 @@ export function AutosuggestMulti<S>(props: Props<S>) {
listRenderer={(listProps) => (
<SuggestionsList
{...listProps}
isFirstItemAlwaysVisible={isFirstItemAlwaysVisible}
isLoading={isLoading}
useOptimizeRender={useOptimizeListRender}
suggestionToKey={suggestionToKey}
suggestionItemRenderer={suggestionItemRenderer}
/>
)}
Expand All @@ -185,4 +193,6 @@ AutosuggestMulti.displayName = 'AutosuggestMulti';
AutosuggestMulti.defaultProps = {
numberOfVisibleTags: 3,
selectedSuggestions: [],
suggestionToKey: null,
isFirstItemAlwaysVisible: false,
};
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ describe('AutosuggestMulti', () => {
expect(wrapper.find('.SuggestionsList__loaderItem')).toHaveLength(5);
expect(toJson(wrapper)).toMatchSnapshot();
});
it('should render the first item with isLoading set to true', () => {
suggestionsList = SUGGESTIONS.slice(1, 20);
wrapper.setProps({
suggestions: suggestionsList,
isLoading: true,
isFirstItemAlwaysVisible: true,
});
setFocusOnInput();
wrapper.find('input').simulate('change', { target: { value: 'driver' } });
expect(wrapper.find('span')).toHaveLength(1);
expect(wrapper.find('.SuggestionsList__loaderItem')).toHaveLength(4);
});
it('should render empty component correctly when focused', async () => {
setFocusOnInput();
const inputNode = wrapper.find('input').getDOMNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
exports[`AutosuggestMulti rendering should initially render empty component correctly 1`] = `
<AutosuggestMulti
inputPlaceholder="type here..."
isFirstItemAlwaysVisible={false}
isLoading={false}
numberOfVisibleTags={3}
onBlur={[MockFunction]}
onInputValueChange={[MockFunction]}
onSelectionChange={[MockFunction]}
onSelectionRemove={[MockFunction]}
selectedSuggestions={Array []}
suggestionToKey={null}
suggestionToString={[Function]}
suggestions={Array []}
>
Expand Down Expand Up @@ -133,6 +135,7 @@ exports[`AutosuggestMulti rendering should initially render empty component corr
exports[`AutosuggestMulti rendering should render component with suggestions 1`] = `
<AutosuggestMulti
inputPlaceholder="type here..."
isFirstItemAlwaysVisible={false}
isLoading={false}
numberOfVisibleTags={3}
onBlur={[MockFunction]}
Expand All @@ -154,6 +157,7 @@ exports[`AutosuggestMulti rendering should render component with suggestions 1`]
onSelectionChange={[MockFunction]}
onSelectionRemove={[MockFunction]}
selectedSuggestions={Array []}
suggestionToKey={null}
suggestionToString={[Function]}
suggestions={
Array [
Expand Down Expand Up @@ -325,9 +329,11 @@ exports[`AutosuggestMulti rendering should render component with suggestions 1`]
getItemProps={[Function]}
highlightedIndex={0}
inputValue="driver"
isFirstItemAlwaysVisible={false}
isLoading={false}
key=".0"
noSuggestionsPlaceholder=""
suggestionToKey={null}
suggestionToString={[Function]}
suggestions={
Array [
Expand Down Expand Up @@ -743,6 +749,7 @@ exports[`AutosuggestMulti rendering should render component with suggestions 1`]
exports[`AutosuggestMulti rendering should render isLoading state 1`] = `
<AutosuggestMulti
inputPlaceholder="type here..."
isFirstItemAlwaysVisible={false}
isLoading={true}
numberOfVisibleTags={3}
onBlur={[MockFunction]}
Expand All @@ -764,6 +771,7 @@ exports[`AutosuggestMulti rendering should render isLoading state 1`] = `
onSelectionChange={[MockFunction]}
onSelectionRemove={[MockFunction]}
selectedSuggestions={Array []}
suggestionToKey={null}
suggestionToString={[Function]}
suggestions={Array []}
>
Expand Down Expand Up @@ -881,9 +889,11 @@ exports[`AutosuggestMulti rendering should render isLoading state 1`] = `
getItemProps={[Function]}
highlightedIndex={0}
inputValue="driver"
isFirstItemAlwaysVisible={false}
isLoading={true}
key=".0"
noSuggestionsPlaceholder=""
suggestionToKey={null}
suggestionToString={[Function]}
suggestions={Array []}
useOptimizeRender={false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ exports[`ComboboxMulti rendering should render all suggestions from the list 1`]
getItemProps={[Function]}
highlightedIndex={0}
inputValue=""
isFirstItemAlwaysVisible={false}
isLoading={false}
key=".0"
noSuggestionsPlaceholder="No suggestions..."
Expand Down
19 changes: 13 additions & 6 deletions src/components/Select/SelectBase/SelectBase.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import Downshift from 'downshift';
import { bem } from '../../../utils/bem';
import { useBrowserTabVisibilityChange } from '../../../hooks';
import { FieldWrapper } from '../../FieldWrapper';
import { List } from '../../List';
import { Props } from './interfaces';
Expand Down Expand Up @@ -50,6 +51,7 @@ export function SelectBase<S>(props: SelectBaseProps<S>) {
const [inputValue, setInputValue] = React.useState('');
const [inputValueRecall, setInputValueRecall] = React.useState('');
const [focused, setFocused] = React.useState(false);
const isBrowserTabVisible = useBrowserTabVisibilityChange();

// focus input field if component is focused
React.useEffect(() => {
Expand Down Expand Up @@ -80,10 +82,12 @@ export function SelectBase<S>(props: SelectBaseProps<S>) {
}, [rootRefFromProps]);

const handleBlur = () => {
setFocused(false);
setInputValue('');
setInputValueRecall('');
if (focused) onBlur?.();
if (isBrowserTabVisible) {
setFocused(false);
setInputValue('');
setInputValueRecall('');
if (focused) onBlur?.();
}
};

const handleChange = (selectedItem, downshift) => {
Expand Down Expand Up @@ -139,7 +143,10 @@ export function SelectBase<S>(props: SelectBaseProps<S>) {
if (!focused) {
focus(openMenu);
}
onFocus?.();

if (isBrowserTabVisible) {
onFocus?.();
}
};

const stateUpdater = (change, state) => {
Expand Down Expand Up @@ -179,7 +186,7 @@ export function SelectBase<S>(props: SelectBaseProps<S>) {
isEscapeAction: true,
};
case Downshift.stateChangeTypes.blurInput:
if (selectOnTab && !state.isEscapeAction) {
if (selectOnTab && !state.isEscapeAction && isBrowserTabVisible) {
return {
...changes,
selectedItem: suggestions[state.highlightedIndex],
Expand Down
33 changes: 24 additions & 9 deletions src/components/Select/SuggestionsList/SuggestionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ export interface Props<S> {
useOptimizeRender?: boolean;
/** suggestionToString(suggestion) should return a string to be displayed in the UI. e.g.: suggestion => suggestion.name */
suggestionToString: (suggestion: S) => string;
/** suggestionToKey(suggestion) makes a key to be used for a suggestion item */
suggestionToKey?: (suggestion: S) => string;
/** render function for suggestion list item */
suggestionItemRenderer?: (suggestion: S) => ReactNode;
/** to be shown when no suggestions are available */
noSuggestionsPlaceholder?: string;
/** Defines if the first item of suggestions list is always visible */
isFirstItemAlwaysVisible?: boolean;
/** a function which gets props for the item in the list */
getItemProps: (options: GetItemPropsOptions<S>) => object;
/** index of the item from the list to be highlighted */
Expand All @@ -36,9 +40,11 @@ export function SuggestionsList<S>(props: Props<S>) {
useOptimizeRender,
suggestions,
isLoading,
isFirstItemAlwaysVisible,
noSuggestionsPlaceholder,
getItemProps,
highlightedIndex,
suggestionToKey,
suggestionItemRenderer,
inputValue,
} = props;
Expand Down Expand Up @@ -69,14 +75,20 @@ export function SuggestionsList<S>(props: Props<S>) {
const renderLoadingPlaceholders = () =>
Array(NUMBER_OF_SUGGESTION_LOADING_PLACEHOLDERS)
.fill('')
.map((el, i) => (
// eslint-disable-next-line react/no-array-index-key
<ListItem key={i}>
<div {...elem('loaderItem')}>
<ContentPlaceholder />
</div>
</ListItem>
));
.map((el, i) => {
if (isFirstItemAlwaysVisible && i === 0) {
return renderItem({ key: 'firstItem', index: 0 });
}

return (
// eslint-disable-next-line react/no-array-index-key
<ListItem key={i}>
<div {...elem('loaderItem')}>
<ContentPlaceholder />
</div>
</ListItem>
);
});

if (isLoading) {
return <>{renderLoadingPlaceholders()}</>;
Expand All @@ -102,7 +114,9 @@ export function SuggestionsList<S>(props: Props<S>) {
) : (
<>
{suggestions.map((item, index) => {
const key = suggestionToString(item);
const key = suggestionToKey
? suggestionToKey(item)
: suggestionToString(item);
return renderItem({ key, index });
})}
</>
Expand All @@ -115,6 +129,7 @@ SuggestionsList.defaultProps = {
noSuggestionsPlaceholder: '',
useOptimizeRender: false,
isLoading: false,
isFirstItemAlwaysVisible: false,
inputValue: '',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ exports[`SuggestionsList should initially render component correctly 1`] = `
}
highlightedIndex={1}
inputValue=""
isFirstItemAlwaysVisible={false}
isLoading={false}
noSuggestionsPlaceholder="noSuggestionsPlaceholder"
suggestionToString={[Function]}
Expand Down Expand Up @@ -585,6 +586,7 @@ exports[`SuggestionsList should render isLoading state 1`] = `
}
highlightedIndex={1}
inputValue=""
isFirstItemAlwaysVisible={false}
isLoading={true}
noSuggestionsPlaceholder="noSuggestionsPlaceholder"
suggestionToString={[Function]}
Expand Down Expand Up @@ -979,6 +981,7 @@ exports[`SuggestionsList should render optimization list correctly 1`] = `
}
highlightedIndex={1}
inputValue=""
isFirstItemAlwaysVisible={false}
isLoading={false}
noSuggestionsPlaceholder="noSuggestionsPlaceholder"
suggestionToString={[Function]}
Expand Down Expand Up @@ -1389,6 +1392,7 @@ exports[`SuggestionsList should run suggestionItemRenderer function correctly 1`
}
highlightedIndex={1}
inputValue=""
isFirstItemAlwaysVisible={false}
isLoading={false}
noSuggestionsPlaceholder="noSuggestionsPlaceholder"
suggestionItemRenderer={[Function]}
Expand Down
4 changes: 4 additions & 0 deletions stories/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ storiesOf('Organisms|Select', module)
onBlur={onBlur}
onFocus={onFocus}
onSubmit={onSubmit}
isFirstItemAlwaysVisible={
boolean('First item is always visible', false) &&
!!store.get('inputValue').length
}
onSelectionChange={onSelectionChange}
onSelectionRemove={onSelectionRemove}
isProminent={boolean('Use prominent styling', true)}
Expand Down

0 comments on commit 2925f10

Please sign in to comment.