0.2.9 • Published 6 months ago

theme-system v0.2.9

Weekly downloads
891
License
MIT
Repository
github
Last release
6 months ago

Theme System

Note: This is not production ready

At Reversed we make heavy use of both styled-components and styled-system. It offers a great DX but comes at a cost, since each Box component and styled.div call is adding bytes to the JS bundle and these styles are inserted during runtime. We've looked for alternatives and found Linaria which looks great. It's mainly the same API as styled-components, but extracts styles to static css. On the other hand we've looked at https://tailwindcss.com/, which is gaining a lot of attention and rightfully so.

We didn't want to lose our Box component though. So we've build Theme System (name suggestions welcome). Theme-System combines best of both worlds, e.g. utility-clases for maximum reusability but with the DX of styled-system props.

How it works

First step: generating utility classes.

Generate

The generate function accepts a theme object it this form:

import { generate } from 'theme-system'

type Theme = {
  breakpoints: { [key: string]: string | number }
  fontWeights: { [key: string]: string | number }
  fontFamilies: { [key: string]: string | number }
  space: { [key: string]: string | number }
  colors: { [key: string]: string | number }
}

When run, generate will return an object of utility classes based on the values in your theme. You can use this object as a global style with any css-in-js library that supports object style css. For example, with Linaria you can do this:

import { css } from 'linaria'
import { generate } from 'theme-system'
import { theme } from './theme'

export default css`
  :global() {
    ${generate(theme)}
  }
`

Then just import this file once in your application and if your bundler is setup right, you'll have list of utility classes in an external css file.

The amount of properties is limited and based on our most used ones, keeping the css file slim. They could be extended in the future.

Parsins

The parsers are the other half of Theme System. It maps specific props of a component to the utility classes based on your theme. By using generics we have type safety on every available property. Here is an example of a Box component:

import { cx } from 'linaria'
import {
  BackgroundColorProps,
  FlexProps,
  GridProps,
  LayoutProps,
  PositionProps,
  SpaceProps,
  TypographyProps,
  bg,
  flex,
  grid,
  layout,
  position,
  space,
  typography,
} from 'theme-system'
import { theme, Theme } from './theme'

type Props = Omit<HTMLAttributes<HTMLElement>, 'color'> &
  PositionProps &
  SpaceProps<Theme['space']> &
  LayoutProps &
  TypographyProps<Theme['fontFamilies'], Theme['fontWeights'], Theme['colors']> &
  BackgroundColorProps<Theme['colors']> &
  FlexProps &
  GridProps<Theme['space']>

const Box: FC<Props> = ({ children, className, ...rest }) => {
  const classNames = [
    ...bg(rest, theme),
    ...flex(rest, theme),
    ...grid(rest, theme),
    ...layout(rest, theme),
    ...position(rest, theme),
    ...space(rest, theme),
    ...typography(rest, theme),
  ]
  return <div className={cx(...classNames, className)}>{children}</div>
}

export default Box

To ensure type safety, make sure you export the type of your Theme like so: export type Theme = typeof theme

Given that theme.ratio["0"] exists using <Box mt="0"></Box> would render <div className="mt-0"></div>.

Media queries

Equal to styled-system you can use media queries like so: <Box mt={{_: "0", lg: "2"}}/>. Use the _ key for your initial styles, the following keys (like lg) has to match the keys of theme.breakpoints. You'll receive a warning in development if it doens't.

Contributing

Note that this is expiremtal but ideas and pr's are welcome. Theme System is based on TSDX, check that out if you'd like to contribute.

0.2.9-rc1

6 months ago

0.2.9

3 years ago

0.2.8

4 years ago

0.2.7

4 years ago

0.2.6

4 years ago

0.2.5

4 years ago

0.2.3

4 years ago

0.2.4

4 years ago

0.2.2

4 years ago

0.2.1

4 years ago

0.2.0

4 years ago

0.2.0-beta.2

4 years ago

0.2.0-beta.1

4 years ago

0.2.0-beta.0

4 years ago

0.1.1

4 years ago

0.1.0

4 years ago