Skip to content

Commit

Permalink
chore(Search*): use React.forwardRef() (#4270)
Browse files Browse the repository at this point in the history
  • Loading branch information
layershifter committed Jun 21, 2022
1 parent 4565f8c commit ee09958
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 33 deletions.
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export RatingIcon from './modules/Rating/RatingIcon'

export Search from './modules/Search'
export SearchCategory from './modules/Search/SearchCategory'
export SearchCategoryLayout from './modules/Search/SearchCategoryLayout'
export SearchResult from './modules/Search/SearchResult'
export SearchResults from './modules/Search/SearchResults'

Expand Down
2 changes: 2 additions & 0 deletions src/modules/Search/Search.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from '../../lib'
import Input from '../../elements/Input'
import SearchCategory from './SearchCategory'
import SearchCategoryLayout from './SearchCategoryLayout'
import SearchResult from './SearchResult'
import SearchResults from './SearchResults'

Expand Down Expand Up @@ -683,5 +684,6 @@ Search.defaultProps = {
Search.autoControlledProps = ['open', 'value']

Search.Category = SearchCategory
Search.CategoryLayout = SearchCategoryLayout
Search.Result = SearchResult
Search.Results = SearchResults
8 changes: 5 additions & 3 deletions src/modules/Search/SearchCategory.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import {
} from '../../lib'
import SearchCategoryLayout from './SearchCategoryLayout'

function SearchCategory(props) {
const SearchCategory = React.forwardRef(function (props, ref) {
const { active, children, className, content, layoutRenderer, renderer } = props

const classes = cx(useKeyOnly(active, 'active'), 'category', className)
const rest = getUnhandledProps(SearchCategory, props)
const ElementType = getElementType(SearchCategory, props)
Expand All @@ -21,17 +22,18 @@ function SearchCategory(props) {
const resultsContent = childrenUtils.isNil(children) ? content : children

return (
<ElementType {...rest} className={classes}>
<ElementType {...rest} className={classes} ref={ref}>
{layoutRenderer({ categoryContent, resultsContent })}
</ElementType>
)
}
})

SearchCategory.defaultProps = {
layoutRenderer: SearchCategoryLayout,
renderer: ({ name }) => name,
}

SearchCategory.displayName = 'SearchCategory'
SearchCategory.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down
3 changes: 0 additions & 3 deletions src/modules/Search/SearchCategoryLayout.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import * as React from 'react'

import { SemanticShorthandContent } from '../../generic'
import SearchResult from './SearchResult'

export interface SearchCategoryLayoutProps extends StrictSearchCategoryLayoutProps {
[key: string]: any
}
Expand Down
1 change: 1 addition & 0 deletions src/modules/Search/SearchCategoryLayout.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react'

function SearchCategoryLayout(props) {
const { categoryContent, resultsContent } = props

return (
<>
<div className='name'>{categoryContent}</div>
Expand Down
48 changes: 24 additions & 24 deletions src/modules/Search/SearchResult.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import cx from 'clsx'
import _ from 'lodash'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import React from 'react'

import {
createHTMLImage,
Expand Down Expand Up @@ -30,32 +31,29 @@ const defaultRenderer = ({ image, price, title, description }) => [
</div>,
]

export default class SearchResult extends Component {
handleClick = (e) => {
const { onClick } = this.props
const SearchResult = React.forwardRef(function (props, ref) {
const { active, className, renderer } = props

if (onClick) onClick(e, this.props)
const handleClick = (e) => {
_.invoke(props, 'onClick', e, props)
}

render() {
const { active, className, renderer } = this.props

const classes = cx(useKeyOnly(active, 'active'), 'result', className)
const rest = getUnhandledProps(SearchResult, this.props)
const ElementType = getElementType(SearchResult, this.props)

// Note: You technically only need the 'content' wrapper when there's an
// image. However, optionally wrapping it makes this function a lot more
// complicated and harder to read. Since always wrapping it doesn't affect
// the style in any way let's just do that.
return (
<ElementType {...rest} className={classes} onClick={this.handleClick}>
{renderer(this.props)}
</ElementType>
)
}
}

const classes = cx(useKeyOnly(active, 'active'), 'result', className)
const rest = getUnhandledProps(SearchResult, props)
const ElementType = getElementType(SearchResult, props)

// Note: You technically only need the 'content' wrapper when there's an
// image. However, optionally wrapping it makes this function a lot more
// complicated and harder to read. Since always wrapping it doesn't affect
// the style in any way let's just do that.
return (
<ElementType {...rest} className={classes} onClick={handleClick} ref={ref}>
{renderer(props)}
</ElementType>
)
})

SearchResult.displayName = 'SearchResult'
SearchResult.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down Expand Up @@ -104,3 +102,5 @@ SearchResult.propTypes = {
SearchResult.defaultProps = {
renderer: defaultRenderer,
}

export default SearchResult
7 changes: 4 additions & 3 deletions src/modules/Search/SearchResults.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ import React from 'react'

import { childrenUtils, customPropTypes, getElementType, getUnhandledProps } from '../../lib'

function SearchResults(props) {
const SearchResults = React.forwardRef(function (props, ref) {
const { children, className, content } = props
const classes = cx('results transition', className)
const rest = getUnhandledProps(SearchResults, props)
const ElementType = getElementType(SearchResults, props)

return (
<ElementType {...rest} className={classes}>
<ElementType {...rest} className={classes} ref={ref}>
{childrenUtils.isNil(children) ? content : children}
</ElementType>
)
}
})

SearchResults.displayName = 'SearchResults'
SearchResults.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down
1 change: 1 addition & 0 deletions test/specs/modules/Search/SearchCategory-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as common from 'test/specs/commonTests'

describe('SearchCategory', () => {
common.isConformant(SearchCategory)
common.forwardsRef(SearchCategory)
common.rendersChildren(SearchCategory)

describe('children', () => {
Expand Down
13 changes: 13 additions & 0 deletions test/specs/modules/Search/SearchCategoryLayout-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as React from 'react'

import SearchCategoryLayout from 'src/modules/Search/SearchCategoryLayout'
import * as common from 'test/specs/commonTests'

const requiredProps = {
categoryContent: <div />,
resultsContent: <div />,
}

describe('SearchCategoryLayout', () => {
common.isConformant(SearchCategoryLayout, { requiredProps, rendersChildren: false })
})
14 changes: 14 additions & 0 deletions test/specs/modules/Search/SearchResult-test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
import React from 'react'

import SearchResult from 'src/modules/Search/SearchResult'
import * as common from 'test/specs/commonTests'
import { sandbox } from 'test/utils'

const requiredProps = { title: '' }

describe('SearchResult', () => {
common.isConformant(SearchResult, { requiredProps })
common.forwardsRef(SearchResult, { requiredProps })
common.propKeyOnlyToClassName(SearchResult, 'active', { requiredProps })

describe('onClick', () => {
it('is called with (e, data) when clicked', () => {
const onClick = sandbox.spy()
mount(<SearchResult onClick={onClick} {...requiredProps} />).simulate('click')

onClick.should.have.been.calledOnce()
onClick.should.have.been.calledWithMatch({ type: 'click' }, requiredProps)
})
})
})
1 change: 1 addition & 0 deletions test/specs/modules/Search/SearchResults-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import * as common from 'test/specs/commonTests'

describe('SearchResults', () => {
common.isConformant(SearchResults)
common.forwardsRef(SearchResults)
common.rendersChildren(SearchResults)
})

0 comments on commit ee09958

Please sign in to comment.