erikdstock / roses

an opinionated take on styled-system.
https://roses-ui.netlify.com/
9 stars 0 forks source link

npm version CircleCI

🌹 Roses 🌹

React component library layered atop emotion and @styled-system/css. Built with Typescript.

Skip to setup

roses is a simple, extendable design system. It's written with typescript and builds upon an opinionated extension of the system-ui interface, so type support is first-class.

It builds on the following libraries, so it's best to be familiar with them as well:

For more context and alternatives, see Related Projects

I already know what this stuff is.

TLDR:

Motivation

roses began as work on a design system for my own use- an extension of rebass using styled-components to build a library of reusable, themable components. Over time (and having never built a design system on my own) a couple pain points crept in:

Emotion as the css-in-js library: Early on I ran into some wrinkles around the styled-components' @types package. This was part of the motivation for switching to emotion. Additionally, it is smaller and (as of early 2019) rumoured to be more performant than styled-components.

Responsive, theme-aware styles in a single prop: Collaborators were less enthusiastic about the many styled-system props, especially when combined with the need to define Ts interfaces, account for the presence of a theme and know which props you could use where. By electing to restrict themed styles to a single prop, the total surface area of props to maintain and remember is greatly reduced. It is also designed to be more friendly to users who aren't completely sold on css-in-js. Notably this prop is baldly stolen from theme-ui.

Define core component styles and variants on the theme: Because the system-ui theme spec is wide open, different libraries have augmented it with their own keys. This is fine, but I wanted to introduce a bit of stability and the ability to define core component styles like those exported from rebass within the theme itself. @styled-system/css makes this pretty straightforward:

Setup

Add the package and any missing peer dependencies:

yarn add roses @styled-system/css @emotion/core @emotion/styled
# if using ts
# yarn add -D @types/styled-system__css @types/styled-system etc ...

Configure ThemeProvider

All of your components must to be wrapped in an emotion ThemeProvider containing a theme object. You can bring your own from the emotion-theming package or import it directly for some extra type hints:

import { RosesTheme, defaultTheme } from "roses"
// import { ThemeProvider } from 'emotion-theming'

const theme = {
  ...defaultTheme,
  colors: {
    ...defaultTheme.colors,
    white: "black",
    black: "white",
  },
}

// RosesTheme is just a rebranded ThemeProvider.
export const App = props => {
  return <RosesTheme theme={theme}>{props.everythingElse}</RosesTheme>
}

The defaultTheme export is an extension of the theme-ui base preset

Usage

Defining components

Basic component styles can be defined under the theme componentStyles key. Rebass apparently uses a similar, undocumented approach but keys are at the top level- this one I didn't know about.

Given a theme:


// extending the default theme..
{
  ...defaultTheme
  breakpoints: ["780px"], // just a single breakpoint.
  radii: [0, "2px", "4px", "8px"],
  componentStyles: {
    Rectangle: {
      color: ["black", "red"] // at 1st breakpoint the text turns red for some reason.
      padding: 1,  // indexed to `space` key
      mx: 3,
      variants: {
        hot: {
          bg: "primary"
        },
        cold: { ... }
      }

    },
    Widget: { ... }
  }

}

We can make a `Rectangle using the full api:

const Rectangle = themed({
  name: "Rectangle",
  component: "div",
})

... Or a string shorthand - with a default base component of styled('div')({boxSizing: 'border-box'}):

const Widget = themed("Widget")

Since this is all just emotion in the context of a system-ui theme under the covers, you can also build more complex components (whose styles probably won't belong in your theme). See the emotion/@styled-system/css docs for more details.

Variants

Component variant styles can be defined via a special variants key, are accessible via the variant prop and applied over the base styles:

theme.componentStyles.Card = {
  p: 2,
  m: 1,
  display: "inline-block",
  borderRadius: 2,
  variants: {
    shadow: {
      boxShadow: "0 0 16px rgba(0, 0, 0, .25)",
    },
  },
}

// later...

<Card variant="shadow">{ /* etc */ } </Card>

The sx prop

heavily inspired by theme-ui's sx prop.

The final styles applied come from the sx prop.

theme-ui introduced the sx prop. It seemed like a good idea, so roses decided to copy it. Similar to a vanilla react component's styles prop, sx accepts a [SystemStyleObject]. This is a familiar extension of the vanilla styles api with the responsive, theme-aware values and shortcuts that styled-system/css introduced. sx is a functional copy of theme-ui's version: It passes your styles on to the emotion css prop: <Box sx={myStyles} /> == <Box css={{styledCss(myStyles)}}/>.

Related projects

roses is heavily inspired by these projects:

License

MIT for now.

Contributors

Docs, PRs and Bug reports welcome. Contributors agree that this project may be relicensed in the future.