Repository: hackclub/design-system
Branch: master
Commit: 0a4ced2b81a8
Files: 130
Total size: 165.5 KB
Directory structure:
gitextract_7404ezv9/
├── .babelrc
├── .gitignore
├── .npmignore
├── .storybook/
│ ├── .babelrc
│ ├── AAA.js
│ ├── Avatar.js
│ ├── BackgroundImage.js
│ ├── Badge.js
│ ├── BlockLink.js
│ ├── Box.js
│ ├── Button.js
│ ├── Card.js
│ ├── Colors.js
│ ├── Container.js
│ ├── Field.js
│ ├── Flex.js
│ ├── Heading.js
│ ├── Hide.js
│ ├── Icon.js
│ ├── IconButton.js
│ ├── Image.js
│ ├── Input.js
│ ├── Label.js
│ ├── LargeButton.js
│ ├── Layouts.js
│ ├── Link.js
│ ├── Loading.js
│ ├── OutlineButton.js
│ ├── Section.js
│ ├── Sheet.js
│ ├── Slider.js
│ ├── Submit.js
│ ├── Text.js
│ └── config.js
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── docs/
│ ├── Contributing.md
│ ├── GettingStarted.md
│ ├── README.md
│ ├── Theme.md
│ └── ThemeProvider.md
├── package.json
├── src/
│ ├── Avatar.js
│ ├── BackgroundImage.js
│ ├── Badge.js
│ ├── BlockLink.js
│ ├── Box.js
│ ├── Button.js
│ ├── Card.js
│ ├── Container.js
│ ├── Field.js
│ ├── Flex.js
│ ├── Heading.js
│ ├── Hide.js
│ ├── Icon.js
│ ├── IconButton.js
│ ├── Image.js
│ ├── Input.js
│ ├── Label.js
│ ├── LargeButton.js
│ ├── Link.js
│ ├── Loading.js
│ ├── OutlineButton.js
│ ├── Section.js
│ ├── Sheet.js
│ ├── Slider.js
│ ├── Submit.js
│ ├── Text.js
│ ├── ThemeProvider.js
│ ├── __tests__/
│ │ ├── Avatar.js
│ │ ├── BackgroundImage.js
│ │ ├── Badge.js
│ │ ├── BlockLink.js
│ │ ├── Box.js
│ │ ├── Button.js
│ │ ├── Card.js
│ │ ├── Container.js
│ │ ├── Field.js
│ │ ├── Flex.js
│ │ ├── Heading.js
│ │ ├── Hide.js
│ │ ├── Icon.js
│ │ ├── IconButton.js
│ │ ├── Image.js
│ │ ├── Input.js
│ │ ├── Label.js
│ │ ├── LargeButton.js
│ │ ├── Link.js
│ │ ├── Loading.js
│ │ ├── OutlineButton.js
│ │ ├── Section.js
│ │ ├── Sheet.js
│ │ ├── Slider.js
│ │ ├── Submit.js
│ │ ├── Text.js
│ │ ├── ThemeProvider.js
│ │ ├── __snapshots__/
│ │ │ ├── Avatar.js.snap
│ │ │ ├── BackgroundImage.js.snap
│ │ │ ├── Badge.js.snap
│ │ │ ├── BlockLink.js.snap
│ │ │ ├── Box.js.snap
│ │ │ ├── Button.js.snap
│ │ │ ├── Card.js.snap
│ │ │ ├── Container.js.snap
│ │ │ ├── Field.js.snap
│ │ │ ├── Flex.js.snap
│ │ │ ├── Heading.js.snap
│ │ │ ├── Hide.js.snap
│ │ │ ├── Icon.js.snap
│ │ │ ├── IconButton.js.snap
│ │ │ ├── Image.js.snap
│ │ │ ├── Input.js.snap
│ │ │ ├── Label.js.snap
│ │ │ ├── LargeButton.js.snap
│ │ │ ├── Link.js.snap
│ │ │ ├── Loading.js.snap
│ │ │ ├── OutlineButton.js.snap
│ │ │ ├── Section.js.snap
│ │ │ ├── Sheet.js.snap
│ │ │ ├── Slider.js.snap
│ │ │ ├── Submit.js.snap
│ │ │ ├── Text.js.snap
│ │ │ ├── ThemeProvider.js.snap
│ │ │ └── theme.js.snap
│ │ └── theme.js
│ ├── index.js
│ └── theme.js
└── test-setup.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .babelrc
================================================
{
"presets": ["@babel/env", "@babel/preset-react"]
}
================================================
FILE: .gitignore
================================================
node_modules
npm-debug.log
coverage
dist
.site
.DS_Store
================================================
FILE: .npmignore
================================================
src
storybook
docs
test
================================================
FILE: .storybook/.babelrc
================================================
{ "presets": ["@babel/preset-env", "@babel/preset-react"] }
================================================
FILE: .storybook/AAA.js
================================================
import React, { Fragment } from 'react'
import { storiesOf } from '@storybook/react'
import { Box, Flex, Heading, Text, Link, Button, Avatar } from '../src'
import styled from 'styled-components'
const List = Box.withComponent('ul')
const Item = Text.withComponent('li')
const Code = Text.withComponent('pre')
const Flag = styled(Link)`
display: inline-block;
background: url(//hackclub.com/orpheus_flag.svg) no-repeat;
background-position: top center;
width: 8rem;
height: 3rem;
z-index: 0;
margin-top: -1rem;
`
storiesOf('👋 Welcome!', module).add('About the project', () => (
Welcome!
This is{' '}
’s Design System.
It’s a collection of React components designed to:
- Speed up design and development velocity
-
Help create consistent, beautiful, and usable UI in our various websites
-
Promote best practices for accessibility and responsive web design
We hope to accomplish these goals by:
- Reducing the number of decisions needed when iterating on UI
- Reducing the amount of code duplication in our apps
- Serving as the standard for hackclub.com’s visual language
-
Providing easy-to-use and extensible components for anyone to consume
yarn add @hackclub/design-system
- @lachlanjc
))
================================================
FILE: .storybook/Avatar.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Avatar } from '../src'
storiesOf('Avatar', module)
.add(
'Avatar component',
withInfo({
inline: true,
text: 'A circular avatar image primitive.'
})(() => )
)
.add('Team', () => (
<>
{['zach', 'max', 'lachlan', 'mingjie', 'athul'].map(key => (
))}
>
))
================================================
FILE: .storybook/BackgroundImage.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { BackgroundImage, Box, Text, Flex } from '../src'
const props = {
src:
'https://images.unsplash.com/photo-1416339684178-3a239570f315?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max',
'aria-label': 'Wooden desk with tools and chair'
}
storiesOf('BackgroundImage', module)
.add(
'BackgroundImage component',
withInfo({
inline: true,
text: 'A extension for adding a CSS background-image.'
})(() => (
Hello
))
)
.add('Fixed height', () => (
Height
))
.add('Responsive', () => (
Hello
))
.add('Scale', () => (
Hover
))
================================================
FILE: .storybook/Badge.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Badge } from '../src'
storiesOf('Badge', module)
.add(
'Badge component',
withInfo({
inline: true,
text: 'Use the component to render a primitive badge.'
})(() => badge )
)
.add('All colors', () => (
{[
'primary',
'accent',
'error',
'warning',
'success',
'info',
'muted'
].map(key => (
))}
))
================================================
FILE: .storybook/BlockLink.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { BlockLink, BackgroundImage, Box, Text } from '../src'
storiesOf('BlockLink', module).add(
'BlockLink',
withInfo({
inline: true,
text: ` is a styled-components wrapper of component to remove text-decoration and color styles, and set display as block.`
})(() => (
Click to open hackclub.com in a new tab!
))
)
================================================
FILE: .storybook/Box.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Box } from '../src'
storiesOf('Box', module)
.add(
'Layout component',
withInfo({
text:
'A low-level layout component for setting width, margin, padding, and color',
inline: true
})(() => Hello )
)
.add('Padding', () => Hello )
.add('Margin', () => Hello )
.add('Color', () => (
Hello
))
.add('Background Color', () => (
Hello
))
.add('Width', () => (
Half Width
))
.add('Pixel Width', () => (
256px width
))
.add('VW Width', () => (
50vw width
))
.add('Directional Padding', () => (
Padding Top
Padding Right
Padding Bottom
Padding Left
Padding X-Axis
Padding Y-Axis
))
.add('Directional Margin', () => (
Margin Top
Margin Right
Margin Bottom
Margin Left
Margin X-Axis
Margin Y-Axis
))
================================================
FILE: .storybook/Button.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Button, Flex } from '../src'
storiesOf('Button', module)
.add(
'Button component',
withInfo({
inline: true,
text: 'Use the component to render a primitive button.'
})(() => Button )
)
.add('Colors', () => (
Button
Accent
Success
Inverted
))
.add('Font size', () => (
Size 1
Size 2
Size 3
Size 4
))
.add('Width', () => Full Width )
.add('Disabled', () => Disabled )
.add('Scale', () => Scale )
.add('Chevrons', () => (
Back
Forward
))
================================================
FILE: .storybook/Card.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Card } from '../src'
storiesOf('Card', module)
.add(
'Card component',
withInfo({
inline: true,
text: 'Box extension to control box-shadow.'
})(() => (
Small Shadow
Medium Shadow
Large Shadow
XLarge Shadow
))
)
.add('Box Shadows with custom borders', () => (
Small Shadow
Medium Shadow
Large Shadow
XLarge Shadow
))
.add('Box Shadows with varying border radii', () => (
Small Shadow
Medium Shadow
Large Shadow
XLarge Shadow
))
================================================
FILE: .storybook/Colors.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import styled from 'styled-components'
import { Box, Flex, Text, Heading, theme } from '../src'
const keys = Object.keys(theme.colors).filter(
key => !Array.isArray(theme.colors[key])
)
const next = keys.map(key => ({ key, value: theme.colors[key] }))
const Chip = props =>
const Pre = styled(Text.withComponent('pre'))`
font-family: ${theme.mono};
`
const Card = ({ name, color }) => (
{name}
{color}
)
storiesOf('Color', module).add('Palette', () => (
Color Palette
{next.map(
color =>
!color.key[color.key.length - 1].match(/^\d+$/) ? (
) : null
)}
))
================================================
FILE: .storybook/Container.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Container } from '../src'
storiesOf('Container', module)
.add(
'Container component',
withInfo({
inline: true,
text:
' to constrain the width of content and center it. Uses theme.maxContainerWidth if no maxWidth is provided'
})(() => (
Container Component
))
)
.add('Custom maxWidth', () => (
32rem-width Container
))
================================================
FILE: .storybook/Field.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Field } from '../src'
storiesOf('Field', module)
.add(
'Field component',
withInfo({
inline: true,
text: 'Compound component for form fields.'
})(() => )
)
.add('with error', () => (
))
.add('textarea type', () => (
))
.add('select type', () => (
Two
Four
Eight
Sixteen
Thirty-Two
Sixty-Four
))
================================================
FILE: .storybook/Flex.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { Flex, Box } from '../src'
storiesOf('Flex', module)
.add('Basic', () => (
Flex
Box
))
.add('Wrap', () => (
Flex
Wrap
Wrap
))
.add('Justify', () => (
Flex
Justify
))
.add('Direction', () => (
Flex
Direction
))
================================================
FILE: .storybook/Heading.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Heading } from '../src'
const description =
'A type of the component' +
' using HTML h1-h6 element for setting section headings,' +
' supporting all props.'
storiesOf('Heading', module)
.add(
'Heading component',
withInfo({
inline: true,
text: description
})(() => Heading component (renders h2) )
)
.add('Using dot-notation with h1-h6', () => (
Heading h1
Heading h2 (default)
Heading h3
Heading h4
Heading h5
Heading h6
))
.add('Using props', () => (
Heading Left
Heading Center
Heading Right
))
================================================
FILE: .storybook/Hide.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { Hide, Flex } from '../src'
storiesOf('Hide', module).add('Hide', () => (
Hide xs
Hide sm
Hide md
Hide lg
Hide xl
))
================================================
FILE: .storybook/Icon.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Icon, Flex, LargeButton } from '../src'
storiesOf('Icon', module)
.add(
'Icon component',
withInfo({
inline: true,
text: 'A wrapper component for @hackclub/icons.'
})(() => )
)
.add('Examples', () => (
See all icons
))
================================================
FILE: .storybook/IconButton.js
================================================
import React, { Fragment } from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { IconButton } from '../src'
storiesOf('IconButton', module)
.add(
'IconButton component',
withInfo({
inline: true,
text: 'Use the component to render a primitive button.'
})(() => )
)
.add('Rectangular button', () => (
))
.add('Circular button', () => (
))
.add('Disabled circular buttons', () => (
))
================================================
FILE: .storybook/Image.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Image, Box } from '../src'
const text = 'A low-level layout component that renders an image'
const props = {
src: 'https://hackclub.com/social-photo_2.jpg',
alt: 'Smiling students at a hackathon'
}
storiesOf('Image', module)
.add(
'Image component',
withInfo({
text,
inline: true
})(() => )
)
.add('Responsive width, with Box', () => (
))
================================================
FILE: .storybook/Input.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Box, Input, Label, theme } from '../src'
storiesOf('Input', module)
.add(
'Input component',
withInfo({
inline: true,
text:
'Simple styled input component that accepts a color and optionally, an error message.'
})(() => )
)
.add('With external label', () => (
Label!
))
================================================
FILE: .storybook/Label.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Label, Input } from '../src'
storiesOf('Label', module)
.add(
'Label component',
withInfo({
inline: true,
text:
'Simple styled label component that supports a number of the styled-system props.'
})(() => Label Component )
)
.add('Using fontSize', () => (
Label with fontSize 6
Label with fontSize 5
Label with fontSize 4
Label with fontSize 3
Label with fontSize 2
Label with fontSize 1
Label with fontSize 0
))
.add('Spacing', () => (
A tish of margin
A dash of padding
))
.add('Colors', () => (
A primary label
An accent label
))
.add('htmlFor', () => (
Clicking{' '}
here
{' '}
should focus on the input element.
))
================================================
FILE: .storybook/LargeButton.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { LargeButton } from '../src'
storiesOf('LargeButton', module)
.add(
'LargeButton component',
withInfo({
inline: true,
text: 'A bigger component.'
})(() => Button )
)
.add('Colors', () => (
Button
Accent
Success
Inverted
))
.add('Width', () => Full Width )
.add('Disabled', () => Disabled )
================================================
FILE: .storybook/Layouts.js
================================================
import React from 'react'
import styled from 'styled-components'
import { storiesOf } from '@storybook/react'
import { Flex, Box, Text, Icon, Image, Heading, Card, theme } from '../src'
storiesOf('Layout Examples', module)
.add('Grid', () => (
Hello
Hello
))
.add('Two-column', () => (
Hello
Hello
))
.add('Navbar', () => (
Hello
Navbar
Right Side
))
.add('Tiled Cards', () => (
{cards.map(card => (
))}
))
const Border = styled(Box)`
border: 1px solid ${({ theme }) => theme.colors.smoke};
border-radius: ${({ theme }) => theme.radius};
line-height: 0;
`
const Tile = ({ image, title, text }) => (
{title}
{text}
)
const cards = Array.from({ length: 12 }).map((n, i) => ({
id: i,
title: 'Hello' + i,
text: 'Card',
image: `http://placehold.it/512x256/${theme.colors.accent.replace('#', '')}`
}))
================================================
FILE: .storybook/Link.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Link } from '../src'
storiesOf('Link', module)
.add(
'Link component',
withInfo({
inline: true,
text: ' extension for links.'
})(() => (
Homepage
))
)
.add('Open in same tab', () => (
Open the homepage in same tab
))
.add('Color underline', () => (
I’m extra Hack Club
))
.add('Chevrons', () => (
Explore more
))
================================================
FILE: .storybook/Loading.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Loading } from '../src'
storiesOf('Loading', module).add(
'Loading component',
withInfo({
inline: true,
text: 'An animated loading indicator. Centers itself in parent container.'
})(() => )
)
================================================
FILE: .storybook/OutlineButton.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { OutlineButton, LargeButton } from '../src'
storiesOf('OutlineButton', module)
.add(
'OutlineButton component',
withInfo({
inline: true,
text: 'A component with only an outline.'
})(() => Button )
)
.add('Colors', () => (
Button
Accent
Success
))
.add('Width', () => Full Width )
.add('Disabled', () => Disabled )
================================================
FILE: .storybook/Section.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Section, Heading, Text } from '../src'
storiesOf('Section', module).add(
'Section component',
withInfo({
inline: true,
text:
'A section component meant to be used with a solid/gradient background.'
})(() => (
))
)
================================================
FILE: .storybook/Sheet.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Sheet } from '../src'
storiesOf('Sheet', module).add(
'Sheet component',
withInfo({
inline: true,
text: 'A large, raised container card.'
})(() => (
Hi, I’m a Sheet!
))
)
================================================
FILE: .storybook/Slider.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Slider } from '../src'
storiesOf('Slider', module).add(
'Slider component',
withInfo({
inline: true,
text: 'Range input slider.'
})(() => )
)
================================================
FILE: .storybook/Submit.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Submit } from '../src'
storiesOf('Submit', module).add(
'Submit component',
withInfo({
inline: true,
text: 'A form component for a submit button. Available in two sizes.'
})(() => (
))
)
================================================
FILE: .storybook/Text.js
================================================
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { Text } from '../src'
storiesOf('Text', module)
.add(
'Typography component',
withInfo({
inline: true,
text:
'A low-level component for setting font-size, typographic styles, margin, and color'
})(() => Hello )
)
.add('fontSize', () => (
Hello 6
Hello 5
Hello 4
Hello 3
Hello 2
Hello 1
Hello 0
))
.add('align', () => (
Hello Left
Hello Center
Hello Right
))
.add('regular', () => Hello Regular )
.add('bold', () => Hello Bold )
.add('caps', () => Hello Caps )
.add('maxWidth', () => (
Hello I am some very long text that will be wrapped at 16rem because of my
maxWidth prop!
))
.add('strikethrough', () => Hello Strikethrough )
.add('spacing', () => (
Hello Margin
Hello Padding
))
.add('color', () => (
Hello Primary
Hello Accent
Hello Error
))
================================================
FILE: .storybook/config.js
================================================
import React from 'react'
import { configure, addDecorator } from '@storybook/react'
import { ThemeProvider, Box } from '../src'
addDecorator(story => (
{story()}
))
const req = require.context('.', true, /\.js$/)
const load = () => {
req.keys().forEach(req)
}
configure(load, module)
================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
- 12
after_success:
- npm run storybook
deploy:
provider: pages
skip_cleanup: true
github_token: $GH_TOKEN
local_dir: .site
on:
branch: master
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
If you’d like to contribute to the design system, we’d love to have your help.
Contributing doesn’t necessarily mean committing code, we also encourage you to:
- Open issues
- Join in on discussions in issues and PRs
- Help write documentation (storybook)
- Use the Design System and provide feedback
## Local Development
To contribute code to the Design System, first you’ll need to set it up for local development.
### Clone the repo
```sh
git clone https://github.com/hackclub/design-system.git
cd design-system
```
### Install dependencies
```sh
yarn
```
### Running tests
We use [Jest][jest] for testing, including unit tests for functionality and [snapshot testing][snapshots] for components.
```sh
yarn test
```
If you make intentional changes to an existing component, you will need to update its snapshot:
```sh
yarn test -u
```
If you want to check test coverage (goal is 100% coverage):
```sh
yarn run coverage
```
Jest will run, generate a coverage report, and open it in your browser.
### Storybook
We use [Storybook][storybook] for isolated UI component development, and
documentation for all the available components.
To run storybook locally:
```sh
yarn run dev
open http://localhost:8000/
```
## Creating a New Component
To make a new component you’ll need to make three files: the source code,
the test, and the storybook demo.
1. **Source file.** This goes in `src/New.js`, and should export a
`styled-component` with `export default New` at the end and the component’s
`propTypes` defined. Add an export to `src/index.js` so the component can be
used elsewhere.
2. **Test.** The test should verify the core functionality works, using
Jest’s snapshot testing. It should be located at `src/__tests__/New.js`,
and follow the others’ formats, like [this example test][example_test].
Once you’ve written the test, check that it passes (`npm test -- -u`) and
verify 100% test coverage of your component (`npm run coverage`).
3. **Storybook.** We use the storybook as a development environment and for
documentation. Create `.storybook/New.js` following the format of
[this example storybook][example_storybook] demoing sample usage and props.
[jest]: https://facebook.github.io/jest/
[snapshots]: https://facebook.github.io/jest/docs/en/snapshot-testing.html#content
[storybook]: https://storybook.js.org
[example_test]: ../src/__tests__/Badge.js
[example_storybook]: ../.storybook/Badge.js
================================================
FILE: LICENSE.md
================================================
# The MIT License (MIT)
Copyright (c) 2017–2019 hackclub.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# Hack Club Design System
> Hack Club has transitioned to using `hackclub/theme` as its design system. This project is only being patched when needed.
https://design.hackclub.com/
```sh
yarn add @hackclub/design-system
```
This project is heavily inspired by [Priceline.com’s design system][pcln].
## Contributing
Please be sure to read the [Contributing](docs/Contributing.md) doc :)
## [Documentation](docs)
- [Getting Started](docs/GettingStarted.md)
- [Contributing](docs/Contributing.md)
- [Theme](docs/Theme.md)
- [ThemeProvider](docs/ThemeProvider.md)
## Goals
The core goals of this project are to:
- Speed up design and development velocity
- Help create consistent, beautiful, and usable UI in our various websites
- Promote best practices for accessibility and responsive web design
We hope to accomplish these goals by:
- Reducing the number of decisions needed when iterating on UI
- Reducing the amount of code duplication in our apps
- Serving as the standard for hackclub.com’s visual language
- Providing easy-to-use and extensible components for anyone to consume
[pcln]: https://github.com/pricelinelabs/design-system
[site]: https://design.hackclub.com/
[MIT License](LICENSE.md)
================================================
FILE: docs/Contributing.md
================================================
# Contributing
If you’d like to contribute to the design system, we’d love to have your help.
Contributing doesn’t necessarily mean committing code, we also encourage you to:
- Open issues
- Join in on discussions in issues and PRs
- Help write documentation (storybook)
- Use the Design System and provide feedback
## Local Development
To contribute code to the Design System, first you’ll need to set it up for local development.
### Clone the repo
```sh
git clone https://github.com/hackclub/design-system.git
cd design-system
```
### Install dependencies
```sh
yarn
```
### Running tests
We use [Jest][jest] for testing, including unit tests for functionality and [snapshot testing][snapshots] for components.
```sh
yarn test
```
If you make intentional changes to an existing component, you will need to update its snapshot:
```sh
yarn test -u
```
If you want to check test coverage (goal is 100% coverage):
```sh
yarn run coverage
```
Jest will run, generate a coverage report, and open it in your browser.
### Storybook
We use [Storybook][storybook] for isolated UI component development, and
documentation for all the available components.
To run storybook locally:
```sh
yarn run dev
open http://localhost:8000/
```
## Creating a New Component
To make a new component you’ll need to make three files: the source code,
the test, and the storybook demo.
1. **Source file.** This goes in `src/New.js`, and should export a
`styled-component` with `export default New` at the end and the component’s
`propTypes` defined. Add an export to `src/index.js` so the component can be
used elsewhere.
2. **Test.** The test should verify the core functionality works, using
Jest’s snapshot testing. It should be located at `src/__tests__/New.js`,
and follow the others’ formats, like [this example test][example_test].
Once you’ve written the test, check that it passes (`npm test -- -u`) and
verify 100% test coverage of your component (`npm run coverage`).
3. **Storybook.** We use the storybook as a development environment and for
documentation. Create `.storybook/New.js` following the format of
[this example storybook][example_storybook] demoing sample usage and props.
[jest]: https://facebook.github.io/jest/
[snapshots]: https://facebook.github.io/jest/docs/en/snapshot-testing.html#content
[storybook]: https://storybook.js.org
[example_test]: ../src/__tests__/Badge.js
[example_storybook]: ../.storybook/Badge.js
================================================
FILE: docs/GettingStarted.md
================================================
# Getting Started
Install the Design System in your application
```sh
yarn add @hackclub/design-system
```
## ThemeProvider
Wrap the root of your application with the `ThemeProvider` component,
which adds the Design System theme to context for use in `styled-components`
and sets typographic defaults (including loading our webfont, Averta).
This should only be included once in your application.
```jsx
import React from 'react'
import { ThemeProvider } from '@hackclub/design-system'
const App = () => (
Hello
)
```
## Primitive UI Components
The preferred way of using the design system in a React application is with UI primitives.
With effective use of the UI primitives, you can reduce the need to write custom CSS in your application.
```jsx
import React from 'react'
import { Box, Text } from '@hackclub/design-system'
const SomeView = props => (
Hello
)
```
================================================
FILE: docs/README.md
================================================
# Documentation
- [Getting Started](GettingStarted.md)
- [Contributing](Contributing.md)
- [ThemeProvider](ThemeProvider.md)
- [Theme](Theme.md)
================================================
FILE: docs/Theme.md
================================================
# Theme
The theme style constants should be used whenever low-level access to font
sizes, margin, padding, media queries, and colors are needed.
```js
import { theme } from '@hackclub/design-system'
// or
import { colors, mediaQueries, fontSizes, space } from '@hackclub/design-system'
```
## Colors
```js
import { colors } from '@hackclub/design-system'
colors.primary // '#e42d42'
```
## Font Sizes
```js
import { fontSizes } from '@hackclub/design-system'
fontSizes[2] // 16
```
The theme includes a typographic scale as the `fontSizes` array.
Use these values whenever declaring a `font-size` in CSS.
## Spacing Scale
The `space` array should be used whenever declaring margin or padding values.
```js
import { space } from '@hackclub/design-system'
space[0] // 0
space[1] // 4
space[2] // 8
space[3] // 16
space[4] // 32
space[5] // 64
space[6] // 128
```
## Media Queries
The `mediaQueries` array can be used to add styles targeted for different
screen sizes. The design system is built for mobile-first design, so all media
queries use min-width.
```js
import { mediaQueries } from '@hackclub/design-system'
mediaQueries[0] // @media screen and (min-width:32em)
mediaQueries[1] // @media screen and (min-width:48em)
mediaQueries[2] // @media screen and (min-width:64em)
mediaQueries[3] // @media screen and (min-width:80em)
mediaQueries.sm // alias for mediaQueries[0]
mediaQueries.md // alias for mediaQueries[1]
mediaQueries.lg // alias for mediaQueries[2]
mediaQueries.xl // alias for mediaQueries[3]
```
================================================
FILE: docs/ThemeProvider.md
================================================
# ThemeProvider
The ThemeProvider component is a wrapper around the styled-components’ [ThemeProvider][1]
Wrap the root of your application with the `ThemeProvider` component,
which adds the Design System theme to context for use in styled-components
and sets typographic defaults (including, optionally, loading our webfont, Averta).
This should only be included once in your application.
```jsx
Hello
```
[1]: https://www.styled-components.com/docs/advanced#theming
================================================
FILE: package.json
================================================
{
"name": "@hackclub/design-system",
"version": "0.0.1-18",
"description": "Hack Club Design System",
"main": "dist/index.js",
"scripts": {
"prepare": "babel src -d dist --ignore __tests__ && yarn run fmt",
"dev": "start-storybook -p 9000 -c .storybook",
"build": "rm -rf .site && build-storybook -c .storybook -o .site",
"deploy": "storybook-to-ghpages",
"fmt": "npx prettier {.storybook,src}/**/*.js --single-quote --no-semi --write",
"coverage": "jest --coverage && serve coverage -o",
"test": "jest"
},
"author": "Lachlan Campbell ",
"license": "MIT",
"dependencies": {
"@hackclub/icons": "^0.0.3",
"lodash": "^4.17.15",
"palx": "1.0.2",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"styled-components": "3.4.10",
"styled-system": "1.1.7"
},
"devDependencies": {
"@babel/cli": "^7.8.3",
"@babel/core": "^7.8.3",
"@babel/preset-env": "^7.8.3",
"@babel/preset-react": "^7.8.3",
"@storybook/addon-info": "^5.3.9",
"@storybook/react": "^5.3.9",
"@storybook/storybook-deployer": "^2.8.1",
"babel-jest": "^24.9.0",
"babel-loader": "^8.0.6",
"babel-preset-stage-0": "^6.24.1",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"jest": "^24.9.0",
"jest-styled-components": "^6.3.4",
"react-test-renderer": "^16.12.0"
},
"jest": {
"coverageReporters": [
"text",
"lcov",
"html"
],
"collectCoverage": true,
"coveragePathIgnorePatterns": [
"dist/"
],
"setupFilesAfterEnv": [
"./test-setup.js"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/hackclub/design-system.git"
},
"bugs": {
"url": "https://github.com/hackclub/design-system/issues"
},
"homepage": "https://design.hackclub.com"
}
================================================
FILE: src/Avatar.js
================================================
import styled from 'styled-components'
import Box from './Box'
import PropTypes from 'prop-types'
import theme from './theme'
const px = a => (typeof a === 'number' ? `${a}px` : a)
const Avatar = styled(Box.withComponent('img'))`
border-radius: ${({ theme }) => theme.pill};
display: inline-block;
width: ${props => px(props.size)};
height: ${props => px(props.size)};
`
Avatar.displayName = 'Avatar'
Avatar.propTypes = {
size: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
}
Avatar.defaultProps = {
theme,
size: 48
}
export default Avatar
================================================
FILE: src/BackgroundImage.js
================================================
import Box from './Box'
import PropTypes from 'prop-types'
import theme from './theme'
import styled, { css } from 'styled-components'
const src = props => props.src && { backgroundImage: `url(${props.src})` }
const height = props => props.height && { height: props.height }
const BackgroundImage = styled(Box)`
background-position: center;
background-size: cover;
background-repeat: no-repeat;
${src} ${height};
${props =>
props.scale &&
css`
overflow: hidden;
transition: ${({ theme }) => theme.transition} background-size;
will-change: background-size;
background-size: auto ${({ theme }) => theme.scaleFactor * 100}%;
&:hover {
background-size: auto
${({ theme }) => (theme.scaleFactor + 1 / 16) * 100}%;
}
${({ theme }) => theme.mediaQueries.reduceMotion} {
transition: none;
background-size: cover !important;
}
`};
`
BackgroundImage.displayName = 'BackgroundImage'
BackgroundImage.propTypes = {
/** background-image url */
src: PropTypes.string.isRequired,
/** add hover animation */
scale: PropTypes.bool,
/** accessible label */
'aria-label': PropTypes.string.isRequired
}
BackgroundImage.defaultProps = {
theme,
bg: 'smoke'
}
export default BackgroundImage
================================================
FILE: src/Badge.js
================================================
import styled from 'styled-components'
import Text from './Text'
import theme from './theme'
const Badge = styled(Text.span)`
border-radius: ${({ theme }) => theme.pill};
display: inline-block;
font-weight: normal;
letter-spacing: 0.0375em;
line-height: 1.125;
text-transform: uppercase;
`
Badge.displayName = 'Badge'
Badge.defaultProps = {
theme,
px: 2,
py: 1,
bg: 'primary',
color: 'white',
fontSize: 1
}
export default Badge
================================================
FILE: src/BlockLink.js
================================================
import styled from 'styled-components'
import Text from './Text'
const BlockLink = styled(Text.withComponent('a')).attrs({ color: 'inherit' })`
display: block;
text-decoration: none;
`
BlockLink.displayName = 'BlockLink'
export default BlockLink
================================================
FILE: src/Box.js
================================================
import React from 'react'
import styled from 'styled-components'
import {
space,
width,
color,
fontSize,
textAlign,
propTypes
} from 'styled-system'
import theme from './theme'
const Box = styled.div([], space, width, color, fontSize, textAlign)
Box.displayName = 'Box'
Box.header = Box.withComponent('header')
Box.main = Box.withComponent('main')
Box.article = Box.withComponent('article')
Box.section = Box.withComponent('section')
Box.footer = Box.withComponent('footer')
Box.defaultProps = {
theme
}
Box.propTypes = {
...propTypes.textAlign,
...propTypes.fontSize,
...propTypes.space,
...propTypes.color
}
export default Box
================================================
FILE: src/Button.js
================================================
import Box from './Box'
import theme, { cx, hexa } from './theme'
import { css } from 'styled-components'
import PropTypes from 'prop-types'
const Button = Box.withComponent('a').extend`
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: ${({ theme }) => theme.bold};
line-height: 1.125;
appearance: none;
cursor: pointer;
transition: ${({ theme }) => theme.transition} box-shadow;
box-shadow: 0 2px 4px ${({ theme }) => theme.shadowColor};
border-radius: ${({ theme }) => theme.pill};
border: none;
${props =>
props.inverted && {
backgroundColor: cx(props.color),
color: cx(props.bg)
}};
&:hover,
&:focus {
outline: 0;
box-shadow: 0 2px 6px
${props =>
props.inverted ? props.theme.shadowColor : hexa(props.bg, 0.25)};
}
&:active {
outline: 0;
box-shadow: 0 2px 8px 2px
${props =>
props.inverted ? props.theme.shadowColor : hexa(props.bg, 0.25)};
}
${props => props.disabled && { opacity: 0.25, cursor: 'not-allowed' }};
${props =>
props.scale &&
css`
transition: ${({ theme }) => theme.transition} all;
will-change: transform;
transform: scale(1);
&:hover,
&:focus {
transform: scale(${({ theme }) => theme.scaleFactor});
}
${({ theme }) => theme.mediaQueries.reduceMotion} {
transform: none;
}
`};
${props =>
props.chevronLeft &&
css`
&:before {
content: '«';
padding-right: 0.25em;
}
`};
${props =>
props.chevronRight &&
css`
&:after {
content: '»';
padding-left: 0.25em;
}
`};
`
Button.displayName = 'Button'
Button.propTypes = {
/** flip colors */
inverted: PropTypes.bool,
/** add hover/focus animation */
scale: PropTypes.bool,
/** add left text arrows */
chevronLeft: PropTypes.bool,
/** add right text arrows */
chevronRight: PropTypes.bool
}
Button.defaultProps = {
theme,
bg: 'primary',
color: 'white',
fontSize: 3,
m: 0,
px: 3,
py: 2
}
Button.button = Button.withComponent('button')
Button.input = Button.withComponent('input')
export default Button
================================================
FILE: src/Card.js
================================================
import styled from 'styled-components'
import Box from './Box'
import theme from './theme'
import PropTypes from 'prop-types'
import { borderRadius, propTypes } from 'styled-system'
const boxShadow = props => {
const boxShadows = {
sm: theme.boxShadows[0],
md: theme.boxShadows[1],
lg: theme.boxShadows[2],
xl: theme.boxShadows[3]
}
return { boxShadow: boxShadows[props.boxShadowSize] }
}
const boxBorder = props => ({
border:
props.borderWidth > 0
? `${props.borderWidth}px solid ${props.theme.colors[props.borderColor]}`
: null
})
const Card = styled(Box)([], boxShadow, boxBorder, borderRadius)
Card.propTypes = {
/** use scale alias for theme values or null to remove shadow */
boxShadowSize: PropTypes.oneOf([null, 'sm', 'md', 'lg', 'xl']),
borderColor: PropTypes.string,
...propTypes.borderRadius,
/** use 0 to remove border */
borderWidth: PropTypes.oneOf([0, 1, 2])
}
Card.defaultProps = {
theme,
borderColor: 'smoke',
borderRadius: 1,
borderWidth: 0
}
Card.displayName = 'Card'
export default Card
================================================
FILE: src/Container.js
================================================
import styled from 'styled-components'
import Box from './Box'
import PropTypes from 'prop-types'
const Container = styled(Box)`
max-width: ${props => props.maxWidth}rem;
`
Container.displayName = 'Container'
Container.propTypes = {
maxWidth: PropTypes.number
}
Container.defaultProps = {
width: 1,
maxWidth: 72,
mx: 'auto'
}
export default Container
================================================
FILE: src/Field.js
================================================
import React from 'react'
import Label from './Label'
import Flex from './Flex'
import Text from './Text'
import Input, { InputSelect, InputTextarea } from './Input'
import Slider from './Slider'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import theme from './theme'
export const Error = styled(Text).attrs({
className: 'error',
color: 'error',
fontSize: 1,
ml: 1,
my: 0
})`
font-weight: normal;
&:before {
content: '— ';
}
`
const Field = ({ type, name, label, placeholder, error, ...props }) => {
const Component =
{
select: InputSelect,
slider: Slider,
textarea: InputTextarea
}[type] || Input
return (
{label}
{error && }
)
}
Field.displayName = 'Field'
Field.propTypes = {
/** choose alternate field type (like email, password, textarea, or select) */
type: PropTypes.oneOf([
'checkbox',
'date',
'email',
'file',
'number',
'password',
'select',
'tel',
'textarea',
'url',
'text'
]),
name: PropTypes.string.isRequired,
/** label text */
label: PropTypes.string.isRequired,
/** validation message */
error: PropTypes.string,
/** placeholder text */
placeholder: PropTypes.string
}
Field.defaultProps = {
theme,
type: 'text'
}
export default Field
================================================
FILE: src/Flex.js
================================================
import styled from 'styled-components'
import {
alignSelf,
alignItems,
justifyContent,
flexDirection,
flex,
propTypes
} from 'styled-system'
import Box from './Box'
import PropTypes from 'prop-types'
const wrap = props => (props.wrap ? { flexWrap: 'wrap' } : null)
const Flex = styled(Box)`
display: flex;
${alignSelf} ${alignItems} ${justifyContent} ${wrap} ${flexDirection} ${flex};
`
Flex.propTypes = {
wrap: PropTypes.bool,
...propTypes.alignSelf,
...propTypes.alignItems,
...propTypes.justifyContent,
...propTypes.flexDirection,
...propTypes.flex
}
Flex.displayName = 'Flex'
export default Flex
================================================
FILE: src/Heading.js
================================================
import styled from 'styled-components'
import Text from './Text'
import theme from './theme'
const Heading = Text.withComponent('h2').extend`
line-height: 1.25;
`
Heading.displayName = 'Heading'
Heading.defaultProps = {
theme,
regular: true,
fontSize: 5,
m: 0
}
Heading.h1 = styled(Heading.withComponent('h1'))``
Heading.h1.defaultProps = {
bold: true,
fontSize: 6,
m: 0
}
Heading.h2 = Heading.withComponent('h2')
Heading.h2.defaultProps = {
bold: true,
fontSize: 5,
m: 0
}
Heading.h3 = Heading.withComponent('h3')
Heading.h3.defaultProps = {
bold: true,
fontSize: 4,
m: 0
}
Heading.h4 = Heading.withComponent('h4')
Heading.h4.defaultProps = {
regular: true,
fontSize: 3,
m: 0
}
Heading.h5 = Heading.withComponent('h5')
Heading.h5.defaultProps = {
bold: true,
fontSize: 2,
m: 0
}
Heading.h6 = Heading.withComponent('h6')
Heading.h6.defaultProps = {
bold: true,
caps: true,
fontSize: 0,
m: 0
}
export default Heading
================================================
FILE: src/Hide.js
================================================
import styled from 'styled-components'
import Box from './Box'
import PropTypes from 'prop-types'
import theme from './theme'
const mw = em => em - 0.01
const breakpoints = props => ({
xs: `@media screen and (max-width: ${mw(props.theme.breakpoints[0])}em)`,
sm: `@media screen and (min-width: ${
props.theme.breakpoints[0]
}em) and (max-width: ${mw(props.theme.breakpoints[1])}em)`,
md: `@media screen and (min-width: ${
props.theme.breakpoints[1]
}em) and (max-width: ${mw(props.theme.breakpoints[2])}em)`,
lg: `@media screen and (min-width: ${
props.theme.breakpoints[2]
}em) and (max-width: ${mw(props.theme.breakpoints[3])}em)`,
xl: `@media screen and (min-width: ${props.theme.breakpoints[3]}em)`
})
const hidden = key => props =>
props[key] ? { [breakpoints(props)[key]]: { display: 'none' } } : null
const Hide = styled(Box)(
[],
hidden('xs'),
hidden('sm'),
hidden('md'),
hidden('lg'),
hidden('xl')
)
Hide.displayName = 'Hide'
Hide.propTypes = {
xs: PropTypes.bool,
sm: PropTypes.bool,
md: PropTypes.bool,
lg: PropTypes.bool,
xl: PropTypes.bool
}
Hide.defaultProps = {
theme
}
export default Hide
================================================
FILE: src/Icon.js
================================================
import styled from 'styled-components'
import PropTypes from 'prop-types'
import Box from './Box'
import HCIcon from '@hackclub/icons'
const Icon = styled(Box.withComponent(HCIcon))`
flex: none;
`
Icon.displayName = 'Icon'
Icon.propTypes = {
/** which icon to draw */
glyph: PropTypes.string,
/** width/height, numbers in px */
size: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
}
Icon.defaultProps = {
glyph: 'flag',
size: 24
}
export default Icon
================================================
FILE: src/IconButton.js
================================================
import React from 'react'
import styled, { css } from 'styled-components'
import Icon from './Icon'
import Button from './Button'
import PropTypes from 'prop-types'
import theme from './theme'
const Base = styled(Button.button)`
box-shadow: none !important;
line-height: 0 !important;
${props =>
props.circle &&
css`
padding: ${props.theme.space[props.p || 2]}px;
`};
`
const IconButton = ({ glyph, size, color, ...props }) => (
}
{...props}
/>
)
IconButton.displayName = 'IconButton'
IconButton.propTypes = {
glyph: PropTypes.string,
onClick: PropTypes.func,
circle: PropTypes.bool
}
IconButton.defaultProps = {
theme,
glyph: 'flag',
bg: 'transparent',
circle: false
}
export default IconButton
================================================
FILE: src/Image.js
================================================
import styled from 'styled-components'
import Box from './Box'
import PropTypes from 'prop-types'
const Image = styled(Box.withComponent('img'))`
display: block;
max-width: 100%;
height: auto;
`
Image.displayName = 'Image'
Image.propTypes = {
alt: PropTypes.string.isRequired
}
export default Image
================================================
FILE: src/Input.js
================================================
import React from 'react'
import styled from 'styled-components'
import { fontSize, space, width, color, propTypes } from 'styled-system'
import theme from './theme'
import PropTypes from 'prop-types'
const chevron = () => {
const props = `xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'`
const slate = '%23' + theme.colors.slate.replace('#', '')
const pathProps = `fill='${slate}' d='M2 0L0 2h4zm0 5L0 3h4z'`
return `%3Csvg ${props}%3E%3Cpath ${pathProps}/%3E%3C/svg%3E`
}
const Input = styled.input`
appearance: none;
display: block;
vertical-align: middle;
max-width: 32rem;
min-height: 36px;
line-height: inherit;
font-family: inherit;
background-color: transparent;
border-radius: ${({ theme }) => theme.radius};
border-width: 1px;
border-style: solid;
border-color: ${({ theme }) => theme.colors.smoke};
transition: ${({ theme }) => theme.transition} box-shadow;
::placeholder {
color: ${({ theme }) => theme.colors.grey};
}
::-ms-clear {
display: none;
}
&:focus {
outline: none;
border-color: ${({ theme }) => theme.colors.info};
box-shadow: 0 0 0 2px ${({ theme }) => theme.colors.blue[2]};
}
&[type='select'] {
background: #fff url("data:image/svg+xml;charset=utf8,${chevron()}") no-repeat right .75rem center;
background-size: .5rem;
}
&[type='textarea'] {
resize: vertical;
}
${fontSize} ${space} ${width} ${color};
`
Input.displayName = 'Input'
Input.propTypes = {
id: PropTypes.string,
...propTypes.fontSize,
...propTypes.space,
...propTypes.width,
...propTypes.color
}
Input.defaultProps = {
theme,
width: 1,
m: 0,
py: 1,
px: 2,
fontSize: 2,
color: 'inherit',
bg: 'transparent'
}
export const InputSelect = Input.withComponent('select')
export const InputTextarea = Input.withComponent('textarea')
export default Input
================================================
FILE: src/Label.js
================================================
import styled from 'styled-components'
import Text from './Text'
import { propTypes } from 'styled-system'
import theme from './theme'
const Label = styled(Text.withComponent('label'))`
display: block;
a {
color: ${({ theme }) => theme.colors.info};
text-decoration: underline;
}
`
Label.displayName = 'Label'
Label.propTypes = {
...propTypes.width
}
Label.defaultProps = {
theme,
color: 'black',
fontSize: 2,
width: 1
}
export default Label
================================================
FILE: src/LargeButton.js
================================================
import Button from './Button'
import theme, { hexa } from './theme'
const LargeButton = Button.extend`
text-transform: uppercase;
box-shadow: 0 2px 12px ${({ theme }) => theme.shadowColor};
&:hover,
&:focus {
box-shadow: 0 2px 12px 2px
${props =>
props.inverted ? props.theme.shadowColor : hexa(props.bg, 0.25)};
}
&:active {
box-shadow: 0 4px 16px 2px
${props =>
props.inverted ? props.theme.shadowColor : hexa(props.bg, 0.25)};
}
`
LargeButton.displayName = 'LargeButton'
LargeButton.defaultProps = {
theme,
bg: 'primary',
color: 'white',
fontSize: 3,
m: 0,
py: 3,
px: 4
}
LargeButton.button = LargeButton.withComponent('button')
LargeButton.input = LargeButton.withComponent('input')
export default LargeButton
================================================
FILE: src/Link.js
================================================
import Text from './Text'
import PropTypes from 'prop-types'
import { css } from 'styled-components'
import theme from './theme'
const Link = Text.withComponent('a').extend`
text-decoration: ${props => (props.underline ? 'underline' : 'none')};
${props =>
props.hoverline &&
css`
&:focus,
&:hover {
text-decoration: underline;
}
`};
&:before,
&:after {
text-decoration: none !important;
display: inline-block;
}
${props =>
props.chevronLeft &&
css`
&:before {
content: '‹';
padding-right: 0.25em;
}
`};
${props =>
props.chevronRight &&
css`
&:after {
content: '›';
padding-left: 0.25em;
}
`};
`
Link.displayName = 'Link'
Link.propTypes = {
/** you know, where the link goes */
href: PropTypes.string,
/** enable text-decoration: underline */
underline: PropTypes.bool,
/** enable text-decoration: underline on hover*/
hoverline: PropTypes.bool,
/** add left text arrows */
chevronLeft: PropTypes.bool,
/** add right text arrows */
chevronRight: PropTypes.bool
}
Link.defaultProps = {
theme,
color: 'info'
}
export default Link
================================================
FILE: src/Loading.js
================================================
import styled from 'styled-components'
import React from 'react'
import Box from './Box'
import { keyframes } from 'styled-components'
import theme from './theme'
const animation = keyframes`
0% {
width: 0;
height: 0;
opacity: 1;
}
100% {
width: 56px; // 64px - 3px border on two sides
height: 56px;
opacity: 0;
}
`
const Base = styled(Box)`
display: inline-flex;
align-items: center;
justify-content: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 64px;
height: 64px;
border-radius: 50%;
`
const Inner = styled(Box)`
position: absolute;
border: 4px solid currentColor;
opacity: 1;
border-radius: 50%;
transform-origin: center;
animation: ${animation} 0.975s ease-out infinite;
`
const Loading = props => (
)
Loading.defaultProps = {
theme,
color: 'primary'
}
export default Loading
================================================
FILE: src/OutlineButton.js
================================================
import LargeButton from './LargeButton'
import theme, { cx } from './theme'
const OutlineButton = LargeButton.extend`
background: transparent;
border-width: 2px;
border-style: solid;
border-color: ${props => cx(props.bg)};
box-shadow: none;
color: ${props => cx(props.bg)};
&:focus:enabled,
&:hover:enabled {
background: ${props => cx(props.bg)};
color: ${props => cx(props.color)};
transition: ${({ theme }) => theme.transition} background,
${({ theme }) => theme.transition} color;
}
`
OutlineButton.displayName = 'OutlineButton'
OutlineButton.defaultProps = {
theme,
bg: 'primary',
color: 'white',
fontSize: 3,
py: theme.space[3] - 2,
px: theme.space[4] - 2,
m: 0
}
export default OutlineButton
================================================
FILE: src/Section.js
================================================
import styled from 'styled-components'
import Flex from './Flex'
import theme from './theme'
const Section = styled(Flex)`
text-align: center;
`
Section.displayName = 'Section'
Section.defaultProps = {
theme,
align: 'center',
justify: 'center',
flexDirection: 'column',
color: 'white',
py: [4, 5],
px: 3
}
export default Section
================================================
FILE: src/Sheet.js
================================================
import styled from 'styled-components'
import Card from './Card'
import Container from './Container'
import theme from './theme'
const Sheet = styled(Card.withComponent(Container))`
position: relative;
overflow: hidden;
border-radius: ${theme.radii[2]};
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.0625);
`
Sheet.displayName = 'Sheet'
Sheet.defaultProps = {
theme,
bg: 'rgba(255, 255, 255, 0.875)',
p: [3, 4]
}
export default Sheet
================================================
FILE: src/Slider.js
================================================
import styled from 'styled-components'
import { space, width, color, propTypes } from 'styled-system'
import theme from './theme'
const Slider = styled.input.attrs({ type: 'range' })`
appearance: none;
display: block;
border-radius: ${({ theme }) => theme.pill};
height: 4px;
cursor: pointer;
&::-webkit-slider-thumb {
width: 16px;
height: 16px;
background-color: currentColor;
border: 0;
border-radius: ${({ theme }) => theme.pill};
appearance: none;
}
${space} ${width} ${color};
`
Slider.displayName = 'Input'
Slider.propTypes = {
...propTypes.space,
...propTypes.width,
...propTypes.color
}
Slider.defaultProps = {
theme,
width: 1,
bg: 'smoke',
color: 'primary'
}
export default Slider
================================================
FILE: src/Submit.js
================================================
import styled from 'styled-components'
import Button from './Button'
import LargeButton from './LargeButton'
import { caps } from './Text'
import theme from './theme'
const Submit = styled(Button.input).attrs({
type: 'submit'
})([], caps)
Submit.lg = styled(LargeButton.input).attrs({
type: 'submit'
})([], caps)
const attrs = {
theme,
caps: true
}
Submit.defaultProps = attrs
Submit.lg.defaultProps = attrs
export default Submit
================================================
FILE: src/Text.js
================================================
import React from 'react'
import styled from 'styled-components'
import PropTypes from 'prop-types'
import {
fontSize,
fontWeight,
textAlign,
space,
color,
propTypes
} from 'styled-system'
import theme from './theme'
export const caps = props => props.caps && { textTransform: 'uppercase' }
export const regular = props => props.regular && { fontWeight: 'regular' }
export const bold = props => props.bold && { fontWeight: 'bold' }
export const maxWidth = ({ maxWidth }) =>
maxWidth && { maxWidth: `${maxWidth}rem` }
const Text = styled.p(
[],
fontSize,
space,
color,
caps,
textAlign,
bold,
regular,
fontWeight,
maxWidth
)
Text.displayName = 'Text'
Text.propTypes = {
caps: PropTypes.bool,
regular: PropTypes.bool,
bold: PropTypes.bool,
maxWidth: PropTypes.number,
...propTypes.fontSize,
...propTypes.fontWeight,
...propTypes.textAlign,
...propTypes.space,
...propTypes.color
}
Text.defaultProps = {
theme,
m: 0
}
Text.span = Text.withComponent('span')
Text.p = Text.withComponent('p')
Text.s = Text.withComponent('s')
export default Text
================================================
FILE: src/ThemeProvider.js
================================================
import React, { Fragment } from 'react'
import { ThemeProvider as Root, injectGlobal, css } from 'styled-components'
import PropTypes from 'prop-types'
import theme from './theme'
const fontsCss = css`
@font-face {
font-family: 'Phantom Sans';
src: url('https://assets.hackclub.com/fonts/Phantom_Sans_0.7/Regular.woff')
format('woff'),
url('https://assets.hackclub.com/fonts/Phantom_Sans_0.7/Regular.woff2')
format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Phantom Sans';
src: url('https://assets.hackclub.com/fonts/Phantom_Sans_0.7/Bold.woff')
format('woff'),
url('https://assets.hackclub.com/fonts/Phantom_Sans_0.7/Bold.woff2')
format('woff2');
font-weight: bold;
font-style: normal;
font-display: swap;
}
`
injectGlobal`
* {
box-sizing: border-box;
font-weight: inherit;
-webkit-appearance: none;
-moz-appearance: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
html {
-ms-text-size-adjust: 100%;
-moz-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%
}
html,
body {
min-height: 100%;
min-width: 100%;
}
body {
padding: 0;
margin: 0;
font-size: ${theme.fontSizes[2]}px;
font-family: ${theme.font};
line-height: 1.375;
position: relative;
height: 100%;
max-height: 100%;
width: 100%;
}
a {
color: currentColor;
text-decoration: none;
}
textarea {
resize: none;
}
strong {
font-weight: bold;
}
pre,
code,
kbd {
font-family: ${theme.mono};
}
`
const ThemeProvider = ({ theme, webfonts, ...props }) => {
if (webfonts) injectGlobal([], fontsCss)
return (
{props.children}}
/>
)
}
ThemeProvider.propTypes = {
theme: PropTypes.object,
webfonts: PropTypes.bool
}
ThemeProvider.defaultProps = {
theme,
webfonts: false
}
export default ThemeProvider
================================================
FILE: src/__tests__/Avatar.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Avatar } from '..'
describe('Avatar', () => {
test('renders', () => {
const json = renderer
.create( )
.toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('width', '48px')
})
test('renders string width', () => {
const json = renderer
.create( )
.toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('width', '10vw')
})
})
================================================
FILE: src/__tests__/BackgroundImage.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { theme, BackgroundImage } from '..'
const props = {
src:
'https://images.unsplash.com/photo-1416339684178-3a239570f315?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max',
'aria-label': 'Wooden desk with tools and chair'
}
describe('BackgroundImage', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('background-image', `url(${props.src})`)
})
test('renders with height', () => {
const json = renderer
.create( )
.toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('height', '256px')
})
test('scale', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule(
'background-size',
`auto ${theme.scaleFactor * 100}%`
)
expect(json).toHaveStyleRule(
'background-size',
`auto ${(theme.scaleFactor + 1 / 16) * 100}%`,
{ modifier: ':hover' }
)
})
})
================================================
FILE: src/__tests__/Badge.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Badge, theme } from '..'
describe('Badge', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('accepts custom bg and color', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('background-color', theme.colors.white)
expect(json).toHaveStyleRule('color', theme.colors.accent)
})
})
================================================
FILE: src/__tests__/BlockLink.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { BlockLink } from '..'
describe('BlockLink', () => {
test('renders', () => {
const json = renderer.create(raw text ).toJSON()
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/Box.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Box, theme } from '..'
describe('Box', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('width prop sets width', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('width', '50%')
})
test('m prop sets margin', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('margin', theme.space[1] + 'px')
})
test('p prop sets padding', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('padding', theme.space[1] + 'px')
})
test('color prop sets color', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('color', theme.colors.warning)
})
test('bg prop sets background color', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('background-color', theme.colors.accent)
})
test('bg prop sets custom background color', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('background-color', '#ff6d00')
})
})
================================================
FILE: src/__tests__/Button.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Button, theme } from '..'
describe('Button', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('custom bg', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('background-color', theme.colors.accent)
expect(json).toHaveStyleRule('color', theme.colors.white)
})
test('inverted', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('background-color', theme.colors.white)
expect(json).toHaveStyleRule('color', theme.colors.accent)
})
test('scale', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('will-change', 'transform')
expect(json).toHaveStyleRule('transform', 'scale(1)')
expect(json).toHaveStyleRule('transform', `scale(${theme.scaleFactor})`, {
modifier: ':hover'
})
})
test('disabled prop sets', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('opacity', '0.25')
expect(json).toHaveStyleRule('cursor', 'not-allowed')
})
test('without disabled prop sets', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('color', theme.colors.success)
expect(json).toHaveStyleRule(
'box-shadow',
`0 2px 6px ${theme.shadowColor}`,
{ modifier: ':hover' }
)
})
test('left chevron', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('content', `'«'`, { modifier: ':before' })
})
test('right chevron', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('content', `'»'`, { modifier: ':after' })
})
})
================================================
FILE: src/__tests__/Card.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Card, theme } from '..'
describe('Card', () => {
test('renders small box shadow', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('box-shadow', theme.boxShadows[0])
expect(json).toHaveStyleRule('border-radius', theme.radius)
})
test('renders lg shadow', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('box-shadow', theme.boxShadows[2])
})
test('renders with 1px border', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('border', `1px solid ${theme.colors.smoke}`)
})
})
================================================
FILE: src/__tests__/Container.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Container } from '..'
describe('Container', () => {
test('renders with default theme max-width', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('renders with maxWidth', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('max-width', '32rem')
})
})
================================================
FILE: src/__tests__/Field.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Field } from '..'
describe('Field', () => {
test('renders', () => {
const json = renderer
.create( )
.toJSON()
expect(json).toMatchSnapshot()
})
test('with error', () => {
const json = renderer
.create( )
.toJSON()
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/Flex.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Flex } from '..'
describe('Flex', () => {
test('renders', () => {
const flex = renderer.create( ).toJSON()
expect(flex).toMatchSnapshot()
})
test('align prop', () => {
const flex = renderer.create( ).toJSON()
expect(flex).toMatchSnapshot()
expect(flex).toHaveStyleRule('align-items', 'center')
})
test('justify prop', () => {
const flex = renderer.create( ).toJSON()
expect(flex).toMatchSnapshot()
expect(flex).toHaveStyleRule('justify-content', 'space-between')
})
test('wrap prop', () => {
const flex = renderer.create( ).toJSON()
expect(flex).toMatchSnapshot()
expect(flex).toHaveStyleRule('flex-wrap', 'wrap')
})
test('direction prop', () => {
const flex = renderer.create( ).toJSON()
expect(flex).toMatchSnapshot()
expect(flex).toHaveStyleRule('flex-direction', 'column')
})
})
================================================
FILE: src/__tests__/Heading.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Heading, theme } from '..'
describe('Heading', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
const dotNotationTestCase = 'with h1-h6 dot-notation'
test(dotNotationTestCase, () => {
const headingH1json = renderer.create( ).toJSON()
const headingH2json = renderer.create( ).toJSON()
const headingH3json = renderer.create( ).toJSON()
const headingH4json = renderer.create( ).toJSON()
const headingH5json = renderer.create( ).toJSON()
const headingH6json = renderer.create( ).toJSON()
expect(headingH1json).toMatchSnapshot()
expect(headingH2json).toMatchSnapshot()
expect(headingH3json).toMatchSnapshot()
expect(headingH4json).toMatchSnapshot()
expect(headingH5json).toMatchSnapshot()
expect(headingH6json).toMatchSnapshot()
})
const defaultFontSizeTestCase =
'with default theme font size, when fontSize prop not used'
test(defaultFontSizeTestCase, () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('font-size', theme.fontSizes[5] + 'px')
})
const usingTextPropsTestCase = 'uses component properties'
test(usingTextPropsTestCase, () => {
const json = renderer
.create( )
.toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('text-align', 'center')
expect(json).toHaveStyleRule('color', theme.colors['primary'])
})
})
================================================
FILE: src/__tests__/Hide.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Hide } from '..'
describe('Hide', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('renders with xs prop', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('renders with sm prop', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('renders with md prop', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('renders with lg prop', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('renders with xl prop', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/Icon.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Icon } from '..'
describe('Icon', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/IconButton.js
================================================
/* eslint-env jest */
import React from 'react'
import renderer from 'react-test-renderer'
import { shallow } from 'enzyme'
import { IconButton } from '..'
describe('IconButton', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('renders with circle prop', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('border-radius', '9999px')
expect(json).toHaveStyleRule('padding', '12px')
})
test('executes onClick prop on click', () => {
const handleClick = jest.fn()
const wrapper = shallow( )
wrapper.simulate('click')
expect(handleClick).toBeCalled()
})
})
================================================
FILE: src/__tests__/Image.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Image } from '..'
const imageSrc = 'https://hackclub.com/social-photo_2.jpg'
describe('Image', () => {
test('renders', () => {
const json = renderer
.create( )
.toJSON()
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/Input.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Input, theme } from '..'
describe('Input', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('renders with custom spacing', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('padding', theme.space[4] + 'px')
expect(json).toHaveStyleRule('margin', theme.space[4] + 'px')
})
test('renders with custom fontSize', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('font-size', theme.fontSizes[4] + 'px')
})
})
================================================
FILE: src/__tests__/Label.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Label } from '..'
describe('Label', () => {
test('it renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/LargeButton.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { LargeButton, theme } from '..'
describe('LargeButton', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('inverted', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule(
'box-shadow',
`0 2px 12px ${theme.shadowColor}`
)
expect(json).toHaveStyleRule(
'box-shadow',
`0 2px 12px 2px ${theme.shadowColor}`,
{
modifier: ':hover'
}
)
expect(json).toHaveStyleRule(
'box-shadow',
`0 4px 16px 2px ${theme.shadowColor}`,
{
modifier: ':active'
}
)
})
test('larger', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('background-color', theme.colors.accent)
expect(json).toHaveStyleRule('color', theme.colors.white)
expect(json).toHaveStyleRule('padding-left', theme.space[4] + 'px')
})
})
================================================
FILE: src/__tests__/Link.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Link } from '..'
describe('Link', () => {
test('renders', () => {
const json = renderer.create( Hello).toJSON()
expect(json).toMatchSnapshot()
})
test('renders underline', () => {
const json = renderer.create( Underline).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('text-decoration', 'underline')
})
test('renders hoverline', () => {
const json = renderer.create( Hoverline).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('text-decoration', 'none')
expect(json).toHaveStyleRule('text-decoration', 'underline', {
modifier: ':hover'
})
})
test('renders chevronleft', () => {
const json = renderer.create( Left).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('content', `'‹'`, { modifier: ':before' })
})
test('renders chevronright', () => {
const json = renderer.create( Right).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('content', `'›'`, { modifier: ':after' })
})
})
================================================
FILE: src/__tests__/Loading.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Loading } from '..'
describe('Loading', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/OutlineButton.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { OutlineButton, theme } from '..'
describe('OutlineButton', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('border-style', 'solid')
expect(json).toHaveStyleRule('background', 'transparent')
})
test('disabled prop sets', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('opacity', '0.25')
})
test('with custom color', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('color', theme.colors.white)
})
})
================================================
FILE: src/__tests__/Section.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Section } from '..'
describe('Section', () => {
test('renders', () => {
const json = renderer.create().toJSON()
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/Sheet.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Sheet } from '..'
describe('Sheet', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('background-color', 'rgba(255,255,255,0.875)')
})
})
================================================
FILE: src/__tests__/Slider.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Slider, theme } from '..'
describe('Slider', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/Submit.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Submit } from '..'
describe('Submit', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('text-transform', 'uppercase')
})
test('renders lg', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/Text.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { Text, theme } from '..'
describe('Text', () => {
test('renders', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
})
test('align prop sets text-align', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('text-align', 'center')
})
test('regular prop sets font-weight', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('font-weight', 'regular')
})
test('bold prop sets font-weight', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('font-weight', 'bold')
})
test('maxWidth prop sets max-width', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('max-width', '48rem')
})
test('caps prop sets text-transform', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('text-transform', 'uppercase')
})
test('fontSize prop sets font-size', () => {
const f0 = renderer.create( ).toJSON()
const f1 = renderer.create( ).toJSON()
const f2 = renderer.create( ).toJSON()
const f3 = renderer.create( ).toJSON()
const f4 = renderer.create( ).toJSON()
const f5 = renderer.create( ).toJSON()
const f6 = renderer.create( ).toJSON()
expect(f0).toHaveStyleRule('font-size', theme.fontSizes[0] + 'px')
expect(f1).toHaveStyleRule('font-size', theme.fontSizes[1] + 'px')
expect(f2).toHaveStyleRule('font-size', theme.fontSizes[2] + 'px')
expect(f3).toHaveStyleRule('font-size', theme.fontSizes[3] + 'px')
expect(f4).toHaveStyleRule('font-size', theme.fontSizes[4] + 'px')
expect(f5).toHaveStyleRule('font-size', theme.fontSizes[5] + 'px')
expect(f6).toHaveStyleRule('font-size', theme.fontSizes[6] + 'px')
})
test('mt prop sets margin-top', () => {
const json = renderer.create( ).toJSON()
expect(json).toMatchSnapshot()
expect(json).toHaveStyleRule('margin-top', theme.space[2] + 'px')
})
})
================================================
FILE: src/__tests__/ThemeProvider.js
================================================
import React from 'react'
import renderer from 'react-test-renderer'
import { ThemeProvider } from '..'
import styled from 'styled-components'
const Content = styled.p`
color: ${({ theme }) => theme.colors.primary};
`
describe('ThemeProvider', () => {
test('renders content with theme', () => {
const json = renderer.create(
Hello!
)
expect(json).toMatchSnapshot()
})
})
================================================
FILE: src/__tests__/__snapshots__/Avatar.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Avatar renders 1`] = `
.c0 {
border-radius: 9999px;
display: inline-block;
width: 48px;
height: 48px;
}
`;
exports[`Avatar renders string width 1`] = `
.c0 {
border-radius: 9999px;
display: inline-block;
width: 10vw;
height: 10vw;
}
`;
================================================
FILE: src/__tests__/__snapshots__/BackgroundImage.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`BackgroundImage renders 1`] = `
.c1 {
background-color: #dde1e4;
}
.c0 {
background-position: center;
background-size: cover;
background-repeat: no-repeat;
background-image: url(https://images.unsplash.com/photo-1416339684178-3a239570f315?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max);
}
`;
exports[`BackgroundImage renders with height 1`] = `
.c1 {
background-color: #dde1e4;
}
.c0 {
background-position: center;
background-size: cover;
background-repeat: no-repeat;
background-image: url(https://images.unsplash.com/photo-1416339684178-3a239570f315?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max);
height: 256px;
}
`;
exports[`BackgroundImage scale 1`] = `
.c1 {
background-color: #dde1e4;
}
.c0 {
background-position: center;
background-size: cover;
background-repeat: no-repeat;
background-image: url(https://images.unsplash.com/photo-1416339684178-3a239570f315?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max);
overflow: hidden;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) background-size;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) background-size;
will-change: background-size;
background-size: auto 106.25%;
}
.c0:hover {
background-size: auto 112.5%;
}
@media (prefers-reduced-motion:reduce) {
.c0 {
-webkit-transition: none;
transition: none;
background-size: cover !important;
}
}
`;
================================================
FILE: src/__tests__/__snapshots__/Badge.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Badge accepts custom bg and color 1`] = `
.c1 {
font-size: 16px;
margin: 0px;
padding-left: 12px;
padding-right: 12px;
padding-top: 6px;
padding-bottom: 6px;
background-color: #ffffff;
color: #7280ed;
}
.c0 {
border-radius: 9999px;
display: inline-block;
font-weight: normal;
-webkit-letter-spacing: 0.0375em;
-moz-letter-spacing: 0.0375em;
-ms-letter-spacing: 0.0375em;
letter-spacing: 0.0375em;
line-height: 1.125;
text-transform: uppercase;
}
`;
exports[`Badge renders 1`] = `
.c1 {
font-size: 16px;
margin: 0px;
padding-left: 12px;
padding-right: 12px;
padding-top: 6px;
padding-bottom: 6px;
background-color: #e42d42;
color: #ffffff;
}
.c0 {
border-radius: 9999px;
display: inline-block;
font-weight: normal;
-webkit-letter-spacing: 0.0375em;
-moz-letter-spacing: 0.0375em;
-ms-letter-spacing: 0.0375em;
letter-spacing: 0.0375em;
line-height: 1.125;
text-transform: uppercase;
}
`;
================================================
FILE: src/__tests__/__snapshots__/BlockLink.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`BlockLink renders 1`] = `
.c1 {
margin: 0px;
color: inherit;
}
.c0 {
display: block;
-webkit-text-decoration: none;
text-decoration: none;
}
raw text
`;
================================================
FILE: src/__tests__/__snapshots__/Box.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Box bg prop sets background color 1`] = `
.c0 {
background-color: #7280ed;
}
`;
exports[`Box bg prop sets custom background color 1`] = `
.c0 {
background-color: #ff6d00;
}
`;
exports[`Box color prop sets color 1`] = `
.c0 {
color: #e4732d;
}
`;
exports[`Box m prop sets margin 1`] = `
.c0 {
margin: 6px;
}
`;
exports[`Box p prop sets padding 1`] = `
.c0 {
padding: 6px;
}
`;
exports[`Box renders 1`] = `
`;
exports[`Box width prop sets width 1`] = `
.c0 {
width: 50%;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Button.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Button custom bg 1`] = `
.c0 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: #7280ed;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(114,128,237,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(114,128,237,0.25);
}
`;
exports[`Button disabled prop sets 1`] = `
.c0 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
opacity: 0.25;
cursor: not-allowed;
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(228,45,66,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(228,45,66,0.25);
}
`;
exports[`Button inverted 1`] = `
.c0 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: #7280ed;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
background-color: #ffffff;
color: #7280ed;
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(0,0,0,0.125);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(0,0,0,0.125);
}
`;
exports[`Button left chevron 1`] = `
.c0 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(228,45,66,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(228,45,66,0.25);
}
.c0:before {
content: '«';
padding-right: 0.25em;
}
`;
exports[`Button renders 1`] = `
.c0 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(228,45,66,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(228,45,66,0.25);
}
`;
exports[`Button right chevron 1`] = `
.c0 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(228,45,66,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(228,45,66,0.25);
}
.c0:after {
content: '»';
padding-left: 0.25em;
}
`;
exports[`Button scale 1`] = `
.c0 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) all;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) all;
will-change: transform;
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(228,45,66,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(228,45,66,0.25);
}
.c0:hover,
.c0:focus {
-webkit-transform: scale(1.0625);
-ms-transform: scale(1.0625);
transform: scale(1.0625);
}
@media (prefers-reduced-motion:reduce) {
.c0 {
-webkit-transform: none;
-ms-transform: none;
transform: none;
}
}
`;
exports[`Button without disabled prop sets 1`] = `
.c0 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: #2de473;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
background-color: #ffffff;
color: #2de473;
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(0,0,0,0.125);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(0,0,0,0.125);
}
`;
================================================
FILE: src/__tests__/__snapshots__/Card.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Card renders lg shadow 1`] = `
.c0 {
box-shadow: 0 0 2px 0 rgba(0,0,0,.0625),0 12px 12px 0 rgba(0,0,0,0.125);
border-radius: 4px;
}
`;
exports[`Card renders small box shadow 1`] = `
.c0 {
box-shadow: 0 0 2px 0 rgba(0,0,0,.0625),0 2px 4px 0 rgba(0,0,0,0.125);
border-radius: 4px;
}
`;
exports[`Card renders with 1px border 1`] = `
.c0 {
border: 1px solid #dde1e4;
border-radius: 4px;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Container.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Container renders with default theme max-width 1`] = `
.c1 {
margin-left: auto;
margin-right: auto;
width: 100%;
}
.c0 {
max-width: 72rem;
}
`;
exports[`Container renders with maxWidth 1`] = `
.c1 {
margin-left: auto;
margin-right: auto;
width: 100%;
}
.c0 {
max-width: 32rem;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Field.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Field renders 1`] = `
.c3 {
margin-bottom: 2px;
text-align: center;
}
.c1 {
font-size: 18px;
margin: 0px;
margin-bottom: 12px;
color: #384046;
}
.c0 {
display: block;
}
.c0 a {
color: #2d9ee4;
-webkit-text-decoration: underline;
text-decoration: underline;
}
.c2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.c4 {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: block;
vertical-align: middle;
max-width: 32rem;
min-height: 36px;
line-height: inherit;
font-family: inherit;
background-color: transparent;
border-radius: 4px;
border-width: 1px;
border-style: solid;
border-color: #dde1e4;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
font-size: 18px;
margin: 0px;
padding-left: 12px;
padding-right: 12px;
padding-top: 6px;
padding-bottom: 6px;
width: 100%;
color: inherit;
background-color: transparent;
}
.c4::-ms-clear {
display: none;
}
.c4::-ms-clear {
display: none;
}
.c4::-ms-clear {
display: none;
}
.c4::-ms-clear {
display: none;
}
.c4:focus {
outline: none;
border-color: #2d9ee4;
box-shadow: 0 0 0 2px #add9f5;
}
.c4[type='select'] {
background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23606e77' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;
background-size: .5rem;
}
.c4[type='textarea'] {
resize: vertical;
}
Renders
`;
exports[`Field with error 1`] = `
.c3 {
margin-bottom: 2px;
text-align: center;
}
.c5 {
font-size: 16px;
margin: 0px;
margin-left: 6px;
margin-top: 0px;
margin-bottom: 0px;
color: #b52434;
}
.c1 {
font-size: 18px;
margin: 0px;
margin-bottom: 12px;
color: #384046;
}
.c0 {
display: block;
}
.c0 a {
color: #2d9ee4;
-webkit-text-decoration: underline;
text-decoration: underline;
}
.c2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.c6 {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: block;
vertical-align: middle;
max-width: 32rem;
min-height: 36px;
line-height: inherit;
font-family: inherit;
background-color: transparent;
border-radius: 4px;
border-width: 1px;
border-style: solid;
border-color: #dde1e4;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
font-size: 18px;
margin: 0px;
padding-left: 12px;
padding-right: 12px;
padding-top: 6px;
padding-bottom: 6px;
width: 100%;
color: inherit;
background-color: transparent;
}
.c6::-ms-clear {
display: none;
}
.c6::-ms-clear {
display: none;
}
.c6::-ms-clear {
display: none;
}
.c6::-ms-clear {
display: none;
}
.c6:focus {
outline: none;
border-color: #2d9ee4;
box-shadow: 0 0 0 2px #add9f5;
}
.c6[type='select'] {
background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23606e77' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;
background-size: .5rem;
}
.c6[type='textarea'] {
resize: vertical;
}
.c4 {
font-weight: normal;
}
.c4:before {
content: '— ';
}
`;
================================================
FILE: src/__tests__/__snapshots__/Flex.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Flex align prop 1`] = `
.c1 {
text-align: center;
}
.c0 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
`;
exports[`Flex direction prop 1`] = `
.c0 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
`;
exports[`Flex justify prop 1`] = `
.c0 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
}
`;
exports[`Flex renders 1`] = `
.c0 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
`;
exports[`Flex wrap prop 1`] = `
.c0 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Heading.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Heading renders 1`] = `
.c0 {
font-size: 36px;
margin: 0px;
font-weight: regular;
line-height: 1.25;
}
`;
exports[`Heading uses component properties 1`] = `
.c0 {
font-size: 36px;
margin: 0px;
color: #e42d42;
text-align: center;
font-weight: regular;
line-height: 1.25;
}
`;
exports[`Heading with default theme font size, when fontSize prop not used 1`] = `
.c0 {
font-size: 36px;
margin: 0px;
font-weight: regular;
line-height: 1.25;
}
`;
exports[`Heading with h1-h6 dot-notation 1`] = `
.c0 {
font-size: 48px;
margin: 0px;
font-weight: bold;
font-weight: regular;
line-height: 1.25;
}
`;
exports[`Heading with h1-h6 dot-notation 2`] = `
.c0 {
font-size: 32px;
margin: 0px;
font-weight: bold;
line-height: 1.25;
}
`;
exports[`Heading with h1-h6 dot-notation 3`] = `
.c0 {
font-size: 24px;
margin: 0px;
font-weight: bold;
line-height: 1.25;
}
`;
exports[`Heading with h1-h6 dot-notation 4`] = `
.c0 {
font-size: 20px;
margin: 0px;
font-weight: regular;
line-height: 1.25;
}
`;
exports[`Heading with h1-h6 dot-notation 5`] = `
.c0 {
font-size: 16px;
margin: 0px;
font-weight: bold;
line-height: 1.25;
}
`;
exports[`Heading with h1-h6 dot-notation 6`] = `
.c0 {
font-size: 12px;
margin: 0px;
text-transform: uppercase;
font-weight: bold;
line-height: 1.25;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Hide.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Hide renders 1`] = `
`;
exports[`Hide renders with lg prop 1`] = `
@media screen and (min-width:64em) and (max-width:79.99em) {
.c0 {
display: none;
}
}
`;
exports[`Hide renders with md prop 1`] = `
@media screen and (min-width:48em) and (max-width:63.99em) {
.c0 {
display: none;
}
}
`;
exports[`Hide renders with sm prop 1`] = `
@media screen and (min-width:32em) and (max-width:47.99em) {
.c0 {
display: none;
}
}
`;
exports[`Hide renders with xl prop 1`] = `
@media screen and (min-width:80em) {
.c0 {
display: none;
}
}
`;
exports[`Hide renders with xs prop 1`] = `
@media screen and (max-width:31.99em) {
.c0 {
display: none;
}
}
`;
================================================
FILE: src/__tests__/__snapshots__/Icon.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Icon renders 1`] = `
.c0 {
-webkit-flex: none;
-ms-flex: none;
flex: none;
}
`;
================================================
FILE: src/__tests__/__snapshots__/IconButton.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`IconButton renders 1`] = `
.c1 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: transparent;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
}
.c1:hover,
.c1:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(0,0,0,0.125);
}
.c1:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(0,0,0,0.125);
}
.c2 {
-webkit-flex: none;
-ms-flex: none;
flex: none;
}
.c0 {
box-shadow: none !important;
line-height: 0 !important;
}
`;
exports[`IconButton renders with circle prop 1`] = `
.c1 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: transparent;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
}
.c1:hover,
.c1:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(0,0,0,0.125);
}
.c1:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(0,0,0,0.125);
}
.c2 {
-webkit-flex: none;
-ms-flex: none;
flex: none;
}
.c0 {
box-shadow: none !important;
line-height: 0 !important;
padding: 12px;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Image.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Image renders 1`] = `
.c0 {
display: block;
max-width: 100%;
height: auto;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Input.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Input renders 1`] = `
.c0 {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: block;
vertical-align: middle;
max-width: 32rem;
min-height: 36px;
line-height: inherit;
font-family: inherit;
background-color: transparent;
border-radius: 4px;
border-width: 1px;
border-style: solid;
border-color: #dde1e4;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
font-size: 18px;
margin: 0px;
padding-left: 12px;
padding-right: 12px;
padding-top: 6px;
padding-bottom: 6px;
width: 100%;
color: inherit;
background-color: transparent;
}
.c0::-ms-clear {
display: none;
}
.c0::-ms-clear {
display: none;
}
.c0::-ms-clear {
display: none;
}
.c0::-ms-clear {
display: none;
}
.c0:focus {
outline: none;
border-color: #2d9ee4;
box-shadow: 0 0 0 2px #add9f5;
}
.c0[type='select'] {
background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23606e77' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;
background-size: .5rem;
}
.c0[type='textarea'] {
resize: vertical;
}
`;
exports[`Input renders with custom fontSize 1`] = `
.c0 {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: block;
vertical-align: middle;
max-width: 32rem;
min-height: 36px;
line-height: inherit;
font-family: inherit;
background-color: transparent;
border-radius: 4px;
border-width: 1px;
border-style: solid;
border-color: #dde1e4;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
font-size: 27px;
margin: 0px;
padding-left: 12px;
padding-right: 12px;
padding-top: 6px;
padding-bottom: 6px;
width: 100%;
color: inherit;
background-color: transparent;
}
.c0::-ms-clear {
display: none;
}
.c0::-ms-clear {
display: none;
}
.c0::-ms-clear {
display: none;
}
.c0::-ms-clear {
display: none;
}
.c0:focus {
outline: none;
border-color: #2d9ee4;
box-shadow: 0 0 0 2px #add9f5;
}
.c0[type='select'] {
background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23606e77' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;
background-size: .5rem;
}
.c0[type='textarea'] {
resize: vertical;
}
`;
exports[`Input renders with custom spacing 1`] = `
.c0 {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: block;
vertical-align: middle;
max-width: 32rem;
min-height: 36px;
line-height: inherit;
font-family: inherit;
background-color: transparent;
border-radius: 4px;
border-width: 1px;
border-style: solid;
border-color: #dde1e4;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
font-size: 18px;
margin: 24px;
padding: 24px;
padding-left: 12px;
padding-right: 12px;
padding-top: 6px;
padding-bottom: 6px;
width: 100%;
color: inherit;
background-color: transparent;
}
.c0::-ms-clear {
display: none;
}
.c0::-ms-clear {
display: none;
}
.c0::-ms-clear {
display: none;
}
.c0::-ms-clear {
display: none;
}
.c0:focus {
outline: none;
border-color: #2d9ee4;
box-shadow: 0 0 0 2px #add9f5;
}
.c0[type='select'] {
background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23606e77' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;
background-size: .5rem;
}
.c0[type='textarea'] {
resize: vertical;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Label.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Label it renders 1`] = `
.c1 {
font-size: 18px;
margin: 0px;
color: #384046;
}
.c0 {
display: block;
}
.c0 a {
color: #2d9ee4;
-webkit-text-decoration: underline;
text-decoration: underline;
}
`;
================================================
FILE: src/__tests__/__snapshots__/LargeButton.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LargeButton inverted 1`] = `
.c0 {
margin: 0px;
padding-left: 24px;
padding-right: 24px;
padding-top: 18px;
padding-bottom: 18px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
background-color: #ffffff;
color: #e42d42;
text-transform: uppercase;
box-shadow: 0 2px 12px rgba(0,0,0,0.125);
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(0,0,0,0.125);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(0,0,0,0.125);
}
.c0:hover,
.c0:focus {
box-shadow: 0 2px 12px 2px rgba(0,0,0,0.125);
}
.c0:active {
box-shadow: 0 4px 16px 2px rgba(0,0,0,0.125);
}
`;
exports[`LargeButton larger 1`] = `
.c0 {
margin: 0px;
padding-left: 24px;
padding-right: 24px;
padding-top: 18px;
padding-bottom: 18px;
background-color: #7280ed;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
text-transform: uppercase;
box-shadow: 0 2px 12px rgba(0,0,0,0.125);
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(114,128,237,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(114,128,237,0.25);
}
.c0:hover,
.c0:focus {
box-shadow: 0 2px 12px 2px rgba(114,128,237,0.25);
}
.c0:active {
box-shadow: 0 4px 16px 2px rgba(114,128,237,0.25);
}
`;
exports[`LargeButton renders 1`] = `
.c0 {
margin: 0px;
padding-left: 24px;
padding-right: 24px;
padding-top: 18px;
padding-bottom: 18px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
text-transform: uppercase;
box-shadow: 0 2px 12px rgba(0,0,0,0.125);
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(228,45,66,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(228,45,66,0.25);
}
.c0:hover,
.c0:focus {
box-shadow: 0 2px 12px 2px rgba(228,45,66,0.25);
}
.c0:active {
box-shadow: 0 4px 16px 2px rgba(228,45,66,0.25);
}
`;
================================================
FILE: src/__tests__/__snapshots__/Link.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Link renders 1`] = `
.c0 {
color: #2d9ee4;
-webkit-text-decoration: none;
text-decoration: none;
}
.c0:before,
.c0:after {
-webkit-text-decoration: none !important;
text-decoration: none !important;
display: inline-block;
}
Hello
`;
exports[`Link renders chevronleft 1`] = `
.c0 {
color: #2d9ee4;
-webkit-text-decoration: none;
text-decoration: none;
}
.c0:before,
.c0:after {
-webkit-text-decoration: none !important;
text-decoration: none !important;
display: inline-block;
}
.c0:before {
content: '‹';
padding-right: 0.25em;
}
Left
`;
exports[`Link renders chevronright 1`] = `
.c0 {
color: #2d9ee4;
-webkit-text-decoration: none;
text-decoration: none;
}
.c0:before,
.c0:after {
-webkit-text-decoration: none !important;
text-decoration: none !important;
display: inline-block;
}
.c0:after {
content: '›';
padding-left: 0.25em;
}
Right
`;
exports[`Link renders hoverline 1`] = `
.c0 {
color: #2d9ee4;
-webkit-text-decoration: none;
text-decoration: none;
}
.c0:focus,
.c0:hover {
-webkit-text-decoration: underline;
text-decoration: underline;
}
.c0:before,
.c0:after {
-webkit-text-decoration: none !important;
text-decoration: none !important;
display: inline-block;
}
Hoverline
`;
exports[`Link renders underline 1`] = `
.c0 {
color: #2d9ee4;
-webkit-text-decoration: underline;
text-decoration: underline;
}
.c0:before,
.c0:after {
-webkit-text-decoration: none !important;
text-decoration: none !important;
display: inline-block;
}
Underline
`;
================================================
FILE: src/__tests__/__snapshots__/Loading.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Loading renders 1`] = `
.c1 {
color: #e42d42;
}
.c0 {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
transform: translate(-50%,-50%);
width: 64px;
height: 64px;
border-radius: 50%;
}
.c2 {
position: absolute;
border: 4px solid currentColor;
opacity: 1;
border-radius: 50%;
-webkit-transform-origin: center;
-ms-transform-origin: center;
transform-origin: center;
-webkit-animation: EdArQ 0.975s ease-out infinite;
animation: EdArQ 0.975s ease-out infinite;
}
`;
================================================
FILE: src/__tests__/__snapshots__/OutlineButton.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`OutlineButton disabled prop sets 1`] = `
.c0 {
margin: 0px;
padding-left: 22px;
padding-right: 22px;
padding-top: 16px;
padding-bottom: 16px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
opacity: 0.25;
cursor: not-allowed;
text-transform: uppercase;
box-shadow: 0 2px 12px rgba(0,0,0,0.125);
background: transparent;
border-width: 2px;
border-style: solid;
border-color: #e42d42;
box-shadow: none;
color: #e42d42;
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(228,45,66,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(228,45,66,0.25);
}
.c0:hover,
.c0:focus {
box-shadow: 0 2px 12px 2px rgba(228,45,66,0.25);
}
.c0:active {
box-shadow: 0 4px 16px 2px rgba(228,45,66,0.25);
}
.c0:focus:enabled,
.c0:hover:enabled {
background: #e42d42;
color: #ffffff;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) background, 0.1875s cubic-bezier(0.375,0,0.675,1) color;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) background, 0.1875s cubic-bezier(0.375,0,0.675,1) color;
}
`;
exports[`OutlineButton renders 1`] = `
.c0 {
margin: 0px;
padding-left: 22px;
padding-right: 22px;
padding-top: 16px;
padding-bottom: 16px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
text-transform: uppercase;
box-shadow: 0 2px 12px rgba(0,0,0,0.125);
background: transparent;
border-width: 2px;
border-style: solid;
border-color: #e42d42;
box-shadow: none;
color: #e42d42;
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(228,45,66,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(228,45,66,0.25);
}
.c0:hover,
.c0:focus {
box-shadow: 0 2px 12px 2px rgba(228,45,66,0.25);
}
.c0:active {
box-shadow: 0 4px 16px 2px rgba(228,45,66,0.25);
}
.c0:focus:enabled,
.c0:hover:enabled {
background: #e42d42;
color: #ffffff;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) background, 0.1875s cubic-bezier(0.375,0,0.675,1) color;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) background, 0.1875s cubic-bezier(0.375,0,0.675,1) color;
}
`;
exports[`OutlineButton with custom color 1`] = `
.c0 {
margin: 0px;
padding-left: 22px;
padding-right: 22px;
padding-top: 16px;
padding-bottom: 16px;
background-color: #ffffff;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
text-transform: uppercase;
box-shadow: 0 2px 12px rgba(0,0,0,0.125);
background: transparent;
border-width: 2px;
border-style: solid;
border-color: #ffffff;
box-shadow: none;
color: #ffffff;
}
.c0:hover,
.c0:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(255,255,255,0.25);
}
.c0:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(255,255,255,0.25);
}
.c0:hover,
.c0:focus {
box-shadow: 0 2px 12px 2px rgba(255,255,255,0.25);
}
.c0:active {
box-shadow: 0 4px 16px 2px rgba(255,255,255,0.25);
}
.c0:focus:enabled,
.c0:hover:enabled {
background: #ffffff;
color: #ffffff;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) background, 0.1875s cubic-bezier(0.375,0,0.675,1) color;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) background, 0.1875s cubic-bezier(0.375,0,0.675,1) color;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Section.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Section renders 1`] = `
.c2 {
padding-left: 18px;
padding-right: 18px;
padding-top: 24px;
padding-bottom: 24px;
color: #ffffff;
text-align: center;
}
.c1 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.c0 {
text-align: center;
}
@media screen and (min-width:32em) {
.c2 {
padding-top: 36px;
padding-bottom: 36px;
}
}
`;
================================================
FILE: src/__tests__/__snapshots__/Sheet.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Sheet renders 1`] = `
.c3 {
margin-left: auto;
margin-right: auto;
padding: 18px;
width: 100%;
background-color: rgba(255,255,255,0.875);
}
.c2 {
max-width: 72rem;
}
.c1 {
border-radius: 4px;
}
.c0 {
position: relative;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0,0,0,0.0625);
}
@media screen and (min-width:32em) {
.c3 {
padding: 24px;
}
}
`;
================================================
FILE: src/__tests__/__snapshots__/Slider.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Slider renders 1`] = `
.c0 {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: block;
border-radius: 9999px;
height: 4px;
cursor: pointer;
width: 100%;
background-color: #dde1e4;
color: #e42d42;
}
.c0::-webkit-slider-thumb {
width: 16px;
height: 16px;
background-color: currentColor;
border: 0;
border-radius: 9999px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Submit.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Submit renders 1`] = `
.c1 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
}
.c1:hover,
.c1:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(228,45,66,0.25);
}
.c1:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(228,45,66,0.25);
}
.c0 {
text-transform: uppercase;
}
`;
exports[`Submit renders lg 1`] = `
.c1 {
margin: 0px;
padding-left: 18px;
padding-right: 18px;
padding-top: 12px;
padding-bottom: 12px;
background-color: #e42d42;
color: #ffffff;
font-size: 24px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: middle;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: bold;
line-height: 1.125;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
-webkit-transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
transition: 0.1875s cubic-bezier(0.375,0,0.675,1) box-shadow;
box-shadow: 0 2px 4px rgba(0,0,0,0.125);
border-radius: 9999px;
border: none;
}
.c1:hover,
.c1:focus {
outline: 0;
box-shadow: 0 2px 6px rgba(228,45,66,0.25);
}
.c1:active {
outline: 0;
box-shadow: 0 2px 8px 2px rgba(228,45,66,0.25);
}
.c0 {
text-transform: uppercase;
}
`;
================================================
FILE: src/__tests__/__snapshots__/Text.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Text align prop sets text-align 1`] = `
.c0 {
margin: 0px;
text-align: center;
}
`;
exports[`Text bold prop sets font-weight 1`] = `
.c0 {
margin: 0px;
font-weight: bold;
}
`;
exports[`Text caps prop sets text-transform 1`] = `
.c0 {
margin: 0px;
text-transform: uppercase;
}
`;
exports[`Text maxWidth prop sets max-width 1`] = `
.c0 {
margin: 0px;
max-width: 48rem;
}
`;
exports[`Text mt prop sets margin-top 1`] = `
.c0 {
margin: 0px;
margin-top: 12px;
}
`;
exports[`Text regular prop sets font-weight 1`] = `
.c0 {
margin: 0px;
font-weight: regular;
}
`;
exports[`Text renders 1`] = `
.c0 {
margin: 0px;
}
`;
================================================
FILE: src/__tests__/__snapshots__/ThemeProvider.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ThemeProvider renders content with theme 1`] = `
.c0 {
color: #e42d42;
}
Hello!
`;
================================================
FILE: src/__tests__/__snapshots__/theme.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`theme snapshot 1`] = `
Object {
"bold": "bold",
"boxShadows": Array [
"0 0 2px 0 rgba(0,0,0,.0625),0 2px 4px 0 rgba(0,0,0,0.125)",
"0 0 2px 0 rgba(0,0,0,.0625),0 4px 8px 0 rgba(0,0,0,0.125)",
"0 0 2px 0 rgba(0,0,0,.0625),0 12px 12px 0 rgba(0,0,0,0.125)",
"0 0 2px 0 rgba(0,0,0,.0625),0 24px 24px 0 rgba(0,0,0,0.125)",
],
"breakpoints": Array [
32,
48,
64,
80,
],
"colors": Object {
"accent": "#7280ed",
"base": "#2d9ce4",
"black": "#384046",
"blue": Array [
"#e6f4fc",
"#cce7f8",
"#add9f5",
"#8bc9f0",
"#62b6eb",
"#2d9ee4",
"#298fce",
"#247db4",
"#1d6795",
"#154a6b",
],
"cyan": Array [
"#e7fcfa",
"#ccf9f3",
"#aff5ed",
"#8cf0e5",
"#63ebdb",
"#2de4cf",
"#29cebb",
"#24b5a5",
"#1e9789",
"#166d63",
],
"dark": "#17171d",
"darker": "#121217",
"error": "#b52434",
"fuschia": Array [
"#faebfc",
"#f5d4fa",
"#efbaf6",
"#e89bf2",
"#df73ed",
"#cf2de4",
"#bb29ce",
"#a424b5",
"#881d95",
"#61156b",
],
"gray": Array [
"#f9f9fa",
"#ebeeef",
"#dde1e4",
"#cdd4d8",
"#bcc5cb",
"#a9b5bc",
"#93a2ab",
"#7a8c97",
"#606e77",
"#384046",
],
"green": Array [
"#eafce7",
"#d2f9cd",
"#b7f5b0",
"#99f08d",
"#73eb64",
"#42e42d",
"#3cce29",
"#35b524",
"#2c971e",
"#206d16",
],
"indigo": Array [
"#ebedfc",
"#d4d8f9",
"#bac1f6",
"#9aa4f2",
"#7280ed",
"#2d42e4",
"#283bcd",
"#2334b3",
"#1d2a92",
"#141e66",
],
"info": "#2d9ee4",
"lime": Array [
"#f2fbe4",
"#e5f8c6",
"#d6f4a6",
"#c6ef83",
"#b3ea5b",
"#9ee42d",
"#8fce29",
"#7eb524",
"#69971e",
"#4c6d16",
],
"muted": "#7a8c97",
"orange": Array [
"#fcefe7",
"#f9ddcc",
"#f5caaf",
"#f0b38d",
"#eb9763",
"#e4732d",
"#ce6829",
"#b45b24",
"#954b1d",
"#6b3615",
],
"pink": Array [
"#fcebf6",
"#fad5eb",
"#f6bbdf",
"#f29cd1",
"#ed73be",
"#e42d9e",
"#ce298f",
"#b5247d",
"#961e68",
"#6b154a",
],
"primary": "#e42d42",
"red": Array [
"#fcebed",
"#fad5d9",
"#f6bcc2",
"#f29da7",
"#ed7582",
"#e42d42",
"#ce293c",
"#b52434",
"#951d2b",
"#6b151f",
],
"silver": "#7a8c97",
"slate": "#606e77",
"smoke": "#dde1e4",
"snow": "#f9f9fa",
"success": "#2de473",
"teal": Array [
"#e7fcef",
"#cdf9de",
"#b0f5ca",
"#8df0b3",
"#64eb98",
"#2de473",
"#29ce68",
"#24b55c",
"#1e974c",
"#166d37",
],
"violet": Array [
"#f2ebfc",
"#e3d4fa",
"#d1baf6",
"#bd9bf2",
"#a173ed",
"#732de4",
"#6829cd",
"#5a23b3",
"#4a1d93",
"#341467",
],
"warning": "#e4732d",
"white": "#ffffff",
"yellow": Array [
"#fbf9e3",
"#f7f2c4",
"#f3eaa4",
"#efe280",
"#ead959",
"#e4cf2d",
"#cebb29",
"#b5a524",
"#97891e",
"#6d6316",
],
},
"cx": [Function],
"font": "\\"Phantom Sans\\",-apple-system,BlinkMacSystemFont,\\"Segoe UI\\",Roboto,sans-serif,\\"Apple Color Emoji\\",\\"Segoe UI Emoji\\",\\"Segoe UI Symbol\\"",
"fontSizes": Array [
13.5,
16,
18,
24,
27,
36,
48,
54,
72,
96,
],
"fontWeights": Object {
"bold": "bold",
"regular": "regular",
},
"gradient": [Function],
"hexa": [Function],
"mediaQueries": Object {
"0": "@media screen and (min-width:32em)",
"1": "@media screen and (min-width:48em)",
"2": "@media screen and (min-width:64em)",
"3": "@media screen and (min-width:80em)",
"reduceMotion": "@media (prefers-reduced-motion: reduce)",
"reduceTransparency": "@media (prefers-reduced-transparency: reduce)",
},
"mono": "SFMono-Regular,\\"Roboto Mono\\",Menlo,monospace",
"pill": "9999px",
"radii": Array [
"0px",
"4px",
"8px",
"16px",
"9999px",
],
"radius": "4px",
"regular": "regular",
"scaleFactor": 1.0625,
"shadowColor": "rgba(0,0,0,0.125)",
"space": Array [
0,
6,
12,
18,
24,
36,
72,
108,
144,
288,
432,
],
"transition": "0.1875s cubic-bezier(0.375, 0, 0.675, 1)",
}
`;
================================================
FILE: src/__tests__/theme.js
================================================
import theme, { cx, colors, space, fontSizes, boxShadows } from '../theme'
const aliases = ['sm', 'md', 'lg', 'xl']
describe('theme', () => {
test('exports an object', () => {
expect(typeof theme).toBe('object')
})
test('snapshot', () => {
expect(theme).toMatchSnapshot()
})
test('exports colors', () => {
expect(typeof colors).toBe('object')
})
test('cx works', () => {
expect(theme.cx('red.5')).toBe(theme.colors.red[5])
expect(theme.cx('#ff6d00')).toBe('#ff6d00')
})
test('hexa works', () => {
expect(theme.hexa('primary')).toBe('rgb(228, 45, 66)')
expect(theme.hexa('primary', 0.5)).toBe('rgba(228, 45, 66, 0.5)')
})
test('gradient works', () => {
const sample = theme.gradient('accent', 'info')
expect(sample).toMatch('radial-gradient')
expect(sample).toMatch(cx('accent'))
expect(sample).toMatch(cx('info'))
})
test('scales are objects', () => {
expect(typeof space).toBe('object')
expect(typeof fontSizes).toBe('object')
expect(typeof boxShadows).toBe('object')
})
test('breakpoints have aliases', () => {
aliases.forEach((alias, i) =>
expect(theme.breakpoints[alias]).toEqual(theme.breakpoints[i])
)
})
test('media queries have aliases', () => {
aliases.forEach((alias, i) =>
expect(theme.mediaQueries[alias]).toEqual(theme.mediaQueries[i])
)
expect(theme.mediaQueries.reduceMotion).toEqual(
'@media (prefers-reduced-motion: reduce)'
)
expect(theme.mediaQueries.reduceTransparency).toEqual(
'@media (prefers-reduced-transparency: reduce)'
)
})
})
================================================
FILE: src/index.js
================================================
export { default as Avatar } from './Avatar'
export { default as BackgroundImage } from './BackgroundImage'
export { default as Badge } from './Badge'
export { default as BlockLink } from './BlockLink'
export { default as Box } from './Box'
export { default as Button } from './Button'
export { default as Card } from './Card'
export { default as Container } from './Container'
export { default as Field } from './Field'
export { default as Flex } from './Flex'
export { default as Heading } from './Heading'
export { default as Hide } from './Hide'
export { default as Icon } from './Icon'
export { default as IconButton } from './IconButton'
export { default as Image } from './Image'
export { default as Input } from './Input'
export { default as Label } from './Label'
export { default as LargeButton } from './LargeButton'
export { default as Link } from './Link'
export { default as Loading } from './Loading'
export { default as OutlineButton } from './OutlineButton'
export { default as Section } from './Section'
export { default as Sheet } from './Sheet'
export { default as Slider } from './Slider'
export { default as Submit } from './Submit'
export { default as Text } from './Text'
export { default as theme } from './theme'
export { default as ThemeProvider } from './ThemeProvider'
export * from './theme'
================================================
FILE: src/theme.js
================================================
import palx from 'palx'
import { includes, get } from 'lodash'
const red = '#e42d42'
const blue = '#2d9ce4'
export const palette = palx(blue)
export const grays = {
darker: '#121217',
dark: '#17171d',
black: palette.black,
slate: palette.gray[8],
silver: palette.gray[7],
smoke: palette.gray[2],
snow: palette.gray[0],
white: '#ffffff'
}
export const brand = {
primary: red,
accent: palette.indigo[4],
success: palette.teal[5],
info: palette.blue[5],
warning: palette.orange[5],
error: palette.red[7],
muted: grays.silver
}
export const colors = {
...brand,
...grays,
...palette
}
export const cx = key => get(colors, key, key)
const createMediaQuery = n => `@media screen and (min-width:${n}em)`
const addAliases = (arr, aliases) =>
aliases.forEach((key, i) =>
Object.defineProperty(arr, key, {
enumerable: false,
get() {
return this[i]
}
})
)
const aliases = ['sm', 'md', 'lg', 'xl']
export const breakpoints = [32, 48, 64, 80]
export const mediaQueries = {
...breakpoints.map(createMediaQuery),
reduceMotion: '@media (prefers-reduced-motion: reduce)',
reduceTransparency: '@media (prefers-reduced-transparency: reduce)'
}
addAliases(breakpoints, aliases)
addAliases(mediaQueries, aliases)
export const space = [0, 6, 12, 18, 24, 36, 72, 108, 144, 288, 432]
const emoji = '"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"'
export const font = `"Phantom Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif,${emoji}`
export const mono = 'SFMono-Regular,"Roboto Mono",Menlo,monospace'
export const fontSizes = [13.5, 16, 18, 24, 27, 36, 48, 54, 72, 96]
export const regular = 'regular'
export const bold = 'bold'
// styled-system's `fontWeight` function can hook into the `fontWeights` object
export const fontWeights = { regular, bold }
export const scaleFactor = 17 / 16
export const transition = `${3 / 16}s cubic-bezier(0.375, 0, 0.675, 1)`
// styled-system’s `borderRadius` function can hook into the `radii` object/array
export const pill = '9999px'
export const radii = ['0px', '4px', '8px', '16px', pill]
export const radius = '4px'
export const shadowColor = 'rgba(0,0,0,0.125)'
export const baseShadow = '0 0 2px 0 rgba(0,0,0,.0625),'
export const boxShadows = [
baseShadow + `0 2px 4px 0 ${shadowColor}`,
baseShadow + `0 4px 8px 0 ${shadowColor}`,
baseShadow + `0 12px 12px 0 ${shadowColor}`,
baseShadow + `0 24px 24px 0 ${shadowColor}`
]
export const hexa = (color, alpha) => {
const hex = cx(color)
if (!includes(hex, '#')) return shadowColor
const r = parseInt(hex.slice(1, 3), 16),
g = parseInt(hex.slice(3, 5), 16),
b = parseInt(hex.slice(5, 7), 16)
if (alpha >= 0) {
return `rgba(${r}, ${g}, ${b}, ${alpha})`
} else {
return `rgb(${r}, ${g}, ${b})`
}
}
export const gradient = (color1, color2) =>
`radial-gradient(
ellipse farthest-corner at top left,
${cx(color1)} 0%, ${cx(color2)} 100%
)`
const theme = {
breakpoints,
mediaQueries,
space,
mono,
font,
fontSizes,
fontWeights,
regular,
bold,
colors,
radii,
radius,
pill,
scaleFactor,
transition,
boxShadows,
shadowColor,
cx,
hexa,
gradient
}
export default theme
================================================
FILE: test-setup.js
================================================
import 'jest-styled-components'
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
Enzyme.configure({ adapter: new Adapter() })