1.0.1 • Published 3 years ago

@ngneat/variabless v1.0.1

Weekly downloads
231
License
MIT
Repository
github
Last release
3 years ago

Variabless allows you to manage application wide css variables in a single source of truth. Variabless will convert a JS/TS/JSON definitions file to css variables allowing you to use those values both in js and css files.

Why Variabless?

Ever since the introduction of css variables, supporting themes in your app and customizing styles became much more accessible. While developing several apps we noticed a reoccurring need: accessing the theme and variables in our ts files for various reasons (e.g. passing colors to highcharts). At that point, it was either managing two sets on theme definitions one in css and one in ts, or find a solution to centralize our theme and make it accessible for both, thus Variabless was born.

Features

 Convert js to css variables.
 Single source of styling across the app.
 Supports JS, TS and JSON file formats.
 Webpack Plugin.
 Easy CSS rules creation.

👉  Try it in our playground.

Table of content

Installation

Install the Variabless package via yarn or npm by running:

npm i -D variabless
yarn add -D variabless

Usage

There are two ways you can use Variabless:

CLI

Add the following script to your package.json file:

{
  "variabless": "variabless -s src/theme.ts -o src/assets/styles/theme.css"
}

Run npm run variabless to generate the css file.

Webpack plugin

The VariablessWebpackPlugin provides you with the ability to add/remove variables during development, while you're working on the project. Just add the VariablessWebpackPlugin in your plugins list:

// webpack.config.js
const { VariablessWebpackPlugin } = require('variabless/webpack-plugin');

module.exports = {
  plugins: [
    new VariablessWebpackPlugin({
        watch?: boolean, // listen to changes
        srcPath: 'src/theme.ts', // the variables rules file
        outputPath: 'src/theme.css', // generated css file path
    }),
  ]
};

Include the generated file by Variabless in your styles:

@import 'assets/styles/theme.css';

Add the generated file to your .gitignore file, there is no need to track it.

Rules Definition

The Variabless source file exports a map of rules which defines how to create the variables:

// src/theme.ts
export const coreStyles: Record<string, Rule> = {
  myVariable: {
    value: string | object,
    variableName?: string | Resolver,
    appendVariablesTo?: string,
    properties?: PropertyConfig[],
  },
  ...
};

Where each rule has the following options:

value - string | number | object

The css variable value, can be either string, number or a map:

{
  fontFamily: {
    value: 'Roboto'
  },
  blueColors: {
    value: {
      b1: 'lightblue',
      b2: 'blue',
    }   
  }
}

When passing a map, a variable will be created for each value.

variableName - string | Resolver

The css variable name.
When the rule has a primitive value the variableName should be a string:

{
  fontFamily: {
    value: 'Roboto',
    variableName: 'font-family'
  },
}

Will produce:

--font-family: 'Roboto';

When the rule's value is a map, we need to avoid name collisions, the variableName must be one of these two options:

Tokenized string

We can pass a string containing unique tokens which are replaced during the variable's creation:

  • :valueKey
  • :property

The following rule:

{
  blueColors: {
    value: {
      b1: 'lightblue',
      b2: 'blue',
    },
    variableName: ':valueKey-color'
  },
}

Will produce the following variables:

--b1-color: 'lightblue';
--b2-color: 'blue';

Resolver function

The resolver function is similar to the tokenized string but gives you more flexibility:

type Resolver = (params: ResolverParams) => string;

interface ResolverParams {
  valueKey?: string; 
  property?: string;
} 

The following rule:

{
  blueColors: {
    value: {
      b1: 'lightblue',
      b2: 'blue',
    },
    variableName: ({valueKey}) => valueKey.toUpperCase() + '-color'
  },
}

Will produce the following variables:

--B1-color: 'lightblue';
--B2-color: 'blue';

appendVariablesTo - string

The selector hosting the generated variables, defaults to :root:

:root {
  --font-family: 'Roboto'
  ...
}

properties - PropertyConfig[]

It's a common practice to put frequently used styles in shared class or attribute.
Varibless easily allows you to create css selectors for those frequently used variables.

Properties are defined as following:

export interface PropertyConfig {
  prop: string | string[];
  selector: string | Resolver;
} 
  • prop - The css properties to assign the variable's value to.
  • selector - The selector that will hold the css properties.

Similar to the variableName, if the rule's value is a primitive, the selector's value should be a string. If the rule's value is a map, or the selector used for several css properties than the selector should be a tokenized string or a resolver function to prevent collisions.

The following rule:

{
  fontFamily: {
    value: 'Roboto',
    variableName: 'font-family',
    properties: [{
      prop: 'font-family', 
      selector: '.font-family'
    }],
  },
  blueColors: {
    value: {
      b1: 'lightblue',
      b2: 'blue'
    },
    variableName: ':valueKey-color',
    properties: [{
      prop: 'color',
      selector: '.:valueKey-:property'
    }, {
      prop: 'background-color',
      selector: '.:valueKey-bg'
    }],
  }
}

Will produce the following css:

:root {
 --font-family: 'Roboto';
 --b1-color: 'lightblue';
 --b2-color: 'blue';
}

body {

  .font-family {
    font-family: var(--font-family);  
  }  
  
  .b1-color {
    color: var(--b1-color);  
  }
  
  .b2-color {
    color: var(--b2-color);  
  } 
  
  .b1-bg{
    background-color: var(--b1-color);  
  }
  
  .b2-bg {
    background-color: var(--b2-color);  
  }
   
}

Generate Independent Properties

You can also generate properties that don't relay on variables by not providing the variableName property.
The following rule:

{
  fontWeight: {
    properties: [
      {
        prop: 'font-weight',
        selector: '.font-weight-:valueKey'
      }
    ], 
    value: {
      regular: 'normal',
      medium: 500,
      bold: 'bold',
      custom: 'var(--foo)'
    }
  }
}

Will produce the following css:

body {

  .font-weight-regular {
    font-weight: normal;  
  }
  
  .font-weight-medium {
    font-weight: 500;
  }
  
  .font-weight-bold {
    font-weight: bold;
  }
  
  .font-weight-custom {
    font-weight: var(--foo);
  }
  
}

Contributors ✨

Thanks goes to these wonderful people (emoji key):

This project follows the all-contributors specification. Contributions of any kind welcome!