Pinceau

A zero-runtime CSS-in-TS framework made for Vue.

README

🖌 pinceau

NPM version

A _CSS-in-TS_ framework built to feel like a native Vue feature.


- Ships 0kb of JS to the client by default
- DX that feels like a native Vue feature
- Design Tokens compatible configuration system
- Fully-typed styling API
- Integrated with Volar
- Plug & play with  Nuxt 3, Vitesse, @vitejs/plugin-vue

🚨 Warning


Pinceau is still under heavy development, if you are missing some parts of the documentation, please open an issue and describe your problem. I'll be happy to help.


⚙️ Install


  1. ``` sh
  2. npm i pinceau
  3. ```

Nuxt

  1. ```ts
  2. // nuxt.config.js
  3. export default defineNuxtConfig({
  4.   modules: [
  5.     'pinceau/nuxt',
  6.   ],
  7.   pinceau: {
  8.     ...PinceauOptions
  9.   }
  10. })
  11. ```

Example: [playground/](./playground/)

This module only works with Nuxt 3.


Vite

  1. ```ts
  2. // vite.config.ts
  3. import Pinceau from 'pinceau/vite'

  4. export default defineConfig({
  5.   plugins: [
  6.     Pinceau(PinceauOptions),
  7.   ],
  8. })
  9. ```

Example: [playground/](./playground/)

PinceauOptions

  1. ```ts
  2. export interface PinceauOptions {
  3.   /**
  4.    * The root directory of your project.
  5.    *
  6.    * @default process.cwd()
  7.    */
  8.   cwd?: string
  9.   /**
  10.    * The path of your configuration file.
  11.    */
  12.   configOrPaths?: ConfigOrPaths
  13.   /**
  14.    * The path of your configuration file.
  15.    *
  16.    * @default 'pinceau.config'
  17.    */
  18.   configFileName?: string
  19.   /**
  20.    * A callback called each time your config gets resolved.
  21.    */
  22.   configResolved?: (config: PinceauTheme) => void
  23.   /**
  24.    * The directry in which you store your design tokens.
  25.    *
  26.    * @default 'tokens'
  27.    */
  28.   tokensDir?: string
  29.   /**
  30.    * The directory in which you want to output the built version of your configuration.
  31.    */
  32.   outputDir?: string
  33.   /**
  34.    * Imports the default CSS reset in the project.
  35.    *
  36.    * @default true
  37.    */
  38.   preflight?: boolean
  39.   /**
  40.    * Excluded transform paths.
  41.    */
  42.   excludes?: string[]
  43.   /**
  44.    * Included transform paths.
  45.    */
  46.   includes?: string[]
  47.   /**
  48.    * Toggles color .{dark|light} global classes.
  49.    *
  50.    * If set to class, all @dark and @light clauses will also be generated
  51.    * with .{dark|light} classes on tag as a parent selector.
  52.    *
  53.    * @default 'class'
  54.    */
  55.   colorSchemeMode?: 'media' | 'class'
  56. }
  57. ```

Volar

If you want to have all autocomplete and TypeScript powered features, you need to setup Volar in your IDE.

That also means these features sadly won't work in the StackBlitz playground, unless they provide support for it at some point.

Once Volar enabled, add the Pinceau plugin to your tsconfig.json:

  1. ``` json
  2. {
  3.   "vueCompilerOptions": {
  4.     "plugins": ["pinceau/volar"]
  5.   }
  6. }
  7. ```

Once enabled, be sure to restart your TypeScript server, and enjoy autocompletion!


🎨 Configure


The configuration file is made to help you injecting all the Design Tokens you want into your app as CSS variables, JS references, or any other format you need or want.

pinceau.config.ts


You can decide to follow the suggested theme definition keys, but you also are free to define whatever design tokens you want, with the structure of your choice.

As an example, this configuration helped us at NuxtLabs to create a sync between Figma Tokens and our component library.

💡 Configuration example

  1. ```ts
  2. import { defineTheme } from 'pinceau'

  3. export default defineTheme({
  4.   media: {
  5.     sm: '(min-width: 640px)',
  6.     md: '(min-width: 768px)',
  7.     lg: '(min-width: 1024px)',
  8.     xl: '(min-width: 1280px)',
  9.     xxl: '(min-width: 1536px)',
  10.   },
  11.   colors: {
  12.     primary: {
  13.       50: {
  14.         initial: '{colors.orange.50}',
  15.         dark: '{colors.orange.900}'
  16.       },
  17.     },
  18.     orange: {
  19.       50: '#ffe9d9',
  20.       100: '#ffd3b3',
  21.       200: '#ffbd8d',
  22.       300: '#ffa666',
  23.       400: '#ff9040',
  24.       500: '#ff7a1a',
  25.       600: '#e15e00',
  26.       700: '#a94700',
  27.       800: '#702f00',
  28.       900: '#381800',
  29.     }
  30.   }
  31. })
  32. ```
🎨 Output example

  1. ```css
  2. :
  3.   --colors-primary-50: #ffe9d9;
  4.   --colors-orange-50: #ffe9d9;
  5.   --colors-orange-100: #ffd3b3;
  6.   --colors-orange-200: #ffbd8d;
  7.   --colors-orange-300: #ffa666;
  8.   --colors-orange-400: #ff9040;
  9.   --colors-orange-500: #ff7a1a;
  10.   --colors-orange-600: #e15e00;
  11.   --colors-orange-700: #a94700;
  12.   --colors-orange-800: #702f00;
  13.   --colors-orange-900: #381800;
  14. }

  15. html.dark :root {
  16.   --colors-primary-50: #381800;
  17. }
  18. ```

Out of your configuration file, Pinceau will generate multiple output targets which will provide:

- Type completion in css() function for mapped theme tokens
- Token paths completion with globally available $dt() helper
- Globally injected CSS variables
- A lot more for you to discover, and for me to document ✨

This is powered by style-dictionary and runs on style-dictionary-esm.

🖌 Paint


Pinceau styling API is made to feel like a native Vue API.

To do so, it fully takes advantages of the Vue components `