Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(autocomplete simple): react component for autocomplete - simple variation #191

Merged
merged 20 commits into from
Oct 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1693d1b
feat(autocomplete): initial scaffolding for simple autocomplete
juanigalan91 Oct 11, 2019
6874713
feat(autocomplete-simple): simple example and prop types
juanigalan91 Oct 11, 2019
0deba56
feat(autocomplete): create on change for example
juanigalan91 Oct 11, 2019
57bbeac
feat(autocomplete): add keyboard events
juanigalan91 Oct 14, 2019
41d4f80
feat(autocomplete): added docs and unit testing
juanigalan91 Oct 14, 2019
a29e74b
feat(autcomplete): added missing prop doc
juanigalan91 Oct 14, 2019
ac72d24
feat(autocomplete): several documentation fixes and onFocus changes
juanigalan91 Oct 14, 2019
8a56c3b
feat(autocomplete): add onBlur and onFocus to Autocomplete def
juanigalan91 Oct 14, 2019
fa1a228
feat(autocomplete): reset active index on blur and focus
juanigalan91 Oct 14, 2019
24f45ba
feat(autocomplete): create custom hook and change highlighted state
juanigalan91 Oct 15, 2019
b564604
feat(autocomplete): typescript changes and fixes
juanigalan91 Oct 15, 2019
dce5231
feat(autocomplete): move reset to hook
juanigalan91 Oct 16, 2019
2c934e6
feat(autocomplete): update snapshot
juanigalan91 Oct 16, 2019
70414de
feat(autocomplete): revert changes on Text field
juanigalan91 Oct 25, 2019
3648f60
feat(autocomplete): add TextFieldType to exports
juanigalan91 Oct 25, 2019
f688a1e
feat(autocomplete): force text field type
juanigalan91 Oct 28, 2019
4801b90
feat(autocomplete): hide list if there are no results
juanigalan91 Oct 28, 2019
fbdcad1
feat(autocomplete): fix loose focus on text field
juanigalan91 Oct 28, 2019
35f8713
feat(autocomplete-simple): remove tab key code interception
juanigalan91 Oct 28, 2019
b064d4d
feat(autocomplete): update changelog
juanigalan91 Oct 28, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.react.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Text field enhancements (`chips`, `onFocus`, `onBlur`, `textfieldRef`, `inputRef` props) [#199](https://github.com/lumapps/design-system/pull/199)
- Autocomplete component [#191](https://github.com/lumapps/design-system/pull/191)

### Changed

Expand Down
111 changes: 111 additions & 0 deletions demo/react/doc/product/components/autocomplete.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
```javascript import
import { Autocomplete, List, ListItem, ListItemSize, Size, TextField, Chip, ListDivider, Icon, ListSubheader } from 'LumX';
import { useBooleanState } from 'LumX/core/react/hooks';
import { DOWN_KEY_CODE, ENTER_KEY_CODE, TAB_KEY_CODE, UP_KEY_CODE } from 'LumX/core/constants';
gcornut marked this conversation as resolved.
Show resolved Hide resolved
```

# Autocomplete

## Default

```javascript jsx withThemeSwitcher
(theme) => {
const CITIES = [
{
text: 'Los Angeles',
id: 'losangeles'
},
{
text: 'San Francisco',
id: 'sanfrancisco'
},
{
text: 'Paris',
id: 'paris'
},
{
text: 'Montpellier',
id: 'montpellier'
},
{
text: 'Bordeaux',
id: 'bordeaux'
},
{
text: 'Toulouse',
id: 'toulouse'
},
{
text: 'Lyon',
id: 'lyon'
},
{
text: 'Montevideo',
id: 'montevideo'
}
];

const [showSuggestions, setShowSuggestions] = React.useState(false);
const [filterValue, setFilterValue] = React.useState('');
const inputRef = React.useRef(null);

const filteredCities = CITIES.filter(city => city.text.replace(' ', '').toLowerCase().includes(filterValue.replace(' ', '').toLowerCase()));
const closeAutocomplete = () => setShowSuggestions(false);

const setSelectedCity = (city) => {
setFilterValue(city.text);
setShowSuggestions(false);
}

const onChange = (value) => {
setFilterValue(value);
setShowSuggestions(value.length > 0);
};

const {
activeItemIndex,
} = List.useKeyboardListNavigation(
filteredCities,
setSelectedCity,
inputRef,
);

const onFocus = (evt) => {
setShowSuggestions(filterValue.length > 0);
}

const hasSuggestions = filteredCities.length > 0;

return (
<Autocomplete
theme={theme}
isOpen={showSuggestions && hasSuggestions}
onClose={closeAutocomplete}
value={filterValue}
onChange={onChange}
onFocus={onFocus}
inputRef={inputRef}
>
{ hasSuggestions && (
<List>
{filteredCities.map((city, index) => (
<ListItem
size={ListItemSize.tiny}
isClickable
key={city.id}
isHighlighted={index === activeItemIndex}
onItemSelected={() => setSelectedCity(city)}
>
<div>{city.text}</div>
</ListItem>
))}
</List>
)}
</Autocomplete>
);
};
```

### Properties

<PropTable component="Autocomplete" />
1 change: 1 addition & 0 deletions demo/react/layout/MainNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const ITEMS: Item[] = [
{
label: 'Components',
children: [
'Autocomplete',
'Avatar',
'Button',
'Checkbox',
Expand Down
99 changes: 99 additions & 0 deletions src/components/autocomplete/react/Autocomplete.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React, { ReactElement } from 'react';

import { mount, shallow } from 'enzyme';

import { ICommonSetup, Wrapper, commonTestsSuite } from 'LumX/core/testing/utils.test';

import { Autocomplete, AutocompleteProps, CLASSNAME } from './Autocomplete';

/////////////////////////////

/**
* Define the overriding properties waited by the `setup` function.
*/
type ISetupProps = Partial<AutocompleteProps>;

/**
* Defines what the `setup` function will return.
*/
interface ISetup extends ICommonSetup {
props: ISetupProps;

/**
* The <div> element that holds the popover content.
*/
wrapper: Wrapper;
}

/////////////////////////////

/**
* Mounts the component and returns common DOM elements / data needed in multiple tests further down.
*
* @param props The props to use to override the default props of the component.
* @param [shallowRendering=true] Indicates if we want to do a shallow or a full rendering.
* @return An object with the props, the component wrapper and some shortcut to some element inside of the component.
*/
const setup = (props: ISetupProps = {}, shallowRendering: boolean = true): ISetup => {
const renderer: (el: ReactElement) => Wrapper = shallowRendering ? shallow : mount;

// @ts-ignore
const wrapper: Wrapper = renderer(<Autocomplete {...props} />);

return {
props,
wrapper,
};
};

describe(`<${Autocomplete.displayName}>`, (): void => {
// 1. Test render via snapshot (default states of component).
describe('Snapshots and structure', (): void => {
// Here is an example of a basic rendering check, with snapshot.

it('should render correctly', (): void => {
const { wrapper } = setup();
expect(wrapper).toMatchSnapshot();

expect(wrapper).toExist();

expect(wrapper).toHaveClassName(CLASSNAME);
});
});

/////////////////////////////

// 2. Test defaultProps value and important props custom values.
describe('Props', (): void => {
it('should use default props', (): void => {
const { wrapper }: ISetup = setup();

expect(wrapper).toHaveClassName(CLASSNAME);
});
});

/////////////////////////////

// 3. Test events.
describe('Events', (): void => {
// Nothing to do here.
});
/////////////////////////////

// 4. Test conditions (i.e. things that display or not in the UI based on props).
describe('Conditions', (): void => {
// Nothing to do here.
});

/////////////////////////////

// 5. Test state.
describe('State', (): void => {
// Nothing to do here.
});

/////////////////////////////

// Common tests suite.
commonTestsSuite(setup, { className: 'wrapper', prop: 'wrapper' }, { className: CLASSNAME });
});
Loading