Skip to content

Instantly share code, notes, and snippets.

@kjbrum
Last active April 19, 2023 22:51
Show Gist options
  • Save kjbrum/a5a0bd2bebcd5e8701ff2ef971d66967 to your computer and use it in GitHub Desktop.
Save kjbrum/a5a0bd2bebcd5e8701ff2ef971d66967 to your computer and use it in GitHub Desktop.
React primitive components using styled-system (with styled-components).
# React Primitives
> React primitive components using styled-system.
import React, { forwardRef } from 'react'
import styled from 'styled-components'
import css, { get } from '@styled-system/css'
import {
system,
compose,
space,
color,
typography,
layout,
flexbox,
grid,
background,
border,
position,
shadow,
} from 'styled-system'
import { getMarginProps, omitMarginProps } from '@utils/helpers'
// Next Link
// import { default as NextLink } from 'next/link'
// Gatsby Link
// import { Link as GatsbyLink } from 'gatsby'
const base = props => css(props.__css)
const sx = props => css(props.sx)
const variant = ({ theme, variant, tx = '' }) =>
css(get(theme, 'variants.' + tx + '.' + variant))(theme)
export const Box = styled.div(
css({
// boxSizing: 'border-box',
// minWidth: 0,
// margin: 0,
// fontFamily: 'sans',
// color: 'gray.900',
}),
base,
variant,
sx,
props => props.css,
system({
textTransform: true,
textDecoration: true,
transform: true,
transition: true,
visibility: true,
pointerEvent: true,
}),
compose(
space,
color,
typography,
layout,
flexbox,
grid,
background,
border,
position,
shadow
)
)
export const Flex = styled(Box)({
display: 'flex',
})
export const Grid = forwardRef((props, ref) => (
<Box
ref={ref}
tx="grid"
__css={css({
display: 'grid',
})}
{...props}
/>
))
export const Text = forwardRef((props, ref) => (
<Box ref={ref} as="p" tx="texts" {...props} />
))
export const Heading = forwardRef((props, ref) => (
<Box ref={ref} as="h2" tx="headings" variant="h2" {...props} />
))
export const Link = forwardRef((props, ref) => (
<Box ref={ref} as="a" tx="links" {...props} />
))
// Next
// export const Link = forwardRef(
// ({ href, as, prefetch, replace, scroll, ...props }, ref) =>
// href && (href.startsWith('/') || href.startsWith('#')) ? (
// <NextLink
// as={as}
// href={href}
// prefetch={prefetch}
// replace={replace}
// scroll={scroll}
// passHref
// >
// <Box ref={ref} as="a" tx="links" {...props} />
// </NextLink>
// ) : (
// <Box
// ref={ref}
// as="a"
// href={href}
// rel="nofollow noopener"
// tx="links"
// {...props}
// />
// )
// )
// Gatsby
// export const Link = forwardRef(({ href, to, isExternal, ...props }, ref) => {
// const url = to || href
// return isExternal || isAbsoluteURL(url) ? (
// <Box
// ref={ref}
// as="a"
// href={url}
// rel="nofollow noopener"
// tx="links"
// {...props}
// />
// ) : (
// <Box ref={ref} as={GatsbyLink} to={url} tx="links" {...props} />
// )
// })
export const Divider = forwardRef((props, ref) => (
<Box
ref={ref}
as="hr"
tx="dividers"
__css={css({
height: 'px',
my: 8,
bg: 'gray.300',
border: 'none',
})}
{...props}
/>
))
export const Button = forwardRef((props, ref) => {
const defaultStyles = {
cursor: 'pointer',
appearance: 'none',
display: 'inline-block',
textAlign: 'center',
lineHeight: 'inherit',
textDecoration: 'none',
fontSize: 'inherit',
}
const specialStyles =
props.variant !== 'plain'
? {
px: 6,
py: 3,
border: 1,
borderRadius: 3,
}
: {
'&:hover': {
color: 'gray.600',
},
}
return (
<Box
ref={ref}
as="button"
tx="buttons"
variant="primary"
__css={css({
...defaultStyles,
...specialStyles,
})}
{...props}
/>
)
})
export const Image = forwardRef((props, ref) => (
<Box ref={ref} as="img" tx="images" alt="" {...props} />
))
export const SVG = ({ width = 16, height = 16, ...props }) => (
<Box
as="svg"
xmlns="http://www.w3.org/2000/svg"
// width={width || null}
// height={height || null}
viewBox={`0 0 ${parseInt(width, 10)} ${parseInt(height, 10)}`}
fill="currentcolor"
{...props}
/>
)
export const Code = forwardRef((props, ref) => {
const sharedStyles = {
m: '0',
direction: 'ltr',
fontFamily: 'mono',
color: 'gray.900',
textAlign: 'left',
fontSize: 'xs',
fontWeight: 'normal',
lineHeight: 'normal',
textDecoration: 'none',
whiteSpace: 'pre',
wordSpacing: 'normal',
wordBreak: 'normal',
wordWrap: 'normal',
tabSize: '4',
hyphens: 'none',
bg: 'gray.100',
borderRadius: 3,
}
return (
<Box
as="pre"
{...getMarginProps(props)}
__css={css({
...sharedStyles,
overflow: 'auto',
p: 4,
border: '1px solid',
borderColor: 'gray.200',
})}
>
<Box
ref={ref}
as="code"
tx="code"
{...omitMarginProps(props)}
__css={css({
...sharedStyles,
})}
/>
</Box>
)
})
import { createGlobalStyle } from 'styled-components'
export const CSSReset = createGlobalStyle`
/* CSS Reset (Inspired by TailwindCSS) */
html{
line-height: 1.15;
-webkit-text-size-adjust: 100%;
}
body{
margin: 0;
}
main{
display: block;
}
hr{
box-sizing: content-box;
height: 0;
overflow: visible;
}
pre{
font-family: monospace,monospace;
font-size: 1em;
}
a{
background-color: transparent;
}
abbr[title]{
border-bottom: none;
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
b,strong{
font-weight: bold;
}
code,kbd,samp{
font-family: monospace,monospace;
font-size: 1em;
}
small{
font-size: 80%;
}
sub,sup{
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub{
bottom: -0.25em;
}
sup{
top: -.5em;
}
img{
border-style: none;
}
button,input,optgroup,select,textarea{
font-family: inherit;
font-size: 100%;
line-height: 1.15;
margin: 0;
}
button,input{
overflow: visible;
}
button,select{
text-transform: none;
}
[type=button],[type=reset],[type=submit],button{
-webkit-appearance: button;
}
[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{
border-style: none;
padding: 0;
}
[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{
outline: 1px dotted ButtonText;
}
fieldset{
padding: 0.35em 0.75em 0.625em;
}
legend{
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal;
}
progress{
vertical-align: baseline;
}
textarea{
overflow: auto;
}
[type=checkbox],
[type=radio]{
box-sizing: border-box;
padding: 0;
}
[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{
height: auto;
}
[type=search]{
-webkit-appearance: textfield;
outline-offset: -2px;
}
[type=search]::-webkit-search-decoration{
-webkit-appearance: none;
}
::-webkit-file-upload-button{
-webkit-appearance: button;
font: inherit;
}
details{
display: block;
}
summary{
display: list-item;
}
template{
display: none;
}
[hidden]{
display: none;
}
html{
box-sizing: border-box;
font-family: sans-serif;
}
*,::after,::before{
box-sizing: inherit;
}
blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{
margin: 0;
}
button{
background: 0 0;
padding: 0;
border: 0;
}
button:focus{
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
fieldset{
margin: 0;
padding: 0;
}
ol,ul{
list-style: none;
margin: 0;
padding: 0;
}
html{
font-family: ${props => props.theme.fonts.sans};
line-height: 1.5;
}
img{
border: 0;
}
textarea{
resize: vertical;
}
input:-ms-input-placeholder,textarea:-ms-input-placeholder{
color: ${props => props.theme.colors.neutral[700]};
}
input::-ms-input-placeholder,textarea::-ms-input-placeholder{
color: ${props => props.theme.colors.neutral[700]};
}
input::placeholder,textarea::placeholder{
color: ${props => props.theme.colors.neutral[700]};
}
[role=button],button{
cursor: pointer;
}
table{
border-collapse: collapse;
}
h1,h2,h3,h4,h5,h6{
font-size: inherit;
font-weight: inherit;
}
a{
color: inherit;
text-decoration: inherit;
}
button,input,optgroup,select,textarea{
padding: 0;
line-height: inherit;
color: inherit;
}
code,kbd,pre,samp{
font-family: ${props => props.theme.fonts.mono}
}
audio,canvas,embed,iframe,img,object,svg,video{
display: block;
vertical-align: middle;
}
img,video{
max-width: 100%;
height: auto;
}
`
export default CSSReset
import React, { forwardRef } from 'react'
import { Box, Flex, SVG } from './Base'
import { getMarginProps, omitMarginProps } from '@utils/helpers'
export const Label = forwardRef((props, ref) => (
<Flex
ref={ref}
as="label"
tx="forms"
variant="label"
{...props}
__css={{
width: '100%',
fontWeight: 'bold',
cursor: 'pointer',
}}
/>
))
export const Input = forwardRef((props, ref) => (
<Box
ref={ref}
as="input"
type="text"
tx="forms"
variant="input"
{...props}
__css={{
display: 'block',
width: '100%',
p: 2,
appearance: 'none',
fontSize: 'inherit',
lineHeight: 'inherit',
border: '1px solid',
borderRadius: 3,
color: 'inherit',
bg: 'transparent',
}}
/>
))
export const Textarea = forwardRef((props, ref) => (
<Box
ref={ref}
as="textarea"
tx="forms"
variant="textarea"
{...props}
__css={{
display: 'block',
width: '100%',
p: 2,
appearance: 'none',
fontSize: 'inherit',
lineHeight: 'inherit',
border: '1px solid',
borderRadius: 3,
color: 'inherit',
bg: 'transparent',
}}
/>
))
const SelectArrow = props => (
<SVG {...props}>
<path d="M5.293 6.95L6 7.657 11.657 2 10.243.586 6 4.828 1.757.586.343 2z" />
</SVG>
)
export const Select = forwardRef((props, ref) => (
<Flex {...getMarginProps(props)}>
<Box
ref={ref}
as="select"
tx="forms"
variant="select"
{...omitMarginProps(props)}
__css={{
display: 'block',
width: '100%',
p: 2,
appearance: 'none',
fontSize: 'inherit',
lineHeight: 'inherit',
border: '1px solid',
borderRadius: 3,
color: 'inherit',
bg: 'transparent',
}}
/>
<SelectArrow
width="12"
height="8"
aria-hidden={true}
sx={{
position: 'relative',
right: 2,
ml: '-12px',
alignSelf: 'center',
pointerEvents: 'none',
}}
/>
</Flex>
))
const RadioChecked = props => (
<SVG {...props}>
<path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" />
</SVG>
)
const RadioUnchecked = props => (
<SVG {...props}>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" />
</SVG>
)
const RadioIcon = props => (
<>
<RadioChecked
{...props}
__css={{
display: 'none',
'input:checked ~ &': {
display: 'block',
},
}}
/>
<RadioUnchecked
{...props}
__css={{
display: 'block',
'input:checked ~ &': {
display: 'none',
},
}}
/>
</>
)
export const Radio = forwardRef(
({ className, sx, variant = 'radio', ...props }, ref) => (
<Box>
<Box
ref={ref}
as="input"
type="radio"
{...props}
sx={{
position: 'absolute',
overflow: 'hidden',
width: 1,
height: 1,
opacity: 0,
zIndex: -1,
}}
/>
<Box
as={RadioIcon}
aria-hidden={true}
tx="forms"
variant={variant}
className={className}
sx={sx}
// {...getSystemProps(props)}
__css={{
mr: 2,
borderRadius: 'full',
color: 'gray',
'input:checked ~ &': {
color: 'gray.900',
},
'input:focus ~ &': {
bg: 'gray.400',
},
}}
/>
</Box>
)
)
const CheckboxChecked = props => (
<SVG {...props}>
<path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
</SVG>
)
const CheckboxUnchecked = props => (
<SVG {...props}>
<path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z" />
</SVG>
)
const CheckboxIcon = props => (
<>
<CheckboxChecked
{...props}
__css={{
display: 'none',
'input:checked ~ &': {
display: 'block',
},
}}
/>
<CheckboxUnchecked
{...props}
__css={{
display: 'block',
'input:checked ~ &': {
display: 'none',
},
}}
/>
</>
)
export const Checkbox = forwardRef(
({ className, sx, variant = 'checkbox', ...props }, ref) => (
<Box>
<Box
ref={ref}
as="input"
type="checkbox"
{...props}
sx={{
position: 'absolute',
opacity: 0,
zIndex: -1,
width: 1,
height: 1,
overflow: 'hidden',
}}
/>
<Box
as={CheckboxIcon}
aria-hidden={true}
tx="forms"
variant={variant}
className={className}
sx={sx}
// {...getSystemProps(props)}
__css={{
mr: 2,
borderRadius: 3,
color: 'gray.900',
'input:checked ~ &': {
color: 'gray.900',
},
'input:focus ~ &': {
color: 'gray.900',
bg: 'gray.400',
},
}}
/>
</Box>
)
)
export const Switch = forwardRef(({ checked, ...props }, ref) => {
const switchSize = 6
return (
<Box
ref={ref}
as="button"
type="button"
role="switch"
tx="forms"
variant="switch"
aria-checked={checked}
{...props}
__css={{
appearance: 'none',
m: 0,
p: 0,
width: switchSize * 2,
height: switchSize,
color: 'gray.600',
bg: 'transparent',
border: '1px solid',
borderColor: 'gray.900',
borderRadius: 'full',
// '&[aria-checked=true]': {
// bg: 'gray.100',
// },
':focus': {
outline: 'none',
boxShadow: '0 0 0 2px',
},
}}
>
<Box
aria-hidden={true}
style={{
transform: checked
? `translateX(${switchSize * 4}px)`
: 'translateX(0)',
}}
sx={{
mt: '-1px',
ml: '-1px',
width: switchSize,
height: switchSize,
borderRadius: 'full',
border: '1px solid',
borderColor: 'gray.900',
bg: checked ? 'gray.700' : 'gray.400',
transitionProperty: 'transform',
transitionTimingFunction: 'ease-out',
transitionDuration: '0.1s',
}}
/>
</Box>
)
})
export const Slider = forwardRef(({ ...props }, ref) => (
<Box
ref={ref}
as="input"
type="range"
tx="forms"
variant="slider"
{...props}
__css={{
display: 'block',
width: '100%',
height: '2px',
my: 3,
cursor: 'pointer',
appearance: 'none',
borderRadius: 'full',
color: 'gray.500',
bg: 'gray.200',
':focus': {
outline: 'none',
color: 'gray.700',
},
'&::-webkit-slider-thumb': {
appearance: 'none',
width: 6,
height: 6,
bg: 'currentcolor',
border: '1px solid',
borderColor: 'gray.900',
borderRadius: 'full',
},
}}
/>
))
import { createGlobalStyle } from 'styled-components'
export const GlobalStyles = createGlobalStyle`
html,
body {
box-sizing: border-box;
overflow-x: hidden;
min-width: 320px;
max-width: 100%;
margin: 0;
font-family: ${props => props.theme.fonts.sans};
color: ${props => props.theme.colors.neutral[900]};
}
`
export default GlobalStyles
// Retrieve a key value from an object
export function get(object, key) {
var keys = key.split('.')
for (var i = 0; i < keys.length; i++) {
if (!object.hasOwnProperty(keys[i])) {
return null
}
object = object[keys[i]]
}
return object
}
// Remove margin values from props
const MRE = /^m[trblxy]?$/
export const getProps = test => props => {
const next = {}
for (const key in props) {
if (test(key || '')) next[key] = props[key]
}
return next
}
export const getMarginProps = getProps(k => MRE.test(k))
export const omitMarginProps = getProps(k => !MRE.test(k))
import { fluidRange } from 'polished'
export const theme = {
breakpoints: [
'30rem', // xs / 480px
'40rem', // sm / 640px
'48rem', // md / 768px
'64rem', // lg / 1024px
'80rem', // xl / 1280px
],
colors: {
transparent: 'transparent',
black: '#222222',
white: '#ffffff',
gray: {
100: '#f7fafc',
200: '#edf2f7',
300: '#e2e8f0',
400: '#cbd5e0',
500: '#a0aec0',
600: '#718096',
700: '#4a5568',
800: '#2d3748',
900: '#1a202c',
},
red: {
100: '#fff5f5',
200: '#fed7d7',
300: '#feb2b2',
400: '#fc8181',
500: '#f56565',
600: '#e53e3e',
700: '#c53030',
800: '#9b2c2c',
900: '#742a2a',
},
orange: {
100: '#fffaf0',
200: '#feebc8',
300: '#fbd38d',
400: '#f6ad55',
500: '#ed8936',
600: '#dd6b20',
700: '#c05621',
800: '#9c4221',
900: '#7b341e',
},
yellow: {
100: '#fffff0',
200: '#fefcbf',
300: '#faf089',
400: '#f6e05e',
500: '#ecc94b',
600: '#d69e2e',
700: '#b7791f',
800: '#975a16',
900: '#744210',
},
green: {
100: '#f0fff4',
200: '#c6f6d5',
300: '#9ae6b4',
400: '#68d391',
500: '#48bb78',
600: '#38a169',
700: '#2f855a',
800: '#276749',
900: '#22543d',
},
teal: {
100: '#e6fffa',
200: '#b2f5ea',
300: '#81e6d9',
400: '#4fd1c5',
500: '#38b2ac',
600: '#319795',
700: '#2c7a7b',
800: '#285e61',
900: '#234e52',
},
blue: {
100: '#ebf8ff',
200: '#bee3f8',
300: '#90cdf4',
400: '#63b3ed',
500: '#4299e1',
600: '#3182ce',
700: '#2b6cb0',
800: '#2c5282',
900: '#2a4365',
},
indigo: {
100: '#ebf4ff',
200: '#c3dafe',
300: '#a3bffa',
400: '#7f9cf5',
500: '#667eea',
600: '#5a67d8',
700: '#4c51bf',
800: '#434190',
900: '#3c366b',
},
purple: {
100: '#faf5ff',
200: '#e9d8fd',
300: '#d6bcfa',
400: '#b794f4',
500: '#9f7aea',
600: '#805ad5',
700: '#6b46c1',
800: '#553c9a',
900: '#44337a',
},
pink: {
100: '#fff5f7',
200: '#fed7e2',
300: '#fbb6ce',
400: '#f687b3',
500: '#ed64a6',
600: '#d53f8c',
700: '#b83280',
800: '#97266d',
900: '#702459',
},
},
space: {
auto: 'auto',
px: '1px',
em: '1em',
0: '0',
1: '0.25rem',
2: '0.5rem',
3: '0.75rem',
4: '1rem',
5: '1.25rem',
6: '1.5rem',
8: '2rem',
10: '2.5rem',
12: '3rem',
16: '4rem',
20: '5rem',
24: '6rem',
32: '8rem',
40: '10rem',
48: '12rem',
56: '14rem',
64: '16rem',
80: '20rem',
96: '24rem',
128: '32rem',
160: '40rem',
192: '48rem',
224: '56rem',
256: '64rem',
screenW: '100vw',
screenH: '100vh',
full: '100%',
},
sizes: {
auto: 'auto',
px: '1px',
em: '1em',
0: '0',
1: '0.25rem',
2: '0.5rem',
3: '0.75rem',
4: '1rem',
5: '1.25rem',
6: '1.5rem',
8: '2rem',
10: '2.5rem',
12: '3rem',
16: '4rem',
20: '5rem',
24: '6rem',
32: '8rem',
40: '10rem',
48: '12rem',
56: '14rem',
64: '16rem',
80: '20rem',
96: '24rem',
128: '32rem',
160: '40rem',
192: '48rem',
224: '56rem',
256: '64rem',
screenW: '100vw',
screenH: '100vh',
full: '100%',
},
fonts: {
sans:
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
serif: 'Georgia, Cambria, "Times New Roman", Times, serif',
mono:
'Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
},
fontSizes: {
xxs: '0.625rem',
xs: '0.75rem',
sm: '0.875rem',
base: '1rem',
lg: '1.125rem',
xl: '1.25rem',
'2xl': '1.5rem',
'3xl': '1.875rem',
'4xl': '2.25rem',
'5xl': '3rem',
'6xl': '4rem',
},
fontWeights: {
hairline: '100',
thin: '200',
light: '300',
normal: '400',
medium: '500',
semibold: '600',
bold: '700',
extrabold: '800',
black: '900',
},
lineHeights: {
none: '1',
tight: '1.25',
snug: '1.375',
normal: '1.5',
relaxed: '1.625',
loose: '2',
},
letterSpacings: {
tighter: '-0.05em',
tight: '-0.025em',
normal: '0',
wide: '0.025em',
wider: '0.05em',
widest: '0.1em',
},
borders: {
none: '0',
1: '1px solid',
2: '2px solid',
4: '4px solid',
8: '8px solid',
},
borderWidths: {
0: '0px',
1: '1px',
2: '2px',
4: '4px',
8: '8px',
},
radii: {
none: '0',
3: '3px',
5: '5px',
8: '8px',
16: '16px',
100: '100%',
full: '9999px',
},
shadows: {
none: 'none',
default:
'0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
md:
'0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
lg:
'0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
xl:
'0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
outline: '0 0 0 3px rgba(66, 153, 225, 0.5)',
},
zIndices: {
auto: 'auto',
bottom: '-9999',
'0': '0',
'10': '10',
'20': '20',
'30': '30',
'40': '40',
'50': '50',
top: '9999',
},
}
// Breakpoint aliases
theme.breakpoints.xs = theme.breakpoints[0]
theme.breakpoints.sm = theme.breakpoints[1]
theme.breakpoints.md = theme.breakpoints[2]
theme.breakpoints.lg = theme.breakpoints[3]
theme.breakpoints.xl = theme.breakpoints[4]
// Sizes aliases
theme.sizes = {
...theme.space,
xs: theme.breakpoints.xs,
sm: theme.breakpoints.sm,
md: theme.breakpoints.md,
lg: theme.breakpoints.lg,
xl: theme.breakpoints.xl,
xxl: theme.breakpoints.xxl,
xxxl: theme.breakpoints.xxxl,
}
const fluidFont = (min, max) =>
fluidRange(
{
prop: 'font-size',
fromSize: theme.fontSizes[min],
toSize: theme.fontSizes[max],
},
theme.breakpoints['xs'],
theme.breakpoints['xl']
)
theme.variants = {
general: {},
flex: {},
grid: {},
texts: {},
headings: {
display1: {
...fluidFont('2xl', '6xl'),
lineHeight: 'none',
},
display2: {
...fluidFont('2xl', '5xl'),
lineHeight: 'none',
},
h1: {
...fluidFont('xl', '4xl'),
lineHeight: 'none',
},
h2: {
...fluidFont('xl', '3xl'),
lineHeight: 'tight',
},
h3: {
...fluidFont('xl', '2xl'),
lineHeight: 'tight',
},
h4: {
...fluidFont('base', 'xl'),
lineHeight: 'tight',
},
h5: {
fontSize: 'base',
},
h6: {
fontSize: 'xs',
},
},
links: {},
dividers: {},
buttons: {
primary: {
px: 6,
py: 3,
color: 'white',
bg: 'gray.700',
border: 1,
borderColor: 'gray.700',
borderRadius: 3,
':hover': {
bg: 'gray.500',
borderColor: 'gray.500',
},
},
outline: {
px: 6,
py: 3,
color: 'gray.700',
bg: 'transparent',
border: 1,
borderColor: 'gray.700',
borderRadius: 3,
':hover': {
color: 'gray.500',
borderColor: 'gray.500',
},
},
},
images: {},
forms: {
label: {},
error: {
fontSize: 'sm',
color: 'red',
},
input: {},
textarea: {},
select: {},
radio: {},
checkbox: {},
switch: {},
slider: {},
},
}
export default theme
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment