diff --git a/src/views/Card/Card.js b/src/views/Card/Card.js
index a414d633d3..13cefed144 100644
--- a/src/views/Card/Card.js
+++ b/src/views/Card/Card.js
@@ -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,
@@ -9,6 +10,7 @@ import {
getUnhandledProps,
SUI,
useKeyOnly,
+ useEventCallback,
} from '../../lib'
import Image from '../../elements/Image'
import CardContent from './CardContent'
@@ -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 (
+
+ {children}
+
)
- const rest = getUnhandledProps(Card, this.props)
- const ElementType = getElementType(Card, this.props, () => {
- if (onClick) return 'a'
- })
-
- if (!childrenUtils.isNil(children)) {
- return (
-
- {children}
-
- )
- }
- if (!childrenUtils.isNil(content)) {
- return (
-
- {content}
-
- )
- }
-
+ }
+ if (!childrenUtils.isNil(content)) {
return (
-
- {Image.create(image, {
- autoGenerateKey: false,
- defaultProps: {
- ui: false,
- wrapped: true,
- },
- })}
- {(description || header || meta) && (
-
- )}
- {extra && {extra}}
+
+ {content}
)
}
-}
+ return (
+
+ {Image.create(image, {
+ autoGenerateKey: false,
+ defaultProps: {
+ ui: false,
+ wrapped: true,
+ },
+ })}
+ {(description || header || meta) && (
+
+ )}
+ {extra && {extra}}
+
+ )
+})
+
+Card.displayName = 'Card'
Card.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
@@ -155,3 +156,5 @@ Card.Description = CardDescription
Card.Group = CardGroup
Card.Header = CardHeader
Card.Meta = CardMeta
+
+export default Card
diff --git a/src/views/Card/CardContent.js b/src/views/Card/CardContent.js
index d293948293..475ca2e719 100644
--- a/src/views/Card/CardContent.js
+++ b/src/views/Card/CardContent.js
@@ -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)
@@ -29,21 +29,21 @@ function CardContent(props) {
if (!childrenUtils.isNil(children)) {
return (
-
+
{children}
)
}
if (!childrenUtils.isNil(content)) {
return (
-
+
{content}
)
}
return (
-
+
{createShorthand(CardHeader, (val) => ({ content: val }), header, { autoGenerateKey: false })}
{createShorthand(CardMeta, (val) => ({ content: val }), meta, { autoGenerateKey: false })}
{createShorthand(CardDescription, (val) => ({ content: val }), description, {
@@ -51,8 +51,9 @@ function CardContent(props) {
})}
)
-}
+})
+CardContent.displayName = 'CardContent'
CardContent.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
diff --git a/src/views/Card/CardDescription.js b/src/views/Card/CardDescription.js
index 1edc971632..49352e62f7 100644
--- a/src/views/Card/CardDescription.js
+++ b/src/views/Card/CardDescription.js
@@ -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 (
-
+
{childrenUtils.isNil(children) ? content : children}
)
-}
+})
+CardDescription.displayName = 'CardDescription'
CardDescription.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
diff --git a/src/views/Card/CardGroup.js b/src/views/Card/CardGroup.js
index 9402b13da0..276aa27056 100644
--- a/src/views/Card/CardGroup.js
+++ b/src/views/Card/CardGroup.js
@@ -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,
@@ -46,14 +46,14 @@ function CardGroup(props) {
if (!childrenUtils.isNil(children)) {
return (
-
+
{children}
)
}
if (!childrenUtils.isNil(content)) {
return (
-
+
{content}
)
@@ -65,12 +65,13 @@ function CardGroup(props) {
})
return (
-
+
{itemsJSX}
)
-}
+})
+CardGroup.displayName = 'CardGroup'
CardGroup.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
diff --git a/src/views/Card/CardHeader.js b/src/views/Card/CardHeader.js
index abf740da70..9dd0e16d31 100644
--- a/src/views/Card/CardHeader.js
+++ b/src/views/Card/CardHeader.js
@@ -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 (
-
+
{childrenUtils.isNil(children) ? content : children}
)
-}
+})
+CardHeader.displayName = 'CardHeader'
CardHeader.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
diff --git a/src/views/Card/CardMeta.js b/src/views/Card/CardMeta.js
index 20b0ebd9bd..ac1377d220 100644
--- a/src/views/Card/CardMeta.js
+++ b/src/views/Card/CardMeta.js
@@ -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 (
-
+
{childrenUtils.isNil(children) ? content : children}
)
-}
+})
+CardMeta.displayName = 'CardMeta'
CardMeta.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
diff --git a/test/specs/views/Card/Card-test.js b/test/specs/views/Card/Card-test.js
index 2b4f14de10..fcc12c1aca 100644
--- a/test/specs/views/Card/Card-test.js
+++ b/test/specs/views/Card/Card-test.js
@@ -13,6 +13,11 @@ import { sandbox } from 'test/utils'
describe('Card', () => {
common.isConformant(Card)
+
+ common.forwardsRef(Card)
+ common.forwardsRef(Card, { requiredProps: { children: } })
+ common.forwardsRef(Card, { requiredProps: { content: faker.lorem.word() } })
+
common.hasSubcomponents(Card, [CardContent, CardDescription, CardGroup, CardHeader, CardMeta])
common.hasUIClassName(Card)
common.rendersChildren(Card)
diff --git a/test/specs/views/Card/CardContent-test.js b/test/specs/views/Card/CardContent-test.js
index 94ccbdc66b..c58e562ca6 100644
--- a/test/specs/views/Card/CardContent-test.js
+++ b/test/specs/views/Card/CardContent-test.js
@@ -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'
@@ -9,6 +11,9 @@ import * as common from 'test/specs/commonTests'
describe('CardContent', () => {
common.isConformant(CardContent)
+ common.forwardsRef(CardContent)
+ common.forwardsRef(CardContent, { requiredProps: { children: } })
+ common.forwardsRef(CardContent, { requiredProps: { content: faker.lorem.word() } })
common.rendersChildren(CardContent)
common.implementsShorthandProp(CardContent, {
diff --git a/test/specs/views/Card/CardDescription-test.js b/test/specs/views/Card/CardDescription-test.js
index 4a2b1ca386..9929a6c7a8 100644
--- a/test/specs/views/Card/CardDescription-test.js
+++ b/test/specs/views/Card/CardDescription-test.js
@@ -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'))
})
diff --git a/test/specs/views/Card/CardGroup-test.js b/test/specs/views/Card/CardGroup-test.js
index fd114d491b..01cff4137b 100644
--- a/test/specs/views/Card/CardGroup-test.js
+++ b/test/specs/views/Card/CardGroup-test.js
@@ -8,6 +8,11 @@ import * as common from 'test/specs/commonTests'
describe('CardGroup', () => {
common.isConformant(CardGroup)
+
+ common.forwardsRef(CardGroup)
+ common.forwardsRef(CardGroup, { requiredProps: { children: } })
+ common.forwardsRef(CardGroup, { requiredProps: { content: faker.lorem.word() } })
+
common.hasUIClassName(CardGroup)
common.rendersChildren(CardGroup)
diff --git a/test/specs/views/Card/CardHeader-test.js b/test/specs/views/Card/CardHeader-test.js
index f39aa80566..45655f99a6 100644
--- a/test/specs/views/Card/CardHeader-test.js
+++ b/test/specs/views/Card/CardHeader-test.js
@@ -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'))
diff --git a/test/specs/views/Card/CardMeta-test.js b/test/specs/views/Card/CardMeta-test.js
index 221a82fa3d..834e6df494 100644
--- a/test/specs/views/Card/CardMeta-test.js
+++ b/test/specs/views/Card/CardMeta-test.js
@@ -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'))