rainbowindex 0.6.0 → 0.7.0
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 +543 -0
- package/LICENSE +16 -17
- package/NOTICE.md +106 -0
- package/README.md +219 -65
- package/dist/browser.d.ts +4 -2
- package/dist/browser.mjs +12 -4
- package/dist/chunk-2T7V5XLK.mjs +912 -0
- package/dist/chunk-6OORICWF.mjs +16 -0
- package/dist/{chunk-KSNYSR3C.mjs → chunk-FJOZJIKB.mjs} +2499 -329
- package/dist/chunk-L56IRO7A.mjs +491 -0
- package/dist/chunk-PZDVDEZJ.mjs +196 -0
- package/dist/{chunk-3LWJTLOJ.mjs → chunk-RC6DDE4L.mjs} +23 -15
- package/dist/chunk-TQJYVQPE.mjs +217 -0
- package/dist/chunk-W756NVYI.mjs +33 -0
- package/dist/chunk-WBESS2ZD.mjs +598 -0
- package/dist/{chunk-3HRMFZGE.mjs → chunk-X66Z2YHT.mjs} +2 -1
- package/dist/{chunk-6U4IOFOS.mjs → chunk-XQGSG2HK.mjs} +199 -555
- package/dist/cli.mjs +1077 -123
- package/dist/{index-DSgpB6bS.d.ts → context-DcBtnnan.d.ts} +47 -103
- package/dist/editor.d.ts +71 -433
- package/dist/editor.mjs +51 -368
- package/dist/eslint.d.ts +16 -0
- package/dist/eslint.mjs +32 -0
- package/dist/{index-4Kyaq3IZ.d.ts → imports-C9esHd5Q.d.ts} +78 -84
- package/dist/index-CNqdL5U0.d.ts +56 -0
- package/dist/index-Czx-EUwh.d.ts +138 -0
- package/dist/index-DW8YSxTz.d.ts +104 -0
- package/dist/index.d.ts +46 -5
- package/dist/index.mjs +33 -9
- package/dist/oxlint.d.ts +21 -3
- package/dist/oxlint.mjs +19 -1
- package/dist/recipe.d.ts +111 -0
- package/dist/recipe.mjs +71 -0
- package/dist/safelist-CH3_PywB.d.ts +43 -0
- package/dist/session-CMaskdB7.d.ts +543 -0
- package/dist/tailwind.css +644 -0
- package/dist/theme-CIZiGlce.d.ts +115 -0
- package/dist/vite.d.ts +10 -1
- package/dist/vite.mjs +266 -118
- package/package.json +27 -5
- package/dist/chunk-WK6S4HTC.mjs +0 -1921
- package/dist/chunk-ZR7XJMUN.mjs +0 -251
- package/dist/safelist-CGCtF-Fr.d.ts +0 -96
package/NOTICE.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Notices
|
|
2
|
+
|
|
3
|
+
Rainbow Index is licensed under the MIT License — see [LICENSE](LICENSE).
|
|
4
|
+
|
|
5
|
+
It incorporates work from the projects below. Each is MIT-licensed, and MIT's
|
|
6
|
+
notice clause requires their copyright notices and permission notices to travel
|
|
7
|
+
with any copy or substantial portion of that work, so their full license texts
|
|
8
|
+
are reproduced here.
|
|
9
|
+
|
|
10
|
+
## Tailwind CSS
|
|
11
|
+
|
|
12
|
+
Rainbow Index began as a fork of Tailwind CSS v4; portions of this software are
|
|
13
|
+
derived from it.
|
|
14
|
+
|
|
15
|
+
In addition, `src/presets/tailwind.css` — shipped in the package as
|
|
16
|
+
`rainbowindex/tailwind.css` — is a transcription of Tailwind v4's default
|
|
17
|
+
theme. Its color, breakpoint, font-size, line-height, font-weight,
|
|
18
|
+
letter-spacing, radius, shadow, blur, easing, animation, and shadow-family
|
|
19
|
+
values are copied from Tailwind's `packages/tailwindcss/theme.css` and
|
|
20
|
+
rewritten as Rainbow Index directives by
|
|
21
|
+
`scripts/generate-tailwind-preset.mjs`. The values are Tailwind's; only the
|
|
22
|
+
syntax is ours.
|
|
23
|
+
|
|
24
|
+
<https://github.com/tailwindlabs/tailwindcss>
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
MIT License
|
|
28
|
+
|
|
29
|
+
Copyright (c) Tailwind Labs, Inc.
|
|
30
|
+
|
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
32
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
33
|
+
in the Software without restriction, including without limitation the rights
|
|
34
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
35
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
36
|
+
furnished to do so, subject to the following conditions:
|
|
37
|
+
|
|
38
|
+
The above copyright notice and this permission notice shall be included in all
|
|
39
|
+
copies or substantial portions of the Software.
|
|
40
|
+
|
|
41
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
42
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
43
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
44
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
45
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
46
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
47
|
+
SOFTWARE.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## tailwind-merge
|
|
51
|
+
|
|
52
|
+
The class merging algorithm in `src/merge/` is derived from tailwind-merge.
|
|
53
|
+
<https://github.com/dcastil/tailwind-merge>
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
MIT License
|
|
57
|
+
|
|
58
|
+
Copyright (c) 2021 Dany Castillo
|
|
59
|
+
|
|
60
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
61
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
62
|
+
in the Software without restriction, including without limitation the rights
|
|
63
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
64
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
65
|
+
furnished to do so, subject to the following conditions:
|
|
66
|
+
|
|
67
|
+
The above copyright notice and this permission notice shall be included in all
|
|
68
|
+
copies or substantial portions of the Software.
|
|
69
|
+
|
|
70
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
71
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
72
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
73
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
74
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
75
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
76
|
+
SOFTWARE.
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## tw-animate-css
|
|
80
|
+
|
|
81
|
+
The animation system is inspired by tw-animate-css.
|
|
82
|
+
<https://github.com/Wombosvideo/tw-animate-css>
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
MIT License
|
|
86
|
+
|
|
87
|
+
Copyright (c) 2025 Wombosvideo
|
|
88
|
+
|
|
89
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
90
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
91
|
+
in the Software without restriction, including without limitation the rights
|
|
92
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
93
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
94
|
+
furnished to do so, subject to the following conditions:
|
|
95
|
+
|
|
96
|
+
The above copyright notice and this permission notice shall be included in all
|
|
97
|
+
copies or substantial portions of the Software.
|
|
98
|
+
|
|
99
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
100
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
101
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
102
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
103
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
104
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
105
|
+
SOFTWARE.
|
|
106
|
+
```
|
package/README.md
CHANGED
|
@@ -1,26 +1,46 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<a href="https://rainbowindex.dev" target="_blank">
|
|
3
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="
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rainbowindex/rainbowindex/HEAD/.github/assets/logo-dark.svg">
|
|
5
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/rainbowindex/rainbowindex/HEAD/.github/assets/logo-light.svg">
|
|
6
|
+
<img alt="Rainbow Index" src="https://raw.githubusercontent.com/rainbowindex/rainbowindex/HEAD/.github/assets/logo-light.svg" width="161" height="41" style="max-width: 100%;">
|
|
7
7
|
</picture>
|
|
8
8
|
</a>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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.
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://github.com/rainbowindex/rainbowindex/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/rainbowindex/rainbowindex/actions/workflows/ci.yml/badge.svg?branch=main"></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/rainbowindex"><img alt="npm" src="https://img.shields.io/npm/v/rainbowindex.svg"></a>
|
|
14
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/npm/l/rainbowindex.svg"></a>
|
|
15
|
+
</p>
|
|
22
16
|
|
|
23
|
-
|
|
17
|
+
**Rainbow Index** compiles a design system out of CSS. Your tokens live in CSS
|
|
18
|
+
directives rather than a JavaScript config, and the compiler turns them into
|
|
19
|
+
utilities, a typed contract for your editor, and diagnostics when something is
|
|
20
|
+
wrong.
|
|
21
|
+
|
|
22
|
+
- **The theme is CSS.** `@color { brand: 0.18 330; }` declares a generative
|
|
23
|
+
OKLCH palette; `@text`, `@breakpoint`, `@shadow` and the rest work the same
|
|
24
|
+
way. No config file to keep in sync.
|
|
25
|
+
- **Nothing ships until you name it.** `text-lg` and `bg-blue-500` do not exist
|
|
26
|
+
until a directive defines them, so the output is your system rather than a
|
|
27
|
+
filtered copy of someone else's. One import brings Tailwind v4's scales.
|
|
28
|
+
- **It tells you when you are wrong.** Numbered diagnostics for a color that
|
|
29
|
+
fails contrast, a class that can never match, a token that resolves to
|
|
30
|
+
nothing.
|
|
31
|
+
- **Your editor knows your theme.** `rainbowindex/editor` enumerates ~3,900
|
|
32
|
+
completions from your own CSS, and says what a class compiles to and why a
|
|
33
|
+
merge dropped one.
|
|
34
|
+
|
|
35
|
+
It compiles [100% of Tailwind v4's class surface](#tailwind-class-coverage), so
|
|
36
|
+
moving over is mostly copy-paste — and
|
|
37
|
+
`rainbowindex migrate tailwind` translates the theme for you, then tells you
|
|
38
|
+
which of your classes stop resolving ([docs/migrating.md](docs/migrating.md)). [Why Rainbow Index?](docs/why.md) compares it
|
|
39
|
+
against Tailwind, UnoCSS, Panda and StyleX — losses included.
|
|
40
|
+
|
|
41
|
+
The documentation is in [docs/](docs/README.md).
|
|
42
|
+
[docs/frameworks.md](docs/frameworks.md) has copy-paste setup for Vite, React
|
|
43
|
+
Router, SvelteKit, Astro and Next.js.
|
|
24
44
|
|
|
25
45
|
## Install
|
|
26
46
|
|
|
@@ -30,27 +50,9 @@ pnpm add rainbowindex
|
|
|
30
50
|
|
|
31
51
|
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.
|
|
32
52
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```ini
|
|
38
|
-
@rainbowindex:registry=https://npm.pkg.github.com
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
GitHub Packages authenticates every read, including public ones, so put a [personal access token (classic)](https://github.com/settings/tokens) with the `read:packages` scope in your `~/.npmrc`:
|
|
42
|
-
|
|
43
|
-
```ini
|
|
44
|
-
//npm.pkg.github.com/:_authToken=YOUR_TOKEN
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Then install under the alias `rainbowindex`, so every import, `@import`, and CLI invocation in the docs below works unchanged:
|
|
48
|
-
|
|
49
|
-
```sh
|
|
50
|
-
pnpm add rainbowindex@npm:@rainbowindex/rainbowindex
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Without the alias — `pnpm add @rainbowindex/rainbowindex` — the package resolves under its scoped name, and specifiers become `@rainbowindex/rainbowindex`, `@rainbowindex/rainbowindex/vite`, and so on.
|
|
53
|
+
Every release is also published to GitHub Packages under an owner-scoped name.
|
|
54
|
+
That registry authenticates every read, so it needs two lines of `.npmrc` — see
|
|
55
|
+
[Install](docs/getting-started.md#from-github-packages).
|
|
54
56
|
|
|
55
57
|
## Quick start (Vite)
|
|
56
58
|
|
|
@@ -66,6 +68,25 @@ export default defineConfig({
|
|
|
66
68
|
});
|
|
67
69
|
```
|
|
68
70
|
|
|
71
|
+
Then pick a starting theme.
|
|
72
|
+
|
|
73
|
+
**Tailwind-familiar.** One extra import brings Tailwind v4's default scales — 26 color families, the `sm` through `2xl` breakpoints, `text-xs` through `text-9xl`, and the weight, leading, tracking, radius, shadow, blur, easing, and animation names.
|
|
74
|
+
|
|
75
|
+
```css
|
|
76
|
+
/* src/styles.css */
|
|
77
|
+
@import "rainbowindex";
|
|
78
|
+
@import "rainbowindex/tailwind.css";
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
// src/App.tsx
|
|
83
|
+
export default function App() {
|
|
84
|
+
return <div className="sm:flex gap-4 px-6 py-3 text-lg font-bold rounded-lg shadow-md bg-blue-600 text-white">Hello</div>;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**From scratch.** Name the tokens your design system has, and nothing else.
|
|
89
|
+
|
|
69
90
|
```css
|
|
70
91
|
/* src/styles.css */
|
|
71
92
|
@import "rainbowindex";
|
|
@@ -73,16 +94,25 @@ export default defineConfig({
|
|
|
73
94
|
@color {
|
|
74
95
|
brand: 0.18 330;
|
|
75
96
|
}
|
|
97
|
+
|
|
98
|
+
@text { body: 1rem, 1.5; }
|
|
99
|
+
@breakpoint { sm: 40rem; }
|
|
76
100
|
```
|
|
77
101
|
|
|
78
102
|
```tsx
|
|
79
103
|
// src/App.tsx
|
|
80
104
|
export default function App() {
|
|
81
|
-
return <div className="flex gap-4 px-6 py-3 bg-brand-500 text-white">Hello</div>;
|
|
105
|
+
return <div className="sm:flex gap-4 px-6 py-3 text-body bg-brand-500 text-white">Hello</div>;
|
|
82
106
|
}
|
|
83
107
|
```
|
|
84
108
|
|
|
85
|
-
|
|
109
|
+
### What does not ship by default
|
|
110
|
+
|
|
111
|
+
The package ships two scales: the neutral `theme` color and the `0.25rem` spacing base. Breakpoints, text sizes, weights, leading, tracking, radii, shadows, blur, easing, animations, and fluid ranges all start empty, so `sm:flex`, `text-lg`, `font-bold`, `shadow-md`, and `rounded-lg` render nothing until a directive names them. The fixed color names `black`, `white`, `paper`, `ink`, `transparent`, `current`, and `inherit` always work; `blue-500` does not exist until you declare it.
|
|
112
|
+
|
|
113
|
+
The forms that compute rather than look up need no theme at all: `p-4`, `rounded-4`, `font-600`, `z-10`, `text-[18px]`, `blur-none`.
|
|
114
|
+
|
|
115
|
+
`rainbowindex/tailwind.css` is the escape hatch, not the default. It is a plain directive file — read it, copy the blocks you want, or import it whole. Import it after the package, and override any token by declaring it again below. Importing it costs only what you use: every token is pruned to what the build actually references, so a page that names four colors emits four.
|
|
86
116
|
|
|
87
117
|
To scaffold a fresh app instead, use the CLI:
|
|
88
118
|
|
|
@@ -94,13 +124,14 @@ pnpm dlx rainbowindex init
|
|
|
94
124
|
|
|
95
125
|
## CLI
|
|
96
126
|
|
|
97
|
-
The `rainbowindex` binary exposes
|
|
127
|
+
The `rainbowindex` binary exposes seven subcommands. The default is `build`.
|
|
98
128
|
|
|
99
129
|
```
|
|
100
130
|
rainbowindex <glob> [options] Generate CSS from source files
|
|
101
131
|
rainbowindex init Wire Rainbow Index into the current Vite app
|
|
102
132
|
rainbowindex create <dir> Scaffold a Vite app with Rainbow Index ready
|
|
103
133
|
rainbowindex generate-types Generate TypeScript types for ri() autocomplete
|
|
134
|
+
rainbowindex generate-snapshot Generate the theme snapshot that makes client ri() theme-aware
|
|
104
135
|
rainbowindex preload-fonts Print <link rel="preload"> tags for local faces marked preload
|
|
105
136
|
rainbowindex scan <glob> Print the class names the scanner extracts from files
|
|
106
137
|
```
|
|
@@ -152,27 +183,76 @@ Auto-detects your CSS entry, injects a PostCSS config if none exists, supports H
|
|
|
152
183
|
|
|
153
184
|
## Vite+
|
|
154
185
|
|
|
155
|
-
[Vite+](https://viteplus.dev) works out of the box.
|
|
186
|
+
[Vite+](https://viteplus.dev) works out of the box. Four deprecated directive spellings are not valid CSS, so Oxfmt — the formatter behind `vp fmt` and `vp check` — cannot parse a stylesheet that still uses them. The Vite plugin adds only those files to `fmt.ignorePatterns`; a stylesheet written the canonical way is hidden from nothing.
|
|
187
|
+
|
|
188
|
+
See [docs/vite-plus.md](docs/vite-plus.md).
|
|
189
|
+
|
|
190
|
+
## Component variants
|
|
156
191
|
|
|
157
|
-
|
|
192
|
+
`recipe()` is a typed variant layer whose output is ordinary class names — the
|
|
193
|
+
`cva`/`tv` shape, merged through `ri()` so conflicts resolve against your
|
|
194
|
+
compiled theme instead of a Tailwind utility table.
|
|
158
195
|
|
|
159
196
|
```ts
|
|
160
|
-
|
|
197
|
+
import { recipe } from "rainbowindex/recipe";
|
|
198
|
+
|
|
199
|
+
const button = recipe({
|
|
200
|
+
base: "inline-flex items-center rounded-card font-medium",
|
|
201
|
+
variants: {
|
|
202
|
+
tone: { solid: "bg-brand-600 text-white", quiet: "text-brand-700" },
|
|
203
|
+
size: { sm: "h-8 px-3 text-sm", md: "h-10 px-4" },
|
|
204
|
+
},
|
|
205
|
+
defaultVariants: { tone: "solid", size: "md" },
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
button({ size: "sm" }); // → "inline-flex … bg-brand-600 text-white h-8 px-3 text-sm"
|
|
209
|
+
button({ size: "xl" }); // ✗ Type error: "xl" is not a size
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
The classes live in the config, where the scanner already reads them. See
|
|
213
|
+
[docs/recipe.md](docs/recipe.md).
|
|
214
|
+
|
|
215
|
+
## Editor support
|
|
216
|
+
|
|
217
|
+
**Rainbow Index for VS Code**, on the Marketplace and thin over
|
|
218
|
+
`rainbowindex/editor`: completions from *your* theme (a `@color` you added five
|
|
219
|
+
seconds ago completes), hover showing the generated rule and the colour's light
|
|
220
|
+
and dark hex, diagnostics on a class that compiles to nothing, colour chips you
|
|
221
|
+
can drag, an element tree and a theme explorer, go-to-definition, rename, and a
|
|
222
|
+
sort command that matches the order the stylesheet emits. It loads the copy of
|
|
223
|
+
the package your workspace installed, so upgrading the package upgrades what
|
|
224
|
+
your editor knows. Source at https://github.com/miloag/extension — see [docs/editor.md](docs/editor.md).
|
|
225
|
+
|
|
226
|
+
## Lint rules
|
|
227
|
+
|
|
228
|
+
Three opt-in rules, for Oxlint and ESLint. Two of them read your compiled theme,
|
|
229
|
+
so they can tell you a class is wrong rather than merely unfamiliar:
|
|
230
|
+
`no-unknown-class` reports a class that compiles to nothing (with the typo
|
|
231
|
+
suggestion as an editor fix), and `no-conflicting-classes` reports a class that
|
|
232
|
+
another class in the same string erases. `prefer-ri` reports an import of
|
|
233
|
+
`clsx`, `classnames` or `tailwind-merge`.
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
// vite.config.ts
|
|
161
237
|
export default defineConfig({
|
|
162
238
|
lint: {
|
|
163
239
|
jsPlugins: [{ name: "rainbowindex", specifier: "rainbowindex/oxlint" }],
|
|
164
|
-
rules: {
|
|
240
|
+
rules: {
|
|
241
|
+
"rainbowindex/no-unknown-class": "error",
|
|
242
|
+
"rainbowindex/no-conflicting-classes": "warn",
|
|
243
|
+
"rainbowindex/prefer-ri": "error",
|
|
244
|
+
},
|
|
165
245
|
},
|
|
166
246
|
});
|
|
167
247
|
```
|
|
168
248
|
|
|
169
|
-
See [docs/
|
|
249
|
+
See [docs/lint.md](docs/lint.md) for the ESLint flat-config form and the options.
|
|
170
250
|
|
|
171
251
|
## Class syntax
|
|
172
252
|
|
|
173
253
|
### Utilities
|
|
174
254
|
|
|
175
|
-
|
|
255
|
+
The same utility families as Tailwind — spacing, sizing, typography, color, layout, borders, effects, animations, and SVG — but not the same named tokens. `text-lg` and `shadow-md` resolve only once a directive names them, or once you import the preset (see [What does not ship by default](#what-does-not-ship-by-default)). The numeric, keyword, and arbitrary forms need no theme: `p-4`, `rounded-4`, `font-600`, `text-[18px]`, `blur-none`. Use `rainbowindex generate-types` for autocomplete in your editor.
|
|
176
256
|
|
|
177
257
|
### Variants
|
|
178
258
|
|
|
@@ -247,7 +327,7 @@ Customization happens in your CSS input, not a JS config. The engine recognizes:
|
|
|
247
327
|
| `@slot` | Slot marker inside `@custom` block form. |
|
|
248
328
|
| `@source` | Declare additional source globs from CSS. Supports `not "..."` and `inline("...")`. |
|
|
249
329
|
| `@preflight` | Toggle preflight base styles. |
|
|
250
|
-
| `@breakpoint`, `@shadow`, `@weight`, `@ease`, `@blur`, `@z`, `@leading`, `@tracking`, `@opacity`, `@duration` | Key-value token scales;
|
|
330
|
+
| `@breakpoint`, `@shadow`, `@weight`, `@ease`, `@blur`, `@z`, `@leading`, `@tracking`, `@opacity`, `@duration` | Key-value token scales; `key: initial;` removes a token. |
|
|
251
331
|
| `@register` | Emit CSS `@property` registrations. |
|
|
252
332
|
| `@layer` | Place the generated output in cascade layers (intercepted, own grammar). |
|
|
253
333
|
| `@media`, `@import`, other standard at-rules | Standard CSS — passed through untouched. |
|
|
@@ -287,6 +367,8 @@ Example:
|
|
|
287
367
|
|
|
288
368
|
The package ships two defaults: the `colors` palette and the `spacing` base. Every other scale — `text`, `leading`, `tracking`, `shadows`, `radii`, `breakpoints`, `weights`, `easing`, `blur`, `animations`, `fluid`, `z`, `opacity`, `duration` — starts empty, and its directive defines the named tokens. Numeric and keyword class forms are computed, so they work with no theme at all.
|
|
289
369
|
|
|
370
|
+
That is the default because a token you did not define is a token nobody has to reason about. When you want Tailwind's names instead, `@import "rainbowindex/tailwind.css";` after the package import supplies them, written in the same directives documented above — so you can open the file and copy the blocks you want rather than importing all of it.
|
|
371
|
+
|
|
290
372
|
## `ri()` — runtime class merger
|
|
291
373
|
|
|
292
374
|
`ri()` merges class strings with right-most-wins conflict resolution. It replaces both `clsx` (for conditional composition) and `tailwind-merge` (for conflict resolution).
|
|
@@ -309,20 +391,34 @@ Conflict resolution understands shorthands: `p-4` claims all four padding sides,
|
|
|
309
391
|
|
|
310
392
|
### `ri()` vs `createRi()` — which one do I use?
|
|
311
393
|
|
|
312
|
-
| Situation | Use |
|
|
313
|
-
| --- | --- |
|
|
314
|
-
|
|
|
315
|
-
|
|
|
316
|
-
| Single Node compile that exits | **`ri()`** |
|
|
317
|
-
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
394
|
+
| Situation | Use | What you have to do |
|
|
395
|
+
| --- | --- | --- |
|
|
396
|
+
| Vite — client, SSR, build | **`ri()`** | Nothing. |
|
|
397
|
+
| Any other bundler (Next.js, Webpack, Rspack, esbuild) | **`ri()`** | `rainbowindex generate-snapshot`, then import it once. |
|
|
398
|
+
| Single Node compile that exits | **`ri()`** | Nothing. |
|
|
399
|
+
| Many themes in one process (multi-tenant, per-request themes) | **`createRi(snapshot)`** | One merger per theme. |
|
|
400
|
+
|
|
401
|
+
`ri()` answers by asking the *published theme* what properties a class sets.
|
|
402
|
+
Since 0.6.0 every text size, weight, font slot, and color name is
|
|
403
|
+
project-defined, so a client with no theme published reads `text-lg` as a color
|
|
404
|
+
and returns just `text-white` for `ri("text-lg text-white")`.
|
|
405
|
+
|
|
406
|
+
A compile publishes a theme. A browser bundle never compiles — so the Vite
|
|
407
|
+
plugin publishes one for it automatically, and every other bundler gets the
|
|
408
|
+
same result from a generated module:
|
|
409
|
+
|
|
410
|
+
```sh
|
|
411
|
+
rainbowindex generate-snapshot # writes rainbowindex-snapshot.ts
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
```ts
|
|
415
|
+
// app entry, before anything that calls ri()
|
|
416
|
+
import "./rainbowindex-snapshot";
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
If two requests can be merging classes against two different themes in the same
|
|
420
|
+
process, bind each to its own frozen snapshot with `createRi(snapshot)` — the
|
|
421
|
+
generated module exports one.
|
|
326
422
|
|
|
327
423
|
```ts
|
|
328
424
|
// Anywhere ri() is single-compile-safe (browser, Vite, PostCSS):
|
|
@@ -347,9 +443,10 @@ function render(req, res) {
|
|
|
347
443
|
}
|
|
348
444
|
```
|
|
349
445
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
446
|
+
The default `ri()` warns `[RI-2004]` once per process when it merges a
|
|
447
|
+
theme-dependent class with no theme published, naming the class it had to guess
|
|
448
|
+
about. Publishing any theme silences it — a single-theme app that publishes at
|
|
449
|
+
startup is correct, and is not warned at.
|
|
353
450
|
|
|
354
451
|
## Editor tooling API
|
|
355
452
|
|
|
@@ -368,7 +465,7 @@ const session = createEditorSession({ css: themeCss });
|
|
|
368
465
|
session.diagnostics; // positioned problems in the CSS input
|
|
369
466
|
session.inspector.validate("felx"); // { ok: false, reason: "unknown-utility", suggestion: "flex" }
|
|
370
467
|
session.inspector.explain("sm:px-4"); // parsed structure + generated CSS + sort key
|
|
371
|
-
session.enumerate(); // ~3,
|
|
468
|
+
session.enumerate(); // ~3,900 probe-verified completions + templates
|
|
372
469
|
session.analyzeMerge(["px-2", "px-4"]); // which classes ri() drops, and who overrode them
|
|
373
470
|
session.swatch("brand", 500); // light/dark oklch + hex for completions
|
|
374
471
|
session.extractCandidates(source, path); // class tokens with exact source spans
|
|
@@ -413,4 +510,61 @@ Warnings carry `RI-NNNN` codes. Ranges:
|
|
|
413
510
|
|
|
414
511
|
See [docs/diagnostics.md](docs/diagnostics.md) for the full code → cause → fix table.
|
|
415
512
|
|
|
416
|
-
Warnings are deduplicated and capped at 200 per compile, with 20 slots reserved for high-severity errors.
|
|
513
|
+
Warnings are deduplicated and capped at 200 per compile, with 20 slots reserved for high-severity errors.
|
|
514
|
+
|
|
515
|
+
## Benchmarks
|
|
516
|
+
|
|
517
|
+
Measured 2026-09-06 on an Apple M4 (10 cores), Node 24.20.0, against a generated
|
|
518
|
+
10,000-file codebase (12.75 MB of source, 13,507 distinct classes) with
|
|
519
|
+
rainbowindex loading its Tailwind preset so all three engines compile the same
|
|
520
|
+
strings.
|
|
521
|
+
|
|
522
|
+
| Engine | Cold build | Rebuild (unchanged) | Rebuild (1 file) | Scan only | Output | Peak RSS |
|
|
523
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
524
|
+
| rainbowindex 0.6.0 | 845 ms | 583 ms | 585 ms | 539 ms | **977 KB** | **354 MB** |
|
|
525
|
+
| Tailwind CSS 4.3.3 | **330 ms** | **40 ms** | **90 ms** | **39 ms** | 1.01 MB | 391 MB |
|
|
526
|
+
| UnoCSS 66.8.1 | 1.29 s | 503 ms | 502 ms | 440 ms | 1.00 MB | 427 MB |
|
|
527
|
+
|
|
528
|
+
Read that honestly: **Rainbow Index produces the smallest stylesheet of the
|
|
529
|
+
three and is the slowest to rebuild.** Almost all of the gap is the scanner —
|
|
530
|
+
`539 ms` of a `585 ms` rebuild — because Tailwind's is compiled Rust
|
|
531
|
+
(`@tailwindcss/oxide`) and this one is JavaScript. On a cold build, where the
|
|
532
|
+
scan is a smaller share of the work, the gap to Tailwind closes to about 2.6×.
|
|
533
|
+
|
|
534
|
+
Against UnoCSS it is three scenarios each: Rainbow Index wins cold build, output
|
|
535
|
+
size and peak memory; UnoCSS wins both rebuilds and the scan.
|
|
536
|
+
|
|
537
|
+
### Tailwind class coverage
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
pnpm bench:parity
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
This asks Tailwind v4 for its own complete class list — the 23,289 names its
|
|
544
|
+
IntelliSense uses — renders every one, and reports which Rainbow Index does not
|
|
545
|
+
implement.
|
|
546
|
+
|
|
547
|
+
**100.00%.** Every one of the 23,289 renders. The last 297 outstanding were
|
|
548
|
+
`ring-offset-*` (296) and `ring-inset`; both are implemented, and the sweep is
|
|
549
|
+
what says so — it is recomputed on demand rather than quoted from a table
|
|
550
|
+
someone maintains by hand. What still differs is how a handful of them compile,
|
|
551
|
+
not whether they do: see
|
|
552
|
+
[differences from Tailwind](docs/utilities.md#differences-from-tailwind).
|
|
553
|
+
|
|
554
|
+
The harness, the method, and where the comparison stops being fair are all in
|
|
555
|
+
[bench/README.md](bench/README.md); full results, including the 1,000-file tree,
|
|
556
|
+
are in [bench/results/](bench/results/). Reproduce with:
|
|
557
|
+
|
|
558
|
+
```bash
|
|
559
|
+
pnpm bench --sizes=1k,10k
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
## Contributing
|
|
563
|
+
|
|
564
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, the test layout, how to add a utility, and how `RI-NNNN` codes are allocated. Security reports go through [SECURITY.md](SECURITY.md).
|
|
565
|
+
|
|
566
|
+
[docs/stability.md](docs/stability.md) says what is already treated as a contract before 1.0, what warning a change gives you, and which runtimes are supported.
|
|
567
|
+
|
|
568
|
+
## License
|
|
569
|
+
|
|
570
|
+
MIT — see [LICENSE](LICENSE). Rainbow Index began as a fork of Tailwind CSS v4 and carries work derived from tailwind-merge and tw-animate-css; their notices are in [NOTICE.md](NOTICE.md).
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export { C as
|
|
2
|
-
export { c as createRi, r as ri
|
|
1
|
+
export { C as CompilationContext, a as CompilationSnapshot, S as SerializedSnapshot, c as createCompilationContext, f as finalizeCompilationContext, h as hydrateSnapshot, p as publishSnapshot, r as registerColorNames, b as registerCustomFontFamilies, d as registerCustomTextSizes, e as registerCustomUtility, s as serializeSnapshot } from './context-DcBtnnan.js';
|
|
2
|
+
export { c as createRi, r as ri } from './index-CNqdL5U0.js';
|
|
3
|
+
export { s as safelist } from './safelist-CH3_PywB.js';
|
|
4
|
+
export { C as ColorDefinition, F as FluidConfig, T as TextSize, a as Theme, d as defaultTheme } from './index-Czx-EUwh.js';
|
|
3
5
|
|
|
4
6
|
declare function browserEntryUnavailable(): never;
|
|
5
7
|
|
package/dist/browser.mjs
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
safelist
|
|
3
3
|
} from "./chunk-PD4ZXGJ6.mjs";
|
|
4
|
+
import {
|
|
5
|
+
defaultTheme
|
|
6
|
+
} from "./chunk-L56IRO7A.mjs";
|
|
4
7
|
import {
|
|
5
8
|
createCompilationContext,
|
|
6
9
|
createRi,
|
|
7
|
-
defaultTheme,
|
|
8
10
|
devWarn,
|
|
9
11
|
finalizeCompilationContext,
|
|
12
|
+
hydrateSnapshot,
|
|
13
|
+
publishSnapshot,
|
|
10
14
|
registerColorNames,
|
|
11
15
|
registerCustomFontFamilies,
|
|
12
16
|
registerCustomTextSizes,
|
|
13
17
|
registerCustomUtility,
|
|
14
|
-
ri
|
|
15
|
-
|
|
18
|
+
ri,
|
|
19
|
+
serializeSnapshot
|
|
20
|
+
} from "./chunk-XQGSG2HK.mjs";
|
|
16
21
|
|
|
17
22
|
// src/entries/browser.ts
|
|
18
23
|
function browserEntryUnavailable() {
|
|
@@ -30,10 +35,13 @@ export {
|
|
|
30
35
|
browser_default as default,
|
|
31
36
|
defaultTheme,
|
|
32
37
|
finalizeCompilationContext,
|
|
38
|
+
hydrateSnapshot,
|
|
39
|
+
publishSnapshot,
|
|
33
40
|
registerColorNames,
|
|
34
41
|
registerCustomFontFamilies,
|
|
35
42
|
registerCustomTextSizes,
|
|
36
43
|
registerCustomUtility,
|
|
37
44
|
ri,
|
|
38
|
-
safelist
|
|
45
|
+
safelist,
|
|
46
|
+
serializeSnapshot
|
|
39
47
|
};
|