| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- /*
- Copyright (C) 2017 Cloudbase Solutions SRL
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- import React from 'react'
- import { observer } from 'mobx-react'
- import styled, { css } from 'styled-components'
- import autobind from 'autobind-decorator'
- import SearchButton from '@src/components/ui/SearchButton'
- import TextInput from '@src/components/ui/TextInput'
- import StatusIcon from '@src/components/ui/StatusComponents/StatusIcon'
- import { ThemeProps } from '@src/components/Theme'
- const Input = styled(TextInput)<any>`
- padding-left: 32px;
- ${props => (props.loading || (props.showClose && props.value) ? 'padding-right: 32px;' : '')}
- width: 50px;
- opacity: 0;
- transition: all ${ThemeProps.animations.swift};
- `
- const InputAnimation = (props: any) => css`
- ${Input} {
- width: ${props.width};
- opacity: 1;
- }
- `
- const Wrapper = styled.div<any>`
- position: relative;
- width: ${props => (props.open ? props.width : '50px')};
- ${props => (props.open ? InputAnimation(props) : '')}
- `
- const SearchButtonStyled = styled(SearchButton)<any>`
- position: absolute;
- top: 8px;
- left: 8px;
- `
- const StatusIconStyled = styled(StatusIcon)`
- position: absolute;
- right: 8px;
- top: 8px;
- `
- type Props = {
- onChange?: (value: string) => void,
- onCloseClick?: () => void,
- alwaysOpen?: boolean,
- loading?: boolean,
- focusOnMount?: boolean,
- disablePrimary?: boolean,
- useFilterIcon?: boolean,
- placeholder?: string,
- width?: string,
- value?: string,
- className?: string,
- }
- type State = {
- open: boolean,
- hover?: boolean,
- focus: boolean,
- }
- @observer
- class SearchInput extends React.Component<Props, State> {
- static defaultProps = {
- placeholder: 'Search',
- width: `${ThemeProps.inputSizes.regular.width}px`,
- value: '',
- }
- state: State = {
- open: false,
- focus: false,
- }
- input: HTMLElement | null | undefined
- itemMouseDown: boolean | undefined
- componentDidMount() {
- window.addEventListener('mousedown', this.handlePageClick, false)
- if (this.props.focusOnMount && this.input) this.input.focus()
- }
- componentWillUnmount() {
- window.removeEventListener('mousedown', this.handlePageClick, false)
- }
- @autobind
- handlePageClick() {
- if (!this.itemMouseDown) {
- this.setState({ open: false })
- }
- }
- handleSearchButtonClick() {
- if (this.input) this.input.focus()
- this.setState(prevState => ({ open: !prevState.open }))
- }
- handleMouseEnter() {
- this.setState({ hover: true })
- }
- handleMouseLeave() {
- this.setState({ hover: false })
- }
- handleFocus() {
- this.setState({ focus: true })
- }
- handleBlur() {
- this.setState({ focus: false })
- }
- render() {
- return (
- <Wrapper
- open={this.state.open || this.props.alwaysOpen || this.props.value !== ''}
- onMouseDown={() => { this.itemMouseDown = true }}
- onMouseUp={() => { this.itemMouseDown = false }}
- onMouseEnter={() => { this.handleMouseEnter() }}
- onMouseLeave={() => { this.handleMouseLeave() }}
- width={this.props.width}
- className={this.props.className}
- >
- <Input
- _ref={(input: HTMLElement | null | undefined) => { this.input = input }}
- placeholder={this.props.placeholder}
- onChange={(e: { target: { value: string } }) => {
- if (this.props.onChange) this.props.onChange(e.target.value)
- }}
- onFocus={() => { this.handleFocus() }}
- onBlur={() => { this.handleBlur() }}
- loading={this.props.loading}
- value={this.props.value}
- disablePrimary={this.props.disablePrimary}
- showClose={
- !this.props.loading
- && (this.state.open || this.props.alwaysOpen || this.props.value !== '')
- }
- onCloseClick={() => { if (this.props.onCloseClick) this.props.onCloseClick() }}
- />
- <SearchButtonStyled
- primary={
- this.state.open
- || (this.props.alwaysOpen && (this.state.hover || this.state.focus))
- || (this.props.value !== '' && (this.state.hover || this.state.focus))
- }
- onClick={() => { this.handleSearchButtonClick() }}
- useFilterIcon={this.props.useFilterIcon}
- />
- {this.props.loading ? <StatusIconStyled status="RUNNING" /> : null}
- </Wrapper>
- )
- }
- }
- export default SearchInput
|