@seyuna/postcss 1.0.0-canary.25 → 1.0.0-canary.27

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 CHANGED
@@ -1,3 +1,17 @@
1
+ # [1.0.0-canary.27](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.26...v1.0.0-canary.27) (2026-01-20)
2
+
3
+
4
+ ### Features
5
+
6
+ * implement [@import](https://github.com/import) 'seyuna' to replicate CLI behavior ([db3a3ff](https://github.com/seyuna-corp/seyuna-postcss/commit/db3a3fff3664b435840e7421d9b99262dfd31953))
7
+
8
+ # [1.0.0-canary.26](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.25...v1.0.0-canary.26) (2026-01-11)
9
+
10
+
11
+ ### Features
12
+
13
+ * trigger major release\n\nBREAKING CHANGE: rename and prefix all custom CSS functions with Seyuna to avoid conflicts with native CSS functions. ([3a50bca](https://github.com/seyuna-corp/seyuna-postcss/commit/3a50bcafa89d0c3e21e2b9d1acc879458d9b25aa))
14
+
1
15
  # [1.0.0-canary.25](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.24...v1.0.0-canary.25) (2026-01-10)
2
16
 
3
17
 
@@ -0,0 +1,6 @@
1
+ import { PluginContext } from "../types.js";
2
+ /**
3
+ * Handler for @import "seyuna"
4
+ * Injects the core Seyuna Design System variables and base styles
5
+ */
6
+ export declare function handleImport(atRule: any, context: PluginContext): void;
@@ -0,0 +1,120 @@
1
+ import Rule from "postcss/lib/rule";
2
+ import Declaration from "postcss/lib/declaration";
3
+ import AtRule from "postcss/lib/at-rule";
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import { fileURLToPath } from "url";
7
+ import postcss from "postcss";
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+ const STANDARD_HUES = [
11
+ 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon', 'phi', 'chi', 'psi', 'omega'
12
+ ];
13
+ /**
14
+ * Handler for @import "seyuna"
15
+ * Injects the core Seyuna Design System variables and base styles
16
+ */
17
+ export function handleImport(atRule, context) {
18
+ const params = atRule.params.replace(/['"]/g, "");
19
+ if (params === "seyuna") {
20
+ const { config, options } = context;
21
+ if (!config.ui) {
22
+ atRule.remove();
23
+ return;
24
+ }
25
+ const { theme } = config.ui;
26
+ const modeAttribute = options.modeAttribute;
27
+ const nodes = [];
28
+ // 1. Ingest Global Base Styles (Reset, Layers, etc.)
29
+ try {
30
+ const globalStylesPath = path.resolve(__dirname, "../styles/seyuna-global.css");
31
+ if (fs.existsSync(globalStylesPath)) {
32
+ const globalCss = fs.readFileSync(globalStylesPath, "utf-8");
33
+ const cleanCss = globalCss.split('$')[0].trim();
34
+ const parsed = postcss.parse(cleanCss);
35
+ // Only keep layers and reset styles, avoid re-injecting variables
36
+ parsed.each((node) => {
37
+ if (node.type === 'atrule' && (node.name === 'layer' || node.name === 'media')) {
38
+ nodes.push(node.clone());
39
+ }
40
+ });
41
+ }
42
+ else {
43
+ nodes.push(new AtRule({ name: "layer", params: "reset, base, components, utilities" }));
44
+ }
45
+ }
46
+ catch (e) {
47
+ console.warn("[Seyuna PostCSS] Could not load global base styles:", e);
48
+ }
49
+ // 2. Global Hues and Base Colors (:root)
50
+ const rootRule = new Rule({ selector: ":root", source: atRule.source });
51
+ // Process all hues from config plus defaults
52
+ const allHues = new Set([...STANDARD_HUES, ...Object.keys(theme.hues || {})]);
53
+ allHues.forEach((name) => {
54
+ const i = STANDARD_HUES.indexOf(name);
55
+ const defaultValue = i !== -1 ? i * 15 : 0;
56
+ const value = (theme.hues && theme.hues[name] !== undefined) ? theme.hues[name] : defaultValue;
57
+ rootRule.append(new Declaration({ prop: `--${name}-hue`, value: String(value) }));
58
+ });
59
+ // Add shared colors from theme.colors
60
+ if (theme.colors) {
61
+ for (const [name, color] of Object.entries(theme.colors)) {
62
+ rootRule.append(new Declaration({ prop: `--${name}-lightness`, value: String(color.lightness) }));
63
+ rootRule.append(new Declaration({ prop: `--${name}-chroma`, value: String(color.chroma) }));
64
+ rootRule.append(new Declaration({ prop: `--${name}-hue`, value: String(color.hue) }));
65
+ }
66
+ }
67
+ nodes.push(rootRule);
68
+ // Helper to generate palette declarations for a specific mode
69
+ const getPaletteDecls = (palette) => {
70
+ const decls = [];
71
+ if (palette.lightness !== undefined) {
72
+ decls.push(new Declaration({ prop: "--lightness", value: String(palette.lightness) }));
73
+ }
74
+ if (palette.chroma !== undefined) {
75
+ decls.push(new Declaration({ prop: "--chroma", value: String(palette.chroma) }));
76
+ }
77
+ // Standard background/text if they exist
78
+ if (palette.background) {
79
+ decls.push(new Declaration({ prop: "--background", value: `oklch(${palette.background.lightness} ${palette.background.chroma} ${palette.background.hue})` }));
80
+ }
81
+ if (palette.text) {
82
+ decls.push(new Declaration({ prop: "--text", value: `oklch(${palette.text.lightness} ${palette.text.chroma} ${palette.text.hue})` }));
83
+ }
84
+ if (palette.colors) {
85
+ for (const [name, color] of Object.entries(palette.colors)) {
86
+ const c = color;
87
+ decls.push(new Declaration({ prop: `--${name}-lightness`, value: String(c.lightness) }));
88
+ decls.push(new Declaration({ prop: `--${name}-chroma`, value: String(c.chroma) }));
89
+ decls.push(new Declaration({ prop: `--${name}-hue`, value: String(c.hue) }));
90
+ }
91
+ }
92
+ return decls;
93
+ };
94
+ // 3. Explicit Mode Selectors ([data-mode="..."])
95
+ if (theme.light) {
96
+ const lightRule = new Rule({ selector: `[${modeAttribute}="light"]`, source: atRule.source });
97
+ lightRule.append(...getPaletteDecls(theme.light));
98
+ nodes.push(lightRule);
99
+ }
100
+ if (theme.dark) {
101
+ const darkRule = new Rule({ selector: `[${modeAttribute}="dark"]`, source: atRule.source });
102
+ darkRule.append(...getPaletteDecls(theme.dark));
103
+ nodes.push(darkRule);
104
+ }
105
+ // 4. System Preference Support
106
+ const createSystemMedia = (scheme, palette) => {
107
+ const media = new AtRule({ name: "media", params: `(prefers-color-scheme: ${scheme})`, source: atRule.source });
108
+ const rule = new Rule({ selector: `[${modeAttribute}="system"]`, source: atRule.source });
109
+ rule.append(...getPaletteDecls(palette));
110
+ media.append(rule);
111
+ return media;
112
+ };
113
+ if (theme.light)
114
+ nodes.push(createSystemMedia('light', theme.light));
115
+ if (theme.dark)
116
+ nodes.push(createSystemMedia('dark', theme.dark));
117
+ // Replace the @import rule with our generated CSS
118
+ atRule.replaceWith(...nodes);
119
+ }
120
+ }
@@ -2,8 +2,10 @@
2
2
  import { eachStandardColor, eachFixedColor } from "./color.js";
3
3
  import container from "./container.js";
4
4
  import { light, dark } from "./color-scheme.js";
5
+ import { handleImport } from "./import.js";
5
6
  // Ordered array ensures execution order
6
7
  export const atRuleHandlers = [
8
+ { name: "import", handler: handleImport },
7
9
  { name: "each-standard-color", handler: eachStandardColor },
8
10
  { name: "each-fixed-color", handler: eachFixedColor },
9
11
  { name: "light", handler: light },
@@ -1,7 +1,7 @@
1
1
  import { PluginContext } from "../types.js";
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;
2
+ export declare function SeyunaStandardColor(context: PluginContext, name: string, alpha?: string, lightness?: string, chroma?: string): string;
3
+ export declare function SeyunaFixedColor(context: PluginContext, name: string, alpha?: string, lightness?: string, chroma?: string): string;
4
+ export declare function SeyunaAlpha(context: PluginContext, color: string, value: string): string;
5
+ export declare function SeyunaLighten(context: PluginContext, color: string, amount: string): string;
6
+ export declare function SeyunaDarken(context: PluginContext, color: string, amount: string): string;
7
+ export declare function SeyunaContrast(context: PluginContext, color: string): string;
@@ -31,33 +31,33 @@ function getColorVariables(context, color, type) {
31
31
  }
32
32
  throw new Error(`Color '${color}' not found in seyuna.json`);
33
33
  }
34
- export function sc(context, name, alpha, lightness, chroma) {
34
+ export function SeyunaStandardColor(context, name, alpha, lightness, chroma) {
35
35
  const vars = getColorVariables(context, name, 'sc');
36
36
  const a = alpha && alpha !== "null" ? alpha : "1";
37
37
  const l = lightness && lightness !== "null" ? lightness : vars.l;
38
38
  const c = chroma && chroma !== "null" ? chroma : vars.c;
39
39
  return `oklch(${l} ${c} ${vars.h} / ${a})`;
40
40
  }
41
- export function fc(context, name, alpha, lightness, chroma) {
41
+ export function SeyunaFixedColor(context, name, alpha, lightness, chroma) {
42
42
  const vars = getColorVariables(context, name, 'fc');
43
43
  const a = alpha && alpha !== "null" ? alpha : "1";
44
44
  const l = lightness && lightness !== "null" ? lightness : vars.l;
45
45
  const c = chroma && chroma !== "null" ? chroma : vars.c;
46
46
  return `oklch(${l} ${c} ${vars.h} / ${a})`;
47
47
  }
48
- export function alpha(context, color, value) {
48
+ export function SeyunaAlpha(context, color, value) {
49
49
  const { l, c, h } = getColorVariables(context, color);
50
50
  return `oklch(${l} ${c} ${h} / ${value})`;
51
51
  }
52
- export function lighten(context, color, amount) {
52
+ export function SeyunaLighten(context, color, amount) {
53
53
  const { l, c, h } = getColorVariables(context, color);
54
54
  return `oklch(calc(${l} + ${amount}) ${c} ${h} / 1)`;
55
55
  }
56
- export function darken(context, color, amount) {
56
+ export function SeyunaDarken(context, color, amount) {
57
57
  const { l, c, h } = getColorVariables(context, color);
58
58
  return `oklch(calc(${l} - ${amount}) ${c} ${h} / 1)`;
59
59
  }
60
- export function contrast(context, color) {
60
+ export function SeyunaContrast(context, color) {
61
61
  const { l } = getColorVariables(context, color);
62
62
  return `oklch(calc((${l} - 0.6) * -1000) 0 0)`;
63
63
  }
@@ -1,11 +1,11 @@
1
- import { sc, fc, alpha, lighten, darken, contrast } from "./color.js";
2
- import { theme } from "./theme.js";
1
+ import { SeyunaStandardColor, SeyunaFixedColor, SeyunaAlpha, SeyunaLighten, SeyunaDarken, SeyunaContrast, } from "./color.js";
2
+ import { SeyunaTheme } from "./theme.js";
3
3
  export const functions = {
4
- sc,
5
- fc,
6
- alpha,
7
- lighten,
8
- darken,
9
- contrast,
10
- theme,
4
+ SeyunaStandardColor,
5
+ SeyunaFixedColor,
6
+ SeyunaAlpha,
7
+ SeyunaLighten,
8
+ SeyunaDarken,
9
+ SeyunaContrast,
10
+ SeyunaTheme,
11
11
  };
@@ -3,4 +3,4 @@ import { PluginContext } from "../types.js";
3
3
  * Accesses values from the Seyuna configuration using dot notation
4
4
  * Example: theme(ui.theme.breakpoints.tablet)
5
5
  */
6
- export declare function theme(context: PluginContext, path: string): string;
6
+ export declare function SeyunaTheme(context: PluginContext, path: string): string;
@@ -2,7 +2,7 @@
2
2
  * Accesses values from the Seyuna configuration using dot notation
3
3
  * Example: theme(ui.theme.breakpoints.tablet)
4
4
  */
5
- export function theme(context, path) {
5
+ export function SeyunaTheme(context, path) {
6
6
  const parts = path.split('.');
7
7
  let current = context.config;
8
8
  for (const part of parts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seyuna/postcss",
3
- "version": "1.0.0-canary.25",
3
+ "version": "1.0.0-canary.27",
4
4
  "description": "Seyuna UI's postcss plugin",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,136 @@
1
+ import Rule from "postcss/lib/rule";
2
+ import Declaration from "postcss/lib/declaration";
3
+ import AtRule from "postcss/lib/at-rule";
4
+ import { PluginContext } from "../types.js";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import { fileURLToPath } from "url";
8
+ import postcss from "postcss";
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ const STANDARD_HUES = [
14
+ 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon', 'phi', 'chi', 'psi', 'omega'
15
+ ];
16
+
17
+ /**
18
+ * Handler for @import "seyuna"
19
+ * Injects the core Seyuna Design System variables and base styles
20
+ */
21
+ export function handleImport(atRule: any, context: PluginContext) {
22
+ const params = atRule.params.replace(/['"]/g, "");
23
+
24
+ if (params === "seyuna") {
25
+ const { config, options } = context;
26
+ if (!config.ui) {
27
+ atRule.remove();
28
+ return;
29
+ }
30
+
31
+ const { theme } = config.ui;
32
+ const modeAttribute = options.modeAttribute;
33
+ const nodes: any[] = [];
34
+
35
+ // 1. Ingest Global Base Styles (Reset, Layers, etc.)
36
+ try {
37
+ const globalStylesPath = path.resolve(__dirname, "../styles/seyuna-global.css");
38
+ if (fs.existsSync(globalStylesPath)) {
39
+ const globalCss = fs.readFileSync(globalStylesPath, "utf-8");
40
+ const cleanCss = globalCss.split('$')[0].trim();
41
+ const parsed = postcss.parse(cleanCss);
42
+
43
+ // Only keep layers and reset styles, avoid re-injecting variables
44
+ parsed.each((node) => {
45
+ if (node.type === 'atrule' && (node.name === 'layer' || node.name === 'media')) {
46
+ nodes.push(node.clone());
47
+ }
48
+ });
49
+ } else {
50
+ nodes.push(new AtRule({ name: "layer", params: "reset, base, components, utilities" }));
51
+ }
52
+ } catch (e) {
53
+ console.warn("[Seyuna PostCSS] Could not load global base styles:", e);
54
+ }
55
+
56
+ // 2. Global Hues and Base Colors (:root)
57
+ const rootRule = new Rule({ selector: ":root", source: atRule.source });
58
+
59
+ // Process all hues from config plus defaults
60
+ const allHues = new Set([...STANDARD_HUES, ...Object.keys(theme.hues || {})]);
61
+ allHues.forEach((name) => {
62
+ const i = STANDARD_HUES.indexOf(name);
63
+ const defaultValue = i !== -1 ? i * 15 : 0;
64
+ const value = (theme.hues && theme.hues[name] !== undefined) ? theme.hues[name] : defaultValue;
65
+ rootRule.append(new Declaration({ prop: `--${name}-hue`, value: String(value) }));
66
+ });
67
+
68
+ // Add shared colors from theme.colors
69
+ if (theme.colors) {
70
+ for (const [name, color] of Object.entries(theme.colors)) {
71
+ rootRule.append(new Declaration({ prop: `--${name}-lightness`, value: String(color.lightness) }));
72
+ rootRule.append(new Declaration({ prop: `--${name}-chroma`, value: String(color.chroma) }));
73
+ rootRule.append(new Declaration({ prop: `--${name}-hue`, value: String(color.hue) }));
74
+ }
75
+ }
76
+ nodes.push(rootRule);
77
+
78
+ // Helper to generate palette declarations for a specific mode
79
+ const getPaletteDecls = (palette: any) => {
80
+ const decls: Declaration[] = [];
81
+
82
+ if (palette.lightness !== undefined) {
83
+ decls.push(new Declaration({ prop: "--lightness", value: String(palette.lightness) }));
84
+ }
85
+ if (palette.chroma !== undefined) {
86
+ decls.push(new Declaration({ prop: "--chroma", value: String(palette.chroma) }));
87
+ }
88
+
89
+ // Standard background/text if they exist
90
+ if (palette.background) {
91
+ decls.push(new Declaration({ prop: "--background", value: `oklch(${palette.background.lightness} ${palette.background.chroma} ${palette.background.hue})` }));
92
+ }
93
+ if (palette.text) {
94
+ decls.push(new Declaration({ prop: "--text", value: `oklch(${palette.text.lightness} ${palette.text.chroma} ${palette.text.hue})` }));
95
+ }
96
+
97
+ if (palette.colors) {
98
+ for (const [name, color] of Object.entries(palette.colors)) {
99
+ const c = color as any;
100
+ decls.push(new Declaration({ prop: `--${name}-lightness`, value: String(c.lightness) }));
101
+ decls.push(new Declaration({ prop: `--${name}-chroma`, value: String(c.chroma) }));
102
+ decls.push(new Declaration({ prop: `--${name}-hue`, value: String(c.hue) }));
103
+ }
104
+ }
105
+ return decls;
106
+ };
107
+
108
+ // 3. Explicit Mode Selectors ([data-mode="..."])
109
+ if (theme.light) {
110
+ const lightRule = new Rule({ selector: `[${modeAttribute}="light"]`, source: atRule.source });
111
+ lightRule.append(...getPaletteDecls(theme.light));
112
+ nodes.push(lightRule);
113
+ }
114
+
115
+ if (theme.dark) {
116
+ const darkRule = new Rule({ selector: `[${modeAttribute}="dark"]`, source: atRule.source });
117
+ darkRule.append(...getPaletteDecls(theme.dark));
118
+ nodes.push(darkRule);
119
+ }
120
+
121
+ // 4. System Preference Support
122
+ const createSystemMedia = (scheme: 'light' | 'dark', palette: any) => {
123
+ const media = new AtRule({ name: "media", params: `(prefers-color-scheme: ${scheme})`, source: atRule.source });
124
+ const rule = new Rule({ selector: `[${modeAttribute}="system"]`, source: atRule.source });
125
+ rule.append(...getPaletteDecls(palette));
126
+ media.append(rule);
127
+ return media;
128
+ };
129
+
130
+ if (theme.light) nodes.push(createSystemMedia('light', theme.light));
131
+ if (theme.dark) nodes.push(createSystemMedia('dark', theme.dark));
132
+
133
+ // Replace the @import rule with our generated CSS
134
+ atRule.replaceWith(...nodes);
135
+ }
136
+ }
@@ -2,6 +2,7 @@
2
2
  import { eachStandardColor, eachFixedColor } from "./color.js";
3
3
  import container from "./container.js";
4
4
  import { light, dark } from "./color-scheme.js";
5
+ import { handleImport } from "./import.js";
5
6
  import { PluginContext } from "../types.js";
6
7
 
7
8
  // Each handler has a name (matches the at-rule) and the function
@@ -12,6 +13,7 @@ export interface AtRuleHandler {
12
13
 
13
14
  // Ordered array ensures execution order
14
15
  export const atRuleHandlers: AtRuleHandler[] = [
16
+ { name: "import", handler: handleImport },
15
17
  { name: "each-standard-color", handler: eachStandardColor },
16
18
  { name: "each-fixed-color", handler: eachFixedColor },
17
19
  { name: "light", handler: light },
@@ -39,7 +39,7 @@ function getColorVariables(context: PluginContext, color: string, type?: 'sc' |
39
39
  throw new Error(`Color '${color}' not found in seyuna.json`);
40
40
  }
41
41
 
42
- export function sc(
42
+ export function SeyunaStandardColor(
43
43
  context: PluginContext,
44
44
  name: string,
45
45
  alpha?: string,
@@ -54,7 +54,7 @@ export function sc(
54
54
  return `oklch(${l} ${c} ${vars.h} / ${a})`;
55
55
  }
56
56
 
57
- export function fc(
57
+ export function SeyunaFixedColor(
58
58
  context: PluginContext,
59
59
  name: string,
60
60
  alpha?: string,
@@ -69,22 +69,22 @@ export function fc(
69
69
  return `oklch(${l} ${c} ${vars.h} / ${a})`;
70
70
  }
71
71
 
72
- export function alpha(context: PluginContext, color: string, value: string) {
72
+ export function SeyunaAlpha(context: PluginContext, color: string, value: string) {
73
73
  const { l, c, h } = getColorVariables(context, color);
74
74
  return `oklch(${l} ${c} ${h} / ${value})`;
75
75
  }
76
76
 
77
- export function lighten(context: PluginContext, color: string, amount: string) {
77
+ export function SeyunaLighten(context: PluginContext, color: string, amount: string) {
78
78
  const { l, c, h } = getColorVariables(context, color);
79
79
  return `oklch(calc(${l} + ${amount}) ${c} ${h} / 1)`;
80
80
  }
81
81
 
82
- export function darken(context: PluginContext, color: string, amount: string) {
82
+ export function SeyunaDarken(context: PluginContext, color: string, amount: string) {
83
83
  const { l, c, h } = getColorVariables(context, color);
84
84
  return `oklch(calc(${l} - ${amount}) ${c} ${h} / 1)`;
85
85
  }
86
86
 
87
- export function contrast(context: PluginContext, color: string) {
87
+ export function SeyunaContrast(context: PluginContext, color: string) {
88
88
  const { l } = getColorVariables(context, color);
89
89
  return `oklch(calc((${l} - 0.6) * -1000) 0 0)`;
90
90
  }
@@ -1,15 +1,22 @@
1
- import { sc, fc, alpha, lighten, darken, contrast } from "./color.js";
2
- import { theme } from "./theme.js";
1
+ import {
2
+ SeyunaStandardColor,
3
+ SeyunaFixedColor,
4
+ SeyunaAlpha,
5
+ SeyunaLighten,
6
+ SeyunaDarken,
7
+ SeyunaContrast,
8
+ } from "./color.js";
9
+ import { SeyunaTheme } from "./theme.js";
3
10
  import { PluginContext } from "../types.js";
4
11
 
5
12
  export type FnHandler = (context: PluginContext, ...args: string[]) => string;
6
13
 
7
14
  export const functions: Record<string, FnHandler> = {
8
- sc,
9
- fc,
10
- alpha,
11
- lighten,
12
- darken,
13
- contrast,
14
- theme,
15
+ SeyunaStandardColor,
16
+ SeyunaFixedColor,
17
+ SeyunaAlpha,
18
+ SeyunaLighten,
19
+ SeyunaDarken,
20
+ SeyunaContrast,
21
+ SeyunaTheme,
15
22
  };
@@ -4,7 +4,7 @@ import { PluginContext } from "../types.js";
4
4
  * Accesses values from the Seyuna configuration using dot notation
5
5
  * Example: theme(ui.theme.breakpoints.tablet)
6
6
  */
7
- export function theme(context: PluginContext, path: string): string {
7
+ export function SeyunaTheme(context: PluginContext, path: string): string {
8
8
  const parts = path.split('.');
9
9
  let current: any = context.config;
10
10
 
@@ -38,44 +38,44 @@ async function run(input: string, opts: any = {}) {
38
38
  }
39
39
 
40
40
  describe('Seyuna PostCSS Plugin', () => {
41
- it('processes sc() function', async () => {
42
- const input = '.test { color: sc(primary); }';
41
+ it('processes SeyunaStandardColor() function', async () => {
42
+ const input = '.test { color: SeyunaStandardColor(primary); }';
43
43
  const output = '.test { color: oklch(var(--lightness) var(--chroma) var(--primary-hue) / 1)';
44
44
  const result = await run(input);
45
45
  expect(result.css).toContain(output);
46
46
  });
47
47
 
48
- it('processes sc() with alpha', async () => {
49
- const input = '.test { color: sc(primary, 0.5); }';
48
+ it('processes SeyunaStandardColor() with alpha', async () => {
49
+ const input = '.test { color: SeyunaStandardColor(primary, 0.5); }';
50
50
  const output = '.test { color: oklch(var(--lightness) var(--chroma) var(--primary-hue) / 0.5)';
51
51
  const result = await run(input);
52
52
  expect(result.css).toContain(output);
53
53
  });
54
54
 
55
- it('processes alpha() function with color name', async () => {
56
- const input = '.test { color: alpha(primary, 0.5); }';
55
+ it('processes SeyunaAlpha() function with color name', async () => {
56
+ const input = '.test { color: SeyunaAlpha(primary, 0.5); }';
57
57
  const output = 'color: oklch(var(--lightness) var(--chroma) var(--primary-hue) / 0.5)';
58
58
  const result = await run(input);
59
59
  expect(result.css).toContain(output);
60
60
  });
61
61
 
62
- it('processes lighten() function with color name', async () => {
63
- const input = '.test { color: lighten(primary, 0.1); }';
62
+ it('processes SeyunaLighten() function with color name', async () => {
63
+ const input = '.test { color: SeyunaLighten(primary, 0.1); }';
64
64
  const output = 'color: oklch(calc(var(--lightness) + 0.1) var(--chroma) var(--primary-hue) / 1)';
65
65
  const result = await run(input);
66
66
  expect(result.css).toContain(output);
67
67
  });
68
68
 
69
- it('processes darken() function with color name', async () => {
70
- const input = '.test { color: darken(primary, 0.1); }';
69
+ it('processes SeyunaDarken() function with color name', async () => {
70
+ const input = '.test { color: SeyunaDarken(primary, 0.1); }';
71
71
  const output = 'color: oklch(calc(var(--lightness) - 0.1) var(--chroma) var(--primary-hue) / 1)';
72
72
  const result = await run(input);
73
73
  expect(result.css).toContain(output);
74
74
  });
75
75
 
76
- it('processes theme() function', async () => {
76
+ it('processes SeyunaTheme() function', async () => {
77
77
  // We pass the config via opts for testing
78
- const input = '.test { border-radius: theme(ui.theme.breakpoints.tablet); }';
78
+ const input = '.test { border-radius: SeyunaTheme(ui.theme.breakpoints.tablet); }';
79
79
  const result = await run(input, { config: mockConfig });
80
80
  expect(result.css).toContain('.test { border-radius: 48rem');
81
81
  });
@@ -95,49 +95,76 @@ describe('Seyuna PostCSS Plugin', () => {
95
95
  expect(result.css).toContain('[data-mode="light"] &');
96
96
  });
97
97
 
98
- it('processes alpha() with standard color', async () => {
99
- const input = '.test { color: alpha(primary, 0.5); }';
98
+ it('processes SeyunaAlpha() with standard color', async () => {
99
+ const input = '.test { color: SeyunaAlpha(primary, 0.5); }';
100
100
  const output = 'color: oklch(var(--lightness) var(--chroma) var(--primary-hue) / 0.5)';
101
101
  const result = await run(input, { config: mockConfig });
102
102
  expect(result.css).toContain(output);
103
103
  });
104
104
 
105
- it('processes alpha() with fixed color', async () => {
106
- const input = '.test { color: alpha(surface, 0.5); }';
105
+ it('processes SeyunaAlpha() with fixed color', async () => {
106
+ const input = '.test { color: SeyunaAlpha(surface, 0.5); }';
107
107
  const output = 'color: oklch(var(--surface-lightness) var(--surface-chroma) var(--surface-hue) / 0.5)';
108
108
  const result = await run(input, { config: mockConfig });
109
109
  expect(result.css).toContain(output);
110
110
  });
111
111
 
112
- it('processes contrast() with fixed color', async () => {
113
- const input = '.test { color: contrast(surface); }';
112
+ it('processes SeyunaContrast() with fixed color', async () => {
113
+ const input = '.test { color: SeyunaContrast(surface); }';
114
114
  const output = 'color: oklch(calc((var(--surface-lightness) - 0.6) * -1000) 0 0)';
115
115
  const result = await run(input, { config: mockConfig });
116
116
  expect(result.css).toContain(output);
117
117
  });
118
118
 
119
- it('processes contrast() with standard color', async () => {
120
- const input = '.test { color: contrast(primary); }';
119
+ it('processes SeyunaContrast() with standard color', async () => {
120
+ const input = '.test { color: SeyunaContrast(primary); }';
121
121
  const output = 'color: oklch(calc((var(--lightness) - 0.6) * -1000) 0 0)';
122
122
  const result = await run(input, { config: mockConfig });
123
123
  expect(result.css).toContain(output);
124
124
  });
125
125
 
126
126
  it('throws error for unknown standard color in strict mode', async () => {
127
- const input = '.test { color: sc(unknown); }';
127
+ const input = '.test { color: SeyunaStandardColor(unknown); }';
128
128
  await expect(run(input, { config: mockConfig, strict: true }))
129
129
  .rejects.toThrow(/Standard color 'unknown' not found/);
130
130
  });
131
131
 
132
132
  it('throws error for unknown fixed color in strict mode', async () => {
133
- const input = '.test { color: fc(unknown); }';
133
+ const input = '.test { color: SeyunaFixedColor(unknown); }';
134
134
  await expect(run(input, { config: mockConfig, strict: true }))
135
135
  .rejects.toThrow(/Fixed color 'unknown' not found/);
136
136
  });
137
137
 
138
- it('throws error for unknown color in alpha() in strict mode', async () => {
139
- const input = '.test { color: alpha(unknown, 0.5); }';
138
+ it('throws error for unknown color in SeyunaAlpha() in strict mode', async () => {
139
+ const input = '.test { color: SeyunaAlpha(unknown, 0.5); }';
140
140
  await expect(run(input, { config: mockConfig, strict: true }))
141
141
  .rejects.toThrow(/Color 'unknown' not found in seyuna.json/);
142
142
  });
143
+
144
+ it('processes @import "seyuna"', async () => {
145
+ const input = '@import "seyuna";';
146
+ const result = await run(input, { config: mockConfig });
147
+
148
+ // Check for root variables (hues)
149
+ expect(result.css).toContain(':root');
150
+ expect(result.css).toContain('--alpha-hue: 0');
151
+ expect(result.css).toContain('--omega-hue: 345');
152
+ expect(result.css).toContain('--primary-hue: 200'); // Override from mockConfig
153
+
154
+ // Check for mode selectors
155
+ expect(result.css).toContain('[data-mode="light"]');
156
+ expect(result.css).toContain('[data-mode="dark"]');
157
+ expect(result.css).toContain('--lightness: 0.66');
158
+
159
+ // Check for system preference media queries
160
+ expect(result.css).toContain('@media (prefers-color-scheme: light)');
161
+ expect(result.css).toContain('@media (prefers-color-scheme: dark)');
162
+
163
+ // Check for base styles (reset)
164
+ expect(result.css).toContain('@layer reset');
165
+ expect(result.css).toContain('-webkit-text-size-adjust: none');
166
+
167
+ // Check for palette colors
168
+ expect(result.css).toContain('--surface-lightness: 1');
169
+ });
143
170
  });