Skip to content
This repository has been archived by the owner on Aug 21, 2023. It is now read-only.

Commit

Permalink
Card: Enhance with flex and scrollable styles + features
Browse files Browse the repository at this point in the history
In this update, the `Card` and `Card.Block` components have been enhanced with the `flex` prop, which enable flexbox styling. `Card.Block` also receives a `scrollable` prop, which enables a more seamless integration with the `Scrollable` compnent.
  • Loading branch information
ItsJonQ committed Sep 13, 2017
1 parent 2ba1ab7 commit 81446a3
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 13 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 32 additions & 2 deletions src/components/Card/Block.js
@@ -1,27 +1,57 @@
import React from 'react'
import PropTypes from 'prop-types'
import classNames from '../../utilities/classNames'
import Scrollable from '../Scrollable'
import { standardSizeTypes } from '../../constants/propTypes'

export const propTypes = {
bgMuted: PropTypes.bool,
className: PropTypes.string,
scrollable: PropTypes.bool,
flex: PropTypes.bool,
size: standardSizeTypes
}

const Block = props => {
const { className, children, size, ...rest } = props
const {
bgMuted,
className,
children,
scrollable,
flex,
size,
...rest
} = props

const componentClassName = classNames(
'c-card__block',
bgMuted && 'is-bg-muted',
flex && 'is-flex',
scrollable && 'is-scrollable',
size && `c-card__block--${size}`,
className
)

return (
const scrollableClassName = classNames(
'c-card__block',
'c-card__block--scrollable',
flex && 'is-flex',
scrollable && 'is-scrollable'
)

const blockMarkup = scrollable ? (
<Scrollable className={scrollableClassName}>
<div className={componentClassName} {...rest}>
{children}
</div>
</Scrollable>
) : (
<div className={componentClassName} {...rest}>
{children}
</div>
)

return blockMarkup
}

Block.propTypes = propTypes
Expand Down
5 changes: 5 additions & 0 deletions src/components/Card/README.md
Expand Up @@ -15,10 +15,12 @@ A Card component is used to encapsulate pieces of UI that share a common concept

| Prop | Type | Description |
| --- | --- | --- |
| borderless | boolean | Removes the border from the component. |
| onBlur | function | Callback when the component is blurred. |
| onClick | boolean or function | Callback when the component is clicked. |
| onFocus | function | Callback when the component is focused. |
| className | string | Custom class names to be added to the component. |
| flex | boolean | Adds flexbox styles to the component. |
| hover | boolean | Adds a hover style to the component. |
| href | string | Adds an `href` to the component. Transforms it into an `<a>` tag. |
| seamless | boolean | Removes the padding within the component. |
Expand Down Expand Up @@ -51,5 +53,8 @@ Note: It is highly recommended the `seamless` prop is used for the container `<C

| Prop | Type | Description |
| --- | --- | --- |
| bgMuted | boolean | Applies a muted background to the component. |
| className | string | Custom class names to be added to the component. |
| flex | boolean | Adds flexbox styles to the component. |
| scrollable | boolean | Integrates [Scrollable](../Scrollable) into the component. |
| size | string | Adjusts the size of the component. Default is `md`. |
6 changes: 6 additions & 0 deletions src/components/Card/index.js
Expand Up @@ -6,7 +6,9 @@ import { blockSelectorTagTypes } from '../../constants/propTypes'
import Block from './Block'

export const propTypes = {
borderless: PropTypes.bool,
className: PropTypes.string,
flex: PropTypes.bool,
hover: PropTypes.bool,
href: PropTypes.string,
onBlur: PropTypes.func,
Expand All @@ -27,8 +29,10 @@ const defaultProps = {

const Card = props => {
const {
borderless,
className,
children,
flex,
hover,
href,
onClick,
Expand All @@ -41,6 +45,8 @@ const Card = props => {
'c-card',
(onClick || href) && 'is-clickable',
(onClick || hover || href) && 'is-hoverable',
borderless && 'is-borderless',
flex && 'is-flex',
seamless && 'is-seamless',
className
)
Expand Down
44 changes: 44 additions & 0 deletions src/components/Card/tests/Card.Block.test.js
@@ -1,6 +1,7 @@
import React from 'react'
import { mount, shallow } from 'enzyme'
import CardBlock from '../Block'
import Scrollable from '../../Scrollable'

describe('ClassName', () => {
test('Has default className', () => {
Expand Down Expand Up @@ -52,6 +53,37 @@ describe('Click', () => {
})
})

describe('Scrollable', () => {
test('Does not render Scrollable by default', () => {
const wrapper = shallow(<CardBlock />)
const o = wrapper.find(Scrollable)

expect(o.length).toBe(0)
})

test('Renders Scrollable if specified', () => {
const wrapper = mount(<CardBlock scrollable />)
const o = wrapper.find(Scrollable)
const n = wrapper.find('.c-card__block')

expect(o.length).toBe(1)
expect(o.hasClass('c-card__block')).toBeTruthy()
expect(o.hasClass('is-scrollable')).toBeTruthy()
expect(n.length).toBe(2)

wrapper.unmount()
})

test('Renders Scrollable with flex if specified', () => {
const wrapper = shallow(<CardBlock scrollable flex />)
const o = wrapper.find(Scrollable)

expect(o.length).toBe(1)
expect(o.hasClass('is-scrollable')).toBeTruthy()
expect(o.hasClass('is-flex')).toBeTruthy()
})
})

describe('Styles', () => {
test('Does not have a size modifier style by default', () => {
const wrapper = shallow(<CardBlock />)
Expand All @@ -67,4 +99,16 @@ describe('Styles', () => {

expect(wrapper.prop('className')).toContain('c-card__block--sm')
})

test('Renders bgMuted styles, if specified', () => {
const wrapper = shallow(<CardBlock bgMuted />)

expect(wrapper.hasClass('is-bg-muted')).toBeTruthy()
})

test('Renders flex styles, if specified', () => {
const wrapper = shallow(<CardBlock flex />)

expect(wrapper.hasClass('is-flex')).toBeTruthy()
})
})
14 changes: 13 additions & 1 deletion src/components/Card/tests/Card.test.js
Expand Up @@ -92,9 +92,21 @@ describe('Selector', () => {
})

describe('Styles', () => {
test('Renders borderless styles, if specified', () => {
const wrapper = shallow(<Card borderless />)

expect(wrapper.hasClass('is-borderless')).toBeTruthy()
})

test('Renders flex styles, if specified', () => {
const wrapper = shallow(<Card flex />)

expect(wrapper.hasClass('is-flex')).toBeTruthy()
})

test('Renders seamless styles, if specified', () => {
const wrapper = shallow(<Card seamless />)

expect(wrapper.prop('className')).toContain('is-seamless')
expect(wrapper.hasClass('is-seamless')).toBeTruthy()
})
})
7 changes: 5 additions & 2 deletions src/components/index.js
Expand Up @@ -7,18 +7,21 @@ export { default as Card } from './Card'
export { default as Checkbox } from './Checkbox'
export { default as Choice } from './Choice'
export { default as ChoiceGroup } from './ChoiceGroup'
export { default as CloseButton } from './CloseButton'
export { default as EventListener } from './EventListener'
export { default as Flexy } from './Flexy'
export { default as FormGroup } from './FormGroup'
export { default as Grid } from './Grid'
export { default as Heading } from './Heading'
export { default as HelpText } from './HelpText'
export { default as Flexy } from './Flexy'
export { default as Icon } from './Icon'
export { default as Image } from './Image'
export { default as Modal } from './Modal'
export { default as Input } from './Input'
export { default as KeypressListener } from './KeypressListener'
export { default as Label } from './Label'
export { default as Link } from './Link'
export { default as LoadingDots } from './LoadingDots'
export { default as Modal } from './Modal'
export { default as Overlay } from './Overlay'
export { default as Portal } from './Portal'
export { default as PortalWrapper } from './PortalWrapper'
Expand Down
@@ -1,11 +1,10 @@
@import "../configs/_color";
$seed-card-namespace: "c-card";
@import "../../configs/_color";
$seed-card-border: 1px solid rgba(_color(border, ui, dark), 0.7);
// Import Seed Pack
@import "pack/seed-card/_index";

.c-card {
@import "../resets/base";
@import "../../resets/base";
box-shadow: #{
0 0 0 0 rgba(black, 0)
};
Expand All @@ -15,10 +14,21 @@ $seed-card-border: 1px solid rgba(_color(border, ui, dark), 0.7);
text-decoration: none;

// Modifiers
&.is-borderless {
border: none;
}

&.is-clickable {
cursor: pointer;
}

&.is-flex {
display: flex;
flex-direction: column;
min-height: 0;
width: 100%;
}

&.is-hoverable {
box-shadow: #{
0 1px 3px 0 rgba(black, 0.1),
Expand All @@ -35,5 +45,5 @@ $seed-card-border: 1px solid rgba(_color(border, ui, dark), 0.7);

&.is-seamless {
padding: 0;
}
}
}
20 changes: 20 additions & 0 deletions src/styles/components/Card/CardBlock.scss
@@ -0,0 +1,20 @@
@import "../../configs/color";

.c-card__block {
@import "../../resets/base";

// Modifiers
&--scrollable {
padding: 0;
min-height: 0;
max-height: 100%;
}

&.is-bg-muted {
background-color: _color(grey, 200);
}

&.is-flex {
flex: 1;
}
}
2 changes: 2 additions & 0 deletions src/styles/components/Card/__index.scss
@@ -0,0 +1,2 @@
@import "./Card";
@import "./CardBlock";
2 changes: 1 addition & 1 deletion src/styles/components/__index.scss
Expand Up @@ -3,7 +3,7 @@
@import "./AvatarStack";
@import "./Badge";
@import "./Button";
@import "./Card";
@import "./Card/_index";
@import "./Checkbox";
@import "./Choice/_index";
@import "./CloseButton";
Expand Down
2 changes: 1 addition & 1 deletion src/styles/components/__slim.scss
Expand Up @@ -5,7 +5,7 @@
@import "./AvatarStack";
@import "./Badge";
// @import "./Button";
@import "./Card";
@import "./Card/_index";
@import "./Checkbox";
@import "./Choice/_index";
@import "./CloseButton";
Expand Down
6 changes: 6 additions & 0 deletions src/tests/index.test.js
Expand Up @@ -8,13 +8,16 @@ import {
Checkbox,
Choice,
ChoiceGroup,
CloseButton,
EventListener,
Flexy,
FormGroup,
Grid,
Heading,
Icon,
Image,
Input,
KeypressListener,
Label,
Link,
LoadingDots,
Expand All @@ -40,13 +43,16 @@ const components = [
Checkbox,
Choice,
ChoiceGroup,
CloseButton,
EventListener,
Flexy,
FormGroup,
Grid,
Heading,
Icon,
Image,
Input,
KeypressListener,
Label,
Link,
LoadingDots,
Expand Down
32 changes: 31 additions & 1 deletion stories/Card.js
@@ -1,6 +1,6 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import { Card } from '../src/index.js'
import { Card, Heading } from '../src/index.js'

storiesOf('Card', module)
.add('default', () => <Card>Hello</Card>)
Expand All @@ -12,3 +12,33 @@ storiesOf('Card', module)
<Card.Block>Block Three</Card.Block>
</Card>
))
.add('scrollable', () => (
<Card seamless flex style={{ height: '100vh' }}>
<Card.Block>
<Heading>Elf: Synopsis</Heading>
</Card.Block>
<Card.Block bgMuted scrollable flex>
<p>
On Christmas Eve in 1973, an infant boy stows away in Santa Claus' sack. When discovered back at the North Pole, he is adopted by Papa Elf. Papa Elf names his son Buddy.</p>

<p>
Buddy grows up at the North Pole believing he is an elf, but due to his human size he is unable to perform elf tasks. When Buddy accidentally learns that he is human, Papa Elf explains that he was born to Walter Hobbs and Susan Wells, and was given up for adoption without Walter knowing. Susan died and Walter works at a children's book publisher in New York City at the Empire State Building. Santa notes that Walter is on the naughty list due to his greed and selfishness, but suggests Buddy could help redeem him, and so Buddy travels alone to New York.</p>

<p>
Buddy has trouble acclimating to the customs of the human world. Buddy finds his father's office, but Walter has him ejected after Buddy mentions Susan Wells. After following a security guard's sarcastic suggestion to go "back to Gimbels" due to his elf outfit, the Gimbels' manager mistakes him for an employee at Santa Land. He meets Jovie, an unenthused employee to whom he is attracted. Knowing that Santa will arrive the next day, Buddy stays behind and spends the night decorating Santa Land, and buys a nightie for Walter.</p>

<p>
The next day, Buddy is appalled that the store's Santa is not real and rips off the man's fake beard, causing them to fight, with the manager having to subdue the fake Santa. Walter bails Buddy out of prison and takes him to Dr. Leonardo for a DNA test, which confirms that Buddy is Walter's son. The doctor convinces him to take Buddy home to meet his step-mother Emily and 11-year-old half-brother Michael. Walter and Michael are annoyed by Buddy's childlike behavior, but Emily insists that they take care of him until he "recovers".</p>

<p>
Buddy wins Michael over by helping him defeat a gang of bullies in a snowball fight and Michael encourages Buddy to ask Jovie out. Walter learns from his boss Fulton Greenway that his company is in financial trouble after publishing a failed children's book, and organizes a book pitch for Christmas Eve, for which Walter and his associates Eugene and Morris arrange a meeting with best-selling children's author Miles Finch to hire him.</p>

<p>
One night, Buddy goes on a date with Jovie and wins her over. On Christmas Eve, Buddy bursts into Walter's office during a meeting with Finch to tell Walter about his love, and mistakes Finch, who has dwarfism for an elf. Finch loses his temper and attacks Buddy before storming out, causing Walter to harshly disown Buddy.</p>

<p>
Eugene and Morris find a notebook Finch left that is filled with ideas for children's books. Walter pitches these ideas to Greenway, but Michael bursts in to tell Walter that Buddy ran away. Greenway refuses to reschedule; Walter quits his job and leaves to find Buddy.</p>
</Card.Block>
<Card.Block>Block Three</Card.Block>
</Card>
))

0 comments on commit 81446a3

Please sign in to comment.