@bhooai/nexus-postcss 0.1.3 → 0.1.5

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
@@ -29,14 +29,68 @@ export default createPreset({
29
29
  });
30
30
  ```
31
31
 
32
+ ### With Tailwind forms + typography plugins
33
+
34
+ ```js
35
+ import { createPreset } from '@bhooai/nexus-postcss';
36
+ import forms from '@tailwindcss/forms';
37
+ import typography from '@tailwindcss/typography';
38
+
39
+ export default createPreset({
40
+ tailwindPlugins: [forms, typography],
41
+ });
42
+ ```
43
+
44
+ ### Modern CSS nesting (spec-compliant)
45
+
46
+ ```js
47
+ import { createPreset } from '@bhooai/nexus-postcss';
48
+
49
+ export default createPreset({
50
+ nestingMode: 'modern', // use postcss-nesting (real CSS Nesting spec) instead of postcss-nested
51
+ });
52
+ ```
53
+
54
+ ### Lightning CSS engine (experimental, ~100x faster)
55
+
56
+ ```js
57
+ import { createPreset } from '@bhooai/nexus-postcss';
58
+
59
+ export default createPreset({
60
+ engine: 'lightningcss', // replaces preset-env + autoprefixer + cssnano with one lightningcss pass
61
+ });
62
+ ```
63
+
64
+ Note: `lightningcss` targets browsers directly (not CSS stages), so `postcss-preset-env` stage polyfills are not applied. Nesting, prefixing, and minification are all handled by lightningcss.
65
+
66
+ ### RTL/LTR direction-aware CSS
67
+
68
+ ```js
69
+ import { createPreset } from '@bhooai/nexus-postcss';
70
+
71
+ export default createPreset({
72
+ logical: true, // polyfills margin-inline, padding-block, inset-inline, etc.
73
+ });
74
+ ```
75
+
32
76
  ## Plugin chain (in order)
33
77
 
78
+ **Default (`engine: 'postcss'`):**
79
+
80
+ 1. **postcss-import** — resolve `@import` statements
81
+ 2. **postcss-nested** (or **postcss-nesting** when `nestingMode: 'modern'`) — CSS nesting
82
+ 3. **tailwindcss** — base/components/utilities + content scanning
83
+ 4. **postcss-logical** (when `logical: true`) — direction-aware properties
84
+ 5. **postcss-preset-env** (stage 2) — future CSS features today
85
+ 6. **autoprefixer** — vendor prefixes
86
+ 7. **cssnano** — minification (only when `NODE_ENV=production` or `minify: true`)
87
+
88
+ **Lightning CSS (`engine: 'lightningcss'`):**
89
+
34
90
  1. **postcss-import** — resolve `@import` statements
35
- 2. **tailwindcss/nesting** (postcss-nested) — native CSS nesting before `@apply`
91
+ 2. **postcss-nested** (or **postcss-nesting** when `nestingMode: 'modern'`) — CSS nesting
36
92
  3. **tailwindcss** — base/components/utilities + content scanning
37
- 4. **postcss-preset-env** (stage 2) future CSS features today
38
- 5. **autoprefixer** — vendor prefixes
39
- 6. **cssnano** — minification (only when `NODE_ENV=production` or `minify: true`)
93
+ 4. **postcss-lightningcss** prefixing + minification + future CSS (replaces preset-env + autoprefixer + cssnano)
40
94
 
41
95
  ## Options
42
96
 
@@ -45,18 +99,44 @@ export default createPreset({
45
99
  | `content` | `string[]` | `['./index.html', './src/**/*.{ts,tsx}']` | Tailwind content scan paths |
46
100
  | `extraContent` | `string[]` | `[]` | Additional content paths to merge |
47
101
  | `theme` | `object` | `{}` | Tailwind theme extensions |
48
- | `tailwindPlugins` | `array` | `[]` | Tailwind plugins |
102
+ | `tailwindPlugins` | `array` | `[]` | Tailwind plugins (e.g. `@tailwindcss/forms`, `@tailwindcss/typography`) |
49
103
  | `import` | `boolean` | `true` | Enable postcss-import |
50
- | `nested` | `boolean` | `true` | Enable postcss-nested |
51
- | `presetEnv` | `boolean \| 'stage2' \| 'stage3' \| 'stage4'` | `true` (stage2) | Enable postcss-preset-env |
52
- | `autoprefixer` | `boolean \| object` | `true` | Enable autoprefixer (or pass options) |
53
- | `minify` | `boolean` | `NODE_ENV === 'production'` | Enable cssnano |
104
+ | `nested` | `boolean` | `true` | Enable CSS nesting |
105
+ | `nestingMode` | `'classic' \| 'modern'` | `'classic'` | `'modern'` uses postcss-nesting (real CSS Nesting spec); `'classic'` uses postcss-nested |
106
+ | `logical` | `boolean \| object` | `false` | Enable postcss-logical for RTL/LTR direction-aware CSS |
107
+ | `presetEnv` | `boolean \| 'stage2' \| 'stage3' \| 'stage4'` | `true` (stage2) | Enable postcss-preset-env (ignored when `engine: 'lightningcss'`) |
108
+ | `autoprefixer` | `boolean \| object` | `true` | Enable autoprefixer (ignored when `engine: 'lightningcss'`) |
109
+ | `minify` | `boolean` | `NODE_ENV === 'production'` | Enable minification (cssnano or lightningcss) |
110
+ | `sourcemap` | `boolean` | `undefined` | Explicit source map control: `true` = inline + annotation, `false` = disabled, `undefined` = let PostCSS/Vite decide |
111
+ | `engine` | `'postcss' \| 'lightningcss'` | `'postcss'` | CSS processing backend. `'lightningcss'` is experimental and ~100x faster |
54
112
  | `plugins` | `Array<[string, any] \| string>` | `[]` | Custom PostCSS plugins to append |
55
113
 
114
+ ## Theme tokens
115
+
116
+ Two token stylesheets ship with the preset:
117
+
118
+ ### Dark-only (default)
119
+
120
+ ```css
121
+ @import '@bhooai/nexus-postcss/theme.css';
122
+ ```
123
+
124
+ 22 CSS custom properties (`--nexus-bg`, `--nexus-ink`, `--nexus-surface`, `--nexus-accent`, etc.) on `:root`, plus 15 `--admin-*` aliases for backwards compatibility.
125
+
126
+ ### Light/dark dual theme
127
+
128
+ ```css
129
+ @import '@bhooai/nexus-postcss/theme-light-dark.css';
130
+ ```
131
+
132
+ Uses the CSS `light-dark()` function so every token adapts to the user's `prefers-color-scheme`. Sets `color-scheme: light dark` on `:root`. `postcss-preset-env` (stage 2, in the default chain) polyfills `light-dark()` for browsers without native support.
133
+
56
134
  ## Tailwind config
57
135
 
58
136
  `tailwind.config.js` is kept in each app — the preset only injects `content` paths and the plugin chain. Theme extensions and Tailwind plugins stay in your `tailwind.config.js`.
59
137
 
138
+ Note: Tailwind v3.4+ enables container queries by default — the `@container` utility is available out of the box.
139
+
60
140
  ## License
61
141
 
62
142
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bhooai/nexus-postcss",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Opinionated PostCSS preset for BhooAI Nexus apps — Tailwind, nesting, future CSS, autoprefixing, and minification in one curated pipeline.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -8,6 +8,7 @@
8
8
  "exports": {
9
9
  ".": "./src/index.js",
10
10
  "./theme.css": "./src/theme.css",
11
+ "./theme-light-dark.css": "./src/theme-light-dark.css",
11
12
  "./package.json": "./package.json"
12
13
  },
13
14
  "files": [
@@ -18,11 +19,17 @@
18
19
  "test": "vitest run"
19
20
  },
20
21
  "dependencies": {
22
+ "@tailwindcss/forms": "^0.5.9",
23
+ "@tailwindcss/typography": "^0.5.15",
21
24
  "autoprefixer": "^10.4.20",
22
25
  "cssnano": "^7.0.6",
26
+ "lightningcss": "^1.26.0",
23
27
  "postcss": "^8.4.47",
24
28
  "postcss-import": "^16.1.0",
29
+ "postcss-lightningcss": "^1.0.1",
30
+ "postcss-logical": "^8.0.0",
25
31
  "postcss-nested": "^6.2.0",
32
+ "postcss-nesting": "^12.1.5",
26
33
  "postcss-preset-env": "^9.6.0",
27
34
  "tailwindcss": "^3.4.13"
28
35
  },
package/src/plugins.js CHANGED
@@ -1,9 +1,12 @@
1
1
  import postcssImport from 'postcss-import';
2
2
  import postcssNested from 'postcss-nested';
3
+ import postcssNesting from 'postcss-nesting';
4
+ import postcssLogical from 'postcss-logical';
3
5
  import tailwindcss from 'tailwindcss';
4
6
  import postcssPresetEnv from 'postcss-preset-env';
5
7
  import autoprefixer from 'autoprefixer';
6
8
  import cssnano from 'cssnano';
9
+ import postcssLightningcss from 'postcss-lightningcss';
7
10
 
8
11
  export function createPreset(options = {}) {
9
12
  const DEFAULT_CONTENT = ['./index.html', './src/**/*.{ts,tsx}'];
@@ -17,6 +20,8 @@ export function createPreset(options = {}) {
17
20
  const enableImport = options.import ?? true;
18
21
  const enableNested = options.nested ?? true;
19
22
  const enableAutoprefixer = options.autoprefixer !== false;
23
+ const useModernNesting = options.nestingMode === 'modern';
24
+ const useLightningcss = options.engine === 'lightningcss';
20
25
 
21
26
  const content = [...(options.content ?? DEFAULT_CONTENT), ...(options.extraContent ?? [])];
22
27
  const tailwindOpts = {
@@ -27,14 +32,28 @@ export function createPreset(options = {}) {
27
32
 
28
33
  const plugins = [];
29
34
  if (enableImport) plugins.push(postcssImport({}));
30
- if (enableNested) plugins.push(postcssNested({}));
35
+ if (enableNested) {
36
+ plugins.push(useModernNesting ? postcssNesting() : postcssNested());
37
+ }
31
38
  plugins.push(tailwindcss(tailwindOpts));
32
- if (enablePresetEnv) plugins.push(postcssPresetEnv({ stage: presetEnvStage }));
33
- if (enableAutoprefixer) {
34
- const apOpts = typeof options.autoprefixer === 'object' ? options.autoprefixer : {};
35
- plugins.push(autoprefixer(apOpts));
39
+
40
+ if (useLightningcss) {
41
+ // lightningcss handles prefixing + minification + some future CSS in one pass.
42
+ // It replaces postcss-preset-env + autoprefixer + cssnano.
43
+ plugins.push(postcssLightningcss({ minify: shouldMinify }));
44
+ } else {
45
+ if (options.logical) {
46
+ const logicalOpts = typeof options.logical === 'object' ? options.logical : {};
47
+ plugins.push(postcssLogical(logicalOpts));
48
+ }
49
+ if (enablePresetEnv) plugins.push(postcssPresetEnv({ stage: presetEnvStage }));
50
+ if (enableAutoprefixer) {
51
+ const apOpts = typeof options.autoprefixer === 'object' ? options.autoprefixer : {};
52
+ plugins.push(autoprefixer(apOpts));
53
+ }
54
+ if (shouldMinify) plugins.push(cssnano({ preset: 'default' }));
36
55
  }
37
- if (shouldMinify) plugins.push(cssnano({ preset: 'default' }));
56
+
38
57
  if (options.plugins) {
39
58
  for (const p of options.plugins) {
40
59
  if (typeof p === 'string') plugins.push(p);
@@ -42,5 +61,11 @@ export function createPreset(options = {}) {
42
61
  }
43
62
  }
44
63
 
45
- return { plugins };
64
+ const map = options.sourcemap === true
65
+ ? { inline: true, annotation: true }
66
+ : options.sourcemap === false
67
+ ? false
68
+ : undefined;
69
+
70
+ return { plugins, ...(map !== undefined && { map }) };
46
71
  }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @bhooai/nexus-postcss — theme-light-dark.css
3
+ *
4
+ * Dual-theme variant of theme.css using the CSS `light-dark()` function.
5
+ * Opt in with:
6
+ * @import '@bhooai/nexus-postcss/theme-light-dark.css';
7
+ *
8
+ * Requires `color-scheme: light dark` on :root (set below) so the browser
9
+ * knows to honor both palettes. `postcss-preset-env` (stage 2, already in the
10
+ * preset) polyfills `light-dark()` for browsers without native support.
11
+ *
12
+ * Override any token in your own :root block to retheme either side.
13
+ */
14
+
15
+ :root {
16
+ color-scheme: light dark;
17
+
18
+ /* ---- base surface ---- */
19
+ --nexus-bg: light-dark(#ffffff, #050817);
20
+ --nexus-bg-alt: light-dark(#f4f6fb, #0b0d1a);
21
+ --nexus-ink: light-dark(#0b0d1a, #eef6ff);
22
+ --nexus-muted: light-dark(#475569, #8496ad);
23
+ --nexus-surface: light-dark(rgba(241, 245, 249, 0.82), rgba(10, 24, 45, 0.78));
24
+ --nexus-surface-strong: light-dark(rgba(226, 232, 240, 0.78), rgba(8, 25, 48, 0.68));
25
+ --nexus-border: light-dark(rgba(15, 23, 42, 0.16), rgba(125, 174, 235, 0.2));
26
+ --nexus-border-bright: light-dark(rgba(15, 23, 42, 0.22), rgba(112, 168, 228, 0.17));
27
+
28
+ /* ---- accent palette ---- */
29
+ --nexus-accent: light-dark(#0891b2, #67e8f9);
30
+ --nexus-accent-soft: light-dark(rgba(8, 145, 178, 0.08), rgba(103, 232, 249, 0.08));
31
+ --nexus-blue: light-dark(rgba(37, 99, 235, 0.45), rgba(38, 130, 225, 0.55));
32
+ --nexus-violet: light-dark(rgba(124, 58, 237, 0.35), rgba(90, 67, 183, 0.45));
33
+ --nexus-pink: #f43f5e;
34
+ --nexus-emerald: light-dark(#059669, #34d399);
35
+
36
+ /* ---- geometry ---- */
37
+ --nexus-radius: 0.7rem;
38
+ --nexus-radius-lg: 1rem;
39
+ --nexus-shell-width: 1280px;
40
+
41
+ /* ---- ambient mesh ---- */
42
+ --nexus-mesh:
43
+ radial-gradient(54rem 42rem at 84% -12%, light-dark(rgba(124, 58, 237, 0.10), rgba(91, 33, 182, 0.32)), transparent 67%),
44
+ radial-gradient(48rem 38rem at -8% 58%, light-dark(rgba(8, 145, 178, 0.08), rgba(8, 145, 178, 0.2)), transparent 68%),
45
+ radial-gradient(42rem 36rem at 56% 44%, light-dark(rgba(30, 64, 175, 0.06), rgba(30, 64, 175, 0.16)), transparent 72%);
46
+ --nexus-mesh-opacity: 0.27;
47
+
48
+ /* ---- selection + scrollbars ---- */
49
+ --nexus-selection: light-dark(rgba(37, 99, 235, 0.25), rgba(129, 140, 248, 0.35));
50
+ --nexus-scrollbar: light-dark(rgba(15, 23, 42, 0.18), rgba(255, 255, 255, 0.18));
51
+ --nexus-scrollbar-thumb: light-dark(rgba(15, 23, 42, 0.14), rgba(255, 255, 255, 0.14));
52
+
53
+ /* ---- aliases for existing admin consumers ---- */
54
+ --admin-bg: var(--nexus-bg);
55
+ --admin-ink: var(--nexus-ink);
56
+ --admin-muted: var(--nexus-muted);
57
+ --admin-surface: var(--nexus-surface);
58
+ --admin-surface-strong: var(--nexus-surface-strong);
59
+ --admin-border: var(--nexus-border);
60
+ --admin-border-bright: var(--nexus-border-bright);
61
+ --admin-blue: var(--nexus-blue);
62
+ --admin-violet: var(--nexus-violet);
63
+ --admin-pink: var(--nexus-pink);
64
+ --admin-radius: var(--nexus-radius);
65
+ --admin-shell-width: var(--nexus-shell-width);
66
+ --admin-mesh: var(--nexus-mesh);
67
+ --admin-mesh-opacity: var(--nexus-mesh-opacity);
68
+ }
package/src/types.ts CHANGED
@@ -5,8 +5,12 @@ export interface NexusPostcssOptions {
5
5
  tailwindPlugins?: any[];
6
6
  import?: boolean;
7
7
  nested?: boolean;
8
+ nestingMode?: 'classic' | 'modern';
8
9
  presetEnv?: boolean | 'stage2' | 'stage3' | 'stage4';
9
10
  autoprefixer?: boolean | Record<string, string>;
11
+ logical?: boolean | Record<string, any>;
10
12
  minify?: boolean;
13
+ sourcemap?: boolean;
14
+ engine?: 'postcss' | 'lightningcss';
11
15
  plugins?: Array<[string, any] | string>;
12
16
  }