|
1 | | -import React, {useRef, useState, useLayoutEffect, useEffect} from 'react'; |
| 1 | +import React, {useRef, useState, useCallback, useEffect} from 'react'; |
2 | 2 | import Popper from './popper'; |
3 | | -import SearchIcon from './icons/search.js'; |
4 | | -import CloseIcon from './icons/close.js'; |
5 | | -import deop from './defaultOptions.js'; |
| 3 | +import MagnifierIcon from './icons/magnifier.js'; |
| 4 | +import ClearIcon from './icons/clear.js'; |
6 | 5 | /** |
7 | 6 | * |
8 | 7 | * @param {Object} props |
| 8 | + * @param {React.ReactNode} [props.children=null] - will be shown in popup |
9 | 9 | * @param {value} props.value - input value |
10 | | - * @param {Function} props.setValue - setState function for input value |
11 | | - * @param {React.ReactNode} [props.children] - will be shown in popup |
12 | | - * @param {Object} [props.rootStyle] - style object of the root element |
13 | | - * @param {Object} [props.inputStyle] - style object of the input element |
| 10 | + * @param {Function} props.onChange - onChange function for input |
| 11 | + * @param {Object} [props.rootStyle={}] - style object of the root element |
| 12 | + * @param {Object} [props.inputContainerStyle={}] - style object of the parent element of text input |
| 13 | + * @param {Object} [props.inputStyle={}] - style object of the input element |
14 | 14 | * @param {String} [props.placeholder="search"] |
15 | | - * @param {String} [props.iconsColor="gray"] - svg icon's color |
16 | | - * @param {Object} [props.searchIconStyle] - style object for magnifying icon |
17 | | - * @param {Object} [props.clearIconStyle] - style object for clear icon |
18 | | - * @param {Object} [props.popperStyle] - style object for popper container |
19 | | - * @param {Function} [props.onKeyDown] - keydown event for input |
20 | | - * @param {Function} [props.onBlur] - blur event for the input |
21 | | - * @param {Boolean} [props.fullWidth=false] - set popper width same as input |
22 | | - * @param {'auto'| 'auto-start'| 'auto-end'| 'top'| 'top-start'| 'top-end'| 'bottom'| 'bottom-start'| 'bottom-end'| 'right'| 'right-start'| 'right-end'| 'left'| 'left-start'| 'left-end'} [props.placement="bottom"] - popper's placement |
| 15 | + * @param {Function} [props.onKeyDown=()=>{}] - keydown event for input |
| 16 | + * @param {Function} [props.onFocus=()=>{}] - focus event for input |
| 17 | + * @param {Function} [props.onBlur=()=>{}] - blur event for the input |
| 18 | + * @param {Object} [props.popperStyle={}] - style object for popper container |
| 19 | + * @param {Boolean} [props.fullWidth=true] - set popper width same as input |
| 20 | + * @param {'auto'| 'auto-start'| 'auto-end'| 'top'| 'top-start'| 'top-end'| 'bottom'| 'bottom-start'| 'bottom-end'| 'right'| 'right-start'| 'right-end'| 'left'| 'left-start'| 'left-end'} [props.placement="bottom-start"] - popper's placement |
| 21 | + * @param {React.FC} [props.ClearIconComponent=ClearIcon] - custom Clear icon |
| 22 | + * @param {React.FC} [props.MagnifierIconComponent=MagnifierIcon] - custom Magnifier icon |
| 23 | + * @param {Function} [props.onClear=()=>{}] - triggerd when the user clicks on the default Clear icon |
| 24 | + * @param {"underline"|"outline"|"panel"} [props.theme="outline"] - searchbox theme |
| 25 | + * @param {Boolean} [props.corner=true] - if set true then border-radius would be "5px" |
23 | 26 | */ |
24 | 27 | function ReactCustomSearchList(props) { |
25 | 28 | const { |
26 | | - children, |
27 | | - value, |
28 | | - setValue, |
29 | | - rootStyle, |
30 | | - inputStyle, |
31 | | - placeholder, |
32 | | - iconsColor, |
33 | | - searchIconStyle, |
34 | | - clearIconStyle, |
35 | | - onKeyDown, |
36 | | - onBlur, |
37 | | - popperStyle, |
38 | | - fullWidth, |
39 | | - placement, |
40 | | - } = { |
41 | | - ...deop, |
42 | | - ...props, |
43 | | - }; |
| 29 | + children = null, |
| 30 | + value = '', |
| 31 | + onChange, |
| 32 | + rootStyle = {}, |
| 33 | + inputContainerStyle = {}, |
| 34 | + inputStyle = {}, |
| 35 | + placeholder = 'search', |
| 36 | + onKeyDown = () => {}, |
| 37 | + onFocus = () => {}, |
| 38 | + onBlur = () => {}, |
| 39 | + popperStyle = {}, |
| 40 | + fullWidth = true, |
| 41 | + placement = 'bottom-start', |
| 42 | + ClearIconComponent = ClearIcon, |
| 43 | + MagnifierIconComponent = MagnifierIcon, |
| 44 | + onClear = () => {}, |
| 45 | + theme = 'outline', |
| 46 | + corner = true, |
| 47 | + } = props; |
44 | 48 | const [open, setOpen] = useState(false); |
45 | | - const [isBlur, setIsBlur] = useState(false); |
46 | 49 | const rootRef = useRef(); |
47 | | - const onFocus = (e) => { |
| 50 | + const onClickHandler = useCallback(() => { |
48 | 51 | setOpen(true); |
49 | | - }; |
50 | | - const onBlurHandle = (e) => { |
51 | | - e.preventDefault(); |
52 | | - console.log('onBlurHandle'); |
53 | | - debugger; |
54 | | - setOpen(false); |
55 | | - setIsBlur(true); |
56 | | - onBlur(e); |
57 | | - }; |
| 52 | + }, []); |
| 53 | + const onKeyDownHandler = useCallback( |
| 54 | + (e) => { |
| 55 | + (e) => { |
| 56 | + if (e.key.toLowerCase() === 'enter' && open === false) { |
| 57 | + setOpen(true); |
| 58 | + } |
| 59 | + onKeyDown(e); |
| 60 | + }; |
| 61 | + }, |
| 62 | + [onKeyDown], |
| 63 | + ); |
58 | 64 | useEffect(() => { |
59 | | - if (isBlur) { |
60 | | - console.log('useEffect'); |
61 | | - } |
62 | | - }, [isBlur]); |
| 65 | + const click = (e) => { |
| 66 | + setTimeout(() => { |
| 67 | + setOpen(false); |
| 68 | + }); |
| 69 | + }; |
| 70 | + open |
| 71 | + ? document.body.addEventListener('click', click, {once: true, useCapture: true}) |
| 72 | + : document.body.removeEventListener('click', click, {once: true, useCapture: true}); |
| 73 | + return () => { |
| 74 | + if (open) { |
| 75 | + console.log('remove listener'); |
| 76 | + document.body.removeEventListener('click', click, {once: true, useCapture: true}); |
| 77 | + } |
| 78 | + }; |
| 79 | + }, [open]); |
63 | 80 | return ( |
64 | | - <div className="rc-search-suggestions-root"> |
| 81 | + <div className={`rc-search-suggestions-root ${theme}${corner ? ' corner' : ''}`} style={rootStyle}> |
65 | 82 | {open ? ( |
66 | 83 | <Popper |
67 | 84 | rootRef={rootRef} |
68 | | - style={{...deop.popperStyle, ...popperStyle}} |
69 | | - fullWidth={fullWidth} |
| 85 | + style={popperStyle} |
| 86 | + fullWidth={theme === 'panel' ? true : fullWidth} |
70 | 87 | placement={placement}> |
71 | 88 | {children} |
72 | 89 | </Popper> |
73 | 90 | ) : null} |
74 | | - <div className="rc-search-suggestions-container" ref={rootRef} style={{...deop.rootStyle, ...rootStyle}}> |
75 | | - <SearchIcon |
76 | | - className="rc-search-suggestions-magnifying" |
77 | | - fill={iconsColor} |
78 | | - style={{...deop.searchIconStyle, ...searchIconStyle}} |
79 | | - /> |
| 91 | + <div className={`rc-search-suggestions-container`} ref={rootRef} style={inputContainerStyle}> |
| 92 | + {MagnifierIconComponent ? <MagnifierIconComponent /> : null} |
80 | 93 | <input |
81 | | - onFocus={onFocus} |
82 | | - onBlur={onBlurHandle} |
83 | 94 | value={value} |
84 | | - onChange={(e) => setValue(e.target.value)} |
| 95 | + onChange={onChange} |
| 96 | + onFocus={onFocus} |
| 97 | + onClick={onClickHandler} |
| 98 | + onKeyDown={onKeyDownHandler} |
| 99 | + onBlur={onBlur} |
85 | 100 | placeholder={placeholder} |
86 | | - className="rc-search-suggestions-input" |
87 | | - style={{...deop.inputStyle, ...inputStyle}} |
88 | | - onKeyDown={onKeyDown} |
89 | | - /> |
90 | | - <CloseIcon |
91 | | - className="rc-search-suggestions-close" |
92 | | - fill={iconsColor} |
93 | | - style={{opacity: value.length ? 1 : 0, ...deop.clearIconStyle, ...clearIconStyle}} |
94 | | - onClick={() => { |
95 | | - setValue(''); |
96 | | - }} |
| 101 | + style={inputStyle} |
97 | 102 | /> |
| 103 | + {ClearIconComponent ? <ClearIconComponent value={value} onClear={onClear} /> : null} |
98 | 104 |
|
99 | | - {/* <div |
100 | | - className={ |
101 | | - 'rc-search-suggestions-divider ' + open |
102 | | - ? 'rc-search-suggestions-divider-open' |
103 | | - : 'rc-search-suggestions-divider-close' |
104 | | - } |
105 | | - /> */} |
| 105 | + <div className="rc-search-suggestions-divider rc-search-suggestions-divider-bottom" /> |
| 106 | + <div className="rc-search-suggestions-divider rc-search-suggestions-divider-top" /> |
106 | 107 | </div> |
107 | 108 | </div> |
108 | 109 | ); |
|
0 commit comments