-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add Card component * feat: rework Card internals and add more stories * feat: add additional spacing options, docs * test: add test for Card * chore: add additional exports to index * feat: card dividers as individual section props * chore: take out the confusing header suffix option
- Loading branch information
1 parent
f20eb57
commit 0fe438f
Showing
6 changed files
with
511 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
.card { | ||
/* Component Variables */ | ||
--card-spacing-base: var(--bloom-s6); | ||
--card-spacing-sm: var(--bloom-s4); | ||
--card-spacing-md: var(--bloom-s8); | ||
--card-spacing-lg: var(--bloom-s12); | ||
|
||
--card-spacing: var(--card-spacing-base); | ||
|
||
--card-background-color: var(--bloom-color-white); | ||
--card-border-radius: var(--bloom-rounded-lg); | ||
--card-border-width: var(--bloom-border-1); | ||
--card-border-color: var(--bloom-color-gray-450); | ||
--card-divider-width: var(--card-border-width); | ||
--card-divider-color: var(--card-border-color); | ||
|
||
--card-content-padding-block: var(--card-spacing); | ||
--card-content-padding-inline-desktop: var(--card-content-padding-block); | ||
--card-content-padding-inline-mobile: var(--card-content-padding-block); | ||
|
||
--card-header-padding-block: var(--card-spacing); | ||
--card-header-padding-inline-desktop: var(--card-header-padding-block); | ||
--card-header-padding-inline-mobile: var(--card-header-padding-block); | ||
|
||
--card-footer-background-color: var(--card-background-color); | ||
|
||
/* Responsive Settings */ | ||
|
||
--card-header-padding-inline: var(--card-header-padding-inline-desktop); | ||
--card-content-padding-inline: var(--card-content-padding-inline-desktop); | ||
|
||
@media (max-width: 640px) { /* small screen */ | ||
--card-header-padding-inline: var(--card-header-padding-inline-mobile); | ||
--card-content-padding-inline: var(--card-content-padding-inline-mobile); | ||
} | ||
|
||
/* Default Styles */ | ||
background-color: var(--card-background-color); | ||
border: var(--card-border-width) solid var(--card-border-color); | ||
overflow: hidden; | ||
border-radius: var(--card-border-radius); | ||
display: flex; | ||
flex-direction: column; | ||
|
||
&[data-spacing="sm"] { | ||
--card-spacing: var(--card-spacing-sm); | ||
} | ||
|
||
&[data-spacing="md"] { | ||
--card-spacing: var(--card-spacing-md); | ||
} | ||
|
||
&[data-spacing="lg"] { | ||
--card-spacing: var(--card-spacing-lg); | ||
} | ||
|
||
&[data-spacing="none"] { | ||
--card-spacing: 0rem; | ||
} | ||
} | ||
|
||
.card-header { | ||
padding-block-start: var(--card-header-padding-block); | ||
padding-inline: var(--card-header-padding-inline); | ||
|
||
&[data-divider="flush"] { | ||
padding-block-end: var(--card-header-padding-block); | ||
border-bottom: var(--card-divider-width) solid var(--card-divider-color); | ||
} | ||
|
||
&[data-divider="inset"] { | ||
padding-inline: 0; | ||
margin-inline: var(--card-header-padding-inline); | ||
padding-block-end: var(--card-header-padding-block); | ||
border-bottom: var(--card-divider-width) solid var(--card-divider-color); | ||
} | ||
} | ||
|
||
.card-section { | ||
padding-block-start: var(--card-content-padding-block); | ||
padding-inline: var(--card-content-padding-inline); | ||
|
||
&[data-divider="flush"] { | ||
padding-block-end: var(--card-content-padding-block); | ||
border-bottom: var(--card-divider-width) solid var(--card-divider-color); | ||
|
||
&:last-of-type { | ||
border-bottom: none; | ||
} | ||
} | ||
|
||
&[data-divider="inset"] { | ||
padding-inline: 0; | ||
margin-inline: var(--card-content-padding-inline); | ||
padding-block-end: var(--card-content-padding-block); | ||
border-bottom: var(--card-divider-width) solid var(--card-divider-color); | ||
|
||
&:last-of-type { | ||
border-bottom: none; | ||
} | ||
} | ||
|
||
> *:first-child { | ||
margin-block-start: 0; | ||
} | ||
|
||
> *:last-child { | ||
margin-block-end: 0; | ||
} | ||
} | ||
|
||
.card-section:not([data-divider]):last-child { | ||
padding-block-end: var(--card-content-padding-block); | ||
} | ||
|
||
.card-header, | ||
.card-footer { | ||
> * { | ||
margin-block: 0; | ||
} | ||
|
||
> * { | ||
margin-block: 0; | ||
} | ||
} | ||
|
||
.card-footer { | ||
background-color: var(--card-footer-background-color); | ||
|
||
&:not([data-divider]):first-of-type { | ||
margin-block-start: var(--card-content-padding-block); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import React from "react" | ||
import "./Card.scss" | ||
|
||
export interface CardHeaderProps { | ||
/** Add divider between this and the next element */ | ||
divider?: "flush" | "inset" | ||
/** Element ID */ | ||
id?: string | ||
/** Additional class name */ | ||
className?: string | ||
children: React.ReactNode | ||
} | ||
|
||
const CardHeader = (props: CardHeaderProps) => { | ||
const classNames = ["card-header"] | ||
if (props.className) classNames.push(props.className) | ||
|
||
return ( | ||
<header id={props.id} className={classNames.join(" ")} data-divider={props.divider}> | ||
{props.children} | ||
</header> | ||
) | ||
} | ||
|
||
export interface CardSectionProps { | ||
/** Add divider between this and the next element */ | ||
divider?: "flush" | "inset" | ||
/** Element ID */ | ||
id?: string | ||
/** Additional class name */ | ||
className?: string | ||
children: React.ReactNode | ||
} | ||
|
||
const CardSection = (props: CardSectionProps) => { | ||
const classNames = ["card-section"] | ||
if (props.className) classNames.push(props.className) | ||
|
||
return ( | ||
<div id={props.id} className={classNames.join(" ")} data-divider={props.divider}> | ||
{props.children} | ||
</div> | ||
) | ||
} | ||
|
||
export interface CardFooterProps { | ||
/** Add divider between this and the next element */ | ||
divider?: "flush" | "inset" | ||
/** Element ID */ | ||
id?: string | ||
/** Additional class name */ | ||
className?: string | ||
children: React.ReactNode | ||
} | ||
|
||
const CardFooter = (props: CardFooterProps) => { | ||
const classNames = ["card-footer"] | ||
if (props.className) classNames.push(props.className) | ||
|
||
return ( | ||
<footer id={props.id} className={classNames.join(" ")} data-divider={props.divider}> | ||
{props.children} | ||
</footer> | ||
) | ||
} | ||
|
||
export interface CardProps { | ||
/** Control spacing around card elements | ||
* @default base | ||
*/ | ||
spacing?: "sm" | "base" | "md" | "lg" | "none" | ||
/** Element ID */ | ||
id?: string | ||
/** Additional class name */ | ||
className?: string | ||
children: React.ReactNode | ||
} | ||
|
||
const Card = (props: CardProps) => { | ||
const classNames = ["card"] | ||
const spacing = props.spacing || "base" | ||
if (props.className) classNames.push(props.className) | ||
|
||
return ( | ||
<article id={props.id} className={classNames.join(" ")} data-spacing={spacing}> | ||
{props.children} | ||
</article> | ||
) | ||
} | ||
|
||
Card.Header = CardHeader | ||
Card.Section = CardSection | ||
Card.Footer = CardFooter | ||
|
||
export { Card as default, CardHeader, CardSection, CardFooter } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { ArgsTable } from "@storybook/addon-docs" | ||
import Card from "../Card" | ||
import { Swatch } from "../../../documentation/components/Swatch.tsx" | ||
|
||
# <Card /> | ||
|
||
## Properties | ||
|
||
<ArgsTable of={Card} /> | ||
|
||
## Card Header Properties | ||
|
||
<ArgsTable of={Card.Header} /> | ||
|
||
## Card Section Properties | ||
|
||
<ArgsTable of={Card.Section} /> | ||
|
||
## Card Footer Properties | ||
|
||
<ArgsTable of={Card.Footer} /> | ||
|
||
## Theme Variables | ||
|
||
| Name | Description | Default | | ||
| --------------------------------------- | -------------------------------------------------------------------- | ------------------------- | | ||
| `--card-spacing-base` | Default spacing around card elements | `--bloom-s6` | | ||
| `--card-spacing-sm` | Small card spacing | `--bloom-s4` | | ||
| `--card-spacing-md` | Medium card spacing | `--bloom-s8` | | ||
| `--card-spacing-lg` | Large card spacing | `--bloom-s12` | | ||
| `--card-background-color` | Background of the card | `--bloom-color-white` | | ||
| `--card-border-radius` | Card corner radius | `--bloom-rounded-lg` | | ||
| `--card-border-width` | Border width | `--bloom-border-1` | | ||
| `--card-border-color` | <Swatch color="bloom-color-gray-450" /> Border color | `--bloom-color-gray-450` | | ||
| `--card-divider-width` | Width of intra-card dividers | `--card-border-width` | | ||
| `--card-divider-color` | <Swatch color="bloom-color-gray-450" /> Color of intra-card dividers | `--card-border-color` | | ||
| `--card-footer-background-color` | Background of the footer | `--card-background-color` | | ||
| `--card-content-padding-block` | Vertical padding between elements | (card spacing) | | ||
| `--card-content-padding-inline-desktop` | Horizontal padding | (card spacing) | | ||
| `--card-content-padding-inline-mobile` | Horizontal padding on mobile | (card spacing) | | ||
| `--card-header-padding-block` | Vertical padding within the header | (card spacing) | | ||
| `--card-header-padding-inline-desktop` | Horizontal padding within the header | (card spacing) | | ||
| `--card-header-padding-inline-mobile` | Horizontal padding within the header | (card spacing) | |
Oops, something went wrong.