diff --git a/desktop/app/src/chrome/DropDownSearchView.tsx b/desktop/app/src/chrome/DropDownSearchView.tsx deleted file mode 100644 index ab9574c29..000000000 --- a/desktop/app/src/chrome/DropDownSearchView.tsx +++ /dev/null @@ -1,229 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import { - SearchInput, - styled, - colors, - SearchIcon, - SearchBox, - FlexColumn, - FlexRow, - Text, - Tooltip, - Line, - Spacer, - Glyph, -} from '../ui'; -import React, {useState, useCallback, useEffect, useRef} from 'react'; - -const RowComponentContainer = styled(FlexRow)({ - height: '24px', - margin: '4px', - alignItems: 'center', - flexShrink: 0, -}); - -const Separator = styled(Line)({margin: '2px 0px'}); - -const OverlayContainer = styled.div({ - height: '100%', - overflow: 'visible', - position: 'absolute', - top: '30px', - left: '0px', - width: '100%', - zIndex: 100, -}); - -const ListViewContainer = styled(FlexColumn)({ - borderWidth: '0px 1px 1px', - borderStyle: 'solid', - borderColor: colors.greyTint2, - margin: '0px 10px', - maxHeight: '300px', - backgroundColor: colors.white, -}); - -const StyledSearchInput = styled(SearchInput)({ - height: '20px', - margin: '4px', -}); - -type Element = {id: string; label: string}; -type Props = { - list: Array; - onSelect?: (id: string, label: string) => void; - handleNoResults?: (value: string) => void; - selectedElementID?: string; -}; - -function RowComponent(props: { - elem: Element; - onClick: (id: string) => void; - selected?: boolean; -}) { - return ( - { - props.onClick(props.elem.id); - }}> - {props.elem.label} - - {props.selected && ( - - )} - - ); -} - -export default function (props: Props) { - const {list, handleNoResults, onSelect, selectedElementID} = props; - - const [filteredElements, setFilteredElements] = useState>([]); - const [searchedValue, setSearchedValue] = useState(''); - const [selectedElement, setSelectedElement] = useState( - undefined, - ); - const [focussed, setFocus] = useState(false); - const wrapperRef = useRef(null); - - const onChangeCallBack = useCallback( - (e: React.ChangeEvent) => { - setSearchedValue(e.target.value.trim()); - }, - [setSearchedValue], - ); - - const onSelectCallBack = useCallback( - (id: string) => { - const elem = list.find((e) => { - return e.id === id; - }); - if (elem) { - setSearchedValue(elem.label); - setSelectedElement(elem); - } - setFocus(false); - if (elem && onSelect) { - onSelect(elem.id, elem.label); - } - }, - [list, onSelect, setSearchedValue], - ); - - const onFocusCallBack = useCallback( - (_e: React.FocusEvent) => { - setFocus(true); - }, - [setFocus], - ); - - // Set the searched value and selectedElement when the selectedElementID changes. - useEffect(() => { - const initialElement = list.find((e) => e.id === selectedElementID); - if (initialElement) { - setSearchedValue(initialElement.label); - } - setSelectedElement(initialElement); - setFocus(false); - }, [selectedElementID, list]); - - // Effect to filter items - useEffect(() => { - if (searchedValue.length > 0) { - const filteredValues = list.filter((s) => { - return s.label.toLowerCase().includes(searchedValue.toLowerCase()); - }); - if (filteredValues.length === 0 && handleNoResults) { - handleNoResults(searchedValue); - } - setFilteredElements(filteredValues); - } else if (focussed) { - setFilteredElements(list); - } - }, [searchedValue, handleNoResults, list, setFilteredElements, focussed]); - - // Effect to detect outside click - useEffect(() => { - //TODO: Generalise this effect so that other components can use it. - function handleClickOutside(event: MouseEvent) { - const current = wrapperRef.current; - const target = event.target; - if ( - wrapperRef && - current && - target && - !current.contains(target as Node) && - focussed - ) { - if (selectedElement && onSelect) { - setSearchedValue(selectedElement.label); - onSelect(selectedElement.id, selectedElement.label); - } - setFocus(false); - } - } - document.addEventListener('mousedown', handleClickOutside); - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [ - wrapperRef, - selectedElement, - onSelect, - setSearchedValue, - setFocus, - focussed, - ]); - const validationError = - filteredElements.length === 0 && searchedValue.length > 0 - ? 'Unsupported element, please try clearing your text to see the list of elements.' - : ''; - return ( - - - 0}> - - - - - {filteredElements.length > 0 && focussed && ( - - - {filteredElements.map((e, idx) => { - return ( - - - {idx < filteredElements.length - 1 && } - - ); - })} - - - )} - - ); -} diff --git a/desktop/app/src/chrome/__tests__/DropDownSearchView.node.tsx b/desktop/app/src/chrome/__tests__/DropDownSearchView.node.tsx deleted file mode 100644 index cfd06c5af..000000000 --- a/desktop/app/src/chrome/__tests__/DropDownSearchView.node.tsx +++ /dev/null @@ -1,166 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import * as React from 'react'; -import {render, fireEvent} from '@testing-library/react'; -import DropDownSearchView from '../DropDownSearchView'; -import {act} from 'react-dom/test-utils'; - -test('Test selected element id is shown as the selected one.', async () => { - const res = render( - , - ); - const searchInput = (await res.findByTestId( - 'search-input', - )) as HTMLInputElement; - expect(searchInput).toBeTruthy(); - expect(searchInput.value).toEqual('label1'); - - searchInput.focus(); -}); - -test('Test the change of the selectedElementID changes the the selected element in the UI.', async () => { - const res = render( - , - ); - const searchInput = (await res.findByTestId( - 'search-input', - )) as HTMLInputElement; - expect(searchInput).toBeTruthy(); - expect(searchInput.value).toEqual('label1'); - - res.rerender( - , - ); - const searchInputRerendered = (await res.findByTestId( - 'search-input', - )) as HTMLInputElement; - expect(searchInputRerendered).toBeTruthy(); - expect(searchInputRerendered.value).toEqual('label2'); -}); - -test('Test the entire flow and click on the available options.', async () => { - const onSelect = jest.fn(); - const res = render( - , - ); - const searchInput = (await res.findByTestId( - 'search-input', - )) as HTMLInputElement; - expect(searchInput).toBeTruthy(); - expect(searchInput.value).toEqual('label1'); - - searchInput.focus(); - // Right now just the filtered elements will show up - expect(res.queryByText('label1')).toBeTruthy(); - expect(res.queryByText('label2')).toBeFalsy(); - expect(res.queryByText('label3')).toBeFalsy(); - expect(res.queryByText('label4')).toBeFalsy(); - act(() => { - fireEvent.change(searchInput, {target: {value: ''}}); - }); - // Once the input field is cleared all the available options will show up. - expect(res.queryByText('label1')).toBeTruthy(); - expect(res.queryByText('label2')).toBeTruthy(); - expect(res.queryByText('label3')).toBeTruthy(); - const text4 = res.queryByText('label4'); - - expect(text4).toBeTruthy(); - - act(() => { - text4?.parentElement?.dispatchEvent( - new MouseEvent('click', {bubbles: true}), - ); - }); - - expect(searchInput.value).toEqual('label4'); - expect(onSelect).toBeCalledTimes(1); - // After onSelect the expanded menu gets closed. - expect(res.queryByText('label1')).toBeFalsy(); - expect(res.queryByText('label2')).toBeFalsy(); - expect(res.queryByText('label3')).toBeFalsy(); - expect(res.queryByText('label4')).toBeFalsy(); -}); - -test('Test the validation error.', async () => { - const handleNoResults = jest.fn(); - const res = render( - , - ); - const searchInput = (await res.findByTestId( - 'search-input', - )) as HTMLInputElement; - expect(searchInput).toBeTruthy(); - expect(searchInput.value).toEqual(''); - - searchInput.focus(); - // Right now just the filtered elements will show up - expect(await res.findByText('label1 group')).toBeTruthy(); - expect(await res.findByText('label2 group')).toBeTruthy(); - expect(await res.findByText('label3 support')).toBeTruthy(); - expect(await res.findByText('label4 support')).toBeTruthy(); - - act(() => { - fireEvent.change(searchInput, {target: {value: 'support'}}); - }); - // Only the items which satisfy the search query should be shown - expect(res.queryByText('label3 support')).toBeTruthy(); - expect(res.queryByText('label4 support')).toBeTruthy(); - expect(res.queryByText('label1 group')).toBeFalsy(); - expect(res.queryByText('label2 group')).toBeFalsy(); - act(() => { - fireEvent.change(searchInput, {target: {value: 'gibberish'}}); - }); - - expect(handleNoResults).toBeCalled(); - expect(res.queryByText('label3 support')).toBeFalsy(); - expect(res.queryByText('label4 support')).toBeFalsy(); - expect(res.queryByText('label1 group')).toBeFalsy(); - expect(res.queryByText('label2 group')).toBeFalsy(); -});