Skip to content

Commit

Permalink
chore(Card): use React.forwardRef() (#4243)
Browse files Browse the repository at this point in the history
  • Loading branch information
layershifter committed Feb 1, 2022
1 parent b1373d7 commit c4ef2d2
Show file tree
Hide file tree
Showing 12 changed files with 112 additions and 86 deletions.
137 changes: 70 additions & 67 deletions src/views/Card/Card.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 {
childrenUtils,
Expand All @@ -9,6 +10,7 @@ import {
getUnhandledProps,
SUI,
useKeyOnly,
useEventCallback,
} from '../../lib'
import Image from '../../elements/Image'
import CardContent from './CardContent'
Expand All @@ -20,80 +22,79 @@ import CardMeta from './CardMeta'
/**
* A card displays site content in a manner similar to a playing card.
*/
export default class Card extends Component {
handleClick = (e) => {
const { onClick } = this.props
const Card = React.forwardRef(function (props, ref) {
const {
centered,
children,
className,
color,
content,
description,
extra,
fluid,
header,
href,
image,
link,
meta,
onClick,
raised,
} = props

const classes = cx(
'ui',
color,
useKeyOnly(centered, 'centered'),
useKeyOnly(fluid, 'fluid'),
useKeyOnly(link, 'link'),
useKeyOnly(raised, 'raised'),
'card',
className,
)
const rest = getUnhandledProps(Card, props)
const ElementType = getElementType(Card, props, () => {
if (onClick) {
return 'a'
}
})

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

render() {
const {
centered,
children,
className,
color,
content,
description,
extra,
fluid,
header,
href,
image,
link,
meta,
onClick,
raised,
} = this.props

const classes = cx(
'ui',
color,
useKeyOnly(centered, 'centered'),
useKeyOnly(fluid, 'fluid'),
useKeyOnly(link, 'link'),
useKeyOnly(raised, 'raised'),
'card',
className,
if (!childrenUtils.isNil(children)) {
return (
<ElementType {...rest} className={classes} href={href} onClick={handleClick} ref={ref}>
{children}
</ElementType>
)
const rest = getUnhandledProps(Card, this.props)
const ElementType = getElementType(Card, this.props, () => {
if (onClick) return 'a'
})

if (!childrenUtils.isNil(children)) {
return (
<ElementType {...rest} className={classes} href={href} onClick={this.handleClick}>
{children}
</ElementType>
)
}
if (!childrenUtils.isNil(content)) {
return (
<ElementType {...rest} className={classes} href={href} onClick={this.handleClick}>
{content}
</ElementType>
)
}

}
if (!childrenUtils.isNil(content)) {
return (
<ElementType {...rest} className={classes} href={href} onClick={this.handleClick}>
{Image.create(image, {
autoGenerateKey: false,
defaultProps: {
ui: false,
wrapped: true,
},
})}
{(description || header || meta) && (
<CardContent description={description} header={header} meta={meta} />
)}
{extra && <CardContent extra>{extra}</CardContent>}
<ElementType {...rest} className={classes} href={href} onClick={handleClick} ref={ref}>
{content}
</ElementType>
)
}
}

return (
<ElementType {...rest} className={classes} href={href} onClick={handleClick} ref={ref}>
{Image.create(image, {
autoGenerateKey: false,
defaultProps: {
ui: false,
wrapped: true,
},
})}
{(description || header || meta) && (
<CardContent description={description} header={header} meta={meta} />
)}
{extra && <CardContent extra>{extra}</CardContent>}
</ElementType>
)
})

Card.displayName = 'Card'
Card.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down Expand Up @@ -155,3 +156,5 @@ Card.Description = CardDescription
Card.Group = CardGroup
Card.Header = CardHeader
Card.Meta = CardMeta

export default Card
11 changes: 6 additions & 5 deletions src/views/Card/CardContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import CardMeta from './CardMeta'
/**
* A card can contain blocks of content or extra content meant to be formatted separately from the main content.
*/
function CardContent(props) {
const CardContent = React.forwardRef(function (props, ref) {
const { children, className, content, description, extra, header, meta, textAlign } = props

const classes = cx(useKeyOnly(extra, 'extra'), useTextAlignProp(textAlign), 'content', className)
Expand All @@ -29,30 +29,31 @@ function CardContent(props) {

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

return (
<ElementType {...rest} className={classes}>
<ElementType {...rest} className={classes} ref={ref}>
{createShorthand(CardHeader, (val) => ({ content: val }), header, { autoGenerateKey: false })}
{createShorthand(CardMeta, (val) => ({ content: val }), meta, { autoGenerateKey: false })}
{createShorthand(CardDescription, (val) => ({ content: val }), description, {
autoGenerateKey: false,
})}
</ElementType>
)
}
})

CardContent.displayName = 'CardContent'
CardContent.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down
7 changes: 4 additions & 3 deletions src/views/Card/CardDescription.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ import {
/**
* A card can contain a description with one or more paragraphs.
*/
function CardDescription(props) {
const CardDescription = React.forwardRef(function (props, ref) {
const { children, className, content, textAlign } = props
const classes = cx(useTextAlignProp(textAlign), 'description', className)
const rest = getUnhandledProps(CardDescription, props)
const ElementType = getElementType(CardDescription, props)

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

CardDescription.displayName = 'CardDescription'
CardDescription.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down
11 changes: 6 additions & 5 deletions src/views/Card/CardGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Card from './Card'
/**
* A group of cards.
*/
function CardGroup(props) {
const CardGroup = React.forwardRef(function (props, ref) {
const {
centered,
children,
Expand Down Expand Up @@ -46,14 +46,14 @@ function CardGroup(props) {

if (!childrenUtils.isNil(children)) {
return (
<ElementType {...rest} className={classes}>
<ElementType {...rest} className={classes} ref={ref}>
{children}
</ElementType>
)
}
if (!childrenUtils.isNil(content)) {
return (
<ElementType {...rest} className={classes}>
<ElementType {...rest} className={classes} ref={ref}>
{content}
</ElementType>
)
Expand All @@ -65,12 +65,13 @@ function CardGroup(props) {
})

return (
<ElementType {...rest} className={classes}>
<ElementType {...rest} className={classes} ref={ref}>
{itemsJSX}
</ElementType>
)
}
})

CardGroup.displayName = 'CardGroup'
CardGroup.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down
7 changes: 4 additions & 3 deletions src/views/Card/CardHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ import {
/**
* A card can contain a header.
*/
function CardHeader(props) {
const CardHeader = React.forwardRef(function (props, ref) {
const { children, className, content, textAlign } = props
const classes = cx(useTextAlignProp(textAlign), 'header', className)
const rest = getUnhandledProps(CardHeader, props)
const ElementType = getElementType(CardHeader, props)

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

CardHeader.displayName = 'CardHeader'
CardHeader.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down
7 changes: 4 additions & 3 deletions src/views/Card/CardMeta.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ import {
/**
* A card can contain content metadata.
*/
function CardMeta(props) {
const CardMeta = React.forwardRef(function (props, ref) {
const { children, className, content, textAlign } = props
const classes = cx(useTextAlignProp(textAlign), 'meta', className)
const rest = getUnhandledProps(CardMeta, props)
const ElementType = getElementType(CardMeta, props)

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

CardMeta.displayName = 'CardMeta'
CardMeta.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down
5 changes: 5 additions & 0 deletions test/specs/views/Card/Card-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import { sandbox } from 'test/utils'

describe('Card', () => {
common.isConformant(Card)

common.forwardsRef(Card)
common.forwardsRef(Card, { requiredProps: { children: <span /> } })
common.forwardsRef(Card, { requiredProps: { content: faker.lorem.word() } })

common.hasSubcomponents(Card, [CardContent, CardDescription, CardGroup, CardHeader, CardMeta])
common.hasUIClassName(Card)
common.rendersChildren(Card)
Expand Down
5 changes: 5 additions & 0 deletions test/specs/views/Card/CardContent-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import faker from 'faker'
import _ from 'lodash'
import React from 'react'

import { SUI } from 'src/lib'
import CardContent from 'src/views/Card/CardContent'
Expand All @@ -9,6 +11,9 @@ import * as common from 'test/specs/commonTests'

describe('CardContent', () => {
common.isConformant(CardContent)
common.forwardsRef(CardContent)
common.forwardsRef(CardContent, { requiredProps: { children: <span /> } })
common.forwardsRef(CardContent, { requiredProps: { content: faker.lorem.word() } })
common.rendersChildren(CardContent)

common.implementsShorthandProp(CardContent, {
Expand Down
1 change: 1 addition & 0 deletions test/specs/views/Card/CardDescription-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as common from 'test/specs/commonTests'

describe('CardDescription', () => {
common.isConformant(CardDescription)
common.forwardsRef(CardDescription)
common.rendersChildren(CardDescription)
common.implementsTextAlignProp(CardDescription, _.without(SUI.TEXT_ALIGNMENTS, 'justified'))
})
5 changes: 5 additions & 0 deletions test/specs/views/Card/CardGroup-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import * as common from 'test/specs/commonTests'

describe('CardGroup', () => {
common.isConformant(CardGroup)

common.forwardsRef(CardGroup)
common.forwardsRef(CardGroup, { requiredProps: { children: <span /> } })
common.forwardsRef(CardGroup, { requiredProps: { content: faker.lorem.word() } })

common.hasUIClassName(CardGroup)
common.rendersChildren(CardGroup)

Expand Down
1 change: 1 addition & 0 deletions test/specs/views/Card/CardHeader-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as common from 'test/specs/commonTests'

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

common.implementsTextAlignProp(CardHeader, _.without(SUI.TEXT_ALIGNMENTS, 'justified'))
Expand Down
1 change: 1 addition & 0 deletions test/specs/views/Card/CardMeta-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as common from 'test/specs/commonTests'

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

common.implementsTextAlignProp(CardMeta, _.without(SUI.TEXT_ALIGNMENTS, 'justified'))
Expand Down

0 comments on commit c4ef2d2

Please sign in to comment.