Skip to content

Commit

Permalink
Desktop search (#53)
Browse files Browse the repository at this point in the history
* Add some actions to support desktop

* Some cleanup

* Add props to Search components to support desktop view

* Pr fixes

* Conflict resolve

* Merge fix

* Move onClose from Provider to components

* Pr fix

* Add tests

* Pr fixes

* PR fix
  • Loading branch information
leotoll committed Mar 12, 2020
1 parent e516af7 commit cc883f1
Show file tree
Hide file tree
Showing 13 changed files with 418 additions and 174 deletions.
20 changes: 13 additions & 7 deletions src/search/SearchDrawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import Drawer from '../drawer/Drawer'
import { makeStyles } from '@material-ui/core/styles'
import PropTypes from 'prop-types'
import SearchProvider from './SearchProvider'
import useNavigationEvent from 'react-storefront/hooks/useNavigationEvent'

export const styles = theme => ({
/**
Expand All @@ -24,12 +24,18 @@ const useStyles = makeStyles(styles, { name: 'RSFSearch' })
export default function SearchDrawer({ DrawerComponent, classes, open, onClose, children }) {
classes = useStyles({ classes })

const handleNavigation = () => {
if (onClose) {
onClose()
}
}

useNavigationEvent(handleNavigation)

return (
<SearchProvider onClose={onClose} open={open}>
<DrawerComponent classes={classes} open={open} anchor="bottom" onClose={onClose} fullscreen>
{children}
</DrawerComponent>
</SearchProvider>
<DrawerComponent classes={classes} open={open} anchor="bottom" onClose={onClose} fullscreen>
{children}
</DrawerComponent>
)
}

Expand All @@ -52,7 +58,7 @@ SearchDrawer.propTypes = {
/**
* A function that is called when the user closes the drawer.
*/
onClose: PropTypes.func,
onClose: PropTypes.func.isRequired,

/**
* A component type to use for the drawer.
Expand Down
198 changes: 115 additions & 83 deletions src/search/SearchField.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React, { useState, useRef, useContext } from 'react'
import makeStyles from '@material-ui/core/styles/makeStyles'
import React, { useRef, forwardRef } from 'react'
import { makeStyles, fade } from '@material-ui/core/styles'
import PropTypes from 'prop-types'
import withDefaultHandler from '../utils/withDefaultHandler'
import SearchContext from './SearchContext'
import { IconButton } from '@material-ui/core'
import ClearIcon from '@material-ui/icons/Clear'
import SearchSubmitButton from './SearchSubmitButton'
Expand Down Expand Up @@ -36,12 +34,34 @@ export const styles = theme => ({
border: 'none',
background: 'none',
flex: 1,
padding: '0 0 0 20px',
padding: theme.spacing(0, 2.5, 0, 2.5),
...theme.typography.body1,
'&:focus': {
outline: 'none',
},
[theme.breakpoints.up('sm')]: {
border: '1px solid',
borderColor: theme.palette.divider,
borderRadius: theme.spacing(1),
margin: theme.spacing(0.5, 0, 0.5, 0),
zIndex: 9999,
transition: 'border-color linear 0.1s',
'&:hover': {
borderColor: fade(theme.palette.divider, 0.25),
},
'&:focus': {
borderColor: theme.palette.primary.main,
},
},
},

/**
* Styles applied to the input if showClearnButton prop is true.
*/
inputClearIcon: {
paddingRight: 0,
},

/**
* Styles applied to the submit button element if [submitButtonVariant](#prop-submitButtonVariant)
* is `'fab'`.
Expand All @@ -67,92 +87,93 @@ const useStyles = makeStyles(styles, { name: 'RSFSearchField' })
* A search text field. Additional props are spread to the underlying
* [Input](https://material-ui.com/api/input/).
*/
export default function SearchField({
classes,
onChange,
submitButtonVariant,
showClearButton,
SubmitButtonComponent,
clearButtonProps,
inputProps,
submitButtonProps,
...others
}) {
classes = useStyles({ classes })
const inputRef = useRef(null)
const { fetchSuggestions } = useContext(SearchContext)
const [text, setText] = useState('')
const empty = text.trim().length === 0
const SearchField = forwardRef(
(
{
classes,
onChange,
submitButtonVariant,
showClearButton,
SubmitButtonComponent,
clearButtonProps,
inputProps,
value,
onFocus,
submitButtonProps,
...others
},
ref,
) => {
classes = useStyles({ classes })
const inputRef = ref || useRef(null)
const empty = value.trim().length === 0

const handleInputFocus = () => {
inputRef.current.setSelectionRange(0, inputRef.current.value.length)
}
const handleInputFocus = () => {
if (onFocus) {
onFocus()
}

const handleChange = withDefaultHandler(onChange, e => {
const text = e.target.value
setText(text)
fetchSuggestions(text)
})
inputRef.current.setSelectionRange(0, inputRef.current.value.length)
}

const handleClearClick = () => {
const text = ''
setText(text)
fetchSuggestions(text)
}
const handleClearClick = () => {
onChange('')
}

return (
<div className={classes.root} data-empty={text.trim().length === 0 ? 'on' : 'off'}>
<div className={classes.inputWrap}>
<input
{...others}
type="text"
value={text}
onChange={handleChange}
onFocus={handleInputFocus}
ref={inputRef}
className={classes.input}
{...inputProps}
/>
{showClearButton ? (
<IconButton
{...clearButtonProps}
onClick={handleClearClick}
rel="clear"
className={clsx({
[classes.searchReset]: true,
[classes.hidden]: empty,
})}
>
<ClearIcon rel="clear" />
</IconButton>
) : (
submitButtonVariant === 'icon' && (
<SubmitButtonComponent
Component={Button}
return (
<div className={classes.root} data-empty={value.trim().length === 0 ? 'on' : 'off'}>
<div className={classes.inputWrap}>
<input
{...others}
type="text"
value={value}
onChange={e => onChange(e.target.value)}
onFocus={handleInputFocus}
ref={inputRef}
className={clsx(classes.input, showClearButton && classes.inputClearIcon)}
{...inputProps}
/>
{showClearButton ? (
<IconButton
{...clearButtonProps}
onClick={handleClearClick}
rel="clear"
className={clsx({
[classes.searchButton]: true,
[classes.searchReset]: true,
[classes.hidden]: empty,
})}
text={text}
{...submitButtonProps}
/>
)
>
<ClearIcon rel="clear" />
</IconButton>
) : (
submitButtonVariant === 'icon' && (
<SubmitButtonComponent
Component={Button}
className={clsx({
[classes.searchButton]: true,
[classes.hidden]: empty,
})}
text={value}
{...submitButtonProps}
/>
)
)}
</div>
{submitButtonVariant === 'fab' && (
<SubmitButtonComponent
Component={Fab}
className={clsx({
[classes.searchFab]: true,
[classes.hidden]: empty,
})}
text={value}
{...submitButtonProps}
/>
)}
</div>
{submitButtonVariant === 'fab' && (
<SubmitButtonComponent
Component={Fab}
className={clsx({
[classes.searchFab]: true,
[classes.hidden]: empty,
})}
text={text}
{...submitButtonProps}
/>
)}
</div>
)
}
)
},
)

SearchField.propTypes = {
/**
Expand All @@ -166,7 +187,7 @@ SearchField.propTypes = {
/**
* The type of submit button to display.
*/
submitButtonVariant: PropTypes.oneOf(['icon', 'fab']),
submitButtonVariant: PropTypes.oneOf(['icon', 'fab', 'none']),
/**
* If `true`, show the clear button when text is entered.
*/
Expand All @@ -187,6 +208,14 @@ SearchField.propTypes = {
* A function to call when the search query value is changed.
*/
onChange: PropTypes.func,
/**
* Input value.
*/
value: PropTypes.string,
/**
* A function to call when input is focused.
*/
onFocus: PropTypes.func,
}

SearchField.defaultProps = {
Expand All @@ -195,4 +224,7 @@ SearchField.defaultProps = {
showClearButton: true,
placeholder: 'Search...',
name: 'q',
value: '',
}

export default SearchField
17 changes: 15 additions & 2 deletions src/search/SearchForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const useStyles = makeStyles(styles, { name: 'RSFSearchForm' })
/**
* A form used to submit a search query.
*/
export default function SearchForm({ classes, children, action }) {
export default function SearchForm({ classes, children, action, autoComplete }) {
classes = useStyles({ classes })

const ref = useRef()
Expand All @@ -42,7 +42,14 @@ export default function SearchForm({ classes, children, action }) {
}

return (
<form ref={ref} action={action} onSubmit={handleSubmit} className={classes.root} target="_top">
<form
ref={ref}
action={action}
onSubmit={handleSubmit}
className={classes.root}
target="_top"
autoComplete={autoComplete ? 'on' : 'off'}
>
{children}
</form>
)
Expand All @@ -63,8 +70,14 @@ SearchForm.propTypes = {
* An `action` attribute to use for the `<form>` element.
*/
action: PropTypes.string,

/**
* Form auto complete
*/
autoComplete: PropTypes.bool,
}

SearchForm.defaultProps = {
action: '/search',
autoComplete: false,
}
Loading

0 comments on commit cc883f1

Please sign in to comment.