Skip to main content
Deno 2 is finally here πŸŽ‰οΈ
Learn more

mapcss

Tiny, composable Atomic CSS engine

deno land nest.land

release deno version deno doc

test codecov DeepSource DeepScan grade

Semver Conventional Commits semantic-release: angular license


:construction: This project is currently in beta release. All interfaces are subject to change.

Features

  • πŸŽ“ Hierarchical mapping strategy

    Map CSS Statements with hierarchical identifiers. Compared to flat, it is more readable and uses as few regular expressions as possible. In addition, regular expression matching is scoped, improving performance.

  • πŸ’… Flexible

    The CSS Statement is written in CSS-in-JS style. It is a plain JavaScript Object with excellent readability.

  • 🌳 AST based

    CSS-in-JS is converted to AST(postcss AST). postcss AST is a widely known standard format that can be freely converted and added to and benefits from a large ecosystem.

  • 🌐 Universal

    It works with Browser, Deno, and Node.js without polyfill.

    Internally using the universal version of postcss postcss-core.

    The bundle size has been taken into consideration, and the code base is created with pure functions.

  • πŸ” Orderless(experiment)

    User does not need to care about the order of the CSS Statement at all. Therefore, there is no concept of order or layer.

    The RuleSet will be sorted by the number of properties in the Declaration Block.

Usage

mapcss provides several preset.

For example, using presetTw, you can use the utility class of TailwindCSS.

import {
  extractSimple,
  generate,
} from "https://deno.land/x/mapcss@$VERSION/core/mod.ts";
import { presetTw } from "https://deno.land/x/mapcss@$VERSION/preset_tw/mod.ts";

const code = `<div className="relative flex">
  <p className="text-red-500/20"></p>  
</div>
`;
const tokens = extractSimple(code);
const output = generate(tokens, { preset: [presetTw()] });
console.log(output.css);
/*
  .relative{position:relative;}
  .flex{display:flex;}
  .text-red-500\/20{color:rgb(239 68 68/.2);}
*/

What

mapcss is an Atomic-oriented CSS generator.

It is strongly influenced by TailwindCSS and UnocCSS, but with the following differences.

identifier to CSS-in-JS

The essence of mapcss is to map an identifier to a CSS Statement with JavaScript Object notation (CSS-in-JS).

A Map is a Plain Object with a hierarchical structure, which can be expressed concisely with Object literals.

For example, the following CSS Statement can be mapped as follows:

.inline-block{display: inline;}
import type { CSSMap } from "https://deno.land/x/mapcss@$VERSION/core/mod.ts";
const cssMap: CSSMap = {
  inline: {
    block: { display: "inline" },
  },
};

It is also possible to express dynamic identifiers using regular expressions.

.z-123{z-index: 123;}
import type { CSSMap } from "https://deno.land/x/mapcss@$VERSION/core/mod.ts";
const rePositiveNumber = /^(\d+)$/;
const cssMap: CSSMap = {
  z: {
    "*": ({ id }) => {
      // It actually checks the validity of the numbers
      const regExpExecResult = rePositiveNumber.exec(id);
      if (regExpExecResult) {
        return { zIndex: Number(regExpExecResult[1]) };
      }
    },
  },
};

We support the first class because it is the most frequent mapping to CSS declaration block.

For the definition of any CSS Statement, CSS-in-JS representation is also supported.

@media (min-width: 640px) {
  .container {
    max-width: 640px;
  }
}
.container{width: 100%;}
import type { CSSMap } from "https://deno.land/x/mapcss@$VERSION/core/mod.ts";
const cssMap: CSSMap = {
  // className: .container
  container: (_, { className }) => ({
    type: "css",
    value: {
      "@media (min-width: 640px)": {
        [className]: {
          maxWidth: "640px",
        },
      },
      [className]: {
        width: "100%",
      },
    },
  }),
};

The Object search model

Explore the object hierarchy based on identifier. Hierarchy traversal is much more performant than flat traversal.

For example, the computational complexity of regular expression matching from a flat structure is O(N).

If the search finds CSS-in-JS, it will be converted to AST. The AST currently uses the postcss AST.

This will benefit from the postcss ecosystem.

Finally, we show the conversion transition.

token -> DeepMap { identifier -> CSS-in-JS } -> AST -> Style Sheet

License

Copyright Β© 2021-present TomokiMiyauci.

Released under the MIT license