Skip to content

Commit

Permalink
Merge 8bb3a25 into ee6a79f
Browse files Browse the repository at this point in the history
  • Loading branch information
igorarkhipenko committed Jun 17, 2020
2 parents ee6a79f + 8bb3a25 commit eff0470
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 15 deletions.
14 changes: 13 additions & 1 deletion 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 All @@ -60,7 +66,10 @@ export function AutosuggestMulti<S>(props: Props<S>) {

const renderFullTagsList = () => {
return selectedSuggestions.map((item) => (
<SuggestionTag key={suggestionToString(item)} onClick={() => onSelectionRemove(item)}>
<SuggestionTag
key={suggestionToKey ? suggestionToKey(item) : suggestionToString(item)}
onClick={() => onSelectionRemove(item)}
>
{suggestionToString(item)}
</SuggestionTag>
));
Expand Down Expand Up @@ -164,6 +173,7 @@ export function AutosuggestMulti<S>(props: Props<S>) {
listRenderer={(listProps) => (
<SuggestionsList
{...listProps}
isFirstItemAlwaysVisible={isFirstItemAlwaysVisible}
isLoading={isLoading}
useOptimizeRender={useOptimizeListRender}
suggestionItemRenderer={suggestionItemRenderer}
Expand All @@ -185,4 +195,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,6 +329,7 @@ exports[`AutosuggestMulti rendering should render component with suggestions 1`]
getItemProps={[Function]}
highlightedIndex={0}
inputValue="driver"
isFirstItemAlwaysVisible={false}
isLoading={false}
key=".0"
noSuggestionsPlaceholder=""
Expand Down Expand Up @@ -743,6 +748,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 +770,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,6 +888,7 @@ exports[`AutosuggestMulti rendering should render isLoading state 1`] = `
getItemProps={[Function]}
highlightedIndex={0}
inputValue="driver"
isFirstItemAlwaysVisible={false}
isLoading={true}
key=".0"
noSuggestionsPlaceholder=""
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
34 changes: 28 additions & 6 deletions src/components/Select/SelectBase/SelectBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,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, setIsBrowserTabVisible] = React.useState(true);

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

React.useEffect(() => {
const handleFocusHandleVisibilityChange = () => {
if (document.hidden) {
setIsBrowserTabVisible(false);
} else {
setTimeout(() => setIsBrowserTabVisible(true), 250);
}
};

document.addEventListener('visibilitychange', handleFocusHandleVisibilityChange);

return () => {
document.removeEventListener('visibilitychange', handleFocusHandleVisibilityChange);
};
});

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 +158,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 +201,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
26 changes: 18 additions & 8 deletions src/components/Select/SuggestionsList/SuggestionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export interface Props<S> {
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,6 +38,7 @@ export function SuggestionsList<S>(props: Props<S>) {
useOptimizeRender,
suggestions,
isLoading,
isFirstItemAlwaysVisible,
noSuggestionsPlaceholder,
getItemProps,
highlightedIndex,
Expand Down Expand Up @@ -69,14 +72,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 Down Expand Up @@ -115,6 +124,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 eff0470

Please sign in to comment.