@birdycom/omniacss-migrate 0.11.0 → 0.11.2

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Serge Cools (Birdycom)
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Serge Cools (Birdycom)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,129 +1,129 @@
1
- # @birdycom/omniacss-migrate
2
-
3
- Switch a **Laravel, Vue or React** project from Tailwind CSS to OmniaCSS **and keep your class names**.
4
- `flex items-center gap-4 p-4 md:p-8 bg-white dark:bg-gray-900 hover:bg-red-500/50 w-[37px]` keeps working: the classes are resolved on demand and emitted as CSS that only uses OmniaCSS tokens (Omnia palette in OKLCH, `rem` scales, Omnia shadows and breakpoints).
5
-
6
- Coming from **Bootstrap 3, 4 or 5**? See [From Bootstrap](#from-bootstrap).
7
-
8
- > This is the only package that names Tailwind and Bootstrap, because it is a migration tool.
9
-
10
- ## Laravel in 3 steps
11
-
12
- ```bash
13
- # 1. see what changes (dry run, nothing is written) and how much of your markup is covered
14
- npx @birdycom/omniacss-migrate scan .
15
- npx @birdycom/omniacss-migrate setup .
16
-
17
- # 2. apply the switch: removes the Tailwind packages from package.json, swaps the Vite/PostCSS plugin, carries your theme into CSS
18
- npx @birdycom/omniacss-migrate setup . --write
19
- npm uninstall tailwindcss @tailwindcss/vite @tailwindcss/postcss && npm install -D @birdycom/omniacss-migrate
20
-
21
- # 3. build as usual
22
- npm run dev
23
- ```
24
-
25
- Your Blade, Vue and React files stay exactly as they are. By hand it is two edits:
26
-
27
- ```js
28
- // vite.config.js
29
- import omniaMigrate from "@birdycom/omniacss-migrate/vite"; // was: import tailwindcss from "@tailwindcss/vite"
30
- export default defineConfig({ plugins: [laravel({ input: ["resources/css/app.css", "resources/js/app.js"] }), omniaMigrate()] });
31
- ```
32
-
33
- ```css
34
- /* resources/css/app.css: unchanged. Both forms are understood: */
35
- @import "tailwindcss";
36
- /* or */
37
- @tailwind base; @tailwind components; @tailwind utilities;
38
- ```
39
-
40
- Not using Vite? Use the PostCSS plugin instead:
41
-
42
- ```js
43
- // postcss.config.js
44
- import omniaMigrate from "@birdycom/omniacss-migrate/postcss";
45
- export default { plugins: [omniaMigrate({ content: ["resources/views/**/*.blade.php", "resources/js/**/*.{vue,tsx,jsx,js}"] })] };
46
- ```
47
-
48
- ## What the plugin does
49
-
50
- - Replaces `@import "tailwindcss"` / `@tailwind base|components|utilities` with Omnia core (tokens + the Omnia classes you use), a small base reset and the compat CSS for the classes it finds in your content.
51
- - Expands `@apply` (with variants, `!important`, and your own classes), `theme(colors.red.500)`, `--spacing(4)`, `@theme`, `@custom-variant`, `@variant`, `@source`, `@source inline("…")`; ignores `@plugin` and `@config`.
52
- - Reads `tailwind.config.{js,cjs,mjs}` (`darkMode`, `theme.colors`/`extend.colors`, `fontFamily`, `borderRadius`, `spacing`, `boxShadow`, `screens`, `container`, `prefix`, `important`) and your `@theme` blocks.
53
- - Output is wrapped in cascade layers `omnia, theme, base, components, utilities`.
54
-
55
- Class coverage: layout, flex/grid, spacing, sizing, typography, colors (text, bg, border, ring, outline, fill, stroke, divide, accent, caret, decoration, gradients `from-`/`via-`/`to-`), borders, radius, shadow, ring, opacity, filters and backdrop filters, transitions, animations, transforms, display, position, z-index, overflow, cursor, scroll snap, `tailwindcss-animate` classes, arbitrary values (`w-[37px]`, `bg-(--brand)`, `[mask-type:luminance]`), opacity modifiers (`bg-red-500/50`), negatives (`-mt-2`), `!important`, and variants `hover: focus: active: disabled: first: odd: before: after: placeholder: file: marker: selection:`, `sm: md: lg: xl: 2xl: max-md: min-[…]:`, `@md:` container queries, `dark:`, `group-*`, `peer-*`, `data-[…]:`, `aria-*:`, `has-[…]:`, `not-*`, `in-*`, `supports-[…]:`, `*:`, arbitrary variants `[&>svg]:`, `motion-safe:`, `print:`, `rtl:`.
56
-
57
- ### Colors
58
-
59
- Tailwind palette names map to the **nearest Omnia palette token** (`src/data/colors.json`, generated by `scripts/build-color-map.mjs` with `nearestOmnia()`): `bg-red-500` becomes `var(--color-red-50)`. Arbitrary colors (`bg-[#0041a7]`) are mapped to the nearest token too (`arbitraryColors: "keep"` keeps the literal). Opacity modifiers use `color-mix(in oklab, <token> 50%, transparent)`.
60
- Colors from `tailwind.config` are mapped to Omnia tokens as well (`--keep-brand-colors` / `keepBrandColors` keeps them); values that are `var(...)`/`hsl(var(...))` (shadcn style) stay as you wrote them.
61
-
62
- ### Scales
63
-
64
- Spacing, sizing, font sizes, radius, blur and containers use the familiar numbers (`p-4` = `1rem`). Shadows reuse Omnia's own shadow values. Breakpoints follow OmniaCSS (`sm` 36rem, `md` 50rem, `lg` 64rem; `xl` 80rem and `2xl` 96rem exist for compatibility). Use `breakpoints: "tailwind"` for 40/48/64/80/96rem.
65
-
66
- Names that exist in both systems (`p-4`, `flex`, `shadow-md` …) never collide: classes the compat layer resolves are removed from the Omnia core output.
67
-
68
- ## CLI
69
-
70
- ```text
71
- omniacss-migrate scan <dir> coverage: % of class occurrences supported + the unsupported list
72
- omniacss-migrate setup <project> [--write] plan (dry run) or apply: package.json, vite/postcss config, CSS @theme + dark mode
73
- omniacss-migrate codemod <dir> [--write] rewrite to native OmniaCSS class names where the CSS is identical
74
- omniacss-migrate build [-c glob] [-o file] write the CSS once (no Vite or PostCSS)
75
- omniacss-migrate css "md:hover:bg-red-500/50" print the CSS for one class
76
- ```
77
-
78
- `omniacss migrate scan .` does the same through the main CLI (`npm i -D @birdycom/omniacss-migrate`).
79
-
80
- `setup` and `codemod` are dry runs unless you pass `--write`. Commit first: the files are changed in place.
81
-
82
- ## Codemod (optional)
83
-
84
- `codemod` rewrites `class`/`className`/`cn()`/`cva()` strings to **native** OmniaCSS names when an Omnia class has exactly the same declarations (for example `items-center` becomes `align-items-center`, `p-4` becomes `p-1`). Everything else is left alone and listed. After `--write` the file `omniacss-migrate.manifest.json` tells the compat layer which names are now native, so `p-1` (Omnia, `1rem`) is never confused with the old `p-1` (`0.25rem`). Run it over the whole project, not a single folder.
85
-
86
- ## From Bootstrap
87
-
88
- ```bash
89
- npx @birdycom/omniacss-migrate bootstrap scan . # report only
90
- npx @birdycom/omniacss-migrate bootstrap codemod . --write # apply (commit first)
91
- npx omniacss build -o css/omnia.css # OmniaCSS for exactly the classes you use
92
- ```
93
-
94
- Works on HTML, PHP, Blade, Twig, ERB, Vue and JSX templates; template code inside a class attribute (`<?php … ?>`, `{{ … }}`) is left untouched.
95
-
96
- - **Utilities** become the OmniaCSS class with the same declarations, looked up in the installed OmniaCSS build: `mt-3` (1rem) becomes `mt-1`, `d-md-none` becomes `md:d-none`, `justify-content-between` becomes `justify-between`. Theme colors (`text-primary`, `bg-dark`, `border-danger`) map to the nearest Omnia token.
97
- - **Components** become OmniaUI classes: `btn btn-primary` → `oc-btn`, `alert alert-danger` → `oc-alert oc-alert--danger`, `form-control` → `oc-input` (`oc-select` on a `<select>`), `card-body`/`panel-body` → `oc-card-content`, `table table-striped` → `oc-table oc-table--striped`.
98
- - **Grid** classes (`container`, `row`, `col-*`, `offset-*`, `g-*`, `row-cols-*`) stay, served by a generated `bootstrap-compat.css` with only the classes in use, at OmniaCSS breakpoints. Utilities without an OmniaCSS twin (`border` 1px, `z-1`, `mt-n1`) keep their exact CSS in the same file.
99
- - **JavaScript components** (modal, dropdown, collapse, carousel, navbar, tabs, offcanvas, toast) and icon fonts are reported with the native replacement (`<dialog>` + `commandfor`, popover, `<details>`, scroll snap).
100
- - The Bootstrap `<link>` is replaced by `omnia.css`, the OmniaUI CSS and `bootstrap-compat.css` in the same asset folder.
101
- - The report lists classes your JavaScript toggles (`classList.add('btn-primary')`) and Bootstrap 3 classes in a newer site, split into "still styled by your CSS" and "safe to delete".
102
- - `--write` records the classes it produced in `omniacss-migrate.bootstrap.json`, so running it again never reads the new `mt-1` (OmniaCSS, 1rem) as Bootstrap's `mt-1` (0.25rem).
103
-
104
- Options: `--bs 3|4|5` (default: detected from `package.json`, the `<link>`, a local `bootstrap.css` or the markup), `--breakpoints exact` (keep Bootstrap's pixel breakpoints as `min-[48rem]:`), `--compat <file>`, `--omnia-href`, `--omniaui-href`, `--compat-href`.
105
-
106
- ## Options (PostCSS / Vite)
107
-
108
- | Option | Default | Meaning |
109
- | --- | --- | --- |
110
- | `content` | detected (Laravel, Astro, Nuxt, Vite) | globs with class names; `@source` is honoured too |
111
- | `core` | `true` | `true` Omnia core on demand, `"tokens"` only the color tokens and base, `false` you load Omnia yourself |
112
- | `preflight` | `true` | include the base reset |
113
- | `layers` | `true` | cascade layers |
114
- | `tailwind` | detected | `3` or `4` naming (`shadow-sm`, `rounded-sm`, `ring`, `blur-sm` differ) |
115
- | `darkMode` | detected | `"class"` (`.dark`) or `"media"` |
116
- | `breakpoints` | `"omnia"` | or `"tailwind"` |
117
- | `arbitraryColors` | `"nearest"` | or `"keep"` |
118
- | `safelist` | `[]` | extra classes |
119
-
120
- ## Known gaps
121
-
122
- - Plugin classes other than `tailwindcss-animate` (typography `prose`, forms, Iconify `icon-[…]`, container-queries plugin utilities) are not generated.
123
- - `theme.extend.keyframes`/`animation` from `tailwind.config` are not carried over.
124
- - `bg-opacity-*`/`text-opacity-*` (Tailwind 2 style) and `mask-*` utilities are not generated.
125
- - Classes assembled from fragments at runtime (`"bg-" + color + "-500"`) cannot be found by any scanner: add them to `safelist`.
126
- - Breakpoints, shadows and nearest-palette colors differ slightly from Tailwind by design: check the result visually.
127
- - The first build parses the full Omnia CSS (a few seconds); later builds are cached. `core: "tokens"` is instant.
128
-
129
- Node.js 22+. MIT
1
+ # @birdycom/omniacss-migrate
2
+
3
+ Switch a **Laravel, Vue or React** project from Tailwind CSS to OmniaCSS **and keep your class names**.
4
+ `flex items-center gap-4 p-4 md:p-8 bg-white dark:bg-gray-900 hover:bg-red-500/50 w-[37px]` keeps working: the classes are resolved on demand and emitted as CSS that only uses OmniaCSS tokens (Omnia palette in OKLCH, `rem` scales, Omnia shadows and breakpoints).
5
+
6
+ Coming from **Bootstrap 3, 4 or 5**? See [From Bootstrap](#from-bootstrap).
7
+
8
+ > This is the only package that names Tailwind and Bootstrap, because it is a migration tool.
9
+
10
+ ## Laravel in 3 steps
11
+
12
+ ```bash
13
+ # 1. see what changes (dry run, nothing is written) and how much of your markup is covered
14
+ npx @birdycom/omniacss-migrate scan .
15
+ npx @birdycom/omniacss-migrate setup .
16
+
17
+ # 2. apply the switch: removes the Tailwind packages from package.json, swaps the Vite/PostCSS plugin, carries your theme into CSS
18
+ npx @birdycom/omniacss-migrate setup . --write
19
+ npm uninstall tailwindcss @tailwindcss/vite @tailwindcss/postcss && npm install -D @birdycom/omniacss-migrate
20
+
21
+ # 3. build as usual
22
+ npm run dev
23
+ ```
24
+
25
+ Your Blade, Vue and React files stay exactly as they are. By hand it is two edits:
26
+
27
+ ```js
28
+ // vite.config.js
29
+ import omniaMigrate from "@birdycom/omniacss-migrate/vite"; // was: import tailwindcss from "@tailwindcss/vite"
30
+ export default defineConfig({ plugins: [laravel({ input: ["resources/css/app.css", "resources/js/app.js"] }), omniaMigrate()] });
31
+ ```
32
+
33
+ ```css
34
+ /* resources/css/app.css: unchanged. Both forms are understood: */
35
+ @import "tailwindcss";
36
+ /* or */
37
+ @tailwind base; @tailwind components; @tailwind utilities;
38
+ ```
39
+
40
+ Not using Vite? Use the PostCSS plugin instead:
41
+
42
+ ```js
43
+ // postcss.config.js
44
+ import omniaMigrate from "@birdycom/omniacss-migrate/postcss";
45
+ export default { plugins: [omniaMigrate({ content: ["resources/views/**/*.blade.php", "resources/js/**/*.{vue,tsx,jsx,js}"] })] };
46
+ ```
47
+
48
+ ## What the plugin does
49
+
50
+ - Replaces `@import "tailwindcss"` / `@tailwind base|components|utilities` with Omnia core (tokens + the Omnia classes you use), a small base reset and the compat CSS for the classes it finds in your content.
51
+ - Expands `@apply` (with variants, `!important`, and your own classes), `theme(colors.red.500)`, `--spacing(4)`, `@theme`, `@custom-variant`, `@variant`, `@source`, `@source inline("…")`; ignores `@plugin` and `@config`.
52
+ - Reads `tailwind.config.{js,cjs,mjs}` (`darkMode`, `theme.colors`/`extend.colors`, `fontFamily`, `borderRadius`, `spacing`, `boxShadow`, `screens`, `container`, `prefix`, `important`) and your `@theme` blocks.
53
+ - Output is wrapped in cascade layers `omnia, theme, base, components, utilities`.
54
+
55
+ Class coverage: layout, flex/grid, spacing, sizing, typography, colors (text, bg, border, ring, outline, fill, stroke, divide, accent, caret, decoration, gradients `from-`/`via-`/`to-`), borders, radius, shadow, ring, opacity, filters and backdrop filters, transitions, animations, transforms, display, position, z-index, overflow, cursor, scroll snap, `tailwindcss-animate` classes, arbitrary values (`w-[37px]`, `bg-(--brand)`, `[mask-type:luminance]`), opacity modifiers (`bg-red-500/50`), negatives (`-mt-2`), `!important`, and variants `hover: focus: active: disabled: first: odd: before: after: placeholder: file: marker: selection:`, `sm: md: lg: xl: 2xl: max-md: min-[…]:`, `@md:` container queries, `dark:`, `group-*`, `peer-*`, `data-[…]:`, `aria-*:`, `has-[…]:`, `not-*`, `in-*`, `supports-[…]:`, `*:`, arbitrary variants `[&>svg]:`, `motion-safe:`, `print:`, `rtl:`.
56
+
57
+ ### Colors
58
+
59
+ Tailwind palette names map to the **nearest Omnia palette token** (`src/data/colors.json`, generated by `scripts/build-color-map.mjs` with `nearestOmnia()`): `bg-red-500` becomes `var(--color-red-50)`. Arbitrary colors (`bg-[#0041a7]`) are mapped to the nearest token too (`arbitraryColors: "keep"` keeps the literal). Opacity modifiers use `color-mix(in oklab, <token> 50%, transparent)`.
60
+ Colors from `tailwind.config` are mapped to Omnia tokens as well (`--keep-brand-colors` / `keepBrandColors` keeps them); values that are `var(...)`/`hsl(var(...))` (shadcn style) stay as you wrote them.
61
+
62
+ ### Scales
63
+
64
+ Spacing, sizing, font sizes, radius, blur and containers use the familiar numbers (`p-4` = `1rem`). Shadows reuse Omnia's own shadow values. Breakpoints follow OmniaCSS (`sm` 36rem, `md` 50rem, `lg` 64rem; `xl` 80rem and `2xl` 96rem exist for compatibility). Use `breakpoints: "tailwind"` for 40/48/64/80/96rem.
65
+
66
+ Names that exist in both systems (`p-4`, `flex`, `shadow-md` …) never collide: classes the compat layer resolves are removed from the Omnia core output.
67
+
68
+ ## CLI
69
+
70
+ ```text
71
+ omniacss-migrate scan <dir> coverage: % of class occurrences supported + the unsupported list
72
+ omniacss-migrate setup <project> [--write] plan (dry run) or apply: package.json, vite/postcss config, CSS @theme + dark mode
73
+ omniacss-migrate codemod <dir> [--write] rewrite to native OmniaCSS class names where the CSS is identical
74
+ omniacss-migrate build [-c glob] [-o file] write the CSS once (no Vite or PostCSS)
75
+ omniacss-migrate css "md:hover:bg-red-500/50" print the CSS for one class
76
+ ```
77
+
78
+ `omniacss migrate scan .` does the same through the main CLI (`npm i -D @birdycom/omniacss-migrate`).
79
+
80
+ `setup` and `codemod` are dry runs unless you pass `--write`. Commit first: the files are changed in place.
81
+
82
+ ## Codemod (optional)
83
+
84
+ `codemod` rewrites `class`/`className`/`cn()`/`cva()` strings to **native** OmniaCSS names when an Omnia class has exactly the same declarations (for example `items-center` becomes `align-items-center`, `p-4` becomes `p-1`). Everything else is left alone and listed. After `--write` the file `omniacss-migrate.manifest.json` tells the compat layer which names are now native, so `p-1` (Omnia, `1rem`) is never confused with the old `p-1` (`0.25rem`). Run it over the whole project, not a single folder.
85
+
86
+ ## From Bootstrap
87
+
88
+ ```bash
89
+ npx @birdycom/omniacss-migrate bootstrap scan . # report only
90
+ npx @birdycom/omniacss-migrate bootstrap codemod . --write # apply (commit first)
91
+ npx omniacss build -o css/omnia.css # OmniaCSS for exactly the classes you use
92
+ ```
93
+
94
+ Works on HTML, PHP, Blade, Twig, ERB, Vue and JSX templates; template code inside a class attribute (`<?php … ?>`, `{{ … }}`) is left untouched.
95
+
96
+ - **Utilities** become the OmniaCSS class with the same declarations, looked up in the installed OmniaCSS build: `mt-3` (1rem) becomes `mt-1`, `d-md-none` becomes `md:d-none`, `justify-content-between` becomes `justify-between`. Theme colors (`text-primary`, `bg-dark`, `border-danger`) map to the nearest Omnia token.
97
+ - **Components** become OmniaUI classes: `btn btn-primary` → `oc-btn`, `alert alert-danger` → `oc-alert oc-alert--danger`, `form-control` → `oc-input` (`oc-select` on a `<select>`), `card-body`/`panel-body` → `oc-card-content`, `table table-striped` → `oc-table oc-table--striped`.
98
+ - **Grid** classes (`container`, `row`, `col-*`, `offset-*`, `g-*`, `row-cols-*`) stay, served by a generated `bootstrap-compat.css` with only the classes in use, at OmniaCSS breakpoints. Utilities without an OmniaCSS twin (`border` 1px, `z-1`, `mt-n1`) keep their exact CSS in the same file.
99
+ - **JavaScript components** (modal, dropdown, collapse, carousel, navbar, tabs, offcanvas, toast) and icon fonts are reported with the native replacement (`<dialog>` + `commandfor`, popover, `<details>`, scroll snap).
100
+ - The Bootstrap `<link>` is replaced by `omnia.css`, the OmniaUI CSS and `bootstrap-compat.css` in the same asset folder.
101
+ - The report lists classes your JavaScript toggles (`classList.add('btn-primary')`) and Bootstrap 3 classes in a newer site, split into "still styled by your CSS" and "safe to delete".
102
+ - `--write` records the classes it produced in `omniacss-migrate.bootstrap.json`, so running it again never reads the new `mt-1` (OmniaCSS, 1rem) as Bootstrap's `mt-1` (0.25rem).
103
+
104
+ Options: `--bs 3|4|5` (default: detected from `package.json`, the `<link>`, a local `bootstrap.css` or the markup), `--breakpoints exact` (keep Bootstrap's pixel breakpoints as `min-[48rem]:`), `--compat <file>`, `--omnia-href`, `--omniaui-href`, `--compat-href`.
105
+
106
+ ## Options (PostCSS / Vite)
107
+
108
+ | Option | Default | Meaning |
109
+ | --- | --- | --- |
110
+ | `content` | detected (Laravel, Astro, Nuxt, Vite) | globs with class names; `@source` is honoured too |
111
+ | `core` | `true` | `true` Omnia core on demand, `"tokens"` only the color tokens and base, `false` you load Omnia yourself |
112
+ | `preflight` | `true` | include the base reset |
113
+ | `layers` | `true` | cascade layers |
114
+ | `tailwind` | detected | `3` or `4` naming (`shadow-sm`, `rounded-sm`, `ring`, `blur-sm` differ) |
115
+ | `darkMode` | detected | `"class"` (`.dark`) or `"media"` |
116
+ | `breakpoints` | `"omnia"` | or `"tailwind"` |
117
+ | `arbitraryColors` | `"nearest"` | or `"keep"` |
118
+ | `safelist` | `[]` | extra classes |
119
+
120
+ ## Known gaps
121
+
122
+ - Plugin classes other than `tailwindcss-animate` (typography `prose`, forms, Iconify `icon-[…]`, container-queries plugin utilities) are not generated.
123
+ - `theme.extend.keyframes`/`animation` from `tailwind.config` are not carried over.
124
+ - `bg-opacity-*`/`text-opacity-*` (Tailwind 2 style) and `mask-*` utilities are not generated.
125
+ - Classes assembled from fragments at runtime (`"bg-" + color + "-500"`) cannot be found by any scanner: add them to `safelist`.
126
+ - Breakpoints, shadows and nearest-palette colors differ slightly from Tailwind by design: check the result visually.
127
+ - The first build parses the full Omnia CSS (a few seconds); later builds are cached. `core: "tokens"` is instant.
128
+
129
+ Node.js 22+. MIT
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- // File: packages/migrate/bin/omniacss-migrate.mjs
3
- // Author: Serge Cools | Framework: OmniaCSS
4
- import { run } from "../src/cli.mjs";
5
-
6
- run().catch((err) => {
7
- console.error(err.message || err);
8
- process.exitCode = 1;
9
- });
2
+ // File: packages/migrate/bin/omniacss-migrate.mjs
3
+ // Author: Serge Cools | Framework: OmniaCSS
4
+ import { run } from "../src/cli.mjs";
5
+
6
+ run().catch((err) => {
7
+ console.error(err.message || err);
8
+ process.exitCode = 1;
9
+ });
package/package.json CHANGED
@@ -1,61 +1,61 @@
1
- {
2
- "name": "@birdycom/omniacss-migrate",
3
- "version": "0.11.0",
4
- "description": "Switch a Laravel / Vue / React project from Tailwind CSS to OmniaCSS and keep your class names (PostCSS + Vite plugin, scan, setup, codemod), or convert a Bootstrap 3/4/5 site to OmniaCSS + OmniaUI.",
5
- "type": "module",
6
- "license": "MIT",
7
- "author": "Serge Cools (Birdycom)",
8
- "homepage": "https://omniacss.eu",
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/Birdycom/omniacss.git",
12
- "directory": "packages/migrate"
13
- },
14
- "bugs": {
15
- "url": "https://github.com/Birdycom/omniacss/issues"
16
- },
17
- "keywords": [
18
- "css",
19
- "migration",
20
- "tailwind",
21
- "bootstrap",
22
- "laravel",
23
- "vite",
24
- "postcss",
25
- "codemod",
26
- "omniacss"
27
- ],
28
- "engines": {
29
- "node": ">=22"
30
- },
31
- "bin": {
32
- "omniacss-migrate": "./bin/omniacss-migrate.mjs"
33
- },
34
- "exports": {
35
- ".": "./src/index.mjs",
36
- "./postcss": "./src/postcss.mjs",
37
- "./vite": "./src/vite.mjs",
38
- "./cli": "./src/cli.mjs",
39
- "./colors.json": "./src/data/colors.json",
40
- "./package.json": "./package.json"
41
- },
42
- "files": [
43
- "bin",
44
- "src",
45
- "scripts",
46
- "README.md",
47
- "LICENSE"
48
- ],
49
- "scripts": {
50
- "test": "node --test \"test/*.test.mjs\"",
51
- "build:colors": "node scripts/build-color-map.mjs"
52
- },
53
- "dependencies": {
54
- "@birdycom/omniacss": "^0.11.0",
55
- "postcss": "^8.5.3"
56
- },
57
- "publishConfig": {
58
- "access": "public"
59
- },
60
- "sideEffects": false
61
- }
1
+ {
2
+ "name": "@birdycom/omniacss-migrate",
3
+ "version": "0.11.2",
4
+ "description": "Switch a Laravel / Vue / React project from Tailwind CSS to OmniaCSS and keep your class names (PostCSS + Vite plugin, scan, setup, codemod), or convert a Bootstrap 3/4/5 site to OmniaCSS + OmniaUI.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Serge Cools (Birdycom)",
8
+ "homepage": "https://omniacss.eu",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/Birdycom/OmniaCSS.git",
12
+ "directory": "packages/migrate"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/Birdycom/OmniaCSS/issues"
16
+ },
17
+ "keywords": [
18
+ "css",
19
+ "migration",
20
+ "tailwind",
21
+ "bootstrap",
22
+ "laravel",
23
+ "vite",
24
+ "postcss",
25
+ "codemod",
26
+ "omniacss"
27
+ ],
28
+ "engines": {
29
+ "node": ">=22"
30
+ },
31
+ "bin": {
32
+ "omniacss-migrate": "./bin/omniacss-migrate.mjs"
33
+ },
34
+ "exports": {
35
+ ".": "./src/index.mjs",
36
+ "./postcss": "./src/postcss.mjs",
37
+ "./vite": "./src/vite.mjs",
38
+ "./cli": "./src/cli.mjs",
39
+ "./colors.json": "./src/data/colors.json",
40
+ "./package.json": "./package.json"
41
+ },
42
+ "files": [
43
+ "bin",
44
+ "src",
45
+ "scripts",
46
+ "README.md",
47
+ "LICENSE"
48
+ ],
49
+ "scripts": {
50
+ "test": "node --test \"test/*.test.mjs\"",
51
+ "build:colors": "node scripts/build-color-map.mjs"
52
+ },
53
+ "dependencies": {
54
+ "@birdycom/omniacss": "^0.11.2",
55
+ "postcss": "^8.5.3"
56
+ },
57
+ "publishConfig": {
58
+ "access": "public"
59
+ },
60
+ "sideEffects": false
61
+ }
@@ -1,31 +1,31 @@
1
- // File: packages/migrate/scripts/build-color-map.mjs
2
- // Build-time: maps every Tailwind default palette color to the nearest Omnia token (OKLab distance)
3
- // and writes src/data/colors.json. Run: node packages/migrate/scripts/build-color-map.mjs
4
- // Author: Serge Cools | Framework: OmniaCSS
5
-
6
- import fs from "node:fs";
7
- import path from "node:path";
8
- import { fileURLToPath } from "node:url";
9
- import { nearestOmnia } from "../../../scripts/lib/omnia-color.mjs";
10
-
11
- const here = path.dirname(fileURLToPath(import.meta.url));
12
- const root = path.resolve(here, "../../..");
13
- const { colors } = JSON.parse(fs.readFileSync(path.join(here, "tailwind-palette.json"), "utf8"));
14
-
15
- /** oklch(L% C H) -> #rrggbb (gamut clipped). */
16
- function oklchToHex(str) {
17
- const [, L, C, H] = str.match(/oklch\(([\d.]+)% ([\d.]+) ([\d.]+)\)/).map(Number);
18
- const l = L / 100, a = C * Math.cos((H * Math.PI) / 180), b = C * Math.sin((H * Math.PI) / 180);
19
- const l_ = (l + 0.3963377774 * a + 0.2158037573 * b) ** 3;
20
- const m_ = (l - 0.1055613458 * a - 0.0638541728 * b) ** 3;
21
- const s_ = (l - 0.0894841775 * a - 1.291485548 * b) ** 3;
22
- const lin = [4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_, -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_, -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_];
23
- const enc = (v) => { v = Math.min(1, Math.max(0, v)); return Math.round((v <= 0.0031308 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055) * 255); };
24
- return "#" + lin.map((v) => enc(v).toString(16).padStart(2, "0")).join("");
25
- }
26
-
27
- const map = { black: "--color-black-100", white: "--color-white-100" };
28
- for (const [name, value] of Object.entries(colors)) map[name] = nearestOmnia(oklchToHex(value), root).token;
29
- const sorted = Object.fromEntries(Object.entries(map).sort(([a], [b]) => a.localeCompare(b, "en", { numeric: true })));
30
- fs.writeFileSync(path.join(here, "../src/data/colors.json"), JSON.stringify(sorted, null, 1) + "\n");
31
- console.log(`colors.json: ${Object.keys(sorted).length} entries`);
1
+ // File: packages/migrate/scripts/build-color-map.mjs
2
+ // Build-time: maps every Tailwind default palette color to the nearest Omnia token (OKLab distance)
3
+ // and writes src/data/colors.json. Run: node packages/migrate/scripts/build-color-map.mjs
4
+ // Author: Serge Cools | Framework: OmniaCSS
5
+
6
+ import fs from "node:fs";
7
+ import path from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ import { nearestOmnia } from "../../../scripts/lib/omnia-color.mjs";
10
+
11
+ const here = path.dirname(fileURLToPath(import.meta.url));
12
+ const root = path.resolve(here, "../../..");
13
+ const { colors } = JSON.parse(fs.readFileSync(path.join(here, "tailwind-palette.json"), "utf8"));
14
+
15
+ /** oklch(L% C H) -> #rrggbb (gamut clipped). */
16
+ function oklchToHex(str) {
17
+ const [, L, C, H] = str.match(/oklch\(([\d.]+)% ([\d.]+) ([\d.]+)\)/).map(Number);
18
+ const l = L / 100, a = C * Math.cos((H * Math.PI) / 180), b = C * Math.sin((H * Math.PI) / 180);
19
+ const l_ = (l + 0.3963377774 * a + 0.2158037573 * b) ** 3;
20
+ const m_ = (l - 0.1055613458 * a - 0.0638541728 * b) ** 3;
21
+ const s_ = (l - 0.0894841775 * a - 1.291485548 * b) ** 3;
22
+ const lin = [4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_, -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_, -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_];
23
+ const enc = (v) => { v = Math.min(1, Math.max(0, v)); return Math.round((v <= 0.0031308 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055) * 255); };
24
+ return "#" + lin.map((v) => enc(v).toString(16).padStart(2, "0")).join("");
25
+ }
26
+
27
+ const map = { black: "--color-black-100", white: "--color-white-100" };
28
+ for (const [name, value] of Object.entries(colors)) map[name] = nearestOmnia(oklchToHex(value), root).token;
29
+ const sorted = Object.fromEntries(Object.entries(map).sort(([a], [b]) => a.localeCompare(b, "en", { numeric: true })));
30
+ fs.writeFileSync(path.join(here, "../src/data/colors.json"), JSON.stringify(sorted, null, 1) + "\n");
31
+ console.log(`colors.json: ${Object.keys(sorted).length} entries`);
@@ -1,13 +1,13 @@
1
- // File: packages/migrate/scripts/extract-palette.mjs
2
- // One-off helper: re-extract the default palette (oklch) from an installed tailwindcss theme.css into tailwind-palette.json.
3
- // Usage: node scripts/extract-palette.mjs <path/to/node_modules/tailwindcss/theme.css>
4
- import fs from "node:fs";
5
- import path from "node:path";
6
- import { fileURLToPath } from "node:url";
7
-
8
- const here = path.dirname(fileURLToPath(import.meta.url));
9
- const css = fs.readFileSync(process.argv[2], "utf8");
10
- const colors = {};
11
- for (const m of css.matchAll(/--color-([a-z]+-\d+):\s*oklch\(([\d.]+)%\s+([\d.]+)\s+(none|[\d.]+)\)/g)) colors[m[1]] = `oklch(${m[2]}% ${m[3]} ${m[4] === "none" ? 0 : m[4]})`;
12
- fs.writeFileSync(path.join(here, "tailwind-palette.json"), JSON.stringify({ _note: "Tailwind default palette (oklch), input for build-color-map.mjs", colors }, null, 1));
13
- console.log(Object.keys(colors).length, "colors");
1
+ // File: packages/migrate/scripts/extract-palette.mjs
2
+ // One-off helper: re-extract the default palette (oklch) from an installed tailwindcss theme.css into tailwind-palette.json.
3
+ // Usage: node scripts/extract-palette.mjs <path/to/node_modules/tailwindcss/theme.css>
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const here = path.dirname(fileURLToPath(import.meta.url));
9
+ const css = fs.readFileSync(process.argv[2], "utf8");
10
+ const colors = {};
11
+ for (const m of css.matchAll(/--color-([a-z]+-\d+):\s*oklch\(([\d.]+)%\s+([\d.]+)\s+(none|[\d.]+)\)/g)) colors[m[1]] = `oklch(${m[2]}% ${m[3]} ${m[4] === "none" ? 0 : m[4]})`;
12
+ fs.writeFileSync(path.join(here, "tailwind-palette.json"), JSON.stringify({ _note: "Tailwind default palette (oklch), input for build-color-map.mjs", colors }, null, 1));
13
+ console.log(Object.keys(colors).length, "colors");