Skip to content

Instantly share code, notes, and snippets.

@smashercosmo
Last active Jun 2, 2020
Embed
What would you like to do?
Box
* {
--pl: initial;
--pr: initial;
--pt: initial;
--pb: initial;
--ml: initial;
--mr: initial;
--mt: initial;
--mb: initial;
--c: initial;
--bgc: initial;
--bdc: initial;
--bds: initial;
--bdrw: initial;
--bdlw: initial;
--bdtw: initial;
--bdbw: initial;
--fw: initial;
--ff: initial;
--fs: initial;
--fz: initial;
--ws: initial;
--wbrk: initial;
--ta: initial;
--d: initial;
--o: initial;
--pos: initial;
--fxw: initial;
--fxai: initial;
--fxjc: initial;
}
.root {
padding: var(--pt, 0) var(--pr, 0) var(--pb, 0) var(--pl, 0);
margin: var(--mt, 0) var(--mr, 0) var(--mb, 0) var(--ml, 0);
color: var(--c);
background-color: var(--bgc);
border-color: var(--bdc);
border-style: var(--bds);
border-width: var(--bdtw, 0) var(--bdrw, 0) var(--bdbw, 0) var(--bdlw, 0);
font: var(--fs, normal) var(--fw, normal) var(--fz, var(--default-font-size))
var(--ff, var(--default-font-family));
white-space: var(--ws);
word-break: var(--wbrk);
text-align: var(--ta);
display: var(--d, block);
overflow: var(--o);
position: var(--pos);
flex-wrap: var(--fxw);
align-items: var(--fxai);
justify-content: var(--fxjc);
}
import React from 'react'
import styles from './Box.css'
const fontFamily = {
mono: 'Courier, monospace',
sans: '"Roboto Condensed", sans-serif',
}
const fontWeight = {
normal: 400,
bold: 600,
}
export type WhiteSpace = 'nowrap' | 'pre'
export type Overflow = 'auto' | 'scroll' | 'hidden' | 'visible'
export type TextAlign = 'left' | 'center' | 'right'
export type AlignItems = 'baseline' | 'center'
export type JustifyContent =
| 'flex-start'
| 'flex-end'
| 'center'
| 'space-between'
export type FontWeight = keyof typeof fontWeight
export type FontFamily = keyof typeof fontFamily
export type Display =
| 'flex'
| 'grid'
| 'inline'
| 'block'
| 'inline-block'
| 'none'
export type Position = 'relative' | 'absolute' | 'fixed' | 'sticky'
export type FontSize = 12 | 14 | 16 | 18 | 24 | 32
export type Color =
| 'white'
| 'grey-x-light'
| 'grey-light'
| 'grey'
| 'grey-dark'
| 'blue'
| 'blue-dark'
| 'blue-x-dark'
| 'blue-xx-dark'
| 'green'
| 'red'
| 'pink'
export type Stroke = 0 | 1 | 2 | 3 | 4
export type PositiveSpace = 0 | 5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50
export type NegativeSpace =
| -50
| -45
| -40
| -35
| -30
| -25
| -20
| -15
| -10
| -5
export type Space = NegativeSpace | PositiveSpace
export type BoxProps = {
children?: React.ReactNode
__dangerousClassName?: string
as?: 'div' | 'span' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'pre'
pl?: PositiveSpace
pr?: PositiveSpace
pt?: PositiveSpace
pb?: PositiveSpace
ml?: Space
mr?: Space
mt?: Space
mb?: Space
c?: Color
bgc?: Color
bdc?: Color
bds?: 'solid'
bdw?: Stroke
bdlw?: Stroke
bdrw?: Stroke
bdtw?: Stroke
bdbw?: Stroke
fw?: FontWeight
ff?: FontFamily
fs?: 'italic'
fz?: FontSize
ws?: WhiteSpace
wbrk?: 'break-word'
ta?: TextAlign
d?: Display
o?: Overflow
pos?: Position
flexWrap?: 'wrap'
alignItems?: AlignItems
justifyContent?: JustifyContent
}
function getVariablesFromProps(props: BoxProps) {
const {
as,
pl,
pr,
pt,
pb,
ml,
mr,
mt,
mb,
c,
bgc,
bdc,
bds,
bdw,
bdrw,
bdlw,
bdtw,
bdbw,
fw,
ff,
fs,
fz,
ws,
wbrk,
ta,
d,
o,
pos,
flexWrap,
alignItems,
justifyContent,
} = props
return {
...(pl ? { [`--pl`]: `${pl}px` } : {}),
...(pr ? { [`--pr`]: `${pr}px` } : {}),
...(pt ? { [`--pt`]: `${pt}px` } : {}),
...(pb ? { [`--pb`]: `${pb}px` } : {}),
...(ml ? { [`--ml`]: `${ml}px` } : {}),
...(mr ? { [`--mr`]: `${mr}px` } : {}),
...(mt ? { [`--mt`]: `${mt}px` } : {}),
...(mb ? { [`--mb`]: `${mb}px` } : {}),
...(c ? { [`--c`]: `var(--${c}-color)` } : {}),
...(bgc ? { [`--bgc`]: `var(--${bgc}-color)` } : {}),
...(bdc ? { [`--bdc`]: `var(--${bdc}-color)` } : {}),
...(bds ? { [`--bds`]: `${bds}` } : {}),
...(bdw
? {
[`--bdrw`]: `${bdrw}px`,
[`--bdlw`]: `${bdlw}px`,
[`--bdtw`]: `${bdrw}px`,
[`--bdbw`]: `${bdbw}px`,
}
: {}),
...(bdrw ? { [`--bdrw`]: `${bdrw}px` } : {}),
...(bdlw ? { [`--bdlw`]: `${bdlw}px` } : {}),
...(bdtw ? { [`--bdtw`]: `${bdtw}px` } : {}),
...(bdbw ? { [`--bdbw`]: `${bdbw}px` } : {}),
...(fw ? { [`--fw`]: fontWeight[fw] } : {}),
...(ff ? { [`--ff`]: fontFamily[ff] } : {}),
...(fs ? { [`--fs`]: `${fs}` } : {}),
...(fz ? { [`--fz`]: `${fz}px` } : {}),
...(as === 'pre' ? { [`--ws`]: 'pre' } : {}),
...(ws ? { [`--ws`]: ws } : {}),
...(wbrk ? { [`--wbrk`]: wbrk } : {}),
...(ta ? { [`--ta`]: ta } : {}),
...(d ? { [`--d`]: d } : {}),
...(o ? { [`--o`]: o } : {}),
...(pos ? { [`--pos`]: pos } : {}),
...(flexWrap ? { [`--fxw`]: flexWrap } : {}),
...(alignItems ? { [`--fxai`]: alignItems } : {}),
...(justifyContent ? { [`--fxjc`]: justifyContent } : {}),
}
}
function Box(props: BoxProps) {
const { children, as: Component = 'div', __dangerousClassName } = props
const style = getVariablesFromProps(props)
return (
<Component
// @ts-ignore
style={style}
className={[styles.root, __dangerousClassName].filter(Boolean).join(' ')}>
{children}
</Component>
)
}
export { Box }
import React, { Children } from 'react'
import flattenChildren from 'react-keyed-flatten-children'
import { Box, PositiveSpace, NegativeSpace } from '../Box/Box'
function getNegativeSpace(space: PositiveSpace) {
return (-1 * space) as NegativeSpace
}
const alignMap = {
left: 'flex-start',
right: 'flex-end',
center: 'center',
justify: 'space-between',
} as const
const valignMap = {
middle: 'center',
baseline: 'baseline',
} as const
type InlineProps = {
children: React.ReactNode
space?: PositiveSpace
align?: keyof typeof alignMap
valign?: keyof typeof valignMap
}
export function Inline(props: InlineProps) {
const { children, space, align, valign } = props
const negativeMargin = space ? getNegativeSpace(space) : undefined
return (
<Box
ml={negativeMargin}
mt={negativeMargin}
d="flex"
flexWrap="wrap"
alignItems={valign ? valignMap[valign] : undefined}
justifyContent={align ? alignMap[align] : undefined}>
{Children.map(flattenChildren(children), (child) =>
child !== null && child !== undefined ? (
<Box pl={space} pt={space}>
{child}
</Box>
) : null,
)}
</Box>
)
}
.item:empty {
display: none;
}
import React, { Children } from 'react'
import flattenChildren from 'react-keyed-flatten-children'
import { Box, Stroke, PositiveSpace, NegativeSpace, Color } from '../Box/Box'
import { Divider } from '../Divider/Divider'
import styles from './Stack.css'
type StackProps = {
children: React.ReactNode
dividerSize?: Stroke
dividerColor?: Color
space?: PositiveSpace
}
function Stack(props: StackProps) {
const { children, space, dividerSize, dividerColor } = props
const rootProps = (space ? { mt: -1 * space } : {}) as { mt?: NegativeSpace }
const itemProps = space ? { pt: space } : {}
const dividerProps =
space && dividerSize && dividerSize > 0 ? { pb: space } : {}
return (
<Box {...rootProps}>
{Children.map(flattenChildren(children), (child, index) => {
return child !== null && child !== undefined ? (
<Box {...itemProps} __dangerousClassName={styles.item}>
{dividerSize && dividerSize > 0 && index > 0 ? (
<Box {...dividerProps}>
<Divider size={dividerSize} color={dividerColor} />
</Box>
) : null}
{child}
</Box>
) : null
})}
</Box>
)
}
export { Stack }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment