Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(Search*): use React.forwardRef() #4270

Merged
merged 1 commit into from
Aug 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -679,5 +680,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
5 changes: 1 addition & 4 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 All @@ -15,6 +12,6 @@ export interface StrictSearchCategoryLayoutProps {
resultsContent: React.ReactElement<any>
}

declare const SearchCategoryLayout: React.StatelessComponent<SearchCategoryLayoutProps>
declare const SearchCategoryLayout: React.FunctionComponent<SearchCategoryLayoutProps>

export default SearchCategoryLayout
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)
})