@seyuna/postcss 1.0.0-canary.2 → 1.0.0-canary.20
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/.github/workflows/release.yml +1 -1
- package/CHANGELOG.md +139 -0
- package/README.md +275 -0
- package/dist/at-rules/color-scheme.d.ts +4 -0
- package/dist/at-rules/color-scheme.js +43 -0
- package/dist/at-rules/color.d.ts +10 -0
- package/dist/at-rules/color.js +30 -0
- package/dist/at-rules/container.d.ts +19 -0
- package/dist/at-rules/container.js +48 -0
- package/dist/at-rules/index.d.ts +7 -3
- package/dist/at-rules/index.js +16 -13
- package/dist/config.d.ts +6 -0
- package/dist/config.js +47 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +14 -0
- package/dist/functions/color.d.ts +7 -1
- package/dist/functions/color.js +59 -14
- package/dist/functions/index.d.ts +2 -1
- package/dist/functions/index.js +10 -11
- package/dist/functions/theme.d.ts +6 -0
- package/dist/functions/theme.js +17 -0
- package/dist/helpers.d.ts +11 -0
- package/dist/helpers.js +54 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +6 -5
- package/dist/parser.d.ts +4 -0
- package/dist/parser.js +59 -0
- package/dist/plugin.d.ts +1 -3
- package/dist/plugin.js +22 -22
- package/dist/types.d.ts +59 -0
- package/dist/types.js +3 -0
- package/package.json +15 -5
- package/release.config.mjs +6 -1
- package/src/at-rules/color-scheme.ts +52 -0
- package/src/at-rules/color.ts +33 -0
- package/src/at-rules/container.ts +57 -0
- package/src/at-rules/index.ts +23 -9
- package/src/config.ts +59 -0
- package/src/errors.ts +23 -0
- package/src/functions/color.ts +80 -14
- package/src/functions/index.ts +11 -5
- package/src/functions/theme.ts +20 -0
- package/src/helpers.ts +74 -0
- package/src/index.ts +5 -3
- package/src/parser.ts +81 -0
- package/src/plugin.ts +21 -23
- package/src/types.ts +72 -0
- package/tests/plugin.test.ts +143 -0
- package/tsconfig.json +2 -2
- package/dist/at-rules/dark.d.ts +0 -2
- package/dist/at-rules/dark.js +0 -28
- package/dist/at-rules/light.d.ts +0 -2
- package/dist/at-rules/light.js +0 -28
- package/dist/functions/spacing.d.ts +0 -1
- package/dist/functions/spacing.js +0 -6
- package/src/at-rules/dark.ts +0 -33
- package/src/at-rules/light.ts +0 -33
- package/src/functions/spacing.ts +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,142 @@
|
|
|
1
|
+
# [1.0.0-canary.20](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.19...v1.0.0-canary.20) (2026-01-10)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* remove @seyuna/cli dependency to prevent bundler loading Deno polyfills ([544a37e](https://github.com/seyuna-corp/seyuna-postcss/commit/544a37e412fcfd585c1dbcdfe28484ce63bec3c1))
|
|
7
|
+
|
|
8
|
+
# [1.0.0-canary.19](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.18...v1.0.0-canary.19) (2026-01-10)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* define types locally to avoid @seyuna/cli polyfill side-effects ([acdbcc9](https://github.com/seyuna-corp/seyuna-postcss/commit/acdbcc977fd2a501302d675ff7ffd2c307e25a95))
|
|
14
|
+
|
|
15
|
+
# [1.0.0-canary.18](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.17...v1.0.0-canary.18) (2026-01-10)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* break circular dependency between config.ts and parser.ts ([88ae984](https://github.com/seyuna-corp/seyuna-postcss/commit/88ae9848ed2eb4d4ca5fb6340cbe5aa1c986f1b8))
|
|
21
|
+
|
|
22
|
+
# [1.0.0-canary.17](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.16...v1.0.0-canary.17) (2026-01-10)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* transition to proper ESM with correct file extensions ([b330b4f](https://github.com/seyuna-corp/seyuna-postcss/commit/b330b4fcd3394b78ecc39ef5f23f5e993bd425be))
|
|
28
|
+
|
|
29
|
+
# [1.0.0-canary.16](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.15...v1.0.0-canary.16) (2026-01-10)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Bug Fixes
|
|
33
|
+
|
|
34
|
+
* Fixed release configuration. ([3e7f764](https://github.com/seyuna-corp/seyuna-postcss/commit/3e7f76488e109110cbec50cb4c5bdc89397b3b40))
|
|
35
|
+
* release configuration error. ([076eb34](https://github.com/seyuna-corp/seyuna-postcss/commit/076eb348d2ce7ca61bbc1c7a9ad597cadbe59f34))
|
|
36
|
+
|
|
37
|
+
# [1.0.0-canary.15](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.14...v1.0.0-canary.15) (2026-01-09)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### Bug Fixes
|
|
41
|
+
|
|
42
|
+
* workflow node version upgrade. ([e98349a](https://github.com/seyuna-corp/seyuna-postcss/commit/e98349af69aab446f0ac4d0790112d5c702c1b36))
|
|
43
|
+
|
|
44
|
+
# [1.0.0-canary.14](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.13...v1.0.0-canary.14) (2025-10-09)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
### Bug Fixes
|
|
48
|
+
|
|
49
|
+
* bug in generateRules ([d5b66d3](https://github.com/seyuna-corp/seyuna-postcss/commit/d5b66d32786f554c0e4f7ea98ae526e7f7ac82c5))
|
|
50
|
+
* removed pnpm lock file that ([6d87d61](https://github.com/seyuna-corp/seyuna-postcss/commit/6d87d616a79a2a539b09dea26bc907dee1d437e2))
|
|
51
|
+
* updated lock file ([d52dcfb](https://github.com/seyuna-corp/seyuna-postcss/commit/d52dcfb2bccbd502d744ceb09aa83394df4ac057))
|
|
52
|
+
|
|
53
|
+
# [1.0.0-canary.13](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.12...v1.0.0-canary.13) (2025-10-07)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
### Bug Fixes
|
|
57
|
+
|
|
58
|
+
* safely clone nodes and replace {name} placeholders ([8a68ee6](https://github.com/seyuna-corp/seyuna-postcss/commit/8a68ee6f1ade947639151bdbf365c102aa439d37))
|
|
59
|
+
|
|
60
|
+
# [1.0.0-canary.12](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.11...v1.0.0-canary.12) (2025-09-15)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
### Bug Fixes
|
|
64
|
+
|
|
65
|
+
* color functions not running when used inside at-each rules ([995fd98](https://github.com/seyuna-corp/seyuna-postcss/commit/995fd9816f2c2d51caa67add4d3172cee41d0c65))
|
|
66
|
+
|
|
67
|
+
# [1.0.0-canary.11](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.10...v1.0.0-canary.11) (2025-09-15)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Bug Fixes
|
|
71
|
+
|
|
72
|
+
* nested rules for at-each-standard-color & at-each-fixed-color ([197a755](https://github.com/seyuna-corp/seyuna-postcss/commit/197a75542798ecacaa071802b2abbf962bcd6538))
|
|
73
|
+
|
|
74
|
+
# [1.0.0-canary.10](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.9...v1.0.0-canary.10) (2025-09-10)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
### Bug Fixes
|
|
78
|
+
|
|
79
|
+
* registered each breakpoint to the same handler for at-rule `container` ([f3f5b36](https://github.com/seyuna-corp/seyuna-postcss/commit/f3f5b3665291dc94e92f3f7c2b2a576b4bdb4517))
|
|
80
|
+
|
|
81
|
+
# [1.0.0-canary.9](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.8...v1.0.0-canary.9) (2025-09-10)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
### Bug Fixes
|
|
85
|
+
|
|
86
|
+
* colors selector in at-rule `each-fixed-color` ([31adb28](https://github.com/seyuna-corp/seyuna-postcss/commit/31adb28f3576a0dcfb78a9aadf331ee4b7ef3e0c))
|
|
87
|
+
|
|
88
|
+
# [1.0.0-canary.8](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.7...v1.0.0-canary.8) (2025-09-10)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
### Features
|
|
92
|
+
|
|
93
|
+
* added at-rule `each-fixed-color` ([699ee0d](https://github.com/seyuna-corp/seyuna-postcss/commit/699ee0defd1fbb0ff91a90c1e13358b1ef9832b2))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
### BREAKING CHANGES
|
|
97
|
+
|
|
98
|
+
* at-rule `each-seyuna-color` renamed to `each-standard-color`
|
|
99
|
+
|
|
100
|
+
# [1.0.0-canary.7](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.6...v1.0.0-canary.7) (2025-09-10)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
### Features
|
|
104
|
+
|
|
105
|
+
* Added at-rule ([8a08289](https://github.com/seyuna-corp/seyuna-postcss/commit/8a08289023f4aa6f65d56e10697e64d02444f118))
|
|
106
|
+
|
|
107
|
+
# [1.0.0-canary.6](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.5...v1.0.0-canary.6) (2025-09-09)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
### Features
|
|
111
|
+
|
|
112
|
+
* add new color function 'fc' ([70e961f](https://github.com/seyuna-corp/seyuna-postcss/commit/70e961fb0b0a13e358de15b42a87b7890f3fc5c0))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
### BREAKING CHANGES
|
|
116
|
+
|
|
117
|
+
* changed how 'sc' functions, not backward-compatible
|
|
118
|
+
|
|
119
|
+
# [1.0.0-canary.5](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.4...v1.0.0-canary.5) (2025-08-25)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
### Bug Fixes
|
|
123
|
+
|
|
124
|
+
* changed color function name to sc to avoid conflicts with the default css color() function ([a46e96c](https://github.com/seyuna-corp/seyuna-postcss/commit/a46e96c74839f930d39a2c273c822a689a942783))
|
|
125
|
+
|
|
126
|
+
# [1.0.0-canary.4](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.3...v1.0.0-canary.4) (2025-08-24)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
### Bug Fixes
|
|
130
|
+
|
|
131
|
+
* at-rules for mode now ensure that [data-mode=system] before enforcing prefers-color-scheme ([475055d](https://github.com/seyuna-corp/seyuna-postcss/commit/475055db1d5662d25631953af669bf64b2e0468e))
|
|
132
|
+
|
|
133
|
+
# [1.0.0-canary.3](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.2...v1.0.0-canary.3) (2025-08-24)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
### Bug Fixes
|
|
137
|
+
|
|
138
|
+
* prioritized data-mode over prefers-color-scheme for [@dark](https://github.com/dark) & [@light](https://github.com/light) rules ([1dafbe7](https://github.com/seyuna-corp/seyuna-postcss/commit/1dafbe74c2ceae8faf28f55ac64846e9e752405b))
|
|
139
|
+
|
|
1
140
|
# [1.0.0-canary.2](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.1...v1.0.0-canary.2) (2025-08-08)
|
|
2
141
|
|
|
3
142
|
|
package/README.md
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# @seyuna/postcss
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@seyuna/postcss)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
> Build interfaces that transcend resolution.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## What is this
|
|
11
|
+
|
|
12
|
+
Seyuna PostCSS is the engine behind the Seyuna design system. It compiles a declarative color configuration into fully functional CSS, handles theme switching, and provides a suite of utilities that make authoring stylesheets faster and more intuitive.
|
|
13
|
+
|
|
14
|
+
The core philosophy is simple: **design once at 1080p, deploy everywhere**. Seyuna UI handles upscaling automatically through viewport-relative font sizing. The result is pixel-perfect consistency from a laptop to a 4K display without breakpoints, without media queries, without you lifting a finger.
|
|
15
|
+
|
|
16
|
+
```css
|
|
17
|
+
html {
|
|
18
|
+
font-size: max(1rem, 0.833vw);
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This single line is the foundation. At 1920px viewport width, `0.833vw` equals exactly `16px`. Everything scales proportionally. No more designing three versions of every component.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @seyuna/postcss postcss-import postcss-advanced-variables postcss-preset-env --save-dev
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Configuration
|
|
35
|
+
|
|
36
|
+
Create a `postcss.config.js` at your project root:
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
import seyunaPostcss from '@seyuna/postcss';
|
|
40
|
+
import postcssImport from 'postcss-import';
|
|
41
|
+
import postcssAdvancedVariables from 'postcss-advanced-variables';
|
|
42
|
+
import postcssPresetEnv from 'postcss-preset-env';
|
|
43
|
+
|
|
44
|
+
export default {
|
|
45
|
+
plugins: [
|
|
46
|
+
seyunaPostcss({
|
|
47
|
+
configPath: 'seyuna.json',
|
|
48
|
+
modeAttribute: 'data-mode',
|
|
49
|
+
}),
|
|
50
|
+
postcssImport,
|
|
51
|
+
postcssAdvancedVariables,
|
|
52
|
+
postcssPresetEnv({
|
|
53
|
+
stage: 3,
|
|
54
|
+
features: {
|
|
55
|
+
'nesting-rules': true,
|
|
56
|
+
},
|
|
57
|
+
}),
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The plugin reads from `seyuna.json` at build time. This file is your single source of truth for colors, themes, and any other design tokens you want accessible in CSS.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## The Color Model
|
|
67
|
+
|
|
68
|
+
Seyuna operates entirely in the OKLCH color space. Unlike HSL or RGB, OKLCH is perceptually uniform. A lightness of `0.66` looks equally bright across all hues. This makes it possible to build harmonious palettes programmatically.
|
|
69
|
+
|
|
70
|
+
### Standard Colors
|
|
71
|
+
|
|
72
|
+
Standard colors are hue-only tokens. They inherit the global `--lightness` and `--chroma` values from the current theme mode. When the user switches from light to dark, every standard color adapts automatically.
|
|
73
|
+
|
|
74
|
+
```css
|
|
75
|
+
.button {
|
|
76
|
+
background: sc(primary);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Compiles to:
|
|
81
|
+
|
|
82
|
+
```css
|
|
83
|
+
.button {
|
|
84
|
+
background: oklch(var(--lightness) var(--chroma) var(--primary-hue) / 1);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Fixed Colors
|
|
89
|
+
|
|
90
|
+
Fixed colors are absolute. They define their own lightness, chroma, and hue. Use these for colors that must remain constant regardless of theme, like brand logos or semantic status indicators.
|
|
91
|
+
|
|
92
|
+
```css
|
|
93
|
+
.badge {
|
|
94
|
+
background: fc(white);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Compiles to:
|
|
99
|
+
|
|
100
|
+
```css
|
|
101
|
+
.badge {
|
|
102
|
+
background: oklch(var(--white-lightness) var(--white-chroma) var(--white-hue) / 1);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Color Manipulation
|
|
109
|
+
|
|
110
|
+
All color functions accept a color name from your configuration.
|
|
111
|
+
|
|
112
|
+
| Function | Purpose | Example |
|
|
113
|
+
|:----------------------|:-----------------------------------------|:----------------------------|
|
|
114
|
+
| `alpha(color, value)` | Adjusts opacity | `alpha(primary, 0.5)` |
|
|
115
|
+
| `lighten(color, amt)` | Increases lightness by `amt` | `lighten(primary, 0.1)` |
|
|
116
|
+
| `darken(color, amt)` | Decreases lightness by `amt` | `darken(primary, 0.1)` |
|
|
117
|
+
| `contrast(color)` | Returns black or white based on lightness| `color: contrast(surface);` |
|
|
118
|
+
|
|
119
|
+
The `contrast()` function uses a dynamic CSS calculation internally. It does not bake in a static value. If `--surface-lightness` changes at runtime, the contrast color updates with it.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Theme Switching
|
|
124
|
+
|
|
125
|
+
Seyuna supports three modes: `light`, `dark`, and `system`. The system mode respects `prefers-color-scheme`. All switching is handled via the `data-mode` attribute on your root element.
|
|
126
|
+
|
|
127
|
+
```html
|
|
128
|
+
<html data-mode="system">
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The compiled CSS contains rules for all three states:
|
|
132
|
+
|
|
133
|
+
```css
|
|
134
|
+
[data-mode="light"] {
|
|
135
|
+
--lightness: 0.66;
|
|
136
|
+
--chroma: 0.26;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@media (prefers-color-scheme: dark) {
|
|
140
|
+
[data-mode="system"] {
|
|
141
|
+
--lightness: 0.66;
|
|
142
|
+
--chroma: 0.26;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### In-CSS Overrides
|
|
148
|
+
|
|
149
|
+
Need a component to look different in dark mode? Use the `@dark` and `@light` at-rules directly in your stylesheet:
|
|
150
|
+
|
|
151
|
+
```css
|
|
152
|
+
.card {
|
|
153
|
+
background: fc(white);
|
|
154
|
+
|
|
155
|
+
@dark {
|
|
156
|
+
background: fc(black);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Container Queries
|
|
164
|
+
|
|
165
|
+
Seyuna ships with shorthand breakpoints that compile to CSS Container Queries instead of traditional media queries. This means components respond to their container size, not the viewport.
|
|
166
|
+
|
|
167
|
+
```css
|
|
168
|
+
.grid {
|
|
169
|
+
display: grid;
|
|
170
|
+
grid-template-columns: 1fr;
|
|
171
|
+
|
|
172
|
+
@md {
|
|
173
|
+
grid-template-columns: repeat(2, 1fr);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@lg {
|
|
177
|
+
grid-template-columns: repeat(3, 1fr);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Available breakpoints:
|
|
183
|
+
|
|
184
|
+
| At-Rule | Container Width |
|
|
185
|
+
|:--------|:----------------|
|
|
186
|
+
| `@xs` | 20rem |
|
|
187
|
+
| `@sm` | 30rem |
|
|
188
|
+
| `@md` | 48rem |
|
|
189
|
+
| `@lg` | 62rem |
|
|
190
|
+
| `@xl` | 80rem |
|
|
191
|
+
| `@2xl` | 96rem |
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Configuration Reference
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"ui": {
|
|
200
|
+
"theme": {
|
|
201
|
+
"hues": {
|
|
202
|
+
"primary": 240,
|
|
203
|
+
"secondary": 30,
|
|
204
|
+
"accent": 150
|
|
205
|
+
},
|
|
206
|
+
"colors": {
|
|
207
|
+
"white": { "lightness": 1, "chroma": 0, "hue": 0 },
|
|
208
|
+
"black": { "lightness": 0, "chroma": 0, "hue": 0 }
|
|
209
|
+
},
|
|
210
|
+
"light": {
|
|
211
|
+
"lightness": 0.66,
|
|
212
|
+
"chroma": 0.26,
|
|
213
|
+
"background": { "lightness": 1, "chroma": 0, "hue": 0 },
|
|
214
|
+
"text": { "lightness": 0, "chroma": 0, "hue": 0 }
|
|
215
|
+
},
|
|
216
|
+
"dark": {
|
|
217
|
+
"lightness": 0.66,
|
|
218
|
+
"chroma": 0.26,
|
|
219
|
+
"background": { "lightness": 0, "chroma": 0, "hue": 0 },
|
|
220
|
+
"text": { "lightness": 1, "chroma": 0, "hue": 0 }
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
"mode": "system",
|
|
224
|
+
"output_dir": "src/styles"
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
`hues` defines standard colors. Only the hue angle is specified because lightness and chroma come from the theme mode.
|
|
230
|
+
|
|
231
|
+
`colors` defines fixed colors with explicit lightness, chroma, and hue values.
|
|
232
|
+
|
|
233
|
+
`light` and `dark` set the global lightness and chroma for standard colors, plus any mode-specific fixed colors like background and text.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Palette Iteration
|
|
238
|
+
|
|
239
|
+
Generate utility classes by iterating over your entire color configuration:
|
|
240
|
+
|
|
241
|
+
```css
|
|
242
|
+
@each-standard-color {
|
|
243
|
+
.bg-{name} {
|
|
244
|
+
background-color: sc({name});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
@each-fixed-color {
|
|
249
|
+
.text-{name} {
|
|
250
|
+
color: fc({name});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## The Reset Layer
|
|
258
|
+
|
|
259
|
+
Seyuna UI generates a CSS file that includes a minimal, opinionated reset. It zeroes out margins and padding, removes default list styles, and sets sensible defaults for text rendering. The reset is applied to the `reset` layer, so your styles can override it without specificity battles.
|
|
260
|
+
|
|
261
|
+
The upscaling magic happens here:
|
|
262
|
+
|
|
263
|
+
```css
|
|
264
|
+
html {
|
|
265
|
+
font-size: max(1rem, 0.833vw);
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
At 1920px, the computed font size is 16px. At 2560px, it becomes roughly 21px. Every `rem` value in your stylesheet scales accordingly. Design at 1080p. Ship at any resolution.
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## License
|
|
274
|
+
|
|
275
|
+
MIT
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Rule, AtRule } from "postcss";
|
|
2
|
+
/**
|
|
3
|
+
* Custom PostCSS plugin handler factory for `@light` and `@dark` at-rules.
|
|
4
|
+
*/
|
|
5
|
+
function createColorSchemeHandler(scheme) {
|
|
6
|
+
return (atRule, context) => {
|
|
7
|
+
const { options } = context;
|
|
8
|
+
const modeAttribute = options.modeAttribute;
|
|
9
|
+
const clonedNodes = [];
|
|
10
|
+
// Clone all child nodes inside the block
|
|
11
|
+
atRule.each((node) => {
|
|
12
|
+
clonedNodes.push(node.clone());
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Rule 1: [data-mode="scheme"] & { ... } (Explicit mode)
|
|
16
|
+
*/
|
|
17
|
+
const explicitRule = new Rule({
|
|
18
|
+
selector: `[${modeAttribute}="${scheme}"] &`,
|
|
19
|
+
source: atRule.source,
|
|
20
|
+
});
|
|
21
|
+
clonedNodes.forEach((node) => explicitRule.append(node.clone()));
|
|
22
|
+
/**
|
|
23
|
+
* Rule 2: @media (prefers-color-scheme: scheme) { [data-mode="system"] & { ... } } (System preference)
|
|
24
|
+
*/
|
|
25
|
+
const mediaAtRule = new AtRule({
|
|
26
|
+
name: "media",
|
|
27
|
+
params: `(prefers-color-scheme: ${scheme})`,
|
|
28
|
+
source: atRule.source,
|
|
29
|
+
});
|
|
30
|
+
const systemRule = new Rule({
|
|
31
|
+
selector: `[${modeAttribute}="system"] &`,
|
|
32
|
+
source: atRule.source,
|
|
33
|
+
});
|
|
34
|
+
clonedNodes.forEach((node) => systemRule.append(node.clone()));
|
|
35
|
+
mediaAtRule.append(systemRule);
|
|
36
|
+
/**
|
|
37
|
+
* Replace the original at-rule with the generated rules.
|
|
38
|
+
*/
|
|
39
|
+
atRule.replaceWith(mediaAtRule, explicitRule);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export const light = createColorSchemeHandler('light');
|
|
43
|
+
export const dark = createColorSchemeHandler('dark');
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AtRule } from "postcss";
|
|
2
|
+
import { PluginContext } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Handler for @each-standard-color
|
|
5
|
+
*/
|
|
6
|
+
export declare function eachStandardColor(atRule: AtRule, context: PluginContext): void;
|
|
7
|
+
/**
|
|
8
|
+
* Handler for @each-fixed-color
|
|
9
|
+
*/
|
|
10
|
+
export declare function eachFixedColor(atRule: AtRule, context: PluginContext): void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { generateRules } from "../helpers.js";
|
|
2
|
+
/**
|
|
3
|
+
* Handler for @each-standard-color
|
|
4
|
+
*/
|
|
5
|
+
export function eachStandardColor(atRule, context) {
|
|
6
|
+
const { config } = context;
|
|
7
|
+
const hueNames = config.ui ? Object.keys(config.ui.theme.hues) : [];
|
|
8
|
+
const rules = generateRules(hueNames, atRule, context);
|
|
9
|
+
if (rules.length)
|
|
10
|
+
atRule.replaceWith(...rules);
|
|
11
|
+
else
|
|
12
|
+
atRule.remove();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Handler for @each-fixed-color
|
|
16
|
+
*/
|
|
17
|
+
export function eachFixedColor(atRule, context) {
|
|
18
|
+
const { config } = context;
|
|
19
|
+
const mergedNames = [
|
|
20
|
+
...new Set([
|
|
21
|
+
...(config.ui ? Object.keys(config.ui.theme.light.colors) : []),
|
|
22
|
+
...(config.ui ? Object.keys(config.ui.theme.dark.colors) : []),
|
|
23
|
+
]),
|
|
24
|
+
];
|
|
25
|
+
const rules = generateRules(mergedNames, atRule, context);
|
|
26
|
+
if (rules.length)
|
|
27
|
+
atRule.replaceWith(...rules);
|
|
28
|
+
else
|
|
29
|
+
atRule.remove();
|
|
30
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AtRule } from "postcss";
|
|
2
|
+
import { PluginContext } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Custom PostCSS plugin handler for responsive at-rules.
|
|
5
|
+
*
|
|
6
|
+
* Example:
|
|
7
|
+
*
|
|
8
|
+
* @xs {
|
|
9
|
+
* .box { color: red; }
|
|
10
|
+
* }
|
|
11
|
+
*
|
|
12
|
+
* Into:
|
|
13
|
+
*
|
|
14
|
+
* @xs (min-width: 234px) {
|
|
15
|
+
* .box { color: red; }
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
export default function container(atRule: AtRule, context: PluginContext): void;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { AtRule } from "postcss";
|
|
2
|
+
/**
|
|
3
|
+
* Custom PostCSS plugin handler for responsive at-rules.
|
|
4
|
+
*
|
|
5
|
+
* Example:
|
|
6
|
+
*
|
|
7
|
+
* @xs {
|
|
8
|
+
* .box { color: red; }
|
|
9
|
+
* }
|
|
10
|
+
*
|
|
11
|
+
* Into:
|
|
12
|
+
*
|
|
13
|
+
* @xs (min-width: 234px) {
|
|
14
|
+
* .box { color: red; }
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
export default function container(atRule, context) {
|
|
19
|
+
const { config } = context;
|
|
20
|
+
// Default breakpoints
|
|
21
|
+
const defaultBreakpoints = {
|
|
22
|
+
xs: "20rem",
|
|
23
|
+
sm: "40rem",
|
|
24
|
+
md: "48rem",
|
|
25
|
+
lg: "64rem",
|
|
26
|
+
xl: "80rem",
|
|
27
|
+
"2xl": "96rem",
|
|
28
|
+
};
|
|
29
|
+
// Merge with config if available (assuming config.ui.breakpoints exists)
|
|
30
|
+
const breakpoints = {
|
|
31
|
+
...defaultBreakpoints,
|
|
32
|
+
...(config.ui?.theme?.breakpoints || {}),
|
|
33
|
+
};
|
|
34
|
+
if (Object.keys(breakpoints).includes(atRule.name)) {
|
|
35
|
+
const minWidth = breakpoints[atRule.name];
|
|
36
|
+
const clonedNodes = [];
|
|
37
|
+
atRule.each((node) => {
|
|
38
|
+
clonedNodes.push(node.clone());
|
|
39
|
+
});
|
|
40
|
+
const containerAtRule = new AtRule({
|
|
41
|
+
name: "container",
|
|
42
|
+
params: `(min-width: ${minWidth})`,
|
|
43
|
+
source: atRule.source,
|
|
44
|
+
});
|
|
45
|
+
clonedNodes.forEach((node) => containerAtRule.append(node));
|
|
46
|
+
atRule.replaceWith(containerAtRule);
|
|
47
|
+
}
|
|
48
|
+
}
|
package/dist/at-rules/index.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
export
|
|
1
|
+
import { AtRule } from "postcss";
|
|
2
|
+
import { PluginContext } from "../types.js";
|
|
3
|
+
export interface AtRuleHandler {
|
|
4
|
+
name: string;
|
|
5
|
+
handler: (atRule: AtRule, context: PluginContext) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const atRuleHandlers: AtRuleHandler[];
|
package/dist/at-rules/index.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
1
|
+
import { eachStandardColor, eachFixedColor } from "./color.js";
|
|
2
|
+
import container from "./container.js";
|
|
3
|
+
import { light, dark } from "./color-scheme.js";
|
|
4
|
+
// Ordered array ensures execution order
|
|
5
|
+
export const atRuleHandlers = [
|
|
6
|
+
{ name: "each-standard-color", handler: eachStandardColor },
|
|
7
|
+
{ name: "each-fixed-color", handler: eachFixedColor },
|
|
8
|
+
{ name: "light", handler: light },
|
|
9
|
+
{ name: "dark", handler: dark },
|
|
10
|
+
{ name: "xs", handler: container },
|
|
11
|
+
{ name: "sm", handler: container },
|
|
12
|
+
{ name: "md", handler: container },
|
|
13
|
+
{ name: "lg", handler: container },
|
|
14
|
+
{ name: "xl", handler: container },
|
|
15
|
+
{ name: "2xl", handler: container },
|
|
16
|
+
];
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
const DEFAULT_OPTIONS = {
|
|
4
|
+
configPath: 'seyuna.json',
|
|
5
|
+
modeAttribute: 'data-mode',
|
|
6
|
+
strict: false,
|
|
7
|
+
config: undefined,
|
|
8
|
+
functions: undefined,
|
|
9
|
+
};
|
|
10
|
+
let cachedConfig = null;
|
|
11
|
+
let cachedConfigPath = null;
|
|
12
|
+
export function loadConfig(options = {}) {
|
|
13
|
+
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
14
|
+
if (mergedOptions.config) {
|
|
15
|
+
return { config: mergedOptions.config, options: mergedOptions };
|
|
16
|
+
}
|
|
17
|
+
const configPath = path.resolve(process.cwd(), mergedOptions.configPath);
|
|
18
|
+
// Cache config if it's the same path
|
|
19
|
+
if (cachedConfig && cachedConfigPath === configPath) {
|
|
20
|
+
return { config: cachedConfig, options: mergedOptions };
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
if (!fs.existsSync(configPath)) {
|
|
24
|
+
if (mergedOptions.strict) {
|
|
25
|
+
throw new Error(`Seyuna config not found at ${configPath}`);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
config: { ui: { theme: { hues: {}, light: { colors: {} }, dark: { colors: {} } } } },
|
|
29
|
+
options: mergedOptions,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
33
|
+
cachedConfig = data;
|
|
34
|
+
cachedConfigPath = configPath;
|
|
35
|
+
return { config: data, options: mergedOptions };
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (mergedOptions.strict) {
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
console.warn(`[Seyuna PostCSS] Warning: Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
|
+
return {
|
|
43
|
+
config: { ui: { theme: { hues: {}, light: { colors: {} }, dark: { colors: {} } } } },
|
|
44
|
+
options: mergedOptions,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|