Skip to content

atanasster/babel-plugin-theme-ui

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

About

babel-plugin-theme-ui babel plugin transformations for theme-ui themes.

Install

yarn add babel-plugin-theme-ui --dev

Configuration

You can configure the plugin in your webpack configuration as a babel-loader plugin see examples

Options

useCustomProperties: boolean (default true)

When this option is set to false, the plugin will not transform color properties to use css variables ie var(--theme-ui-colors-primary)

colorNames: string[] (default []),

a list of the color property names to be transformed to css variables. We are using internally micromatch - a glob matching for javascript/node.js and you can use matching patterns for the color properties.

rootNames: string[] (default ['root', 'colors'])

a list of the theme section not the be transformed into using css variables.

transformNativeColors: boolean (default false)

if you set this option to true, the plugin will also transform the native color names of theme-ui - such as bg. This can offset the color lookups at build-time rather than run-time.

Currently the following property names are treated as color style names:

  "color",
  "backgroundColor",
  "borderColor",
  "caretColor",
  "columnRuleColor",
  "borderTopColor",
  "borderBottomColor",
  "borderLeftColor",
  "borderRightColor",
  "outlineColor",
  "fill",
  "stroke",
  "bg",

spaceFormats: Record<string, string | function (value: any) => string> (default { space: value => "${value}px",})

you can use this option and apply custom formatting to the transformed values - by default the space values are transformed to strings by adding px at the end.

Example configurations

Javascript theme

const babelThemeUI = require('babel-plugin-theme-ui');

module: {
  rules: [
    {
      test: /theme.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader',
      options: {
        plugins: [
          [
            babelThemeUI,
            {
              transformNativeColors: true,
              useCustomProperties: false,
              colorNames: ['--bg-*', '--color-*'],
              rootNames: ['root', 'body'],
            }
          ]
        ]
      }
    },
  ],
},

Gatsby Plugin Theme UI

const path = require("path");
const babelThemeUI = require('babel-plugin-theme-ui');

module: {
  rules: [
    {
      test: /index.js$/,
      exclude: /node_modules/,
      include: path.resolve(__dirname, "src/gatsby-plugin-theme-ui"),
      loader: "babel-loader",
      options: {
        plugins: [
          [
            babelThemeUI,
            {
              colorNames: ["--bg-*", "--color-*"],
            },
          ],
        ],
      },
    },
  ],
},

Next.JS webpack config

// next.config.js
const babelThemeUI = require('babel-plugin-theme-ui');

module.exports = {
  webpack(config, options) {
    config.module.rules.push({
      test: /theme.ts$/,
      use: [
        options.defaultLoaders.babel,
        {
          loader: 'babel-loader',
          options: {
            presets: [['next/babel']],
            plugins: [
              [
                babelThemeUI,
                {
                  transformNativeColors: true,
                  useCustomProperties: false,
                  colorNames: ['--bg-*', '--color-*'],
                  rootNames: ['root', 'body'],
                }
              ]
            ]
          }
        },
      ],
    })
  }
}

Storybook webpack config

// .storybook/wepback.config.js
const babelThemeUI = require('babel-plugin-theme-ui').default

module.exports = async ({ config }) => {
  config.module.rules.push({
    test: /theme.ts$/,
    use: [
      {
        loader: 'babel-loader',
        options: {
          presets: [['next/babel']],
          plugins: [
            [
              babelThemeUI,
              {
                transformNativeColors: true,
                useCustomProperties: false,
                colorNames: ['--bg-*', '--color-*'],
                rootNames: ['root', 'body'],
              }
            ]
          ]
        }
      },
    ],
  })
}

Typescript theme

const babelThemeUI = require('babel-plugin-theme-ui');

module: {
  rules: [
    {
      test: /theme.ts$/,
      exclude: /node_modules/,
      loader: 'babel-loader',
      options: {
        presets: [['typescript']],
        plugins: [
          [
            babelThemeUI,
            {
              transformNativeColors: true,
              useCustomProperties: false,
              colorNames: ['--bg-*', '--color-*'],
              rootNames: ['root', 'body'],
            }
          ]
        ]
      }
    },
  ],
},

Transforms

Keys in current scope

secondary and green are child nodes of the same parent (colors):

export const theme = {
  colors: {
    green:{
      30: '#00aa00',
    },
    secondary: 'green.30'
  },
};

will be transformed to

export const theme = {
  colors: {
    green:{
      30: '#00aa00',
    },
    secondary: '#00aa00'
  },
};

Keys from global scope

in the following example the lookup is in a global scope of the theme colors

export const theme = {
  colors: {
    primary: '#ffffff',
  },
  input: {
    bg: 'primary'
  },
};

will be transformed to

export const theme = {
  colors: {
    primary: '#ffffff',
  },
  input: {
    bg: 'var(--theme-ui-colors-primary)',
  },
};

Objects transforms

to avoid repetitive styles for multiple theme keys:

export const theme = {
  colors: {
    primary: 'tomato',
  },
  input: {
    bg: 'primary',
    '--bg-random': 'primary',
    border: 'solid 1px black',
  },
  styles: {
    select: 'input',
  },
};

will be transformed to

export const theme = {
  colors: {
    primary: "tomato",
  },
  input: {
    bg: "primary",
    "--bg-random": "var(--theme-ui-colors-primary)",
    border: "solid 1px black",
  },
  styles: {
    select: {
      bg: "primary",
      "--bg-random": "var(--theme-ui-colors-primary)",
      border: "solid 1px black",
    },
  },
};

Array index transformations

to get shortcuts into array keys in the theme, such as spaces and fontSizes

export const theme = {
  space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
  button: {
    borderRadius: 'space.2',
  },
};

will be transformed to

export const theme = {
  space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
  button: {
    borderRadius: "8px",
  },
};

Array values transformations

some of the theme-ui values are arrays - to be used based on the current screen resolution

export const theme = {
  space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
  input: {
    '--space-gap': ["space.2", "14px", "space.3", "space.4"],
  },
};

will be transformed to

export const theme = {
  space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
  input: {
    "--space-gap": ["8px", "14px", "16px", "32px"],
  },
};

notice above that the space.2 key is replaced with the second value in the space array, while the 14px is left intact since it is not a valid theme key

References to custom scales

Custom scales can be created to supplement those already existing.

Simply create a new scale, then reference it in a variant

  speed: ["0.35s", "0.5s", "0.75s"],
  ease: {
    in: "ease-in",
    out: "ease-out",
    inOut: "ease-in-out",
  },
  a: {
  color: "primary",
  "--speed": "speed.1",
  "--ease": "ease.out",
  transition: "color var(--speed, 0.35s) var(--ease, ease)"
},

Theme composition

When your theme definition grows, it is common to separate the scales into their on objects that will get merged into the theme object

const scales = {
  space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
}

const layout = {
  '--margin': 'space.3',
  '--bg-random': 'primary',
  ease: 'speed.2'
}

const font = {
  '--margin': 'space.3',
  '--color-some': 'primary',
  ease: 'speed.0'
}

export default {
  ...scales,
  speed: ["0.35s", "0.5s", "0.75"],
  colors: {
    primary: '#333',
    secondary: '#503'
  },
  styles: {
    h1: layout,
    h2: {
      ...layout,
      '--color-more': 'secondary',
    },
    h3: {
      ...font,
    },
    a: {
      '--test': 'space.4',
    },
  },
}

will be transformed to

const scales = {
  space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
};
const layout = {
  "--margin": "16px",
  "--bg-random": "var(--theme-ui-colors-primary)",
  ease: "0.75",
};
const font = {
  "--margin": "16px",
  "--color-some": "var(--theme-ui-colors-primary)",
  ease: "0.35s",
};
export default {
  ...scales,
  speed: ["0.35s", "0.5s", "0.75"],
  colors: {
    primary: "#333",
    secondary: "#503",
  },
  styles: {
    h1: layout,
    h2: { ...layout, "--color-more": "var(--theme-ui-colors-secondary)" },
    h3: { ...font },
    a: {
      "--test": "32px",
    },
  },
};

About

babel transformations for theme-ui themes

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published