@birdycom/omniacss-migrate 0.12.0 → 0.12.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/README.md CHANGED
@@ -31,9 +31,10 @@ export default defineConfig({ plugins: [laravel({ input: ["resources/css/app.css
31
31
  ```
32
32
 
33
33
  ```css
34
- /* resources/css/app.css: unchanged. Both forms are understood: */
34
+ /* resources/css/app.css: the entry, under our own name (setup --write renames @import "tailwindcss" to it): */
35
+ @import "@birdycom/omniacss-migrate";
36
+ /* the Tailwind forms keep working too: */
35
37
  @import "tailwindcss";
36
- /* or */
37
38
  @tailwind base; @tailwind components; @tailwind utilities;
38
39
  ```
39
40
 
@@ -47,7 +48,7 @@ export default { plugins: [omniaMigrate({ content: ["resources/views/**/*.blade.
47
48
 
48
49
  ## What the plugin does
49
50
 
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
+ - Replaces `@import "@birdycom/omniacss-migrate"` / `@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
52
  - 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
53
  - Reads `tailwind.config.{js,cjs,mjs}` (`darkMode`, `theme.colors`/`extend.colors`, `fontFamily`, `borderRadius`, `spacing`, `boxShadow`, `screens`, `container`, `prefix`, `important`) and your `@theme` blocks.
53
54
  - Output is wrapped in cascade layers `omnia, theme, base, components, utilities`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@birdycom/omniacss-migrate",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
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
5
  "type": "module",
6
6
  "license": "MIT",
@@ -32,7 +32,10 @@
32
32
  "omniacss-migrate": "./bin/omniacss-migrate.mjs"
33
33
  },
34
34
  "exports": {
35
- ".": "./src/index.mjs",
35
+ ".": {
36
+ "style": "./src/entry.css",
37
+ "default": "./src/index.mjs"
38
+ },
36
39
  "./postcss": "./src/postcss.mjs",
37
40
  "./vite": "./src/vite.mjs",
38
41
  "./cli": "./src/cli.mjs",
@@ -51,7 +54,7 @@
51
54
  "build:colors": "node scripts/build-color-map.mjs"
52
55
  },
53
56
  "dependencies": {
54
- "@birdycom/omniacss": "^0.12.0",
57
+ "@birdycom/omniacss": "^0.12.1",
55
58
  "postcss": "^8.5.3"
56
59
  },
57
60
  "publishConfig": {
package/src/entry.css ADDED
@@ -0,0 +1,8 @@
1
+ /* File: packages/migrate/src/entry.css
2
+ What `@import "@birdycom/omniacss-migrate";` resolves to when a bundler inlines the import itself (Vite with the
3
+ PostCSS plugin in postcss.config.js). The plugin replaces these directives with OmniaCSS core + compat CSS.
4
+ With the Vite plugin the import never gets this far: it is compiled before Vite looks at it.
5
+ Author: Serge Cools | Framework: OmniaCSS */
6
+ @tailwind base;
7
+ @tailwind components;
8
+ @tailwind utilities;
package/src/index.mjs CHANGED
@@ -8,5 +8,6 @@ export { runCodemod, formatCodemod } from "./codemod.mjs";
8
8
  export { planSetup, applySetup, formatPlan } from "./setup.mjs";
9
9
  export { loadProject, themeFromConfig } from "./project.mjs";
10
10
  export { COLOR_MAP } from "./values.mjs";
11
+ export { loadOmniaIndex, nativeFor } from "./native.mjs";
11
12
  export { default as postcss } from "./postcss.mjs";
12
13
  export { default as vite } from "./vite.mjs";
package/src/postcss.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // File: packages/migrate/src/postcss.mjs
2
2
  // PostCSS plugin "keep your classes": replaces the framework directives in your CSS
3
- // @import "tailwindcss"; / @tailwind base|components|utilities;
3
+ // @import "tailwindcss"; / @import "@birdycom/omniacss-migrate"; / @tailwind base|components|utilities;
4
4
  // with OmniaCSS core + compat CSS for the classes found in your content, and expands @apply, theme() and @theme.
5
5
  //
6
6
  // // postcss.config.js
@@ -21,7 +21,8 @@ import { buildCoreCss } from "./core.mjs";
21
21
  import { COLOR_MAP } from "./values.mjs";
22
22
  import { applyVariant } from "./variants.mjs";
23
23
 
24
- const TW_IMPORT = /^["']tailwindcss(?:\/(theme|preflight|utilities|base|components)(?:\.css)?)?["']/;
24
+ // `@import "tailwindcss"`, or the same entry under our own name, so a project can drop every Tailwind mention.
25
+ const TW_IMPORT = /^["'](?:tailwindcss|@birdycom\/omniacss-migrate)(?:\/(theme|preflight|utilities|base|components)(?:\.css)?)?["']/;
25
26
  const fileTokenCache = new Map();
26
27
 
27
28
  /** Default content globs when none are given. */
@@ -197,7 +198,8 @@ export default function omniaMigrate(options = {}) {
197
198
  pieces.core = options.core === false ? "" : await buildCoreCss({ candidates, compatCss, exclude, cwd, layer: layers ? "omnia" : false, mode: options.core === "tokens" ? "tokens" : true });
198
199
  pieces.utilities = wrap("utilities", compatCss);
199
200
  const all = [pieces.order, pieces.theme, pieces.preflight, pieces.core, pieces.utilities];
200
- const mk = (css) => postcss.parse(css, { from: undefined }).nodes;
201
+ // `from`: the stylesheet being built, so Vite resolves url() in the generated CSS against it (no "did not pass from" warning).
202
+ const mk = (css) => postcss.parse(css, { from: result.opts.from }).nodes;
201
203
  const place = (at, css) => { const nodes = css ? mk(css) : []; if (nodes.length) at.replaceWith(nodes); else at.remove(); };
202
204
 
203
205
  for (const at of twImports) {
@@ -293,7 +295,8 @@ function expandApply(at, ctx, classIndex, usedKeyframes, result) {
293
295
  else extras.push(rule);
294
296
  }
295
297
  }
296
- const nodes = inline.map(([prop, value, imp]) => postcss.decl({ prop, value, important: !!imp }));
298
+ // `source` of the @apply: Vite resolves url() in these declarations against the file they are written in.
299
+ const nodes = inline.map(([prop, value, imp]) => postcss.decl({ prop, value, important: !!imp, source: at.source }));
297
300
  if (nodes.length) at.replaceWith(nodes); else at.remove();
298
301
  if (!extras.length) return;
299
302
  const flat = parent.parent && parent.parent.type !== "rule";
@@ -302,7 +305,7 @@ function expandApply(at, ctx, classIndex, usedKeyframes, result) {
302
305
  const sels = flat ? x.selectors.flatMap((s) => parent.selectors.map((ps) => s.replace(/&/g, ps))) : x.selectors;
303
306
  let css = `${sels.join(",\n")} {\n${x.decls.map(([p, v]) => ` ${p}: ${v};`).join("\n")}\n}`;
304
307
  for (let i = x.media.length - 1; i >= 0; i--) css = `${x.media[i]} {\n${css}\n}`;
305
- const parsed = postcss.parse(css, { from: undefined }).nodes;
308
+ const parsed = postcss.parse(css, { from: at.source?.input.file ?? result.opts.from }).nodes;
306
309
  if (flat) { for (const n of parsed) { anchor.after(n); anchor = n; } } else parent.append(parsed);
307
310
  }
308
311
  }
package/src/project.mjs CHANGED
@@ -146,7 +146,7 @@ export async function loadProject(dir, overrides = {}) {
146
146
  for (const f of info.cssFiles) {
147
147
  const css = await fs.readFile(f, "utf8").catch(() => "");
148
148
  for (const [k, v] of parseThemeBlocks(css)) info.themeVars.set(k, v);
149
- if (/@import\s+["']tailwindcss/.test(css) || /@theme\b/.test(css)) info.tailwindVersion ||= 4;
149
+ if (/@import\s+["'](?:tailwindcss|@birdycom\/omniacss-migrate)/.test(css) || /@theme\b/.test(css)) info.tailwindVersion ||= 4;
150
150
  if (/@tailwind\s+(base|utilities|components)/.test(css)) info.tailwindVersion ||= 3;
151
151
  const cv = css.match(/@custom-variant\s+dark\s*\(([^;]*)\)\s*;/);
152
152
  if (cv) {
package/src/setup.mjs CHANGED
@@ -5,12 +5,14 @@
5
5
 
6
6
  import fs from "node:fs/promises";
7
7
  import path from "node:path";
8
+ import { createRequire } from "node:module";
8
9
  import { loadProject, loadTailwindConfig, themeFromConfig, findFiles } from "./project.mjs";
9
10
  import { createContext } from "./resolve.mjs";
10
11
 
11
12
  const TW_PKGS = ["tailwindcss", "@tailwindcss/vite", "@tailwindcss/postcss"];
12
13
  const TW_NAME = "(?:@tailwindcss\\/vite|@tailwindcss\\/postcss|tailwindcss)";
13
- const VERSION = "^0.4.0";
14
+ // The range written into the project: this package's own version, so it never goes stale.
15
+ const VERSION = `^${createRequire(import.meta.url)("../package.json").version}`;
14
16
 
15
17
  const read = (f) => fs.readFile(f, "utf8").catch(() => null);
16
18
 
@@ -147,10 +149,17 @@ export async function planSetup(dir, { keepBrandColors = false } = {}) {
147
149
  let entryDone = false;
148
150
  for (const f of cssFiles) {
149
151
  const before = await read(f);
150
- if (!/@import\s+["']tailwindcss|@tailwind\s+(base|utilities)/.test(before)) continue;
152
+ if (!/@import\s+["'](?:tailwindcss|@birdycom\/omniacss-migrate)|@tailwind\s+(base|utilities)/.test(before)) continue;
151
153
  detected.css.push(path.relative(dir, f));
152
- if (entryDone) continue;
154
+ // `@import "tailwindcss"` -> `@import "@birdycom/omniacss-migrate"` (same entry, no Tailwind name left).
155
+ // The v3 `@tailwind …` directives stay: they may sit mid-file, where an @import is not allowed.
156
+ const renamed = before.replace(/(@import\s+)(["'])tailwindcss((?:\/[\w.-]+)?)\2/g, "$1$2@birdycom/omniacss-migrate$3$2");
157
+ const isEntry = !entryDone;
153
158
  entryDone = true;
159
+ if (!isEntry) {
160
+ if (renamed !== before) changes.push({ file: f, before, after: renamed, note: 'rename @import "tailwindcss" to @import "@birdycom/omniacss-migrate"' });
161
+ continue;
162
+ }
154
163
  const add = [];
155
164
  if (loaded?.config) {
156
165
  const t = themeFromConfig(loaded.config, createContext({}), { keepColors: keepBrandColors });
@@ -165,15 +174,17 @@ export async function planSetup(dir, { keepBrandColors = false } = {}) {
165
174
  if ((dm === "class" || dm === "selector") && !/@custom-variant\s+dark/.test(before)) add.push("@custom-variant dark (&:where(.dark, .dark *));");
166
175
  }
167
176
  if (add.length) {
168
- const re = /^(@import\s+["']tailwindcss["'][^;\n]*;|@tailwind\s+utilities;)[ \t]*\r?\n/m;
169
- const m = before.match(re);
170
- const eol = before.includes("\r\n") ? "\r\n" : "\n";
171
- const after = m ? before.replace(re, `${m[0]}${eol}${add.join(eol)}${eol}`) : before + eol + add.join(eol) + eol;
172
- changes.push({ file: f, before, after, note: "carry tailwind.config theme into CSS (@theme) and dark mode variant" });
173
- } else notes.push(`${path.relative(dir, f)}: the directives (@import "tailwindcss" / @tailwind …) are handled by the plugin; no change needed.`);
177
+ const re = /^(@import\s+["']@birdycom\/omniacss-migrate["'][^;\n]*;|@tailwind\s+utilities;)[ \t]*\r?\n/m;
178
+ const m = renamed.match(re);
179
+ const eol = renamed.includes("\r\n") ? "\r\n" : "\n";
180
+ const after = m ? renamed.replace(re, `${m[0]}${eol}${add.join(eol)}${eol}`) : renamed + eol + add.join(eol) + eol;
181
+ changes.push({ file: f, before, after, note: `carry tailwind.config theme into CSS (@theme) and dark mode variant${renamed !== before ? '; rename @import "tailwindcss"' : ""}` });
182
+ } else if (renamed !== before) {
183
+ changes.push({ file: f, before, after: renamed, note: 'rename @import "tailwindcss" to @import "@birdycom/omniacss-migrate" (the plugin handles it)' });
184
+ } else notes.push(`${path.relative(dir, f)}: the directives (@import "@birdycom/omniacss-migrate" / @tailwind …) are handled by the plugin; no change needed.`);
174
185
  if (/@plugin\s+['"]@iconify/.test(before)) notes.push("`@plugin '@iconify/...'` is ignored by the plugin (icon-[...] classes are not generated).");
175
186
  }
176
- if (!detected.css.length) notes.push("No CSS file with Tailwind directives found. The plugin works on `@import \"tailwindcss\"` or `@tailwind base/components/utilities`.");
187
+ if (!detected.css.length) notes.push("No CSS file with Tailwind directives found. The plugin works on `@import \"@birdycom/omniacss-migrate\"`, `@import \"tailwindcss\"` or `@tailwind base/components/utilities`.");
177
188
  commands.push("npm uninstall " + (removed.join(" ") || "tailwindcss @tailwindcss/vite"));
178
189
  commands.push("npm install -D @birdycom/omniacss-migrate");
179
190
  return { changes, notes, commands, detected };
package/src/utilities.mjs CHANGED
@@ -262,6 +262,7 @@ const SIDE = { t: "top", r: "right", b: "bottom", l: "left", s: "inline-start",
262
262
  function boxHandler(prop) {
263
263
  // m, mx, my, mt … (margin / padding / scroll-margin / scroll-padding)
264
264
  return (u, root) => {
265
+ // The side after the root: "mt" -> "t", "scroll-mt" -> "t", "scroll-p" -> "".
265
266
  const key = root.slice(prefixLen(prop));
266
267
  const v = sp(u, u.value, { keywords: { auto: "auto" }, fractions: false });
267
268
  if (v == null) return null;
@@ -275,7 +276,7 @@ function boxHandler(prop) {
275
276
  return null;
276
277
  };
277
278
  }
278
- const prefixLen = (prop) => ({ margin: 1, padding: 1, "scroll-margin": 2, "scroll-padding": 2 })[prop];
279
+ const prefixLen = (prop) => ({ margin: 1, padding: 1, "scroll-margin": 8, "scroll-padding": 8 })[prop];
279
280
 
280
281
  function insetHandler(prop) {
281
282
  return (u) => {
package/src/vite.mjs CHANGED
@@ -60,7 +60,7 @@ export default function omniaMigrate(options = {}) {
60
60
  async transform(code, id) {
61
61
  const file = id.split("?")[0];
62
62
  if (!/\.(css|pcss|postcss)$/.test(file)) return null;
63
- if (!/@import\s+["']tailwindcss|@tailwind\s+\w+|@apply\s|@theme\b/.test(code)) return null;
63
+ if (!/@import\s+["'](?:tailwindcss|@birdycom\/omniacss-migrate)|@tailwind\s+\w+|@apply\s|@theme\b/.test(code)) return null;
64
64
  const result = await postcss([omniaMigratePostcss({ cwd: root, ...options })]).process(code, { from: file, map: false });
65
65
  for (const m of result.messages) if (m.type === "dependency" && m.file) this.addWatchFile(m.file);
66
66
  return { code: result.css, map: null };