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

Commit

Permalink
Add SearchBar component
Browse files Browse the repository at this point in the history
<SearchBar /> is a component that renders an <InputText> and an icon.

It needs an 'onChangeHandler' prop that is called  whenever the value of
the <InputText> changes. This can optionally be debounced by passing an
'emitDelay' prop that takes a value in milliseconds.  An initial value
can be passed in using the 'query' prop.
  • Loading branch information
matijs committed Nov 24, 2019
1 parent 65f97e9 commit d0053f0
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/components/search_bar.tsx
@@ -0,0 +1,69 @@
import React from 'react';
import debounce from 'lodash.debounce';
import * as Input from './input';
import * as Icon from './icons';

interface SearchBarProps {
query?: string;
emitDelay?: number;
onChangeHandler: (value: string) => void;
}

interface SearchBarState {
query: string;
}

class SearchBar extends React.Component<SearchBarProps, SearchBarState> {
static defaultProps = {
emitDelay: 0,
}

debouncedEmit = (({ onChangeHandler, emitDelay }) => debounce(
onChangeHandler, emitDelay,
))(this.props);

constructor(props: Readonly<SearchBarProps>) {
super(props);
const { query = '' } = props;
this.state = {
query,
};
this.onChange = this.onChange.bind(this);
}

componentDidMount() {
const { query } = this.state;
if (query !== '') {
this.debouncedEmit(query);
}
}

componentWillUnmount() {
this.debouncedEmit.cancel();
}

onChange(event: React.ChangeEvent<HTMLInputElement>) {
const { value: query } = event.target;

this.setState({
query,
});
event.persist();
this.debouncedEmit(query);
}

render() {
const { query } = this.state;
const { onChange } = this;
return (
<div className="search-bar">
<span className="search-bar__icon">
<Icon.MagnifierSmall />
</span>
<Input.Text className="search-bar__input" value={query} onChange={onChange} />
</div>
);
}
}

export { SearchBar };
27 changes: 27 additions & 0 deletions src/stories/search_bar.stories.tsx
@@ -0,0 +1,27 @@
import * as React from 'react';
/* eslint-disable import/no-extraneous-dependencies */
import { storiesOf } from '@storybook/react';
import { withKnobs } from '@storybook/addon-knobs';
import { action } from '@storybook/addon-actions';
import styles from '@sambego/storybook-styles';
/* eslint-enable import/no-extraneous-dependencies */

import { SearchBar } from '../components/search_bar';

const stories = storiesOf('Search Bar', module);

stories.addDecorator(withKnobs)
.addDecorator(styles({
alignItems: 'center',
display: 'flex',
height: '100vh',
justifyContent: 'center',
padding: '2em',
}));

stories.add('SearchBar', () => (
<SearchBar
onChangeHandler={action('query')}
emitDelay={500}
/>
));
23 changes: 23 additions & 0 deletions src/stylesheets/_search_bar.scss
@@ -0,0 +1,23 @@
.search-bar {
display: flex;
}

.search-bar__icon {
align-items: center;
display: flex;
justify-content: center;
pointer-events: none;
position: relative;
width: 5.5rem;
z-index: 1;
}

.search-bar__icon > svg {
height: 2rem;
width: 2rem;
}

.search-bar__input {
margin-left: -5.5rem;
padding-left: 5.5rem;
}
1 change: 1 addition & 0 deletions src/stylesheets/main.scss
Expand Up @@ -62,3 +62,4 @@
@import 'sub_navigation_menu';
@import 'sub_navigation_mobile_menu';
@import 'box_placeholder';
@import 'search_bar';

0 comments on commit d0053f0

Please sign in to comment.