Skip to content

Commit a8556bd

Browse files
committed
feat(SearchBar): Add multiple props to improve component management
1 parent cf8d201 commit a8556bd

File tree

2 files changed

+91
-18
lines changed

2 files changed

+91
-18
lines changed

react/SearchBar/Readme.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import DemoProvider from 'cozy-ui/docs/components/DemoProvider'
33
import Variants from 'cozy-ui/docs/components/Variants'
44
import SearchBar from 'cozy-ui/transpiled/react/SearchBar'
55
import Typography from 'cozy-ui/transpiled/react/Typography'
6+
import CloudIcon from 'cozy-ui/transpiled/react/Icons/Cloud'
67

7-
const initialVariants = [{ elevation: true }]
8+
const initialVariants = [{ elevation: true, button: false, customIcon: false, disabledClear: false }]
89

910
;
1011

@@ -13,9 +14,22 @@ const initialVariants = [{ elevation: true }]
1314
{variant => (
1415
<>
1516
<Typography className="u-mb-half">Normal</Typography>
16-
<SearchBar className="u-mb-2" elevation={variant.elevation} />
17+
<SearchBar className="u-mb-2"
18+
elevation={variant.elevation}
19+
disabledClear={variant.disabledClear}
20+
type={variant.button ? "button" : "search"}
21+
icon={variant.customIcon ? CloudIcon : undefined}
22+
label={variant.button ? <Typography color="primary">This is a label</Typography> : undefined}
23+
/>
1724
<Typography className="u-mb-half">Disabled</Typography>
18-
<SearchBar elevation={variant.elevation} disabled />
25+
<SearchBar
26+
disabled
27+
elevation={variant.elevation}
28+
disabledClear={variant.disabledClear}
29+
type={variant.button ? "button" : "search"}
30+
icon={variant.customIcon ? CloudIcon : undefined}
31+
label={variant.button ? <Typography color="primary">This is a label</Typography> : undefined}
32+
/>
1933
</>
2034
)}
2135
</Variants>

react/SearchBar/index.jsx

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,31 @@ import PropTypes from 'prop-types'
44
import React, { forwardRef, useState, useMemo } from 'react'
55

66
import withOnlyLocales from './locales/withOnlyLocales'
7+
import ButtonBase from '../ButtonBase'
78
import Icon from '../Icon'
9+
import { iconPropType } from '../Icon'
810
import IconButton from '../IconButton'
911
import CrossCircleIcon from '../Icons/CrossCircle'
1012
import MagnifierIcon from '../Icons/Magnifier'
1113
import InputBase from '../InputBase'
1214
import Paper from '../Paper'
15+
import Typography from '../Typography'
1316
import { useI18n } from '../providers/I18n'
1417
import { makeStyles } from '../styles'
1518

19+
const sizeToPixel = {
20+
small: 40,
21+
medium: 48,
22+
large: 56
23+
}
24+
1625
const useStyles = makeStyles(theme => ({
1726
root: {
1827
display: 'flex',
1928
boxSizing: 'border-box',
2029
position: 'relative',
2130
alignItems: 'center',
22-
height: 40,
31+
height: ({ size }) => sizeToPixel[size],
2332
flex: 1,
2433
borderRadius: 99,
2534
borderStyle: 'solid',
@@ -37,7 +46,19 @@ const useStyles = makeStyles(theme => ({
3746
backgroundColor: theme.palette.background.contrast
3847
},
3948
inputBase: {
40-
flex: 1
49+
flex: 1,
50+
paddingLeft: ({ icon }) => !icon && '1rem'
51+
},
52+
buttonBase: {
53+
flex: 1,
54+
justifyContent: 'start',
55+
height: '100%',
56+
borderRadius: 99
57+
},
58+
typography: {
59+
color: 'currentColor',
60+
opacity: 0.42,
61+
paddingLeft: ({ icon }) => !icon && '1rem'
4162
},
4263
icon: {
4364
color: theme.palette.text.secondary,
@@ -81,6 +102,12 @@ const SearchBar = forwardRef(
81102
(
82103
{
83104
placeholder: placeholderProp,
105+
icon,
106+
size,
107+
type,
108+
label: labelProp,
109+
componentsProps,
110+
disabledClear,
84111
className,
85112
defaultValue,
86113
elevation,
@@ -93,11 +120,12 @@ const SearchBar = forwardRef(
93120
ref
94121
) => {
95122
const { t } = useI18n()
96-
const classes = useStyles()
123+
const classes = useStyles({ size, type, icon })
97124
const [currentValue, setCurrentValue] = useState(defaultValue)
98125
const [isFocused, setIsFocused] = useState(false)
99126

100127
const placeholder = placeholderProp || t('search.placeholder')
128+
const label = labelProp || t('search.placeholder')
101129

102130
const delayedOnChange = useMemo(
103131
() => debounce(event => onChange(event), 375),
@@ -143,18 +171,32 @@ const SearchBar = forwardRef(
143171
ref={ref}
144172
{...props}
145173
>
146-
<Icon className={classes.icon} icon={MagnifierIcon} />
147-
<InputBase
148-
className={classes.inputBase}
149-
placeholder={disabled ? null : placeholder}
150-
value={disabled ? placeholder : currentValue}
151-
disabled={disabled}
152-
aria-label={placeholder}
153-
onChange={handleChange}
154-
onFocus={handleFocus}
155-
onBlur={handleBlur}
156-
/>
157-
{currentValue && (
174+
{type === 'button' ? (
175+
<ButtonBase className={classes.buttonBase}>
176+
{icon && <Icon className={classes.icon} icon={icon} />}
177+
{typeof label === 'string' ? (
178+
<Typography className={classes.typography}>{label}</Typography>
179+
) : (
180+
label
181+
)}
182+
</ButtonBase>
183+
) : (
184+
<>
185+
{icon && <Icon className={classes.icon} icon={icon} />}
186+
<InputBase
187+
{...componentsProps?.inputBase}
188+
className={classes.inputBase}
189+
placeholder={disabled ? null : placeholder}
190+
value={disabled ? placeholder : currentValue}
191+
disabled={disabled}
192+
aria-label={placeholder}
193+
onChange={handleChange}
194+
onFocus={handleFocus}
195+
onBlur={handleBlur}
196+
/>
197+
</>
198+
)}
199+
{currentValue && !disabledClear && (
158200
<IconButton size="medium" onClick={handleClear}>
159201
<Icon icon={CrossCircleIcon} />
160202
</IconButton>
@@ -174,6 +216,10 @@ SearchBar.displayName = 'SearchBar'
174216

175217
SearchBar.defaultProps = {
176218
elevation: true,
219+
icon: MagnifierIcon,
220+
size: 'small',
221+
type: 'search',
222+
disabledClear: false,
177223
defaultValue: '',
178224
onChange: () => {},
179225
onFocus: () => {},
@@ -182,9 +228,22 @@ SearchBar.defaultProps = {
182228

183229
SearchBar.propTypes = {
184230
className: PropTypes.string,
231+
type: PropTypes.oneOf(['button', 'search']),
232+
icon: iconPropType,
233+
size: PropTypes.oneOf(['small', 'medium', 'large']),
234+
componentsProps: PropTypes.shape({
235+
/** Props spread to InputBase component */
236+
inputBase: PropTypes.object
237+
}),
185238
defaultValue: PropTypes.string,
239+
disabledClear: PropTypes.bool,
186240
elevation: PropTypes.bool,
187241
placeholder: PropTypes.string,
242+
label: PropTypes.oneOfType([
243+
PropTypes.string,
244+
PropTypes.func,
245+
PropTypes.object
246+
]),
188247
disabled: PropTypes.bool,
189248
onChange: PropTypes.func,
190249
onFocus: PropTypes.func,

0 commit comments

Comments
 (0)