diff --git a/client/src/components/BoardActions/Filters.jsx b/client/src/components/BoardActions/Filters.jsx index e9083bc..305bf1e 100644 --- a/client/src/components/BoardActions/Filters.jsx +++ b/client/src/components/BoardActions/Filters.jsx @@ -1,6 +1,8 @@ -import React, { useCallback, useEffect, useRef } from 'react'; +import React, { useCallback, useRef, useState } from 'react'; import PropTypes from 'prop-types'; +import classNames from 'classnames'; import { useTranslation } from 'react-i18next'; +import { Icon } from 'semantic-ui-react'; import { usePopup } from '../../lib/popup'; import { Input } from '../../lib/custom-ui'; @@ -30,7 +32,14 @@ const Filters = React.memo( onTextFilterUpdate, }) => { const [t] = useTranslation(); - const searchField = useRef(null); + const [isSearchFocused, setIsSearchFocused] = useState(false); + + const searchFieldRef = useRef(null); + + const cancelSearch = useCallback(() => { + onTextFilterUpdate(''); + searchFieldRef.current.blur(); + }, [onTextFilterUpdate]); const handleRemoveUserClick = useCallback( (id) => { @@ -46,17 +55,39 @@ const Filters = React.memo( [onLabelRemove], ); - const handleKeyUp = useCallback(() => { - onTextFilterUpdate(searchField.current.inputRef.current.value); - }, [onTextFilterUpdate]); + const handleSearchChange = useCallback( + (_, { value }) => { + onTextFilterUpdate(value); + }, + [onTextFilterUpdate], + ); - useEffect(() => { - searchField.current.inputRef.current.value = filterText; - }, [filterText]); + const handleSearchFocus = useCallback(() => { + setIsSearchFocused(true); + }, []); + + const handleSearchKeyDown = useCallback( + (event) => { + if (event.key === 'Escape') { + cancelSearch(); + } + }, + [cancelSearch], + ); + + const handleSearchBlur = useCallback(() => { + setIsSearchFocused(false); + }, []); + + const handleCancelSearchClick = useCallback(() => { + cancelSearch(); + }, [cancelSearch]); const BoardMembershipsPopup = usePopup(BoardMembershipsStep); const LabelsPopup = usePopup(LabelsStep); + const isSearchActive = filterText || isSearchFocused; + return ( <> @@ -114,10 +145,21 @@ const Filters = React.memo( handleKeyUp()} + icon={ + isSearchActive ? ( + + ) : ( + 'search' + ) + } + className={classNames(styles.search, !isSearchActive && styles.searchInactive)} + onFocus={handleSearchFocus} + onKeyDown={handleSearchKeyDown} + onChange={handleSearchChange} + onBlur={handleSearchBlur} /> diff --git a/client/src/components/BoardActions/Filters.module.scss b/client/src/components/BoardActions/Filters.module.scss index 1af6dd2..12c7fc4 100644 --- a/client/src/components/BoardActions/Filters.module.scss +++ b/client/src/components/BoardActions/Filters.module.scss @@ -43,4 +43,32 @@ line-height: 20px; padding: 2px 12px; } + + .search { + height: 30px; + margin: 0 12px; + transition: width 0.2s ease; + width: 280px; + + input { + font-size: 13px; + } + } + + .searchInactive { + color: #fff; + height: 24px; + width: 220px; + + input { + background: rgba(0, 0, 0, 0.24); + border: none; + color: #fff !important; + font-size: 12px; + + &::placeholder { + color: #fff; + } + } + } } diff --git a/client/src/lib/custom-ui/components/Input/Input.jsx b/client/src/lib/custom-ui/components/Input/Input.jsx index f9bf001..4e820fb 100755 --- a/client/src/lib/custom-ui/components/Input/Input.jsx +++ b/client/src/lib/custom-ui/components/Input/Input.jsx @@ -9,4 +9,6 @@ export default class Input extends SemanticUIInput { static Mask = InputMask; focus = (options) => this.inputRef.current.focus(options); + + blur = () => this.inputRef.current.blur(); }