Skip to content
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
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