/style9

CSS-in-JS compiler inspired by Facebook's stylex

Primary LanguageJavaScriptMIT LicenseMIT

style9

CSS-in-JS compiler based on the ideas of Facebook's stylex

Features

  • Compiles to atomic CSS
  • Typed styles using TypeScript
  • Converts font-size to REM¹
  • No selectors

Install

# Yarn
yarn add style9

# npm
npm install style9

Usage

import style9 from 'style9';

// Styles are created by calling style9.create
const styles = style9.create({
  blue: {
    color: 'blue',
  },
  red: {
    color: 'red'
  }
});

// `styles` is now a function which can be called with the keys of the style
// object, and returns a string of class names.
// Ternary operator and logical AND is supported
document.body.className = styles('blue', isRed && 'red');

// `styles` can also be called with an object of booleans
styles({
  blue: isBlue,
  red: isRed
});

// To combine with external styles, style9 can be called with the style objects
style9(styles.blue, otherStyles.yellow);

// Styles have to be statically defined, but constants are supported
const RED = 'red';

const moreStyles = style9.create({
  red: {
    color: RED
  },
  margin: {
    // All properties are written in camelcase
    // Integers are converted to pixels where appropriate
    marginTop: 8
  },
  padding: {
    // Longhands take precedent over shorthands
    // Will resolve to '12px 12px 12px 18px'
    paddingLeft: 18,
    // Shorthand values will be copied to longhands which means
    // `padding: '12px 18px'` etc. is not supported
    padding: 12
  },
  text: {
    // Font size is converted to REMs to follow users settings
    fontSize: 14
  },
  fadeIn: {
    // Animation names are created by calling style9.keyframes
    animationName: style9.keyframes({
      from: {
        opacity: 0
      },
      to: {
        opacity: 1
      }
    }),
    animationDuration: '1s'
  },
  mobile: {
    // Media queries are supported as well
    // They will be sorted mobile-first
    // NOTE: Media queries are not supported in TypeScript due to issue #17867
    '@media (min-width: 800px)': {
      display: 'none'
    }
  },
  pseudo: {
    // Pseudo-classes and elements can be used
    ':hover': {
      // They can be nested, as can media queries
      ':active': {
        '::before': {
          content: 'attr(title)'
        }
      }
    }
  }
});

Options

  • minifyProperties - minify the property names of style objects. Unless you pass custom objects to style9() not generated by style9.create(), this is safe to enable and will lead to smaller JavaScript output but mangled property names. Consider enabling it in production. Default: false

Babel

const babel = require('@babel/core');

const output = babel.transformFile('./file.js', {
  plugins: [['style9/babel', { /* options */ }]]
});
// Generated CSS
console.log(output.metadata.style9);

Rollup

import style9 from 'style9/rollup';

export default {
  // ...
  plugins: [
    style9({
      // include & exclude are supported according to rollup conventions
      // Either fileName or name is required. It will be passed to emitFile
      // fileName: unique name to for output file
      // name: name to use for output.assetFileNames pattern
      // ...Options
    })
  ]
};

Webpack

const Style9Plugin = require('style9/webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.(tsx|ts|js|mjs|jsx)$/,
        use: Style9Plugin.loader,
        options: { /* ...Options */ }
      },
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  plugins: [
    new Style9Plugin(),
    new MiniCssExtractPlugin()
  ]
};

Next.js

const withTM = require('next-transpile-modules')(['style9']);
const withStyle9 = require('style9/next');

module.exports = withStyle9({ /* ...Options */ })(withTM());

Gatsby

module.exports = {
  plugins: [
    {
      resolve: 'style9/gatsby',
      options: { /* ...Options */ }
    }
  ]
}

Vue.js

There is an example repo you can see to get started.