@seyuna/postcss 1.0.0-canary.30 → 1.0.0-canary.32
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 +10 -2
- package/dist/config.js +56 -24
- package/dist/functions/color.js +21 -13
- package/package.json +1 -1
- package/src/config.ts +58 -24
- package/src/functions/color.ts +46 -22
- package/tests/plugin.test.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [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
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* remove color validation to support multi-file CSS processing ([9c6f906](https://github.com/seyuna-corp/seyuna-postcss/commit/9c6f9064ff0a0895506ea95e3a5025523b09271d))
|
|
7
|
+
|
|
8
|
+
# [1.0.0-canary.31](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.30...v1.0.0-canary.31) (2026-01-21)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add 24 default Greek alphabet-based hues ([e6fd8f8](https://github.com/seyuna-corp/seyuna-postcss/commit/e6fd8f8d0c59c8e204c36809a116bb84816ff165))
|
|
14
|
+
|
|
1
15
|
# [1.0.0-canary.30](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.29...v1.0.0-canary.30) (2026-01-21)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -157,13 +157,21 @@ Seyuna operates entirely in the **OKLCH color space**.
|
|
|
157
157
|
|
|
158
158
|
Standard colors define only a hue angle in the config and inherit theme lightness.
|
|
159
159
|
|
|
160
|
+
### Default Hues
|
|
161
|
+
|
|
162
|
+
Seyuna comes with 24 default hues based on the Greek alphabet, spaced evenly at 15-degree increments:
|
|
163
|
+
|
|
164
|
+
`alpha (15)`, `beta (30)`, `gamma (45)`, `delta (60)`, `epsilon (75)`, `zeta (90)`, `eta (105)`, `theta (120)`, `iota (135)`, `kappa (150)`, `lambda (165)`, `mu (180)`, `nu (195)`, `xi (210)`, `omicron (225)`, `pi (240)`, `rho (255)`, `sigma (270)`, `tau (285)`, `upsilon (300)`, `phi (315)`, `chi (330)`, `psi (345)`, `omega (360)`.
|
|
165
|
+
|
|
166
|
+
You can use these directly without configuration, or override them in the `@config` block.
|
|
167
|
+
|
|
160
168
|
```css
|
|
161
169
|
@config "seyuna" {
|
|
162
|
-
--hue-
|
|
170
|
+
--hue-alpha: 200; /* Override default Alpha hue */
|
|
163
171
|
}
|
|
164
172
|
|
|
165
173
|
.badge {
|
|
166
|
-
background: SeyunaStandardColor(
|
|
174
|
+
background: SeyunaStandardColor(alpha);
|
|
167
175
|
}
|
|
168
176
|
```
|
|
169
177
|
|
package/dist/config.js
CHANGED
|
@@ -1,39 +1,71 @@
|
|
|
1
|
+
const DEFAULT_HUES = {
|
|
2
|
+
alpha: 15,
|
|
3
|
+
beta: 30,
|
|
4
|
+
gamma: 45,
|
|
5
|
+
delta: 60,
|
|
6
|
+
epsilon: 75,
|
|
7
|
+
zeta: 90,
|
|
8
|
+
eta: 105,
|
|
9
|
+
theta: 120,
|
|
10
|
+
iota: 135,
|
|
11
|
+
kappa: 150,
|
|
12
|
+
lambda: 165,
|
|
13
|
+
mu: 180,
|
|
14
|
+
nu: 195,
|
|
15
|
+
xi: 210,
|
|
16
|
+
omicron: 225,
|
|
17
|
+
pi: 240,
|
|
18
|
+
rho: 255,
|
|
19
|
+
sigma: 270,
|
|
20
|
+
tau: 285,
|
|
21
|
+
upsilon: 300,
|
|
22
|
+
phi: 315,
|
|
23
|
+
chi: 330,
|
|
24
|
+
psi: 345,
|
|
25
|
+
omega: 360,
|
|
26
|
+
};
|
|
1
27
|
const DEFAULT_OPTIONS = {
|
|
2
28
|
config: undefined,
|
|
3
29
|
functions: undefined,
|
|
4
30
|
};
|
|
5
31
|
export function loadConfig(options = {}) {
|
|
6
32
|
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
33
|
+
const baseConfig = {
|
|
34
|
+
ui: {
|
|
35
|
+
theme: {
|
|
36
|
+
hues: { ...DEFAULT_HUES },
|
|
37
|
+
colors: {},
|
|
38
|
+
light: {
|
|
39
|
+
chroma: 0,
|
|
40
|
+
lightness: 0,
|
|
41
|
+
background: { lightness: 0, chroma: 0, hue: 0 },
|
|
42
|
+
text: { lightness: 0, chroma: 0, hue: 0 },
|
|
43
|
+
colors: {},
|
|
44
|
+
},
|
|
45
|
+
dark: {
|
|
46
|
+
chroma: 0,
|
|
47
|
+
lightness: 0,
|
|
48
|
+
background: { lightness: 0, chroma: 0, hue: 0 },
|
|
49
|
+
text: { lightness: 0, chroma: 0, hue: 0 },
|
|
50
|
+
colors: {},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
};
|
|
7
55
|
if (mergedOptions.config) {
|
|
56
|
+
// Deep merge or at least merge hues
|
|
57
|
+
const config = mergedOptions.config;
|
|
58
|
+
if (config.ui?.theme) {
|
|
59
|
+
config.ui.theme.hues = { ...DEFAULT_HUES, ...config.ui.theme.hues };
|
|
60
|
+
}
|
|
8
61
|
return {
|
|
9
|
-
config:
|
|
62
|
+
config: config,
|
|
10
63
|
options: { ...mergedOptions, modeAttribute: "data-mode" },
|
|
11
64
|
};
|
|
12
65
|
}
|
|
13
|
-
// Return base
|
|
66
|
+
// Return base config with defaults
|
|
14
67
|
return {
|
|
15
|
-
config:
|
|
16
|
-
ui: {
|
|
17
|
-
theme: {
|
|
18
|
-
hues: {},
|
|
19
|
-
colors: {},
|
|
20
|
-
light: {
|
|
21
|
-
chroma: 0,
|
|
22
|
-
lightness: 0,
|
|
23
|
-
background: { lightness: 0, chroma: 0, hue: 0 },
|
|
24
|
-
text: { lightness: 0, chroma: 0, hue: 0 },
|
|
25
|
-
colors: {},
|
|
26
|
-
},
|
|
27
|
-
dark: {
|
|
28
|
-
chroma: 0,
|
|
29
|
-
lightness: 0,
|
|
30
|
-
background: { lightness: 0, chroma: 0, hue: 0 },
|
|
31
|
-
text: { lightness: 0, chroma: 0, hue: 0 },
|
|
32
|
-
colors: {},
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
},
|
|
68
|
+
config: baseConfig,
|
|
37
69
|
options: { ...mergedOptions, modeAttribute: "data-mode" },
|
|
38
70
|
};
|
|
39
71
|
}
|
package/dist/functions/color.js
CHANGED
|
@@ -7,39 +7,47 @@ function getColorVariables(context, color, type) {
|
|
|
7
7
|
const colors = config?.ui?.theme?.colors || {};
|
|
8
8
|
const lightColors = config?.ui?.theme?.light?.colors || {};
|
|
9
9
|
const darkColors = config?.ui?.theme?.dark?.colors || {};
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (type === 'sc' && !isStandard) {
|
|
13
|
-
throw new Error(`Standard color '${color}' not found in seyuna.json hues`);
|
|
14
|
-
}
|
|
15
|
-
if (type === 'fc' && !isFixed) {
|
|
16
|
-
throw new Error(`Fixed color '${color}' not found in seyuna.json colors`);
|
|
17
|
-
}
|
|
18
|
-
if (isStandard) {
|
|
10
|
+
// If explicitly typed, trust the type and generate appropriate variables
|
|
11
|
+
if (type === "sc") {
|
|
19
12
|
return {
|
|
20
13
|
l: "var(--lightness)",
|
|
21
14
|
c: "var(--chroma)",
|
|
22
15
|
h: `var(--${color}-hue)`,
|
|
23
16
|
};
|
|
24
17
|
}
|
|
25
|
-
if (
|
|
18
|
+
if (type === "fc") {
|
|
26
19
|
return {
|
|
27
20
|
l: `var(--${color}-lightness)`,
|
|
28
21
|
c: `var(--${color}-chroma)`,
|
|
29
22
|
h: `var(--${color}-hue)`,
|
|
30
23
|
};
|
|
31
24
|
}
|
|
32
|
-
|
|
25
|
+
// Auto-detect based on config
|
|
26
|
+
const isStandard = color in hues;
|
|
27
|
+
const isFixed = color in colors || color in lightColors || color in darkColors;
|
|
28
|
+
if (isStandard) {
|
|
29
|
+
return {
|
|
30
|
+
l: "var(--lightness)",
|
|
31
|
+
c: "var(--chroma)",
|
|
32
|
+
h: `var(--${color}-hue)`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// Default to fixed color pattern (graceful degradation for multi-file scenarios)
|
|
36
|
+
return {
|
|
37
|
+
l: `var(--${color}-lightness)`,
|
|
38
|
+
c: `var(--${color}-chroma)`,
|
|
39
|
+
h: `var(--${color}-hue)`,
|
|
40
|
+
};
|
|
33
41
|
}
|
|
34
42
|
export function SeyunaStandardColor(context, name, alpha, lightness, chroma) {
|
|
35
|
-
const vars = getColorVariables(context, name,
|
|
43
|
+
const vars = getColorVariables(context, name, "sc");
|
|
36
44
|
const a = alpha && alpha !== "null" ? alpha : "1";
|
|
37
45
|
const l = lightness && lightness !== "null" ? lightness : vars.l;
|
|
38
46
|
const c = chroma && chroma !== "null" ? chroma : vars.c;
|
|
39
47
|
return `oklch(${l} ${c} ${vars.h} / ${a})`;
|
|
40
48
|
}
|
|
41
49
|
export function SeyunaFixedColor(context, name, alpha, lightness, chroma) {
|
|
42
|
-
const vars = getColorVariables(context, name,
|
|
50
|
+
const vars = getColorVariables(context, name, "fc");
|
|
43
51
|
const a = alpha && alpha !== "null" ? alpha : "1";
|
|
44
52
|
const l = lightness && lightness !== "null" ? lightness : vars.l;
|
|
45
53
|
const c = chroma && chroma !== "null" ? chroma : vars.c;
|
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -10,6 +10,33 @@ import {
|
|
|
10
10
|
// Re-export types for backwards compatibility
|
|
11
11
|
export type { PluginOptions, PluginContext, FunctionMap } from "./types.js";
|
|
12
12
|
|
|
13
|
+
const DEFAULT_HUES = {
|
|
14
|
+
alpha: 15,
|
|
15
|
+
beta: 30,
|
|
16
|
+
gamma: 45,
|
|
17
|
+
delta: 60,
|
|
18
|
+
epsilon: 75,
|
|
19
|
+
zeta: 90,
|
|
20
|
+
eta: 105,
|
|
21
|
+
theta: 120,
|
|
22
|
+
iota: 135,
|
|
23
|
+
kappa: 150,
|
|
24
|
+
lambda: 165,
|
|
25
|
+
mu: 180,
|
|
26
|
+
nu: 195,
|
|
27
|
+
xi: 210,
|
|
28
|
+
omicron: 225,
|
|
29
|
+
pi: 240,
|
|
30
|
+
rho: 255,
|
|
31
|
+
sigma: 270,
|
|
32
|
+
tau: 285,
|
|
33
|
+
upsilon: 300,
|
|
34
|
+
phi: 315,
|
|
35
|
+
chi: 330,
|
|
36
|
+
psi: 345,
|
|
37
|
+
omega: 360,
|
|
38
|
+
};
|
|
39
|
+
|
|
13
40
|
const DEFAULT_OPTIONS: Required<PluginOptions> = {
|
|
14
41
|
config: undefined as any,
|
|
15
42
|
functions: undefined as any,
|
|
@@ -21,37 +48,44 @@ export function loadConfig(options: PluginOptions = {}): {
|
|
|
21
48
|
} {
|
|
22
49
|
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
23
50
|
|
|
51
|
+
const baseConfig: SeyunaConfig = {
|
|
52
|
+
ui: {
|
|
53
|
+
theme: {
|
|
54
|
+
hues: { ...DEFAULT_HUES },
|
|
55
|
+
colors: {},
|
|
56
|
+
light: {
|
|
57
|
+
chroma: 0,
|
|
58
|
+
lightness: 0,
|
|
59
|
+
background: { lightness: 0, chroma: 0, hue: 0 },
|
|
60
|
+
text: { lightness: 0, chroma: 0, hue: 0 },
|
|
61
|
+
colors: {},
|
|
62
|
+
},
|
|
63
|
+
dark: {
|
|
64
|
+
chroma: 0,
|
|
65
|
+
lightness: 0,
|
|
66
|
+
background: { lightness: 0, chroma: 0, hue: 0 },
|
|
67
|
+
text: { lightness: 0, chroma: 0, hue: 0 },
|
|
68
|
+
colors: {},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
24
74
|
if (mergedOptions.config) {
|
|
75
|
+
// Deep merge or at least merge hues
|
|
76
|
+
const config = mergedOptions.config;
|
|
77
|
+
if (config.ui?.theme) {
|
|
78
|
+
config.ui.theme.hues = { ...DEFAULT_HUES, ...config.ui.theme.hues };
|
|
79
|
+
}
|
|
25
80
|
return {
|
|
26
|
-
config:
|
|
81
|
+
config: config,
|
|
27
82
|
options: { ...mergedOptions, modeAttribute: "data-mode" },
|
|
28
83
|
};
|
|
29
84
|
}
|
|
30
85
|
|
|
31
|
-
// Return base
|
|
86
|
+
// Return base config with defaults
|
|
32
87
|
return {
|
|
33
|
-
config:
|
|
34
|
-
ui: {
|
|
35
|
-
theme: {
|
|
36
|
-
hues: {},
|
|
37
|
-
colors: {},
|
|
38
|
-
light: {
|
|
39
|
-
chroma: 0,
|
|
40
|
-
lightness: 0,
|
|
41
|
-
background: { lightness: 0, chroma: 0, hue: 0 },
|
|
42
|
-
text: { lightness: 0, chroma: 0, hue: 0 },
|
|
43
|
-
colors: {},
|
|
44
|
-
},
|
|
45
|
-
dark: {
|
|
46
|
-
chroma: 0,
|
|
47
|
-
lightness: 0,
|
|
48
|
-
background: { lightness: 0, chroma: 0, hue: 0 },
|
|
49
|
-
text: { lightness: 0, chroma: 0, hue: 0 },
|
|
50
|
-
colors: {},
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
} as any,
|
|
88
|
+
config: baseConfig,
|
|
55
89
|
options: { ...mergedOptions, modeAttribute: "data-mode" },
|
|
56
90
|
};
|
|
57
91
|
}
|
package/src/functions/color.ts
CHANGED
|
@@ -3,32 +3,26 @@ import { PluginContext } from "../types.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Resolves a color name to its CSS variables based on its type (standard or fixed)
|
|
5
5
|
*/
|
|
6
|
-
function getColorVariables(
|
|
6
|
+
function getColorVariables(
|
|
7
|
+
context: PluginContext,
|
|
8
|
+
color: string,
|
|
9
|
+
type?: "sc" | "fc",
|
|
10
|
+
) {
|
|
7
11
|
const { config } = context;
|
|
8
12
|
const hues = config?.ui?.theme?.hues || {};
|
|
9
13
|
const colors = config?.ui?.theme?.colors || {};
|
|
10
14
|
const lightColors = config?.ui?.theme?.light?.colors || {};
|
|
11
15
|
const darkColors = config?.ui?.theme?.dark?.colors || {};
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (type === 'sc' && !isStandard) {
|
|
17
|
-
throw new Error(`Standard color '${color}' not found in seyuna.json hues`);
|
|
18
|
-
}
|
|
19
|
-
if (type === 'fc' && !isFixed) {
|
|
20
|
-
throw new Error(`Fixed color '${color}' not found in seyuna.json colors`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (isStandard) {
|
|
17
|
+
// If explicitly typed, trust the type and generate appropriate variables
|
|
18
|
+
if (type === "sc") {
|
|
24
19
|
return {
|
|
25
20
|
l: "var(--lightness)",
|
|
26
21
|
c: "var(--chroma)",
|
|
27
22
|
h: `var(--${color}-hue)`,
|
|
28
23
|
};
|
|
29
24
|
}
|
|
30
|
-
|
|
31
|
-
if (isFixed) {
|
|
25
|
+
if (type === "fc") {
|
|
32
26
|
return {
|
|
33
27
|
l: `var(--${color}-lightness)`,
|
|
34
28
|
c: `var(--${color}-chroma)`,
|
|
@@ -36,7 +30,25 @@ function getColorVariables(context: PluginContext, color: string, type?: 'sc' |
|
|
|
36
30
|
};
|
|
37
31
|
}
|
|
38
32
|
|
|
39
|
-
|
|
33
|
+
// Auto-detect based on config
|
|
34
|
+
const isStandard = color in hues;
|
|
35
|
+
const isFixed =
|
|
36
|
+
color in colors || color in lightColors || color in darkColors;
|
|
37
|
+
|
|
38
|
+
if (isStandard) {
|
|
39
|
+
return {
|
|
40
|
+
l: "var(--lightness)",
|
|
41
|
+
c: "var(--chroma)",
|
|
42
|
+
h: `var(--${color}-hue)`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Default to fixed color pattern (graceful degradation for multi-file scenarios)
|
|
47
|
+
return {
|
|
48
|
+
l: `var(--${color}-lightness)`,
|
|
49
|
+
c: `var(--${color}-chroma)`,
|
|
50
|
+
h: `var(--${color}-hue)`,
|
|
51
|
+
};
|
|
40
52
|
}
|
|
41
53
|
|
|
42
54
|
export function SeyunaStandardColor(
|
|
@@ -44,9 +56,9 @@ export function SeyunaStandardColor(
|
|
|
44
56
|
name: string,
|
|
45
57
|
alpha?: string,
|
|
46
58
|
lightness?: string,
|
|
47
|
-
chroma?: string
|
|
59
|
+
chroma?: string,
|
|
48
60
|
) {
|
|
49
|
-
const vars = getColorVariables(context, name,
|
|
61
|
+
const vars = getColorVariables(context, name, "sc");
|
|
50
62
|
const a = alpha && alpha !== "null" ? alpha : "1";
|
|
51
63
|
const l = lightness && lightness !== "null" ? lightness : vars.l;
|
|
52
64
|
const c = chroma && chroma !== "null" ? chroma : vars.c;
|
|
@@ -59,9 +71,9 @@ export function SeyunaFixedColor(
|
|
|
59
71
|
name: string,
|
|
60
72
|
alpha?: string,
|
|
61
73
|
lightness?: string,
|
|
62
|
-
chroma?: string
|
|
74
|
+
chroma?: string,
|
|
63
75
|
) {
|
|
64
|
-
const vars = getColorVariables(context, name,
|
|
76
|
+
const vars = getColorVariables(context, name, "fc");
|
|
65
77
|
const a = alpha && alpha !== "null" ? alpha : "1";
|
|
66
78
|
const l = lightness && lightness !== "null" ? lightness : vars.l;
|
|
67
79
|
const c = chroma && chroma !== "null" ? chroma : vars.c;
|
|
@@ -69,17 +81,29 @@ export function SeyunaFixedColor(
|
|
|
69
81
|
return `oklch(${l} ${c} ${vars.h} / ${a})`;
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
export function SeyunaAlpha(
|
|
84
|
+
export function SeyunaAlpha(
|
|
85
|
+
context: PluginContext,
|
|
86
|
+
color: string,
|
|
87
|
+
value: string,
|
|
88
|
+
) {
|
|
73
89
|
const { l, c, h } = getColorVariables(context, color);
|
|
74
90
|
return `oklch(${l} ${c} ${h} / ${value})`;
|
|
75
91
|
}
|
|
76
92
|
|
|
77
|
-
export function SeyunaLighten(
|
|
93
|
+
export function SeyunaLighten(
|
|
94
|
+
context: PluginContext,
|
|
95
|
+
color: string,
|
|
96
|
+
amount: string,
|
|
97
|
+
) {
|
|
78
98
|
const { l, c, h } = getColorVariables(context, color);
|
|
79
99
|
return `oklch(calc(${l} + ${amount}) ${c} ${h} / 1)`;
|
|
80
100
|
}
|
|
81
101
|
|
|
82
|
-
export function SeyunaDarken(
|
|
102
|
+
export function SeyunaDarken(
|
|
103
|
+
context: PluginContext,
|
|
104
|
+
color: string,
|
|
105
|
+
amount: string,
|
|
106
|
+
) {
|
|
83
107
|
const { l, c, h } = getColorVariables(context, color);
|
|
84
108
|
return `oklch(calc(${l} - ${amount}) ${c} ${h} / 1)`;
|
|
85
109
|
}
|
package/tests/plugin.test.ts
CHANGED
|
@@ -140,7 +140,8 @@ describe("Seyuna PostCSS Plugin", () => {
|
|
|
140
140
|
expect(result.css).toContain(":root");
|
|
141
141
|
expect(result.css).toContain("--primary-hue: 200");
|
|
142
142
|
expect(result.css).toContain("--secondary-hue: 100");
|
|
143
|
-
expect(result.css).
|
|
143
|
+
expect(result.css).toContain("--alpha-hue: 15");
|
|
144
|
+
expect(result.css).toContain("--omega-hue: 360");
|
|
144
145
|
|
|
145
146
|
// Check for mode selectors
|
|
146
147
|
expect(result.css).toContain('[data-mode="light"]');
|