@seyuna/postcss 1.0.0-canary.14 → 1.0.0-canary.16
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 +15 -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 +3 -2
- package/dist/at-rules/color.js +10 -21
- package/dist/at-rules/container.d.ts +2 -1
- package/dist/at-rules/container.js +12 -8
- package/dist/at-rules/index.d.ts +3 -2
- package/dist/at-rules/index.js +14 -23
- package/dist/config.d.ts +18 -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 -2
- package/dist/functions/color.js +58 -29
- package/dist/functions/index.d.ts +2 -1
- package/dist/functions/index.js +10 -12
- package/dist/functions/theme.d.ts +6 -0
- package/dist/functions/theme.js +17 -0
- package/dist/helpers.d.ts +3 -2
- package/dist/helpers.js +13 -28
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -5
- package/dist/parser.d.ts +4 -0
- package/dist/parser.js +59 -0
- package/dist/plugin.d.ts +2 -4
- package/dist/plugin.js +16 -22
- package/dist/types.d.ts +1 -19
- package/dist/types.js +1 -2
- package/package.json +13 -5
- package/release.config.mjs +6 -1
- package/src/at-rules/color-scheme.ts +52 -0
- package/src/at-rules/color.ts +11 -15
- package/src/at-rules/container.ts +13 -3
- package/src/at-rules/index.ts +6 -8
- package/src/config.ts +71 -0
- package/src/errors.ts +23 -0
- package/src/functions/color.ts +70 -29
- package/src/functions/index.ts +9 -4
- package/src/functions/theme.ts +20 -0
- package/src/helpers.ts +23 -22
- package/src/index.ts +3 -1
- package/src/parser.ts +80 -0
- package/src/plugin.ts +12 -21
- package/src/types.ts +1 -19
- package/tests/plugin.test.ts +143 -0
- package/tsconfig.json +2 -2
- package/dist/at-rules/dark.d.ts +0 -23
- package/dist/at-rules/dark.js +0 -65
- package/dist/at-rules/light.d.ts +0 -23
- package/dist/at-rules/light.js +0 -65
- package/dist/functions/spacing.d.ts +0 -1
- package/dist/functions/spacing.js +0 -6
- package/src/at-rules/dark.ts +0 -69
- package/src/at-rules/light.ts +0 -69
- package/src/functions/spacing.ts +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
# [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)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* Fixed release configuration. ([3e7f764](https://github.com/seyuna-corp/seyuna-postcss/commit/3e7f76488e109110cbec50cb4c5bdc89397b3b40))
|
|
7
|
+
* release configuration error. ([076eb34](https://github.com/seyuna-corp/seyuna-postcss/commit/076eb348d2ce7ca61bbc1c7a9ad597cadbe59f34))
|
|
8
|
+
|
|
9
|
+
# [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)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* workflow node version upgrade. ([e98349a](https://github.com/seyuna-corp/seyuna-postcss/commit/e98349af69aab446f0ac4d0790112d5c702c1b36))
|
|
15
|
+
|
|
1
16
|
# [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)
|
|
2
17
|
|
|
3
18
|
|
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');
|
package/dist/at-rules/color.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { AtRule } from "postcss";
|
|
2
|
+
import { PluginContext } from "../config";
|
|
2
3
|
/**
|
|
3
4
|
* Handler for @each-standard-color
|
|
4
5
|
*/
|
|
5
|
-
export declare function eachStandardColor(atRule: AtRule): void;
|
|
6
|
+
export declare function eachStandardColor(atRule: AtRule, context: PluginContext): void;
|
|
6
7
|
/**
|
|
7
8
|
* Handler for @each-fixed-color
|
|
8
9
|
*/
|
|
9
|
-
export declare function eachFixedColor(atRule: AtRule): void;
|
|
10
|
+
export declare function eachFixedColor(atRule: AtRule, context: PluginContext): void;
|
package/dist/at-rules/color.js
CHANGED
|
@@ -1,21 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.eachStandardColor = eachStandardColor;
|
|
7
|
-
exports.eachFixedColor = eachFixedColor;
|
|
8
|
-
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const helpers_1 = require("../helpers");
|
|
1
|
+
import { generateRules } from "../helpers";
|
|
11
2
|
/**
|
|
12
3
|
* Handler for @each-standard-color
|
|
13
4
|
*/
|
|
14
|
-
function eachStandardColor(atRule) {
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const rules = (0, helpers_1.generateRules)(hueNames, atRule);
|
|
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);
|
|
19
9
|
if (rules.length)
|
|
20
10
|
atRule.replaceWith(...rules);
|
|
21
11
|
else
|
|
@@ -24,16 +14,15 @@ function eachStandardColor(atRule) {
|
|
|
24
14
|
/**
|
|
25
15
|
* Handler for @each-fixed-color
|
|
26
16
|
*/
|
|
27
|
-
function eachFixedColor(atRule) {
|
|
28
|
-
const
|
|
29
|
-
const data = JSON.parse(fs_1.default.readFileSync(jsonPath, "utf-8"));
|
|
17
|
+
export function eachFixedColor(atRule, context) {
|
|
18
|
+
const { config } = context;
|
|
30
19
|
const mergedNames = [
|
|
31
20
|
...new Set([
|
|
32
|
-
...Object.keys(
|
|
33
|
-
...Object.keys(
|
|
21
|
+
...(config.ui ? Object.keys(config.ui.theme.light.colors) : []),
|
|
22
|
+
...(config.ui ? Object.keys(config.ui.theme.dark.colors) : []),
|
|
34
23
|
]),
|
|
35
24
|
];
|
|
36
|
-
const rules =
|
|
25
|
+
const rules = generateRules(mergedNames, atRule, context);
|
|
37
26
|
if (rules.length)
|
|
38
27
|
atRule.replaceWith(...rules);
|
|
39
28
|
else
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AtRule } from "postcss";
|
|
2
|
+
import { PluginContext } from "../config";
|
|
2
3
|
/**
|
|
3
4
|
* Custom PostCSS plugin handler for responsive at-rules.
|
|
4
5
|
*
|
|
@@ -15,4 +16,4 @@ import { AtRule } from "postcss";
|
|
|
15
16
|
* }
|
|
16
17
|
*
|
|
17
18
|
*/
|
|
18
|
-
export default function container(atRule: AtRule): void;
|
|
19
|
+
export default function container(atRule: AtRule, context: PluginContext): void;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = container;
|
|
4
|
-
const postcss_1 = require("postcss");
|
|
1
|
+
import { AtRule } from "postcss";
|
|
5
2
|
/**
|
|
6
3
|
* Custom PostCSS plugin handler for responsive at-rules.
|
|
7
4
|
*
|
|
@@ -18,9 +15,10 @@ const postcss_1 = require("postcss");
|
|
|
18
15
|
* }
|
|
19
16
|
*
|
|
20
17
|
*/
|
|
21
|
-
function container(atRule) {
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
export default function container(atRule, context) {
|
|
19
|
+
const { config } = context;
|
|
20
|
+
// Default breakpoints
|
|
21
|
+
const defaultBreakpoints = {
|
|
24
22
|
xs: "20rem",
|
|
25
23
|
sm: "40rem",
|
|
26
24
|
md: "48rem",
|
|
@@ -28,15 +26,21 @@ function container(atRule) {
|
|
|
28
26
|
xl: "80rem",
|
|
29
27
|
"2xl": "96rem",
|
|
30
28
|
};
|
|
29
|
+
// Merge with config if available (assuming config.ui.breakpoints exists)
|
|
30
|
+
const breakpoints = {
|
|
31
|
+
...defaultBreakpoints,
|
|
32
|
+
...(config.ui?.theme?.breakpoints || {}),
|
|
33
|
+
};
|
|
31
34
|
if (Object.keys(breakpoints).includes(atRule.name)) {
|
|
32
35
|
const minWidth = breakpoints[atRule.name];
|
|
33
36
|
const clonedNodes = [];
|
|
34
37
|
atRule.each((node) => {
|
|
35
38
|
clonedNodes.push(node.clone());
|
|
36
39
|
});
|
|
37
|
-
const containerAtRule = new
|
|
40
|
+
const containerAtRule = new AtRule({
|
|
38
41
|
name: "container",
|
|
39
42
|
params: `(min-width: ${minWidth})`,
|
|
43
|
+
source: atRule.source,
|
|
40
44
|
});
|
|
41
45
|
clonedNodes.forEach((node) => containerAtRule.append(node));
|
|
42
46
|
atRule.replaceWith(containerAtRule);
|
package/dist/at-rules/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AtRule } from "postcss";
|
|
2
|
+
import { PluginContext } from "../config";
|
|
2
3
|
export interface AtRuleHandler {
|
|
3
4
|
name: string;
|
|
4
|
-
handler: (atRule: AtRule) => void;
|
|
5
|
+
handler: (atRule: AtRule, context: PluginContext) => void;
|
|
5
6
|
}
|
|
6
7
|
export declare const atRuleHandlers: AtRuleHandler[];
|
package/dist/at-rules/index.js
CHANGED
|
@@ -1,25 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.atRuleHandlers = void 0;
|
|
7
|
-
// atRuleHandlers.ts
|
|
8
|
-
const dark_1 = __importDefault(require("./dark"));
|
|
9
|
-
const light_1 = __importDefault(require("./light"));
|
|
10
|
-
const container_1 = __importDefault(require("./container"));
|
|
11
|
-
const color_1 = require("./color");
|
|
1
|
+
import { eachStandardColor, eachFixedColor } from "./color";
|
|
2
|
+
import container from "./container";
|
|
3
|
+
import { light, dark } from "./color-scheme";
|
|
12
4
|
// Ordered array ensures execution order
|
|
13
|
-
|
|
14
|
-
{ name: "each-standard-color", handler:
|
|
15
|
-
{ name: "each-fixed-color", handler:
|
|
16
|
-
{ name: "light", handler:
|
|
17
|
-
{ name: "dark", handler:
|
|
18
|
-
{ name: "xs", handler:
|
|
19
|
-
{ name: "sm", handler:
|
|
20
|
-
{ name: "md", handler:
|
|
21
|
-
{ name: "lg", handler:
|
|
22
|
-
{ name: "xl", handler:
|
|
23
|
-
{ name: "2xl", handler:
|
|
24
|
-
// add more handlers here as needed
|
|
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 },
|
|
25
16
|
];
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SeyunaConfig } from './types';
|
|
2
|
+
import { FunctionMap } from './parser';
|
|
3
|
+
export interface PluginOptions {
|
|
4
|
+
configPath?: string;
|
|
5
|
+
modeAttribute?: string;
|
|
6
|
+
strict?: boolean;
|
|
7
|
+
config?: SeyunaConfig;
|
|
8
|
+
functions?: FunctionMap;
|
|
9
|
+
}
|
|
10
|
+
export interface PluginContext {
|
|
11
|
+
config: SeyunaConfig;
|
|
12
|
+
options: Required<PluginOptions>;
|
|
13
|
+
functions: FunctionMap;
|
|
14
|
+
}
|
|
15
|
+
export declare function loadConfig(options?: PluginOptions): {
|
|
16
|
+
config: SeyunaConfig;
|
|
17
|
+
options: Required<PluginOptions>;
|
|
18
|
+
};
|
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
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Node } from 'postcss';
|
|
2
|
+
import { PluginContext } from './config';
|
|
3
|
+
export declare function reportError(message: string, node: Node, context: PluginContext, options?: {
|
|
4
|
+
word?: string;
|
|
5
|
+
index?: number;
|
|
6
|
+
}): void;
|
|
7
|
+
export declare function reportWarning(message: string, node: Node): void;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function reportError(message, node, context, options = {}) {
|
|
2
|
+
const { options: pluginOptions } = context;
|
|
3
|
+
const formattedMessage = `[Seyuna PostCSS] ${message}`;
|
|
4
|
+
if (pluginOptions.strict) {
|
|
5
|
+
throw node.error(formattedMessage, options);
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
reportWarning(formattedMessage, node);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function reportWarning(message, node) {
|
|
12
|
+
const result = node.root().toResult();
|
|
13
|
+
node.warn(result, `[Seyuna PostCSS] ${message}`);
|
|
14
|
+
}
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function
|
|
1
|
+
import { PluginContext } from "../config";
|
|
2
|
+
export declare function sc(context: PluginContext, name: string, alpha?: string, lightness?: string, chroma?: string): string;
|
|
3
|
+
export declare function fc(context: PluginContext, name: string, alpha?: string, lightness?: string, chroma?: string): string;
|
|
4
|
+
export declare function alpha(context: PluginContext, color: string, value: string): string;
|
|
5
|
+
export declare function lighten(context: PluginContext, color: string, amount: string): string;
|
|
6
|
+
export declare function darken(context: PluginContext, color: string, amount: string): string;
|
|
7
|
+
export declare function contrast(context: PluginContext, color: string): string;
|