@seyuna/postcss 1.0.0-canary.37 → 1.0.0-canary.39

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +444 -156
  3. package/dist/at-rules/color-scheme.d.ts +3 -2
  4. package/dist/at-rules/color-scheme.js +6 -7
  5. package/dist/at-rules/color.d.ts +5 -4
  6. package/dist/at-rules/color.js +5 -4
  7. package/dist/at-rules/config.d.ts +2 -1
  8. package/dist/at-rules/config.js +44 -13
  9. package/dist/at-rules/container.d.ts +2 -1
  10. package/dist/at-rules/container.js +4 -6
  11. package/dist/at-rules/import.d.ts +3 -2
  12. package/dist/at-rules/import.js +107 -139
  13. package/dist/at-rules/index.d.ts +2 -1
  14. package/dist/at-rules/index.js +3 -4
  15. package/dist/config.js +70 -28
  16. package/dist/errors.d.ts +3 -5
  17. package/dist/errors.js +2 -4
  18. package/dist/functions/color.d.ts +4 -4
  19. package/dist/functions/color.js +4 -4
  20. package/dist/functions/index.js +5 -7
  21. package/dist/helpers.d.ts +4 -6
  22. package/dist/helpers.js +26 -22
  23. package/dist/index.d.ts +8 -1
  24. package/dist/index.js +1 -0
  25. package/dist/parser.js +36 -49
  26. package/dist/plugin.d.ts +3 -1
  27. package/dist/plugin.js +15 -19
  28. package/dist/types.d.ts +6 -1
  29. package/dist/types.js +0 -2
  30. package/package.json +20 -3
  31. package/.github/workflows/release.yml +0 -41
  32. package/.vscode/settings.json +0 -4
  33. package/dist/functions/theme.d.ts +0 -6
  34. package/dist/functions/theme.js +0 -17
  35. package/release.config.mjs +0 -37
  36. package/src/at-rules/color-scheme.ts +0 -54
  37. package/src/at-rules/color.ts +0 -33
  38. package/src/at-rules/config.ts +0 -78
  39. package/src/at-rules/container.ts +0 -58
  40. package/src/at-rules/import.ts +0 -196
  41. package/src/at-rules/index.ts +0 -29
  42. package/src/config.ts +0 -98
  43. package/src/errors.ts +0 -27
  44. package/src/functions/color.ts +0 -123
  45. package/src/functions/index.ts +0 -22
  46. package/src/functions/theme.ts +0 -20
  47. package/src/helpers.ts +0 -75
  48. package/src/index.ts +0 -10
  49. package/src/parser.ts +0 -81
  50. package/src/plugin.ts +0 -58
  51. package/src/styles/seyuna-global.css +0 -94
  52. package/src/types.ts +0 -71
  53. package/tests/plugin.test.ts +0 -244
  54. package/tsconfig.json +0 -14
@@ -1,3 +1,4 @@
1
+ import { type AtRule } from "postcss";
1
2
  import { PluginContext } from "../types.js";
2
- export declare const light: (atRule: any, context: PluginContext) => void;
3
- export declare const dark: (atRule: any, context: PluginContext) => void;
3
+ export declare const light: (atRule: AtRule, context: PluginContext) => void;
4
+ export declare const dark: (atRule: AtRule, context: PluginContext) => void;
@@ -1,5 +1,4 @@
1
- import Rule from "postcss/lib/rule";
2
- import AtRule from "postcss/lib/at-rule";
1
+ import postcss from "postcss";
3
2
  /**
4
3
  * Custom PostCSS plugin handler factory for `@light` and `@dark` at-rules.
5
4
  */
@@ -15,7 +14,7 @@ function createColorSchemeHandler(scheme) {
15
14
  /**
16
15
  * Rule 1: [data-mode="scheme"] & { ... } (Explicit mode)
17
16
  */
18
- const explicitRule = new Rule({
17
+ const explicitRule = postcss.rule({
19
18
  selector: `[${modeAttribute}="${scheme}"] &`,
20
19
  source: atRule.source,
21
20
  });
@@ -23,12 +22,12 @@ function createColorSchemeHandler(scheme) {
23
22
  /**
24
23
  * Rule 2: @media (prefers-color-scheme: scheme) { [data-mode="system"] & { ... } } (System preference)
25
24
  */
26
- const mediaAtRule = new AtRule({
25
+ const mediaAtRule = postcss.atRule({
27
26
  name: "media",
28
27
  params: `(prefers-color-scheme: ${scheme})`,
29
28
  source: atRule.source,
30
29
  });
31
- const systemRule = new Rule({
30
+ const systemRule = postcss.rule({
32
31
  selector: `[${modeAttribute}="system"] &`,
33
32
  source: atRule.source,
34
33
  });
@@ -40,5 +39,5 @@ function createColorSchemeHandler(scheme) {
40
39
  atRule.replaceWith(mediaAtRule, explicitRule);
41
40
  };
42
41
  }
43
- export const light = createColorSchemeHandler('light');
44
- export const dark = createColorSchemeHandler('dark');
42
+ export const light = createColorSchemeHandler("light");
43
+ export const dark = createColorSchemeHandler("dark");
@@ -1,9 +1,10 @@
1
+ import type { AtRule } from "postcss";
1
2
  import { PluginContext } from "../types.js";
2
3
  /**
3
- * Handler for @each-standard-color
4
+ * Handler for @each-tone
4
5
  */
5
- export declare function eachStandardColor(atRule: any, context: PluginContext): void;
6
+ export declare function eachTone(atRule: AtRule, context: PluginContext): void;
6
7
  /**
7
- * Handler for @each-fixed-color
8
+ * Handler for @each-swatch
8
9
  */
9
- export declare function eachFixedColor(atRule: any, context: PluginContext): void;
10
+ export declare function eachSwatch(atRule: AtRule, context: PluginContext): void;
@@ -1,8 +1,8 @@
1
1
  import { generateRules } from "../helpers.js";
2
2
  /**
3
- * Handler for @each-standard-color
3
+ * Handler for @each-tone
4
4
  */
5
- export function eachStandardColor(atRule, context) {
5
+ export function eachTone(atRule, context) {
6
6
  const { config } = context;
7
7
  const hueNames = config.ui ? Object.keys(config.ui.theme.hues) : [];
8
8
  const rules = generateRules(hueNames, atRule, context);
@@ -12,12 +12,13 @@ export function eachStandardColor(atRule, context) {
12
12
  atRule.remove();
13
13
  }
14
14
  /**
15
- * Handler for @each-fixed-color
15
+ * Handler for @each-swatch
16
16
  */
17
- export function eachFixedColor(atRule, context) {
17
+ export function eachSwatch(atRule, context) {
18
18
  const { config } = context;
19
19
  const mergedNames = [
20
20
  ...new Set([
21
+ ...(config.ui ? Object.keys(config.ui.theme.colors) : []),
21
22
  ...(config.ui ? Object.keys(config.ui.theme.light.colors) : []),
22
23
  ...(config.ui ? Object.keys(config.ui.theme.dark.colors) : []),
23
24
  ]),
@@ -1,6 +1,7 @@
1
+ import type { AtRule } from "postcss";
1
2
  import { PluginContext } from "../types.js";
2
3
  /**
3
4
  * Handler for @config "seyuna"
4
5
  * Parses the configuration defined directly in CSS.
5
6
  */
6
- export declare function handleConfig(atRule: any, context: PluginContext): void;
7
+ export declare function handleConfig(atRule: AtRule, context: PluginContext): void;
@@ -1,3 +1,15 @@
1
+ import { reportWarning } from "../errors.js";
2
+ function parseNumber(value) {
3
+ const parsed = Number.parseFloat(value);
4
+ return Number.isFinite(parsed) ? parsed : undefined;
5
+ }
6
+ function parseColorTriplet(value) {
7
+ const parts = value.split(/\s+/).map(parseNumber);
8
+ if (parts.length !== 3 || parts.some((part) => part === undefined)) {
9
+ return undefined;
10
+ }
11
+ return parts;
12
+ }
1
13
  /**
2
14
  * Handler for @config "seyuna"
3
15
  * Parses the configuration defined directly in CSS.
@@ -32,35 +44,54 @@ export function handleConfig(atRule, context) {
32
44
  atRule.walkDecls((decl) => {
33
45
  const prop = decl.prop;
34
46
  const value = decl.value;
35
- // Hues: --hue-alpha: 0;
36
47
  if (prop.startsWith("--hue-")) {
37
48
  const name = prop.replace("--hue-", "");
38
- theme.hues[name] = parseFloat(value);
49
+ const parsed = parseNumber(value);
50
+ if (parsed === undefined) {
51
+ reportWarning(`Ignoring invalid hue value for "${prop}": "${value}"`, decl, context);
52
+ return;
53
+ }
54
+ theme.hues[name] = parsed;
39
55
  }
40
- // Fixed Colors: --color-primary: 0.66 0.26 240;
41
56
  else if (prop.startsWith("--color-")) {
42
57
  const name = prop.replace("--color-", "");
43
- const [l, c, h] = value.split(/\s+/).map(parseFloat);
58
+ const parsed = parseColorTriplet(value);
59
+ if (!parsed) {
60
+ reportWarning(`Ignoring invalid color tuple for "${prop}": "${value}"`, decl, context);
61
+ return;
62
+ }
63
+ const [l, c, h] = parsed;
44
64
  theme.colors[name] = { lightness: l, chroma: c, hue: h };
45
65
  }
46
- // Theme Palettes: --light-lightness: 0.66;
47
66
  else if (prop.startsWith("--light-") || prop.startsWith("--dark-")) {
48
67
  const isLight = prop.startsWith("--light-");
49
68
  const palette = isLight ? theme.light : theme.dark;
50
69
  const key = prop.replace(isLight ? "--light-" : "--dark-", "");
51
- if (key === "lightness")
52
- palette.lightness = parseFloat(value);
53
- else if (key === "chroma")
54
- palette.chroma = parseFloat(value);
70
+ if (key === "lightness" || key === "chroma") {
71
+ const parsed = parseNumber(value);
72
+ if (parsed === undefined) {
73
+ reportWarning(`Ignoring invalid palette value for "${prop}": "${value}"`, decl, context);
74
+ return;
75
+ }
76
+ palette[key] = parsed;
77
+ }
55
78
  else if (key === "background" || key === "text") {
56
- const [l, c, h] = value.split(/\s+/).map(parseFloat);
79
+ const parsed = parseColorTriplet(value);
80
+ if (!parsed) {
81
+ reportWarning(`Ignoring invalid color tuple for "${prop}": "${value}"`, decl, context);
82
+ return;
83
+ }
84
+ const [l, c, h] = parsed;
57
85
  palette[key] = { lightness: l, chroma: c, hue: h };
58
86
  }
59
87
  else {
60
- // Custom colors in palette: --light-surface: 1 0 0;
61
- // Also supports overrides like --light-color-primary: 0.8 0.1 240;
62
88
  const cleanKey = key.replace(/^color-/, "");
63
- const [l, c, h] = value.split(/\s+/).map(parseFloat);
89
+ const parsed = parseColorTriplet(value);
90
+ if (!parsed) {
91
+ reportWarning(`Ignoring invalid color tuple for "${prop}": "${value}"`, decl, context);
92
+ return;
93
+ }
94
+ const [l, c, h] = parsed;
64
95
  palette.colors[cleanKey] = { lightness: l, chroma: c, hue: h };
65
96
  }
66
97
  }
@@ -1,3 +1,4 @@
1
+ import { type AtRule } from "postcss";
1
2
  import { PluginContext } from "../types.js";
2
3
  /**
3
4
  * Custom PostCSS plugin handler for responsive at-rules.
@@ -15,4 +16,4 @@ import { PluginContext } from "../types.js";
15
16
  * }
16
17
  *
17
18
  */
18
- export default function container(atRule: any, context: PluginContext): void;
19
+ export default function container(atRule: AtRule, context: PluginContext): void;
@@ -1,4 +1,4 @@
1
- import AtRule from "postcss/lib/at-rule";
1
+ import postcss from "postcss";
2
2
  /**
3
3
  * Custom PostCSS plugin handler for responsive at-rules.
4
4
  *
@@ -17,7 +17,6 @@ import AtRule from "postcss/lib/at-rule";
17
17
  */
18
18
  export default function container(atRule, context) {
19
19
  const { config } = context;
20
- // Default breakpoints
21
20
  const defaultBreakpoints = {
22
21
  xs: "20rem",
23
22
  sm: "40rem",
@@ -26,18 +25,17 @@ export default function container(atRule, context) {
26
25
  xl: "80rem",
27
26
  "2xl": "96rem",
28
27
  };
29
- // Merge with config if available (assuming config.ui.breakpoints exists)
30
28
  const breakpoints = {
31
29
  ...defaultBreakpoints,
32
- ...(config.ui?.theme?.breakpoints || {}),
30
+ ...(config.ui?.theme.breakpoints ?? {}),
33
31
  };
34
- if (Object.keys(breakpoints).includes(atRule.name)) {
32
+ if (atRule.name in breakpoints) {
35
33
  const minWidth = breakpoints[atRule.name];
36
34
  const clonedNodes = [];
37
35
  atRule.each((node) => {
38
36
  clonedNodes.push(node.clone());
39
37
  });
40
- const containerAtRule = new AtRule({
38
+ const containerAtRule = postcss.atRule({
41
39
  name: "container",
42
40
  params: `(min-width: ${minWidth})`,
43
41
  source: atRule.source,
@@ -1,6 +1,7 @@
1
+ import { type AtRule } from "postcss";
1
2
  import { PluginContext } from "../types.js";
2
3
  /**
3
- * Handler for @import "seyuna"
4
+ * Handler for @seyuna
4
5
  * Injects the core Seyuna Design System variables and base styles
5
6
  */
6
- export declare function handleImport(atRule: any, context: PluginContext): void;
7
+ export declare function handleImport(atRule: AtRule, context: PluginContext): void;
@@ -1,154 +1,122 @@
1
- import Rule from "postcss/lib/rule";
2
- import Declaration from "postcss/lib/declaration";
3
- import AtRule from "postcss/lib/at-rule";
1
+ import postcss from "postcss";
4
2
  import fs from "fs";
5
3
  import path from "path";
6
4
  import { fileURLToPath } from "url";
7
- import postcss from "postcss";
5
+ import { reportWarning } from "../errors.js";
8
6
  const __filename = fileURLToPath(import.meta.url);
9
7
  const __dirname = path.dirname(__filename);
8
+ const GLOBAL_STYLES_PATH = path.resolve(__dirname, "../styles/seyuna-global.css");
9
+ let cachedGlobalStyleNodes;
10
+ function getCachedGlobalStyleNodes() {
11
+ if (cachedGlobalStyleNodes) {
12
+ return cachedGlobalStyleNodes.map((node) => node.clone());
13
+ }
14
+ if (!fs.existsSync(GLOBAL_STYLES_PATH)) {
15
+ cachedGlobalStyleNodes = [
16
+ postcss.atRule({
17
+ name: "layer",
18
+ params: "reset, base, components, utilities",
19
+ }),
20
+ ];
21
+ return cachedGlobalStyleNodes.map((node) => node.clone());
22
+ }
23
+ const globalCss = fs.readFileSync(GLOBAL_STYLES_PATH, "utf-8");
24
+ const parsed = postcss.parse(globalCss, { from: GLOBAL_STYLES_PATH });
25
+ cachedGlobalStyleNodes = parsed.nodes.map((node) => node.clone());
26
+ return cachedGlobalStyleNodes.map((node) => node.clone());
27
+ }
28
+ function createDecl(prop, value) {
29
+ return postcss.decl({ prop, value });
30
+ }
31
+ function createColorVarDecls(name, color) {
32
+ return [
33
+ createDecl(`--${name}-lightness`, String(color.lightness)),
34
+ createDecl(`--${name}-chroma`, String(color.chroma)),
35
+ createDecl(`--${name}-hue`, String(color.hue)),
36
+ ];
37
+ }
10
38
  /**
11
- * Handler for @import "seyuna"
39
+ * Handler for @seyuna
12
40
  * Injects the core Seyuna Design System variables and base styles
13
41
  */
14
42
  export function handleImport(atRule, context) {
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") {
22
- const { config, options } = context;
23
- if (!config.ui) {
24
- atRule.remove();
25
- return;
26
- }
27
- const { theme } = config.ui;
28
- const modeAttribute = options.modeAttribute;
29
- const nodes = [];
30
- // 1. Ingest Global Base Styles (Reset, Layers, etc.)
31
- try {
32
- const globalStylesPath = path.resolve(__dirname, "../styles/seyuna-global.css");
33
- if (fs.existsSync(globalStylesPath)) {
34
- const globalCss = fs.readFileSync(globalStylesPath, "utf-8");
35
- const parsed = postcss.parse(globalCss);
36
- // Push all nodes from the global styles (reset, layers, etc.)
37
- parsed.nodes.forEach((node) => {
38
- nodes.push(node.clone());
39
- });
40
- }
41
- else {
42
- nodes.push(new AtRule({
43
- name: "layer",
44
- params: "reset, base, components, utilities",
45
- }));
46
- }
47
- }
48
- catch (e) {
49
- console.warn("[Seyuna PostCSS] Could not load global base styles:", e);
43
+ if (atRule.name !== "seyuna") {
44
+ return;
45
+ }
46
+ if (context.state.hasInjectedSeyuna) {
47
+ reportWarning("Ignoring duplicate @seyuna; only the first injection is applied.", atRule, context);
48
+ atRule.remove();
49
+ return;
50
+ }
51
+ const { config, options } = context;
52
+ if (!config.ui) {
53
+ atRule.remove();
54
+ return;
55
+ }
56
+ context.state.hasInjectedSeyuna = true;
57
+ const { theme } = config.ui;
58
+ const modeAttribute = options.modeAttribute;
59
+ const nodes = [];
60
+ try {
61
+ nodes.push(...getCachedGlobalStyleNodes());
62
+ }
63
+ catch (error) {
64
+ reportWarning(`Could not load global base styles: ${error instanceof Error ? error.message : String(error)}`, atRule, context);
65
+ }
66
+ const rootRule = postcss.rule({ selector: ":root", source: atRule.source });
67
+ for (const [name, value] of Object.entries(theme.hues)) {
68
+ rootRule.append(createDecl(`--${name}-hue`, String(value)));
69
+ }
70
+ for (const [name, color] of Object.entries(theme.colors)) {
71
+ rootRule.append(...createColorVarDecls(name, color));
72
+ }
73
+ nodes.push(rootRule);
74
+ const getPaletteDecls = (palette) => {
75
+ const decls = [];
76
+ if (palette.lightness !== undefined) {
77
+ decls.push(createDecl("--lightness", String(palette.lightness)));
50
78
  }
51
- // 2. Global Hues and Base Colors (:root)
52
- const rootRule = new Rule({ selector: ":root", source: atRule.source });
53
- // Process all hues from config
54
- if (theme.hues) {
55
- for (const [name, value] of Object.entries(theme.hues)) {
56
- rootRule.append(new Declaration({ prop: `--${name}-hue`, value: String(value) }));
57
- }
79
+ if (palette.chroma !== undefined) {
80
+ decls.push(createDecl("--chroma", String(palette.chroma)));
58
81
  }
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({
63
- prop: `--${name}-lightness`,
64
- value: String(color.lightness),
65
- }));
66
- rootRule.append(new Declaration({
67
- prop: `--${name}-chroma`,
68
- value: String(color.chroma),
69
- }));
70
- rootRule.append(new Declaration({ prop: `--${name}-hue`, value: String(color.hue) }));
71
- }
82
+ if (palette.background) {
83
+ decls.push(createDecl("--background", `oklch(${palette.background.lightness} ${palette.background.chroma} ${palette.background.hue})`));
72
84
  }
73
- nodes.push(rootRule);
74
- // Helper to generate palette declarations for a specific mode
75
- const getPaletteDecls = (palette) => {
76
- const decls = [];
77
- if (palette.lightness !== undefined) {
78
- decls.push(new Declaration({
79
- prop: "--lightness",
80
- value: String(palette.lightness),
81
- }));
82
- }
83
- if (palette.chroma !== undefined) {
84
- decls.push(new Declaration({ prop: "--chroma", value: String(palette.chroma) }));
85
- }
86
- // Standard background/text if they exist
87
- if (palette.background) {
88
- decls.push(new Declaration({
89
- prop: "--background",
90
- value: `oklch(${palette.background.lightness} ${palette.background.chroma} ${palette.background.hue})`,
91
- }));
92
- }
93
- if (palette.text) {
94
- decls.push(new Declaration({
95
- prop: "--text",
96
- value: `oklch(${palette.text.lightness} ${palette.text.chroma} ${palette.text.hue})`,
97
- }));
98
- }
99
- if (palette.colors) {
100
- for (const [name, color] of Object.entries(palette.colors)) {
101
- const c = color;
102
- decls.push(new Declaration({
103
- prop: `--${name}-lightness`,
104
- value: String(c.lightness),
105
- }));
106
- decls.push(new Declaration({
107
- prop: `--${name}-chroma`,
108
- value: String(c.chroma),
109
- }));
110
- decls.push(new Declaration({ prop: `--${name}-hue`, value: String(c.hue) }));
111
- }
112
- }
113
- return decls;
114
- };
115
- // 3. Explicit Mode Selectors ([data-mode="..."])
116
- if (theme.light) {
117
- const lightRule = new Rule({
118
- selector: `[${modeAttribute}="light"]`,
119
- source: atRule.source,
120
- });
121
- lightRule.append(...getPaletteDecls(theme.light));
122
- nodes.push(lightRule);
85
+ if (palette.text) {
86
+ decls.push(createDecl("--text", `oklch(${palette.text.lightness} ${palette.text.chroma} ${palette.text.hue})`));
123
87
  }
124
- if (theme.dark) {
125
- const darkRule = new Rule({
126
- selector: `[${modeAttribute}="dark"]`,
127
- source: atRule.source,
128
- });
129
- darkRule.append(...getPaletteDecls(theme.dark));
130
- nodes.push(darkRule);
88
+ for (const [name, color] of Object.entries(palette.colors)) {
89
+ decls.push(...createColorVarDecls(name, color));
131
90
  }
132
- // 4. System Preference Support
133
- const createSystemMedia = (scheme, palette) => {
134
- const media = new AtRule({
135
- name: "media",
136
- params: `(prefers-color-scheme: ${scheme})`,
137
- source: atRule.source,
138
- });
139
- const rule = new Rule({
140
- selector: `[${modeAttribute}="system"]`,
141
- source: atRule.source,
142
- });
143
- rule.append(...getPaletteDecls(palette));
144
- media.append(rule);
145
- return media;
146
- };
147
- if (theme.light)
148
- nodes.push(createSystemMedia("light", theme.light));
149
- if (theme.dark)
150
- nodes.push(createSystemMedia("dark", theme.dark));
151
- // Replace the @import rule with our generated CSS
152
- atRule.replaceWith(...nodes);
153
- }
91
+ return decls;
92
+ };
93
+ const lightRule = postcss.rule({
94
+ selector: `[${modeAttribute}="light"]`,
95
+ source: atRule.source,
96
+ });
97
+ lightRule.append(...getPaletteDecls(theme.light));
98
+ nodes.push(lightRule);
99
+ const darkRule = postcss.rule({
100
+ selector: `[${modeAttribute}="dark"]`,
101
+ source: atRule.source,
102
+ });
103
+ darkRule.append(...getPaletteDecls(theme.dark));
104
+ nodes.push(darkRule);
105
+ const createSystemMedia = (scheme, palette) => {
106
+ const media = postcss.atRule({
107
+ name: "media",
108
+ params: `(prefers-color-scheme: ${scheme})`,
109
+ source: atRule.source,
110
+ });
111
+ const rule = postcss.rule({
112
+ selector: `[${modeAttribute}="system"]`,
113
+ source: atRule.source,
114
+ });
115
+ rule.append(...getPaletteDecls(palette));
116
+ media.append(rule);
117
+ return media;
118
+ };
119
+ nodes.push(createSystemMedia("light", theme.light));
120
+ nodes.push(createSystemMedia("dark", theme.dark));
121
+ atRule.replaceWith(...nodes);
154
122
  }
@@ -1,6 +1,7 @@
1
+ import type { AtRule } from "postcss";
1
2
  import { PluginContext } from "../types.js";
2
3
  export interface AtRuleHandler {
3
4
  name: string;
4
- handler: (atRule: any, context: PluginContext) => void;
5
+ handler: (atRule: AtRule, context: PluginContext) => void;
5
6
  }
6
7
  export declare const atRuleHandlers: AtRuleHandler[];
@@ -1,5 +1,4 @@
1
- // import type { AtRule } from "postcss";
2
- import { eachStandardColor, eachFixedColor } from "./color.js";
1
+ import { eachTone, eachSwatch } from "./color.js";
3
2
  import container from "./container.js";
4
3
  import { light, dark } from "./color-scheme.js";
5
4
  import { handleImport } from "./import.js";
@@ -8,8 +7,8 @@ import { handleConfig } from "./config.js";
8
7
  export const atRuleHandlers = [
9
8
  { name: "config", handler: handleConfig },
10
9
  { name: "seyuna", handler: handleImport },
11
- { name: "each-standard-color", handler: eachStandardColor },
12
- { name: "each-fixed-color", handler: eachFixedColor },
10
+ { name: "each-tone", handler: eachTone },
11
+ { name: "each-swatch", handler: eachSwatch },
13
12
  { name: "light", handler: light },
14
13
  { name: "dark", handler: dark },
15
14
  { name: "xs", handler: container },
package/dist/config.js CHANGED
@@ -28,44 +28,86 @@ const DEFAULT_OPTIONS = {
28
28
  config: undefined,
29
29
  functions: undefined,
30
30
  };
31
- export function loadConfig(options = {}) {
32
- const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
33
- const baseConfig = {
31
+ const DEFAULT_THEME = {
32
+ hues: { ...DEFAULT_HUES },
33
+ colors: {},
34
+ light: {
35
+ chroma: 0,
36
+ lightness: 0,
37
+ background: { lightness: 0, chroma: 0, hue: 0 },
38
+ text: { lightness: 0, chroma: 0, hue: 0 },
39
+ colors: {},
40
+ },
41
+ dark: {
42
+ chroma: 0,
43
+ lightness: 0,
44
+ background: { lightness: 0, chroma: 0, hue: 0 },
45
+ text: { lightness: 0, chroma: 0, hue: 0 },
46
+ colors: {},
47
+ },
48
+ breakpoints: {},
49
+ };
50
+ function normalizeConfig(config) {
51
+ const theme = config?.ui?.theme;
52
+ return {
53
+ ...config,
34
54
  ui: {
55
+ ...config?.ui,
35
56
  theme: {
36
- hues: { ...DEFAULT_HUES },
37
- colors: {},
57
+ ...DEFAULT_THEME,
58
+ ...theme,
59
+ hues: {
60
+ ...DEFAULT_HUES,
61
+ ...(theme?.hues ?? {}),
62
+ },
63
+ colors: {
64
+ ...DEFAULT_THEME.colors,
65
+ ...(theme?.colors ?? {}),
66
+ },
38
67
  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: {},
68
+ ...DEFAULT_THEME.light,
69
+ ...(theme?.light ?? {}),
70
+ background: {
71
+ ...DEFAULT_THEME.light.background,
72
+ ...(theme?.light?.background ?? {}),
73
+ },
74
+ text: {
75
+ ...DEFAULT_THEME.light.text,
76
+ ...(theme?.light?.text ?? {}),
77
+ },
78
+ colors: {
79
+ ...DEFAULT_THEME.light.colors,
80
+ ...(theme?.light?.colors ?? {}),
81
+ },
44
82
  },
45
83
  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: {},
84
+ ...DEFAULT_THEME.dark,
85
+ ...(theme?.dark ?? {}),
86
+ background: {
87
+ ...DEFAULT_THEME.dark.background,
88
+ ...(theme?.dark?.background ?? {}),
89
+ },
90
+ text: {
91
+ ...DEFAULT_THEME.dark.text,
92
+ ...(theme?.dark?.text ?? {}),
93
+ },
94
+ colors: {
95
+ ...DEFAULT_THEME.dark.colors,
96
+ ...(theme?.dark?.colors ?? {}),
97
+ },
98
+ },
99
+ breakpoints: {
100
+ ...DEFAULT_THEME.breakpoints,
101
+ ...(theme?.breakpoints ?? {}),
51
102
  },
52
103
  },
53
104
  },
54
105
  };
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
- }
61
- return {
62
- config: config,
63
- options: { ...mergedOptions, modeAttribute: "data-mode" },
64
- };
65
- }
66
- // Return base config with defaults
106
+ }
107
+ export function loadConfig(options = {}) {
108
+ const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
67
109
  return {
68
- config: baseConfig,
110
+ config: normalizeConfig(mergedOptions.config),
69
111
  options: { ...mergedOptions, modeAttribute: "data-mode" },
70
112
  };
71
113
  }