rainbowindex 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +133 -0
- package/{LICENSE.md → LICENSE} +3 -3
- package/README.md +262 -125
- package/dist/browser.d.ts +3 -1321
- package/dist/browser.mjs +41 -20
- package/dist/chunk-5ECTKN44.mjs +679 -0
- package/dist/chunk-5N4GPK26.mjs +2664 -0
- package/dist/chunk-PD4ZXGJ6.mjs +14 -0
- package/dist/chunk-RPXZ3O6R.mjs +10518 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +1258 -0
- package/dist/index.css +2 -0
- package/dist/index.d.ts +266 -5207
- package/dist/index.mjs +70 -68
- package/dist/optimize-6NWJVT6W.mjs +24 -0
- package/dist/safelist-DRk1XXxi.d.ts +239 -0
- package/dist/vite.d.ts +5 -0
- package/dist/vite.mjs +320 -0
- package/package.json +102 -87
- package/css/index.css +0 -5
- package/css/preflight.css +0 -370
- package/css/theme.css +0 -308
- package/dist/browser.mjs.map +0 -1
- package/dist/index.cjs +0 -69
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -5230
- package/dist/index.mjs.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.2.1] - 2026-07-28
|
|
9
|
+
|
|
10
|
+
### Added — diagnostics
|
|
11
|
+
|
|
12
|
+
- **Vite misuse guard (`[RI-1606]`)** — the default `rainbowindex` export is
|
|
13
|
+
the PostCSS plugin; placing it in Vite's `plugins: []` array previously did
|
|
14
|
+
nothing (no CSS, no error). It now carries an inert Vite-plugin facade that
|
|
15
|
+
throws `[RI-1606]` when Vite resolves config, pointing to
|
|
16
|
+
`import rainbowindex from "rainbowindex/vite"`. The guard is never dispatched
|
|
17
|
+
by PostCSS, so raw PostCSS usage is unaffected.
|
|
18
|
+
|
|
19
|
+
## [0.2.0] - 2026-07-16
|
|
20
|
+
|
|
21
|
+
Initial public release. Rainbow Index began as a fork of Tailwind CSS v4; the
|
|
22
|
+
entries below list the capabilities this release adds **on top of** what
|
|
23
|
+
Tailwind CSS v4 provides. Shared functionality (utility classes, variants,
|
|
24
|
+
`@apply`, CSS-first theming, `@source`, arbitrary values, the Vite/PostCSS
|
|
25
|
+
plugins as such) is not repeated here.
|
|
26
|
+
|
|
27
|
+
### Added — runtime & programmatic API
|
|
28
|
+
|
|
29
|
+
- **`ri()` class merger** — built-in class composition with right-most-wins
|
|
30
|
+
conflict resolution, replacing both `clsx` (conditional composition) and
|
|
31
|
+
`tailwind-merge` (conflict resolution). Understands shorthand property
|
|
32
|
+
claims (`p-4` owns all four padding sides), variant-order canonicalization
|
|
33
|
+
(`sm:hover:` ≡ `hover:sm:`), `!important`, negative utilities, and
|
|
34
|
+
arbitrary properties; bracket-aware tokenization with LRU caching.
|
|
35
|
+
- **`createRi(snapshot)`** — SSR- and multi-tenant-safe merger bound to a
|
|
36
|
+
frozen compilation snapshot, for servers where concurrent requests may
|
|
37
|
+
target different themes in one process. `ri()` emits a throttled
|
|
38
|
+
`[RI-2004]` warning when it detects that situation.
|
|
39
|
+
- **Programmatic compilation API** — `compileProject()`, `createCompiler()`,
|
|
40
|
+
`createCompilationContext()`, `finalizeCompilationContext()`, and
|
|
41
|
+
registration helpers (`registerCustomUtility`, `registerCustomTextSizes`,
|
|
42
|
+
`registerCustomFontFamilies`, `registerColorNames`) as a stable library
|
|
43
|
+
surface for driving compilation and feeding the merge engine.
|
|
44
|
+
- **`safelist()` helper** — a runtime identity-join whose static string
|
|
45
|
+
arguments are extracted by the scanner at build time, so component/icon
|
|
46
|
+
libraries can ship class names that are always emitted.
|
|
47
|
+
- **Package-based safelist auto-discovery** — installed dependencies can
|
|
48
|
+
declare `rainbowindex.safelistSources` globs in their own `package.json`
|
|
49
|
+
to opt their published files into scanning, with no manual `@source`.
|
|
50
|
+
- **Browser entry guard** — importing the PostCSS-plugin default export in a
|
|
51
|
+
browser bundle throws `[RI-2003]` with guidance to use named imports.
|
|
52
|
+
|
|
53
|
+
### Added — CLI
|
|
54
|
+
|
|
55
|
+
- **`rainbowindex generate-types`** — generates a `rainbowindex-env.d.ts`
|
|
56
|
+
with a `RainbowClass` TypeScript union (colors × stops, spacing, text
|
|
57
|
+
sizes, weights, variants, custom utilities) for editor autocomplete;
|
|
58
|
+
`--strict` drops the string escape hatch; hand-edited files are backed up
|
|
59
|
+
before overwrite.
|
|
60
|
+
- **`rainbowindex preload-fonts`** — emits `<link rel="preload" as="font">`
|
|
61
|
+
tags for resolved font faces.
|
|
62
|
+
- **`rainbowindex init`** — wires Rainbow Index into an existing Vite app:
|
|
63
|
+
detects the package manager, installs the dependency, patches
|
|
64
|
+
`vite.config.*`, and creates or updates the CSS entry.
|
|
65
|
+
- **`rainbowindex create <dir>`** — scaffolds a fresh Vite app (default
|
|
66
|
+
template `react-ts`) with Rainbow Index pre-wired.
|
|
67
|
+
- **`--optimize`** — LightningCSS pass with browser-fallback down-leveling
|
|
68
|
+
in addition to minification.
|
|
69
|
+
- **Atomic output writes** — CSS output is written via temp-file + rename so
|
|
70
|
+
interrupted builds never leave partial files.
|
|
71
|
+
|
|
72
|
+
### Added — theming directives
|
|
73
|
+
|
|
74
|
+
- **Generative color system (`@color`)** — declare a color as two numbers
|
|
75
|
+
(`brand: 0.18 330;` — chroma + hue) and get a full 19-stop OKLCH palette
|
|
76
|
+
with automatic dark mode via ramp mirroring, tuned for even perceived
|
|
77
|
+
contrast. Also supports explicit values, light/dark pairs, aliases,
|
|
78
|
+
per-color dark-override strategies, and contrast warnings.
|
|
79
|
+
- **Font system (`@font`)** — register font slots from Google Fonts, local
|
|
80
|
+
files, or URLs in CSS; multi-face slots (upright + italic via an
|
|
81
|
+
`italic:` shorthand), system/manual stacks, and metrics-adjusted fallback
|
|
82
|
+
`@font-face` blocks (size-adjust/ascent/descent overrides) for zero
|
|
83
|
+
cumulative layout shift. On-disk font metadata cache governed by
|
|
84
|
+
`RI_OFFLINE`, `RI_FETCH_FONTS`, `RI_CACHE_DIR`, and `RI_FONT_CACHE_TTL`.
|
|
85
|
+
- **`@fluid`** — configurable fluid type/spacing range driving
|
|
86
|
+
`text-fluid-*` and `*-fluid` spacing/inset utilities with curve keywords.
|
|
87
|
+
- **`@rounded` corner shapes** — border-radius tokens with corner-shape
|
|
88
|
+
modifiers and `corner-round/scoop/bevel/notch/square/squircle` (plus
|
|
89
|
+
`corner-[superellipse(N)]`) utilities mapping to the CSS `corner-shape`
|
|
90
|
+
property.
|
|
91
|
+
- **`@animate`** — register named animations with inline `@keyframes`, plus
|
|
92
|
+
compositional enter/exit utilities (`animate-in`/`animate-out` with
|
|
93
|
+
`fade-`, `zoom-`, `spin-`, `blur-`, and `slide-` parts, each driving
|
|
94
|
+
independent CSS variables) and preset accordion/collapsible keyframes.
|
|
95
|
+
- **`@register`** — declare typed custom properties (`@property`-style
|
|
96
|
+
registrations with syntax and initial value) directly from CSS.
|
|
97
|
+
- **`@preflight`** — toggle preflight base styles from CSS.
|
|
98
|
+
|
|
99
|
+
### Added — class-string syntax
|
|
100
|
+
|
|
101
|
+
- **Variant groups** — `hover:{text-red-500 bg-blue-100 underline}` expands
|
|
102
|
+
at scan time to the repeated-prefix form; groups stack and nest
|
|
103
|
+
(`sm:hover:{…}`, `data-[state=open]:{…}`) with depth and output caps, and
|
|
104
|
+
are also expanded inside `@apply` bodies.
|
|
105
|
+
- **Helper-call-aware scanner** — class literals are extracted from
|
|
106
|
+
`clsx`/`cn`/`classnames`/`cx`/`twJoin`/`twMerge`/`cva`/`tv`/`classMap`/
|
|
107
|
+
`safelist` call sites rather than treating source files as flat text.
|
|
108
|
+
- **Math-operator value parsing** — CSS math functions (`calc`, `min`,
|
|
109
|
+
`max`, `clamp`, `mod`, trigonometric functions, `pow`, `round`, …) are
|
|
110
|
+
recognized inside utility values.
|
|
111
|
+
|
|
112
|
+
### Added — integrations
|
|
113
|
+
|
|
114
|
+
- **Vite plugin extras** — auto-injects a PostCSS config only when none
|
|
115
|
+
exists, auto-discovers the CSS entry on first dev-server listen (warning
|
|
116
|
+
`[RI-1602]` if Rainbow Index never activates), tracks per-file versions
|
|
117
|
+
for HMR, and pre-rewrites Rainbow-Index-specific directive syntax into
|
|
118
|
+
PostCSS-parseable form before PostCSS runs.
|
|
119
|
+
- **PostCSS plugin `sources` option** — declare scan globs from
|
|
120
|
+
`postcss.config.js` in addition to CSS `@source`, merged with
|
|
121
|
+
package-discovered safelist sources.
|
|
122
|
+
|
|
123
|
+
### Added — diagnostics
|
|
124
|
+
|
|
125
|
+
- **`RI-NNNN` error-code system** — every warning carries a namespaced code
|
|
126
|
+
(10xx compilation, 11xx color, 12xx fonts, 13xx merge, 14xx scanner, 15xx
|
|
127
|
+
typography, 16xx integrations, 20xx CSS functions, 21xx runtime), with a
|
|
128
|
+
parity test enforcing that every emitted code is documented.
|
|
129
|
+
- **Warning deduplication and severity budgeting** — warnings are deduped
|
|
130
|
+
and capped per compile, with reserved slots so high-severity errors are
|
|
131
|
+
never drowned out by informational warnings.
|
|
132
|
+
- **"Did you mean" suggestions** — optimal-string-alignment matching powers
|
|
133
|
+
typo hints for unknown utilities, variants, and theme variables.
|
package/{LICENSE.md → LICENSE}
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
This project is a fork of Tailwind CSS v4.
|
|
3
|
+
This project is a fork of Tailwind CSS v4. Portions of this software are derived from Tailwind CSS: Copyright (c) Tailwind Labs, Inc.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The class merging algorithm is derived from tailwind-merge: Copyright (c) 2021 Dany Castillo
|
|
6
6
|
|
|
7
7
|
The animation system is inspired by tw-animate-css: Copyright (c) 2025 Wombosvideo (Luca Bosin)
|
|
8
8
|
|
|
9
|
-
Rainbow Index
|
|
9
|
+
Rainbow Index Copyright (c) 2026 Milo Tech Forecast
|
|
10
10
|
|
|
11
11
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
12
12
|
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
package/README.md
CHANGED
|
@@ -1,192 +1,329 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://rainbowindex.dev" target="_blank">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rainbowindex/rainbowindex/HEAD/.github/logo-dark.svg">
|
|
5
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/rainbowindex/rainbowindex/HEAD/.github/logo-light.svg">
|
|
6
|
+
<img alt="Rainbow Index" src="https://raw.githubusercontent.com/rainbowindex/rainbowindex/HEAD/.github/logo-light.svg" width="144" height="41" style="max-width: 100%;">
|
|
7
|
+
</picture>
|
|
8
|
+
</a>
|
|
9
|
+
</p>
|
|
2
10
|
|
|
3
|
-
|
|
4
|
-
to turn utility classes into CSS.
|
|
11
|
+
**Rainbow Index** is a CSS-first system for building and maintaining consistent user interfaces.
|
|
5
12
|
|
|
6
|
-
The
|
|
7
|
-
through the [Vite plugin](../vite) or [CLI](../cli), but direct access to the compiler is useful for building custom
|
|
8
|
-
tooling or understanding how the system works.
|
|
13
|
+
The project began as a fork of [Tailwind CSS](https://github.com/tailwindlabs/tailwindcss), then diverged with clear intent: to treat CSS as the primary source of truth for styling decisions and to provide tooling that translates design system definitions into predictable, inspectable output. Styling behavior is explicit and traceable, allowing developers to understand not only what is happening, but why.
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
We built the system around composable primitives rather than finished components. Instead of prescribing layout patterns or UI components, it focuses on utilities, directives, and tokens that can be combined without accumulating configuration debt.
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
Rainbow Index challenges several assumptions common in modern styling workflows. Configuration does not default to JavaScript. Flexibility is not achieved through layered indirection. Utility-based systems are not assumed to be verbose, opaque, or fragile.
|
|
18
|
+
|
|
19
|
+
The product is not a visual design tool, a component library, or a framework abstraction layer. It assumes familiarity with core CSS concepts and expects users to engage with the underlying model.
|
|
20
|
+
|
|
21
|
+
When tradeoffs arise, we consistently prioritize composability, user control, predictable performance, explicit behavior, and correctness over convenience or familiarity.
|
|
15
22
|
|
|
16
|
-
##
|
|
23
|
+
## Install
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
```sh
|
|
26
|
+
pnpm add rainbowindex
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Requires Node `>=20.19`. The package is **ESM-only** — there is no CommonJS build, so `require("rainbowindex")` is only supported on runtimes that can `require()` ES modules (Node 20.19+); use `import` otherwise (e.g. an ESM `postcss.config.js`/`.mjs`). `postcss` is a required peer dependency, `vite` an optional one; `lightningcss`, `chokidar`, and `tinyglobby` are bundled as direct deps.
|
|
19
30
|
|
|
20
|
-
|
|
31
|
+
## Quick start (Vite)
|
|
21
32
|
|
|
22
|
-
|
|
23
|
-
import { compileClasses, createDesignSystem } from "rainbowindex";
|
|
33
|
+
The fastest path is the Vite plugin, which auto-injects PostCSS config and discovers your CSS entry on first dev-server listen.
|
|
24
34
|
|
|
25
|
-
|
|
35
|
+
```ts
|
|
36
|
+
// vite.config.ts
|
|
37
|
+
import { defineConfig } from "vite";
|
|
38
|
+
import rainbowindex from "rainbowindex/vite";
|
|
26
39
|
|
|
27
|
-
|
|
28
|
-
|
|
40
|
+
export default defineConfig({
|
|
41
|
+
plugins: [rainbowindex()],
|
|
29
42
|
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```css
|
|
46
|
+
/* src/styles.css */
|
|
47
|
+
@import "rainbowindex";
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
// src/App.tsx
|
|
52
|
+
export default function App() {
|
|
53
|
+
return <div className="flex gap-4 px-6 py-3 bg-blue-500 text-white">Hello</div>;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
To scaffold a fresh app instead, use the CLI:
|
|
30
58
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
59
|
+
```sh
|
|
60
|
+
pnpm dlx rainbowindex create my-app --template react-ts
|
|
61
|
+
# or wire into an existing Vite app
|
|
62
|
+
pnpm dlx rainbowindex init
|
|
35
63
|
```
|
|
36
64
|
|
|
37
|
-
|
|
65
|
+
## CLI
|
|
38
66
|
|
|
39
|
-
The
|
|
40
|
-
that need to analyze or modify CSS programmatically.
|
|
67
|
+
The `rainbowindex` binary exposes five subcommands. The default is `build`.
|
|
41
68
|
|
|
42
|
-
```
|
|
43
|
-
|
|
69
|
+
```
|
|
70
|
+
rainbowindex <glob> [options] Generate CSS from source files
|
|
71
|
+
rainbowindex init Wire Rainbow Index into the current Vite app
|
|
72
|
+
rainbowindex create <dir> Scaffold a Vite app with Rainbow Index ready
|
|
73
|
+
rainbowindex generate-types Generate TypeScript types for ri() autocomplete
|
|
74
|
+
rainbowindex preload-fonts Generate <link rel="preload"> tags for resolved fonts
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Common flags:
|
|
44
78
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
`
|
|
79
|
+
| Flag | Description |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `-o`, `--output <file>` | Output CSS file path. Required with `--watch`. |
|
|
82
|
+
| `--watch` | Re-run on source-file changes (chokidar). |
|
|
83
|
+
| `--minify` | Minify output via LightningCSS. |
|
|
84
|
+
| `--optimize` | Minification + browser-fallback passes. |
|
|
85
|
+
| `--css <file>` | CSS input with directives. Auto-detected if omitted. |
|
|
86
|
+
| `--strict` | Drop the string escape hatch in generated types. |
|
|
87
|
+
| `--template <name>` | Vite template to scaffold (default: `react-ts`). |
|
|
51
88
|
|
|
52
|
-
|
|
89
|
+
Example:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
rainbowindex "src/**/*.{ts,tsx}" -o dist/styles.css --watch
|
|
53
93
|
```
|
|
54
94
|
|
|
55
|
-
|
|
95
|
+
## PostCSS plugin
|
|
96
|
+
|
|
97
|
+
The package's default Node export is a PostCSS plugin.
|
|
56
98
|
|
|
57
|
-
|
|
58
|
-
|
|
99
|
+
```js
|
|
100
|
+
// postcss.config.js
|
|
101
|
+
import rainbowindex from "rainbowindex";
|
|
59
102
|
|
|
60
|
-
|
|
61
|
-
|
|
103
|
+
export default {
|
|
104
|
+
plugins: [rainbowindex({ sources: ["src/**/*.{ts,tsx,html}"] })],
|
|
105
|
+
};
|
|
106
|
+
```
|
|
62
107
|
|
|
63
|
-
|
|
108
|
+
Options:
|
|
64
109
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
110
|
+
| Option | Type | Description |
|
|
111
|
+
| --- | --- | --- |
|
|
112
|
+
| `sources` | `string[]` | Glob patterns for files to scan. Can also be declared via `@source` in CSS. |
|
|
113
|
+
| `cwd` | `string` | Working directory. Defaults to `process.cwd()`. |
|
|
69
114
|
|
|
70
|
-
|
|
71
|
-
background: var(--color-primary);
|
|
72
|
-
}
|
|
73
|
-
`);
|
|
115
|
+
## Vite plugin
|
|
74
116
|
|
|
75
|
-
|
|
76
|
-
|
|
117
|
+
```ts
|
|
118
|
+
import rainbowindex from "rainbowindex/vite";
|
|
77
119
|
```
|
|
78
120
|
|
|
79
|
-
|
|
121
|
+
Auto-detects your CSS entry, injects a PostCSS config if none exists, supports HMR with file versioning. No options required for the common case.
|
|
80
122
|
|
|
81
|
-
|
|
82
|
-
`@tailwind`) are preserved and pass through unchanged, rather than being treated as migration inputs.
|
|
123
|
+
## Class syntax
|
|
83
124
|
|
|
84
|
-
|
|
125
|
+
### Utilities
|
|
85
126
|
|
|
86
|
-
|
|
127
|
+
Roughly the same surface area as Tailwind: spacing, sizing, typography, color, layout, borders, effects, animations, and SVG. Use `rainbowindex generate-types` for autocomplete in your editor.
|
|
87
128
|
|
|
88
|
-
|
|
129
|
+
### Variants
|
|
89
130
|
|
|
90
|
-
|
|
91
|
-
interface CompileOptions {
|
|
92
|
-
designSystem: DesignSystem;
|
|
93
|
-
}
|
|
131
|
+
Prefix any utility with one or more variants, separated by `:`.
|
|
94
132
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
classes: string[];
|
|
98
|
-
}
|
|
133
|
+
```html
|
|
134
|
+
<button class="bg-blue-500 hover:bg-blue-600 dark:bg-blue-400 sm:px-6">…</button>
|
|
99
135
|
```
|
|
100
136
|
|
|
101
|
-
|
|
137
|
+
Supported variants:
|
|
102
138
|
|
|
103
|
-
|
|
104
|
-
|
|
139
|
+
- **Pseudo-classes** — `hover`, `focus`, `focus-visible`, `active`, `visited`, `disabled`, `enabled`, `checked`, `empty`, `first`, `last`, `odd`, `even`, `only`
|
|
140
|
+
- **Pseudo-elements** — `before`, `after`, `placeholder`, `file`, `marker`, `selection`, `first-line`, `first-letter`, `backdrop`
|
|
141
|
+
- **Media** — `dark`, `print`, `portrait`, `landscape`, `motion-safe`, `motion-reduce`, `starting`
|
|
142
|
+
- **Breakpoints** — `sm`, `md`, `lg`, `xl` (theme-driven, customizable via `@breakpoint`)
|
|
143
|
+
- **Container queries** — `@sm`, `@md`, …
|
|
144
|
+
- **Attribute selectors** — `data-[state=open]`, `aria-[pressed=true]`
|
|
145
|
+
- **Arbitrary** — `[selector]`, `[@media(...)]`
|
|
105
146
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
variants: Variants;
|
|
111
|
-
parseCandidate(candidate: string): Candidate[];
|
|
112
|
-
compileAstNodes(candidate: Candidate): AstNode[];
|
|
113
|
-
getClassOrder(classes: string[]): [string, bigint | null][];
|
|
114
|
-
}
|
|
147
|
+
### Arbitrary values
|
|
148
|
+
|
|
149
|
+
```html
|
|
150
|
+
<div class="w-[37rem] bg-[#1a73e8] data-[state=open]:opacity-100"></div>
|
|
115
151
|
```
|
|
116
152
|
|
|
117
|
-
|
|
153
|
+
CSS variable shorthand:
|
|
118
154
|
|
|
119
|
-
|
|
155
|
+
```html
|
|
156
|
+
<div class="bg-(--brand-color) text-(--brand-text)"></div>
|
|
157
|
+
```
|
|
120
158
|
|
|
121
|
-
|
|
122
|
-
interface ParseOptions {
|
|
123
|
-
from?: string; // Source file path for source maps
|
|
124
|
-
}
|
|
159
|
+
### Variant groups
|
|
125
160
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
161
|
+
When multiple utilities share the same variant prefix, group them with `{…}` instead of repeating the prefix:
|
|
162
|
+
|
|
163
|
+
```html
|
|
164
|
+
<!-- These two lines are equivalent -->
|
|
165
|
+
<div class="hover:text-red-500 hover:bg-blue-100 hover:underline">…</div>
|
|
166
|
+
<div class="hover:{text-red-500 bg-blue-100 underline}">…</div>
|
|
129
167
|
```
|
|
130
168
|
|
|
131
|
-
|
|
169
|
+
Groups stack and nest:
|
|
132
170
|
|
|
133
|
-
|
|
171
|
+
```html
|
|
172
|
+
<!-- Chained variants -->
|
|
173
|
+
<div class="sm:hover:{bg-gray-700 text-white}">…</div>
|
|
134
174
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
175
|
+
<!-- Multiple groups in one class string -->
|
|
176
|
+
<div class="focus:{outline-2 outline-blue-500} disabled:{opacity-50 cursor-not-allowed}">…</div>
|
|
177
|
+
|
|
178
|
+
<!-- The data-attribute case -->
|
|
179
|
+
<div class="data-[active]:{relative px-2} data-[slot=sidebar]:{fixed leading-none}">…</div>
|
|
140
180
|
```
|
|
141
181
|
|
|
142
|
-
|
|
182
|
+
Expansion happens at scan-time, so the runtime never sees the grouped form. Nesting is capped at depth 10; expanded output is capped at 1MB.
|
|
183
|
+
|
|
184
|
+
## Theming with CSS directives
|
|
185
|
+
|
|
186
|
+
Customization happens in your CSS input, not a JS config. The engine recognizes:
|
|
187
|
+
|
|
188
|
+
| Directive | Purpose |
|
|
189
|
+
| --- | --- |
|
|
190
|
+
| `@color` | Define color tokens. Supports generative (`chroma hue`), explicit (`oklch(...)`, `#rrggbb`), light/dark pairs, and aliases. |
|
|
191
|
+
| `@spacing` | Set the spacing base unit. |
|
|
192
|
+
| `@text` | Define text size tokens (`size, line-height`). |
|
|
193
|
+
| `@font`, `@font-face` | Register font families inside a single `@font { … }` block. One slot can own multiple `@face` faces (e.g. upright + italic) or use the `italic:` shorthand. |
|
|
194
|
+
| `@rounded` | Border-radius tokens; modifier sets corner shape (`round`, `squircle`, `superellipse(N)`, etc). |
|
|
195
|
+
| `@fluid` | Configure fluid type/spacing range. |
|
|
196
|
+
| `@animate` | Register named animations with inline `@keyframes`. |
|
|
197
|
+
| `@utility` | Define a custom utility (static or functional `name-*`). |
|
|
198
|
+
| `@apply` | Compose utilities into a single rule. |
|
|
199
|
+
| `@custom` | Define a custom variant. |
|
|
200
|
+
| `@slot` | Slot marker inside `@custom` block form. |
|
|
201
|
+
| `@source` | Declare additional source globs from CSS. Supports `not "..."` and `inline("...")`. |
|
|
202
|
+
| `@preflight` | Toggle preflight base styles. |
|
|
203
|
+
| `@layer`, `@media`, `@custom-media`, `@import` | Standard CSS plus a few extensions. |
|
|
204
|
+
|
|
205
|
+
Example:
|
|
206
|
+
|
|
207
|
+
```css
|
|
208
|
+
@import "rainbowindex";
|
|
209
|
+
|
|
210
|
+
@color {
|
|
211
|
+
brand: 0.18 330; /* generative: chroma hue */
|
|
212
|
+
brand-soft: oklch(0.92 0.04 330); /* explicit */
|
|
213
|
+
surface: oklch(0.98 0.01 260) / oklch(0.15 0.01 260); /* light/dark pair */
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
@spacing { base: 0.5rem; }
|
|
143
217
|
|
|
144
|
-
|
|
218
|
+
@text {
|
|
219
|
+
display: 4rem, 1.05;
|
|
220
|
+
body: 1rem, 1.5;
|
|
221
|
+
}
|
|
145
222
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
223
|
+
@font {
|
|
224
|
+
sans: "Inter" from google { weight: 400 700; }
|
|
225
|
+
display: "Satoshi" from "/fonts/Satoshi.woff2" {
|
|
226
|
+
weight: 300 900;
|
|
227
|
+
italic: "/fonts/Satoshi-Italic.woff2"; /* second face, font-style: italic */
|
|
228
|
+
}
|
|
149
229
|
}
|
|
230
|
+
|
|
231
|
+
@source "../emails/**/*.html";
|
|
232
|
+
@source not "../**/legacy/*";
|
|
150
233
|
```
|
|
151
234
|
|
|
152
|
-
|
|
235
|
+
Default theme keys: `colors`, `spacing`, `text`, `breakpoints`, `rounded`, `shadows`, `weights`, `easing`, `fluid`, `animations`, `blur`, `z`.
|
|
236
|
+
|
|
237
|
+
## `ri()` — runtime class merger
|
|
153
238
|
|
|
154
|
-
|
|
239
|
+
`ri()` merges class strings with right-most-wins conflict resolution. It replaces both `clsx` (for conditional composition) and `tailwind-merge` (for conflict resolution).
|
|
155
240
|
|
|
156
|
-
|
|
157
|
-
|
|
241
|
+
```ts
|
|
242
|
+
import { ri } from "rainbowindex";
|
|
158
243
|
|
|
159
|
-
|
|
160
|
-
|
|
244
|
+
ri("px-2 py-1", isActive && "bg-blue-500", "px-4");
|
|
245
|
+
// → "py-1 bg-blue-500 px-4" (px-2 is dropped — px-4 wins)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Accepted inputs:
|
|
161
249
|
|
|
162
|
-
|
|
250
|
+
```ts
|
|
251
|
+
type ClassInput = string | false | null | undefined | ClassInput[];
|
|
252
|
+
ri(...inputs: ClassInput[]): string;
|
|
253
|
+
```
|
|
163
254
|
|
|
164
|
-
|
|
255
|
+
Conflict resolution understands shorthands: `p-4` claims all four padding sides, but only drops if every side is overwritten by a class to its right.
|
|
256
|
+
|
|
257
|
+
### `ri()` vs `createRi()` — which one do I use?
|
|
258
|
+
|
|
259
|
+
| Situation | Use |
|
|
260
|
+
| --- | --- |
|
|
261
|
+
| Browser bundle / client components | **`ri()`** |
|
|
262
|
+
| Vite build / PostCSS one-shot | **`ri()`** |
|
|
263
|
+
| Single Node compile that exits | **`ri()`** |
|
|
264
|
+
| Concurrent SSR (one server, many requests) | **`createRi(snapshot)`** |
|
|
265
|
+
| Multi-tenant compile (different themes in the same process) | **`createRi(snapshot)`** |
|
|
266
|
+
| Edge / serverless functions sharing module state across invocations | **`createRi(snapshot)`** |
|
|
267
|
+
|
|
268
|
+
`ri()` reads module-level state published by the most recent compile. That's
|
|
269
|
+
fast and ergonomic in any environment where there is exactly one compile
|
|
270
|
+
per process. If two requests can be merging classes against two different
|
|
271
|
+
themes in the same Node process, that shared state will leak — use
|
|
272
|
+
`createRi(snapshot)` to bind each request to its own frozen snapshot.
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
// Anywhere ri() is single-compile-safe (browser, Vite, PostCSS):
|
|
276
|
+
import { ri } from "rainbowindex";
|
|
277
|
+
|
|
278
|
+
const className = ri("px-2 py-1", isActive && "bg-blue-500", "px-4");
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
// SSR / multi-tenant — capture the snapshot at compile time, bind per-request:
|
|
283
|
+
import { compileProject, createRi, finalizeCompilationContext } from "rainbowindex";
|
|
284
|
+
|
|
285
|
+
// At server startup (once per theme):
|
|
286
|
+
const ctx = await compileProject({ cwd, css });
|
|
287
|
+
const snapshot = finalizeCompilationContext(ctx);
|
|
288
|
+
const ri = createRi(snapshot);
|
|
289
|
+
|
|
290
|
+
// In your request handler:
|
|
291
|
+
function render(req, res) {
|
|
292
|
+
const html = `<div class="${ri("px-2 py-1", req.dark && "dark:bg-slate-900")}">…</div>`;
|
|
293
|
+
res.send(html);
|
|
294
|
+
}
|
|
295
|
+
```
|
|
165
296
|
|
|
166
|
-
|
|
297
|
+
If you call `ri()` while a compilation is still in progress (e.g. inside a
|
|
298
|
+
server-rendering pass that triggers a fresh compile), the runtime emits a
|
|
299
|
+
throttled `[RI-2004]` warning. That's your signal to switch to `createRi()`.
|
|
167
300
|
|
|
168
|
-
|
|
301
|
+
## Environment variables
|
|
169
302
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
- **Effects**: `shadow-*`, `opacity-*`, `blur-*`
|
|
178
|
-
- **Borders**: `rounded-*`, `border-*`
|
|
303
|
+
| Variable | Effect |
|
|
304
|
+
| --- | --- |
|
|
305
|
+
| `RI_DEBUG=1` | Enable debug logging. |
|
|
306
|
+
| `RI_OFFLINE=1` | Skip network calls; use cached font data only. |
|
|
307
|
+
| `RI_FETCH_FONTS=0` | Disable Google Fonts metadata requests. |
|
|
308
|
+
| `RI_CACHE_DIR` | Override font cache directory (default: `node_modules/.cache/rainbowindex`). |
|
|
309
|
+
| `RI_FONT_CACHE_TTL` | Font cache max age in seconds (default: `604800` — 7 days). |
|
|
179
310
|
|
|
180
|
-
##
|
|
311
|
+
## Diagnostics
|
|
181
312
|
|
|
182
|
-
|
|
313
|
+
Warnings carry `RI-NNNN` codes. Ranges:
|
|
183
314
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
315
|
+
| Range | Subsystem |
|
|
316
|
+
| --- | --- |
|
|
317
|
+
| 10xx | Compilation & directives |
|
|
318
|
+
| 11xx | Color directives |
|
|
319
|
+
| 12xx | Font system |
|
|
320
|
+
| 13xx | Merge / compilation context |
|
|
321
|
+
| 14xx | Source scanner |
|
|
322
|
+
| 15xx | Typography utilities |
|
|
323
|
+
| 16xx | Integration plugins (Vite, PostCSS, CLI wiring) |
|
|
324
|
+
| 20xx | CSS function processing |
|
|
325
|
+
| 21xx | `ri()` runtime |
|
|
189
326
|
|
|
190
|
-
|
|
327
|
+
See the [diagnostics reference](https://rainbowindex.dev/docs/diagnostics) for the full code → cause → fix table.
|
|
191
328
|
|
|
192
|
-
|
|
329
|
+
Warnings are deduplicated and capped at 200 per compile, with 20 slots reserved for high-severity errors.
|