redoc/src/components/SearchBox/SearchBox.tsx

177 lines
4.2 KiB
TypeScript
Raw Normal View History

2018-02-08 19:41:02 +03:00
import * as React from 'react';
import styled from '../../styled-components';
import { IMenuItem } from '../../services/MenuStore';
import { SearchStore } from '../../services/SearchStore';
import { MenuItem } from '../SideMenu/MenuItem';
import { MenuItemLabel } from '../SideMenu/styled.elements';
2018-02-22 12:26:53 +03:00
import { MarkerService } from '../../services/MarkerService';
import { SearchDocument } from '../../services/SearchWorker.worker';
2018-02-08 19:41:02 +03:00
const SearchInput = styled.input.attrs({
className: 'search-input',
})`
2018-02-08 19:41:02 +03:00
width: calc(100% - ${props => props.theme.spacingUnit * 2}px);
box-sizing: border-box;
margin: 0 ${props => props.theme.spacingUnit}px;
padding: 5px 0 5px ${props => props.theme.spacingUnit}px;
border: 0;
border-bottom: 1px solid #e1e1e1;
font-weight: bold;
font-size: 13px;
color: ${props => props.theme.colors.text};
background-color: transparent;
outline: none;
`;
const SearchIcon = styled((props: any) => (
<svg
className={props.className}
version="1.1"
viewBox="0 0 1000 1000"
x="0px"
xmlns="http://www.w3.org/2000/svg"
y="0px"
>
<path d="M968.2,849.4L667.3,549c83.9-136.5,66.7-317.4-51.7-435.6C477.1-25,252.5-25,113.9,113.4c-138.5,138.3-138.5,362.6,0,501C219.2,730.1,413.2,743,547.6,666.5l301.9,301.4c43.6,43.6,76.9,14.9,104.2-12.4C981,928.3,1011.8,893,968.2,849.4z M524.5,522c-88.9,88.7-233,88.7-321.8,0c-88.9-88.7-88.9-232.6,0-321.3c88.9-88.7,233-88.7,321.8,0C613.4,289.4,613.4,433.3,524.5,522z" />
</svg>
)).attrs({
className: 'search-icon',
})`
2018-02-08 19:41:02 +03:00
position: absolute;
left: ${props => props.theme.spacingUnit}px;
height: 1.8em;
width: 0.9em;
path {
fill: ${props => props.theme.colors.text};
}
`;
const SearchResultsBox = styled.div.attrs({
className: 'search-results',
})`
2018-02-08 19:41:02 +03:00
padding: ${props => props.theme.spacingUnit / 4}px 0;
background-color: #ededed;
min-height: 150px;
max-height: 250px;
border-top: 1px solid #e1e1e1;
border-bottom: 1px solid #e1e1e1;
margin-top: 10px;
line-height: 1.4;
font-size: 0.9em;
overflow: auto;
${MenuItemLabel} {
padding-top: 6px;
padding-bottom: 6px;
&:hover {
background-color: #e1e1e1;
}
> svg {
display: none;
}
}
`;
export interface SearchBoxProps {
search: SearchStore;
2018-02-22 12:26:53 +03:00
marker: MarkerService;
2018-02-08 19:41:02 +03:00
getItemById: (id: string) => IMenuItem | undefined;
onActivate: (item: IMenuItem) => void;
}
export interface SearchBoxState {
results: any;
term: string;
}
export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxState> {
constructor(props) {
super(props);
this.state = {
results: [],
term: '',
};
}
2018-02-22 12:26:53 +03:00
clearResults(term: string) {
this.setState({
results: [],
term,
});
this.props.marker.unmark();
}
clear() {
this.setState({
results: [],
term: '',
});
this.props.marker.unmark();
}
clearIfEsq = event => {
if (event && event.keyCode === 27) {
this.clear();
}
};
setResults(results: SearchDocument[], term: string) {
this.setState({
results,
term,
});
this.props.marker.mark(term);
}
2018-02-08 19:41:02 +03:00
search = (event: React.ChangeEvent<HTMLInputElement>) => {
const q = event.target.value;
if (q.length < 3) {
2018-02-22 12:26:53 +03:00
this.clearResults(q);
2018-02-08 19:41:02 +03:00
return;
}
2018-02-22 12:26:53 +03:00
2018-02-08 19:41:02 +03:00
this.setState({
term: q,
});
this.props.search.search(event.target.value).then(res => {
2018-02-22 12:26:53 +03:00
this.setResults(res, q);
2018-02-08 19:41:02 +03:00
});
};
render() {
const items: IMenuItem[] = this.state.results.map(res => this.props.getItemById(res.id));
items.sort((a, b) => (a.depth > b.depth ? 1 : a.depth < b.depth ? -1 : 0));
return (
<div>
<SearchIcon />
<SearchInput
value={this.state.term}
onKeyDown={this.clearIfEsq}
placeholder="Search..."
type="text"
onChange={this.search}
/>
{items.length > 0 && (
<SearchResultsBox>
{items.map(item => (
<MenuItem
item={item}
onActivate={this.props.onActivate}
withoutChildren={true}
key={item.id}
/>
))}
</SearchResultsBox>
)}
</div>
);
}
}