@seyuna/postcss 1.0.0-canary.32 → 1.0.0-canary.34
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/CHANGELOG.md +14 -0
- package/README.md +2 -2
- package/dist/at-rules/import.js +61 -18
- package/dist/at-rules/index.js +1 -1
- package/package.json +1 -1
- package/src/at-rules/import.ts +121 -49
- package/src/at-rules/index.ts +1 -1
- package/src/styles/seyuna-global.css +94 -0
- package/tests/plugin.test.ts +22 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [1.0.0-canary.34](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.33...v1.0.0-canary.34) (2026-01-22)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* integrate CSS reset into [@seyuna](https://github.com/seyuna); and unignore src/styles ([6df5a15](https://github.com/seyuna-corp/seyuna-postcss/commit/6df5a150b806c50b9f64c806f06cdb299d66a3b1))
|
|
7
|
+
|
|
8
|
+
# [1.0.0-canary.33](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.32...v1.0.0-canary.33) (2026-01-22)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* rename [@import](https://github.com/import) 'seyuna' to [@seyuna](https://github.com/seyuna); to avoid Vite resolution conflict ([375e493](https://github.com/seyuna-corp/seyuna-postcss/commit/375e49369f5734486b986ec5c8f46585dd7a1743))
|
|
14
|
+
|
|
1
15
|
# [1.0.0-canary.32](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.31...v1.0.0-canary.32) (2026-01-21)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -111,7 +111,7 @@ export default {
|
|
|
111
111
|
|
|
112
112
|
### CSS Setup
|
|
113
113
|
|
|
114
|
-
Configure your design tokens directly in your CSS using the `@config "seyuna"` at-rule, then
|
|
114
|
+
Configure your design tokens directly in your CSS using the `@config "seyuna"` at-rule, and then initialize the design system using `@seyuna;`:
|
|
115
115
|
|
|
116
116
|
```css
|
|
117
117
|
@config "seyuna" {
|
|
@@ -135,7 +135,7 @@ Configure your design tokens directly in your CSS using the `@config "seyuna"` a
|
|
|
135
135
|
--dark-text: 1 0 0;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
@
|
|
138
|
+
@seyuna;
|
|
139
139
|
|
|
140
140
|
/* Your styles here */
|
|
141
141
|
```
|
package/dist/at-rules/import.js
CHANGED
|
@@ -12,8 +12,13 @@ const __dirname = path.dirname(__filename);
|
|
|
12
12
|
* Injects the core Seyuna Design System variables and base styles
|
|
13
13
|
*/
|
|
14
14
|
export function handleImport(atRule, context) {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
// Support both @seyuna; and the previous @import "seyuna" logic
|
|
16
|
+
// Since this handler is now registered to @seyuna, we just check params or just run it.
|
|
17
|
+
const params = atRule.params.replace(/['"]/g, "").trim();
|
|
18
|
+
// If it's @seyuna; the params will be empty.
|
|
19
|
+
// If it's @import "seyuna", this handler wouldn't be called unless we kept the name "import".
|
|
20
|
+
// But we want this to run for @seyuna;
|
|
21
|
+
if (atRule.name === "seyuna") {
|
|
17
22
|
const { config, options } = context;
|
|
18
23
|
if (!config.ui) {
|
|
19
24
|
atRule.remove();
|
|
@@ -27,17 +32,21 @@ export function handleImport(atRule, context) {
|
|
|
27
32
|
const globalStylesPath = path.resolve(__dirname, "../styles/seyuna-global.css");
|
|
28
33
|
if (fs.existsSync(globalStylesPath)) {
|
|
29
34
|
const globalCss = fs.readFileSync(globalStylesPath, "utf-8");
|
|
30
|
-
const cleanCss = globalCss.split(
|
|
35
|
+
const cleanCss = globalCss.split("$")[0].trim();
|
|
31
36
|
const parsed = postcss.parse(cleanCss);
|
|
32
37
|
// Only keep layers and reset styles, avoid re-injecting variables
|
|
33
38
|
parsed.each((node) => {
|
|
34
|
-
if (node.type ===
|
|
39
|
+
if (node.type === "atrule" &&
|
|
40
|
+
(node.name === "layer" || node.name === "media")) {
|
|
35
41
|
nodes.push(node.clone());
|
|
36
42
|
}
|
|
37
43
|
});
|
|
38
44
|
}
|
|
39
45
|
else {
|
|
40
|
-
nodes.push(new AtRule({
|
|
46
|
+
nodes.push(new AtRule({
|
|
47
|
+
name: "layer",
|
|
48
|
+
params: "reset, base, components, utilities",
|
|
49
|
+
}));
|
|
41
50
|
}
|
|
42
51
|
}
|
|
43
52
|
catch (e) {
|
|
@@ -54,8 +63,14 @@ export function handleImport(atRule, context) {
|
|
|
54
63
|
// Add shared colors from theme.colors
|
|
55
64
|
if (theme.colors) {
|
|
56
65
|
for (const [name, color] of Object.entries(theme.colors)) {
|
|
57
|
-
rootRule.append(new Declaration({
|
|
58
|
-
|
|
66
|
+
rootRule.append(new Declaration({
|
|
67
|
+
prop: `--${name}-lightness`,
|
|
68
|
+
value: String(color.lightness),
|
|
69
|
+
}));
|
|
70
|
+
rootRule.append(new Declaration({
|
|
71
|
+
prop: `--${name}-chroma`,
|
|
72
|
+
value: String(color.chroma),
|
|
73
|
+
}));
|
|
59
74
|
rootRule.append(new Declaration({ prop: `--${name}-hue`, value: String(color.hue) }));
|
|
60
75
|
}
|
|
61
76
|
}
|
|
@@ -64,23 +79,38 @@ export function handleImport(atRule, context) {
|
|
|
64
79
|
const getPaletteDecls = (palette) => {
|
|
65
80
|
const decls = [];
|
|
66
81
|
if (palette.lightness !== undefined) {
|
|
67
|
-
decls.push(new Declaration({
|
|
82
|
+
decls.push(new Declaration({
|
|
83
|
+
prop: "--lightness",
|
|
84
|
+
value: String(palette.lightness),
|
|
85
|
+
}));
|
|
68
86
|
}
|
|
69
87
|
if (palette.chroma !== undefined) {
|
|
70
88
|
decls.push(new Declaration({ prop: "--chroma", value: String(palette.chroma) }));
|
|
71
89
|
}
|
|
72
90
|
// Standard background/text if they exist
|
|
73
91
|
if (palette.background) {
|
|
74
|
-
decls.push(new Declaration({
|
|
92
|
+
decls.push(new Declaration({
|
|
93
|
+
prop: "--background",
|
|
94
|
+
value: `oklch(${palette.background.lightness} ${palette.background.chroma} ${palette.background.hue})`,
|
|
95
|
+
}));
|
|
75
96
|
}
|
|
76
97
|
if (palette.text) {
|
|
77
|
-
decls.push(new Declaration({
|
|
98
|
+
decls.push(new Declaration({
|
|
99
|
+
prop: "--text",
|
|
100
|
+
value: `oklch(${palette.text.lightness} ${palette.text.chroma} ${palette.text.hue})`,
|
|
101
|
+
}));
|
|
78
102
|
}
|
|
79
103
|
if (palette.colors) {
|
|
80
104
|
for (const [name, color] of Object.entries(palette.colors)) {
|
|
81
105
|
const c = color;
|
|
82
|
-
decls.push(new Declaration({
|
|
83
|
-
|
|
106
|
+
decls.push(new Declaration({
|
|
107
|
+
prop: `--${name}-lightness`,
|
|
108
|
+
value: String(c.lightness),
|
|
109
|
+
}));
|
|
110
|
+
decls.push(new Declaration({
|
|
111
|
+
prop: `--${name}-chroma`,
|
|
112
|
+
value: String(c.chroma),
|
|
113
|
+
}));
|
|
84
114
|
decls.push(new Declaration({ prop: `--${name}-hue`, value: String(c.hue) }));
|
|
85
115
|
}
|
|
86
116
|
}
|
|
@@ -88,27 +118,40 @@ export function handleImport(atRule, context) {
|
|
|
88
118
|
};
|
|
89
119
|
// 3. Explicit Mode Selectors ([data-mode="..."])
|
|
90
120
|
if (theme.light) {
|
|
91
|
-
const lightRule = new Rule({
|
|
121
|
+
const lightRule = new Rule({
|
|
122
|
+
selector: `[${modeAttribute}="light"]`,
|
|
123
|
+
source: atRule.source,
|
|
124
|
+
});
|
|
92
125
|
lightRule.append(...getPaletteDecls(theme.light));
|
|
93
126
|
nodes.push(lightRule);
|
|
94
127
|
}
|
|
95
128
|
if (theme.dark) {
|
|
96
|
-
const darkRule = new Rule({
|
|
129
|
+
const darkRule = new Rule({
|
|
130
|
+
selector: `[${modeAttribute}="dark"]`,
|
|
131
|
+
source: atRule.source,
|
|
132
|
+
});
|
|
97
133
|
darkRule.append(...getPaletteDecls(theme.dark));
|
|
98
134
|
nodes.push(darkRule);
|
|
99
135
|
}
|
|
100
136
|
// 4. System Preference Support
|
|
101
137
|
const createSystemMedia = (scheme, palette) => {
|
|
102
|
-
const media = new AtRule({
|
|
103
|
-
|
|
138
|
+
const media = new AtRule({
|
|
139
|
+
name: "media",
|
|
140
|
+
params: `(prefers-color-scheme: ${scheme})`,
|
|
141
|
+
source: atRule.source,
|
|
142
|
+
});
|
|
143
|
+
const rule = new Rule({
|
|
144
|
+
selector: `[${modeAttribute}="system"]`,
|
|
145
|
+
source: atRule.source,
|
|
146
|
+
});
|
|
104
147
|
rule.append(...getPaletteDecls(palette));
|
|
105
148
|
media.append(rule);
|
|
106
149
|
return media;
|
|
107
150
|
};
|
|
108
151
|
if (theme.light)
|
|
109
|
-
nodes.push(createSystemMedia(
|
|
152
|
+
nodes.push(createSystemMedia("light", theme.light));
|
|
110
153
|
if (theme.dark)
|
|
111
|
-
nodes.push(createSystemMedia(
|
|
154
|
+
nodes.push(createSystemMedia("dark", theme.dark));
|
|
112
155
|
// Replace the @import rule with our generated CSS
|
|
113
156
|
atRule.replaceWith(...nodes);
|
|
114
157
|
}
|
package/dist/at-rules/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { handleConfig } from "./config.js";
|
|
|
7
7
|
// Ordered array ensures execution order
|
|
8
8
|
export const atRuleHandlers = [
|
|
9
9
|
{ name: "config", handler: handleConfig },
|
|
10
|
-
{ name: "
|
|
10
|
+
{ name: "seyuna", handler: handleImport },
|
|
11
11
|
{ name: "each-standard-color", handler: eachStandardColor },
|
|
12
12
|
{ name: "each-fixed-color", handler: eachFixedColor },
|
|
13
13
|
{ name: "light", handler: light },
|
package/package.json
CHANGED
package/src/at-rules/import.ts
CHANGED
|
@@ -15,9 +15,14 @@ const __dirname = path.dirname(__filename);
|
|
|
15
15
|
* Injects the core Seyuna Design System variables and base styles
|
|
16
16
|
*/
|
|
17
17
|
export function handleImport(atRule: any, context: PluginContext) {
|
|
18
|
-
|
|
18
|
+
// Support both @seyuna; and the previous @import "seyuna" logic
|
|
19
|
+
// Since this handler is now registered to @seyuna, we just check params or just run it.
|
|
20
|
+
const params = atRule.params.replace(/['"]/g, "").trim();
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
// If it's @seyuna; the params will be empty.
|
|
23
|
+
// If it's @import "seyuna", this handler wouldn't be called unless we kept the name "import".
|
|
24
|
+
// But we want this to run for @seyuna;
|
|
25
|
+
if (atRule.name === "seyuna") {
|
|
21
26
|
const { config, options } = context;
|
|
22
27
|
if (!config.ui) {
|
|
23
28
|
atRule.remove();
|
|
@@ -30,70 +35,124 @@ export function handleImport(atRule: any, context: PluginContext) {
|
|
|
30
35
|
|
|
31
36
|
// 1. Ingest Global Base Styles (Reset, Layers, etc.)
|
|
32
37
|
try {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
const globalStylesPath = path.resolve(
|
|
39
|
+
__dirname,
|
|
40
|
+
"../styles/seyuna-global.css",
|
|
41
|
+
);
|
|
42
|
+
if (fs.existsSync(globalStylesPath)) {
|
|
43
|
+
const globalCss = fs.readFileSync(globalStylesPath, "utf-8");
|
|
44
|
+
const cleanCss = globalCss.split("$")[0].trim();
|
|
45
|
+
const parsed = postcss.parse(cleanCss);
|
|
46
|
+
|
|
47
|
+
// Only keep layers and reset styles, avoid re-injecting variables
|
|
48
|
+
parsed.each((node) => {
|
|
49
|
+
if (
|
|
50
|
+
node.type === "atrule" &&
|
|
51
|
+
(node.name === "layer" || node.name === "media")
|
|
52
|
+
) {
|
|
53
|
+
nodes.push(node.clone());
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
nodes.push(
|
|
58
|
+
new AtRule({
|
|
59
|
+
name: "layer",
|
|
60
|
+
params: "reset, base, components, utilities",
|
|
61
|
+
}),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
48
64
|
} catch (e) {
|
|
49
|
-
|
|
65
|
+
console.warn("[Seyuna PostCSS] Could not load global base styles:", e);
|
|
50
66
|
}
|
|
51
67
|
|
|
52
68
|
// 2. Global Hues and Base Colors (:root)
|
|
53
69
|
const rootRule = new Rule({ selector: ":root", source: atRule.source });
|
|
54
|
-
|
|
70
|
+
|
|
55
71
|
// Process all hues from config
|
|
56
72
|
if (theme.hues) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
for (const [name, value] of Object.entries(theme.hues)) {
|
|
74
|
+
rootRule.append(
|
|
75
|
+
new Declaration({ prop: `--${name}-hue`, value: String(value) }),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
60
78
|
}
|
|
61
79
|
|
|
62
80
|
// Add shared colors from theme.colors
|
|
63
81
|
if (theme.colors) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
82
|
+
for (const [name, color] of Object.entries(theme.colors)) {
|
|
83
|
+
rootRule.append(
|
|
84
|
+
new Declaration({
|
|
85
|
+
prop: `--${name}-lightness`,
|
|
86
|
+
value: String(color.lightness),
|
|
87
|
+
}),
|
|
88
|
+
);
|
|
89
|
+
rootRule.append(
|
|
90
|
+
new Declaration({
|
|
91
|
+
prop: `--${name}-chroma`,
|
|
92
|
+
value: String(color.chroma),
|
|
93
|
+
}),
|
|
94
|
+
);
|
|
95
|
+
rootRule.append(
|
|
96
|
+
new Declaration({ prop: `--${name}-hue`, value: String(color.hue) }),
|
|
97
|
+
);
|
|
98
|
+
}
|
|
69
99
|
}
|
|
70
100
|
nodes.push(rootRule);
|
|
71
101
|
|
|
72
102
|
// Helper to generate palette declarations for a specific mode
|
|
73
103
|
const getPaletteDecls = (palette: any) => {
|
|
74
104
|
const decls: Declaration[] = [];
|
|
75
|
-
|
|
105
|
+
|
|
76
106
|
if (palette.lightness !== undefined) {
|
|
77
|
-
|
|
107
|
+
decls.push(
|
|
108
|
+
new Declaration({
|
|
109
|
+
prop: "--lightness",
|
|
110
|
+
value: String(palette.lightness),
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
78
113
|
}
|
|
79
114
|
if (palette.chroma !== undefined) {
|
|
80
|
-
|
|
115
|
+
decls.push(
|
|
116
|
+
new Declaration({ prop: "--chroma", value: String(palette.chroma) }),
|
|
117
|
+
);
|
|
81
118
|
}
|
|
82
119
|
|
|
83
120
|
// Standard background/text if they exist
|
|
84
121
|
if (palette.background) {
|
|
85
|
-
|
|
122
|
+
decls.push(
|
|
123
|
+
new Declaration({
|
|
124
|
+
prop: "--background",
|
|
125
|
+
value: `oklch(${palette.background.lightness} ${palette.background.chroma} ${palette.background.hue})`,
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
86
128
|
}
|
|
87
129
|
if (palette.text) {
|
|
88
|
-
|
|
130
|
+
decls.push(
|
|
131
|
+
new Declaration({
|
|
132
|
+
prop: "--text",
|
|
133
|
+
value: `oklch(${palette.text.lightness} ${palette.text.chroma} ${palette.text.hue})`,
|
|
134
|
+
}),
|
|
135
|
+
);
|
|
89
136
|
}
|
|
90
137
|
|
|
91
138
|
if (palette.colors) {
|
|
92
139
|
for (const [name, color] of Object.entries(palette.colors)) {
|
|
93
140
|
const c = color as any;
|
|
94
|
-
decls.push(
|
|
95
|
-
|
|
96
|
-
|
|
141
|
+
decls.push(
|
|
142
|
+
new Declaration({
|
|
143
|
+
prop: `--${name}-lightness`,
|
|
144
|
+
value: String(c.lightness),
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
decls.push(
|
|
148
|
+
new Declaration({
|
|
149
|
+
prop: `--${name}-chroma`,
|
|
150
|
+
value: String(c.chroma),
|
|
151
|
+
}),
|
|
152
|
+
);
|
|
153
|
+
decls.push(
|
|
154
|
+
new Declaration({ prop: `--${name}-hue`, value: String(c.hue) }),
|
|
155
|
+
);
|
|
97
156
|
}
|
|
98
157
|
}
|
|
99
158
|
return decls;
|
|
@@ -101,28 +160,41 @@ export function handleImport(atRule: any, context: PluginContext) {
|
|
|
101
160
|
|
|
102
161
|
// 3. Explicit Mode Selectors ([data-mode="..."])
|
|
103
162
|
if (theme.light) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
163
|
+
const lightRule = new Rule({
|
|
164
|
+
selector: `[${modeAttribute}="light"]`,
|
|
165
|
+
source: atRule.source,
|
|
166
|
+
});
|
|
167
|
+
lightRule.append(...getPaletteDecls(theme.light));
|
|
168
|
+
nodes.push(lightRule);
|
|
107
169
|
}
|
|
108
170
|
|
|
109
171
|
if (theme.dark) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
172
|
+
const darkRule = new Rule({
|
|
173
|
+
selector: `[${modeAttribute}="dark"]`,
|
|
174
|
+
source: atRule.source,
|
|
175
|
+
});
|
|
176
|
+
darkRule.append(...getPaletteDecls(theme.dark));
|
|
177
|
+
nodes.push(darkRule);
|
|
113
178
|
}
|
|
114
179
|
|
|
115
180
|
// 4. System Preference Support
|
|
116
|
-
const createSystemMedia = (scheme:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
181
|
+
const createSystemMedia = (scheme: "light" | "dark", palette: any) => {
|
|
182
|
+
const media = new AtRule({
|
|
183
|
+
name: "media",
|
|
184
|
+
params: `(prefers-color-scheme: ${scheme})`,
|
|
185
|
+
source: atRule.source,
|
|
186
|
+
});
|
|
187
|
+
const rule = new Rule({
|
|
188
|
+
selector: `[${modeAttribute}="system"]`,
|
|
189
|
+
source: atRule.source,
|
|
190
|
+
});
|
|
191
|
+
rule.append(...getPaletteDecls(palette));
|
|
192
|
+
media.append(rule);
|
|
193
|
+
return media;
|
|
122
194
|
};
|
|
123
195
|
|
|
124
|
-
if (theme.light) nodes.push(createSystemMedia(
|
|
125
|
-
if (theme.dark) nodes.push(createSystemMedia(
|
|
196
|
+
if (theme.light) nodes.push(createSystemMedia("light", theme.light));
|
|
197
|
+
if (theme.dark) nodes.push(createSystemMedia("dark", theme.dark));
|
|
126
198
|
|
|
127
199
|
// Replace the @import rule with our generated CSS
|
|
128
200
|
atRule.replaceWith(...nodes);
|
package/src/at-rules/index.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface AtRuleHandler {
|
|
|
15
15
|
// Ordered array ensures execution order
|
|
16
16
|
export const atRuleHandlers: AtRuleHandler[] = [
|
|
17
17
|
{ name: "config", handler: handleConfig },
|
|
18
|
-
{ name: "
|
|
18
|
+
{ name: "seyuna", handler: handleImport },
|
|
19
19
|
{ name: "each-standard-color", handler: eachStandardColor },
|
|
20
20
|
{ name: "each-fixed-color", handler: eachFixedColor },
|
|
21
21
|
{ name: "light", handler: light },
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
@layer reset, base, components, utilities;
|
|
2
|
+
|
|
3
|
+
@layer reset {
|
|
4
|
+
/*
|
|
5
|
+
Reset all elements to a zeroed baseline to ensure consistency in all browsers.
|
|
6
|
+
*/
|
|
7
|
+
*,
|
|
8
|
+
*::before,
|
|
9
|
+
*::after {
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
line-height: 2;
|
|
14
|
+
font-family: inherit;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
Prevent automatic font size adjustments on mobile devices to keep text rendering consistent across platforms.
|
|
19
|
+
*/
|
|
20
|
+
html {
|
|
21
|
+
-moz-text-size-adjust: none; /* Firefox */
|
|
22
|
+
-webkit-text-size-adjust: none; /* Safari / older WebKit browsers */
|
|
23
|
+
text-size-adjust: none; /* Modern spec-compliant browsers */
|
|
24
|
+
color: var(--text);
|
|
25
|
+
background-color: var(--background);
|
|
26
|
+
font-size: max(1rem, 0.833vw);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
Remove default list styling from unordered and ordered lists that
|
|
31
|
+
explicitly use role="list".
|
|
32
|
+
*/
|
|
33
|
+
ul[role="list"],
|
|
34
|
+
ol[role="list"] {
|
|
35
|
+
list-style: none;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
Ensure the body element always fills at least the full height of the viewport
|
|
40
|
+
so short pages don't collapse. Improve text rendering across browsers by
|
|
41
|
+
enabling smoother grayscale antialiasing. Set the body as a container
|
|
42
|
+
(queryable by its inline size) for use with CSS container queries, and
|
|
43
|
+
enable smooth scrolling for anchor links and programmatic scroll actions.
|
|
44
|
+
*/
|
|
45
|
+
body {
|
|
46
|
+
min-height: 100vh;
|
|
47
|
+
-webkit-font-smoothing: antialiased;
|
|
48
|
+
-moz-osx-font-smoothing: grayscale;
|
|
49
|
+
container-type: inline-size;
|
|
50
|
+
scroll-behavior: smooth;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
Improve heading readability by evenly distributing words across lines.
|
|
55
|
+
This prevents awkward line breaks and creates more balanced, aesthetic headings.
|
|
56
|
+
*/
|
|
57
|
+
h1,
|
|
58
|
+
h2,
|
|
59
|
+
h3,
|
|
60
|
+
h4,
|
|
61
|
+
h5,
|
|
62
|
+
h6 {
|
|
63
|
+
text-wrap: balance;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
Reset all link styles to inherit from parent elements.
|
|
68
|
+
This removes default colors, underlines, and visited/hover states.
|
|
69
|
+
*/
|
|
70
|
+
a {
|
|
71
|
+
all: unset;
|
|
72
|
+
color: inherit;
|
|
73
|
+
text-decoration: none;
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/*
|
|
78
|
+
Ensure images and <picture> elements scale within their container,
|
|
79
|
+
preventing overflow and maintaining layout integrity on any screen size.
|
|
80
|
+
*/
|
|
81
|
+
img,
|
|
82
|
+
picture {
|
|
83
|
+
max-width: 100%;
|
|
84
|
+
display: block;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
Add extra scroll margin above and below elements targeted via anchors.
|
|
89
|
+
This prevents the element from hugging the top edge of the viewport when navigated to.
|
|
90
|
+
*/
|
|
91
|
+
:target {
|
|
92
|
+
scroll-margin-block: 1rem;
|
|
93
|
+
}
|
|
94
|
+
}
|
package/tests/plugin.test.ts
CHANGED
|
@@ -132,8 +132,8 @@ describe("Seyuna PostCSS Plugin", () => {
|
|
|
132
132
|
expect(result.css).toContain(output);
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
-
it(
|
|
136
|
-
const input =
|
|
135
|
+
it("processes @seyuna;", async () => {
|
|
136
|
+
const input = "@seyuna;";
|
|
137
137
|
const result = await run(input, { config: mockConfig });
|
|
138
138
|
|
|
139
139
|
// Check for root variables (hues)
|
|
@@ -167,7 +167,7 @@ describe("Seyuna PostCSS Plugin", () => {
|
|
|
167
167
|
--color-brand: 0.5 0.2 100;
|
|
168
168
|
--light-lightness: 0.8;
|
|
169
169
|
}
|
|
170
|
-
@
|
|
170
|
+
@seyuna;
|
|
171
171
|
.test {
|
|
172
172
|
color: SeyunaStandardColor(custom);
|
|
173
173
|
background: SeyunaFixedColor(brand);
|
|
@@ -194,7 +194,7 @@ describe("Seyuna PostCSS Plugin", () => {
|
|
|
194
194
|
--color-brand: 0.5 0.2 100;
|
|
195
195
|
--light-color-brand: 1 0 100;
|
|
196
196
|
}
|
|
197
|
-
@
|
|
197
|
+
@seyuna;
|
|
198
198
|
`;
|
|
199
199
|
const result = await postcss([plugin({ config: undefined })]).process(
|
|
200
200
|
input,
|
|
@@ -209,4 +209,22 @@ describe("Seyuna PostCSS Plugin", () => {
|
|
|
209
209
|
expect(result.css).toContain('[data-mode="light"]');
|
|
210
210
|
expect(result.css).toContain("--brand-lightness: 1");
|
|
211
211
|
});
|
|
212
|
+
|
|
213
|
+
it("injects the CSS reset via @seyuna;", async () => {
|
|
214
|
+
const input = "@seyuna;";
|
|
215
|
+
const result = await run(input, { config: mockConfig });
|
|
216
|
+
|
|
217
|
+
// Verify layers
|
|
218
|
+
expect(result.css).toContain("@layer reset, base, components, utilities;");
|
|
219
|
+
expect(result.css).toContain("@layer reset {");
|
|
220
|
+
|
|
221
|
+
// Verify key reset properties
|
|
222
|
+
expect(result.css).toContain("box-sizing: border-box;");
|
|
223
|
+
expect(result.css).toContain("-webkit-text-size-adjust: none;");
|
|
224
|
+
expect(result.css).toContain("text-size-adjust: none;");
|
|
225
|
+
expect(result.css).toContain("container-type: inline-size;");
|
|
226
|
+
expect(result.css).toContain("text-wrap: balance;");
|
|
227
|
+
expect(result.css).toContain("all: unset;");
|
|
228
|
+
expect(result.css).toContain("scroll-margin-block: 1rem;");
|
|
229
|
+
});
|
|
212
230
|
});
|