@clhaas/palette-kit 0.1.8 → 0.4.0

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 (118) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +80 -177
  3. package/dist/contrast/contrast.d.ts +16 -0
  4. package/dist/contrast/contrast.js +102 -0
  5. package/dist/core/intent-registry.d.ts +11 -0
  6. package/dist/core/intent-registry.js +70 -0
  7. package/dist/core/oklch.d.ts +16 -0
  8. package/dist/core/oklch.js +56 -0
  9. package/dist/create-palette-kit.d.ts +9 -0
  10. package/dist/create-palette-kit.js +67 -0
  11. package/dist/engine/context/context.d.ts +13 -0
  12. package/dist/engine/context/context.js +37 -0
  13. package/dist/engine/level/curves.d.ts +17 -0
  14. package/dist/engine/level/curves.js +49 -0
  15. package/dist/engine/level/level.d.ts +4 -0
  16. package/dist/engine/level/level.js +13 -0
  17. package/dist/engine/relation/relation.d.ts +105 -0
  18. package/dist/engine/relation/relation.js +137 -0
  19. package/dist/engine/resolve/resolve.d.ts +36 -0
  20. package/dist/engine/resolve/resolve.js +116 -0
  21. package/dist/engine/state/state.d.ts +46 -0
  22. package/dist/engine/state/state.js +68 -0
  23. package/dist/engine/usage/fill.d.ts +9 -0
  24. package/dist/engine/usage/fill.js +9 -0
  25. package/dist/engine/usage/lines.d.ts +9 -0
  26. package/dist/engine/usage/lines.js +9 -0
  27. package/dist/engine/usage/overlays.d.ts +9 -0
  28. package/dist/engine/usage/overlays.js +9 -0
  29. package/dist/engine/usage/strategy.d.ts +56 -0
  30. package/dist/engine/usage/strategy.js +30 -0
  31. package/dist/engine/usage/visualVocabulary.d.ts +9 -0
  32. package/dist/engine/usage/visualVocabulary.js +9 -0
  33. package/dist/export/serialize.d.ts +14 -0
  34. package/dist/export/serialize.js +89 -0
  35. package/dist/export/types.d.ts +37 -0
  36. package/dist/export/types.js +31 -0
  37. package/dist/index.d.ts +3 -22
  38. package/dist/index.js +2 -18
  39. package/dist/operators/convert.d.ts +32 -0
  40. package/dist/operators/convert.js +80 -0
  41. package/dist/presets/presets.d.ts +95 -0
  42. package/dist/presets/presets.js +308 -0
  43. package/dist/types/index.d.ts +111 -0
  44. package/dist/utils/errors/errors.d.ts +17 -0
  45. package/dist/utils/errors/errors.js +22 -0
  46. package/docs/API.md +167 -0
  47. package/docs/Alpha.md +14 -0
  48. package/docs/Architecture.md +56 -0
  49. package/docs/CLI.md +22 -0
  50. package/docs/Concepts.md +73 -0
  51. package/docs/Config.md +144 -0
  52. package/docs/Diagnostics.md +22 -0
  53. package/docs/Exporters.md +33 -0
  54. package/docs/FAQ.md +59 -0
  55. package/docs/Migration.md +61 -0
  56. package/docs/Overlays.md +33 -0
  57. package/docs/README.md +60 -0
  58. package/docs/Text.md +41 -0
  59. package/docs/Tokens.md +42 -0
  60. package/docs/Usage-JSON.md +39 -0
  61. package/docs/Usage-ReactNative.md +63 -0
  62. package/docs/Usage-Web.md +66 -0
  63. package/docs/Validation.md +97 -0
  64. package/docs/Why.md +37 -0
  65. package/docs/_api-surface.md +53 -0
  66. package/docs/snippets/serialize-oklch.md +9 -0
  67. package/docs/spec.md +98 -0
  68. package/package.json +74 -52
  69. package/dist/alpha/generateAlphaScale.d.ts +0 -5
  70. package/dist/alpha/generateAlphaScale.js +0 -34
  71. package/dist/cli.d.ts +0 -2
  72. package/dist/cli.js +0 -150
  73. package/dist/contrast/apca.d.ts +0 -2
  74. package/dist/contrast/apca.js +0 -5
  75. package/dist/contrast/onSolid.d.ts +0 -6
  76. package/dist/contrast/onSolid.js +0 -28
  77. package/dist/contrast/solveText.d.ts +0 -2
  78. package/dist/contrast/solveText.js +0 -31
  79. package/dist/createTheme.d.ts +0 -38
  80. package/dist/createTheme.js +0 -148
  81. package/dist/data/radixSeeds.d.ts +0 -3
  82. package/dist/data/radixSeeds.js +0 -34
  83. package/dist/diagnostics/analyzeScale.d.ts +0 -2
  84. package/dist/diagnostics/analyzeScale.js +0 -7
  85. package/dist/diagnostics/analyzeTheme.d.ts +0 -2
  86. package/dist/diagnostics/analyzeTheme.js +0 -35
  87. package/dist/diagnostics/warnings.d.ts +0 -2
  88. package/dist/diagnostics/warnings.js +0 -20
  89. package/dist/engine/curves.d.ts +0 -9
  90. package/dist/engine/curves.js +0 -48
  91. package/dist/engine/oklch.d.ts +0 -8
  92. package/dist/engine/oklch.js +0 -40
  93. package/dist/engine/templates.d.ts +0 -14
  94. package/dist/engine/templates.js +0 -45
  95. package/dist/exporters/selectColorMode.d.ts +0 -2
  96. package/dist/exporters/selectColorMode.js +0 -19
  97. package/dist/exporters/toCssVars.d.ts +0 -13
  98. package/dist/exporters/toCssVars.js +0 -108
  99. package/dist/exporters/toJson.d.ts +0 -3
  100. package/dist/exporters/toJson.js +0 -25
  101. package/dist/exporters/toReactNative.d.ts +0 -54
  102. package/dist/exporters/toReactNative.js +0 -33
  103. package/dist/exporters/toTailwind.d.ts +0 -17
  104. package/dist/exporters/toTailwind.js +0 -111
  105. package/dist/exporters/toTs.d.ts +0 -3
  106. package/dist/exporters/toTs.js +0 -43
  107. package/dist/generateScale.d.ts +0 -48
  108. package/dist/generateScale.js +0 -274
  109. package/dist/overlays/generateOverlayScale.d.ts +0 -2
  110. package/dist/overlays/generateOverlayScale.js +0 -34
  111. package/dist/text/generateTextScale.d.ts +0 -8
  112. package/dist/text/generateTextScale.js +0 -18
  113. package/dist/text/resolveOnBgText.d.ts +0 -9
  114. package/dist/text/resolveOnBgText.js +0 -28
  115. package/dist/tokens/presetRadixLikeUi.d.ts +0 -5
  116. package/dist/tokens/presetRadixLikeUi.js +0 -55
  117. package/dist/types.d.ts +0 -69
  118. /package/dist/{types.js → types/index.js} +0 -0
package/package.json CHANGED
@@ -1,54 +1,76 @@
1
1
  {
2
- "name": "@clhaas/palette-kit",
3
- "version": "0.1.8",
4
- "description": "Easy way to create the color palette of your app",
5
- "license": "MIT",
6
- "author": "Claus Haas",
7
- "type": "module",
8
- "main": "dist/index.js",
9
- "types": "dist/index.d.ts",
10
- "bin": {
11
- "palette-kit": "./dist/cli.js"
12
- },
13
- "exports": {
14
- ".": {
15
- "types": "./dist/index.d.ts",
16
- "default": "./dist/index.js"
17
- }
18
- },
19
- "publishConfig": {
20
- "access": "public"
21
- },
22
- "scripts": {
23
- "build": "tsc -p tsconfig.build.json",
24
- "clean": "rm -rf dist",
25
- "generate:theme": "tsx -e \"import { createTheme, toTs } from './src/index.ts'; import { writeFileSync } from 'node:fs'; const theme = createTheme({ neutral: { source: 'seed', value: '#111827' }, accent: { source: 'seed', value: '#3d63dd' }, semantic: { success: { source: 'seed', value: '#16a34a' }, warning: { source: 'seed', value: '#f59e0b' }, danger: { source: 'seed', value: '#ef4444' } }, tokens: { preset: 'radix-like-ui' }, alpha: { enabled: true, background: { light: '#ffffff', dark: '#111111' } }, contrast: { textPrimary: 75, textSecondary: 60 }, p3: true }); const ts = toTs(theme); writeFileSync('docs/theme.generated.ts', ts);\"",
26
- "prepublishOnly": "npm run build",
27
- "test": "vitest run",
28
- "test:watch": "vitest",
29
- "typecheck": "tsc -p tsconfig.json --noEmit",
30
- "typecheck:tests": "tsc -p tsconfig.test.json --noEmit",
31
- "lint:biome": "biome check --unsafe --write",
32
- "lint:md": "markdownlint \"**/*.md\" --ignore node_modules",
33
- "lint": "npm run lint:biome && npm run lint:md && npm run typecheck && npm run typecheck:tests",
34
- "update": "npx npm-check-updates -i"
35
- },
36
- "files": [
37
- "dist",
38
- "README.md",
39
- "LICENSE"
40
- ],
41
- "dependencies": {
42
- "apca-w3": "^0.1.9",
43
- "colorjs.io": "^0.6.0"
44
- },
45
- "devDependencies": {
46
- "@biomejs/biome": "^2.3.11",
47
- "@types/apca-w3": "^0.1.3",
48
- "@types/node": "^22.10.5",
49
- "markdownlint-cli": "^0.47.0",
50
- "tsx": "^4.21.0",
51
- "typescript": "^5.9.3",
52
- "vitest": "^4.0.16"
53
- }
2
+ "author": "Claus Haas",
3
+ "dependencies": {
4
+ "apca-w3": "^0.1.9"
5
+ },
6
+ "description": "Easy way to create the color palette of your app",
7
+ "devDependencies": {
8
+ "@biomejs/biome": "^2.4.13",
9
+ "@types/apca-w3": "^0.1.3",
10
+ "@types/node": "^25.6.0",
11
+ "markdownlint-cli": "^0.48.0",
12
+ "tsx": "^4.21.0",
13
+ "typescript": "^6.0.3",
14
+ "vitest": "^4.1.5"
15
+ },
16
+ "exports": {
17
+ ".": {
18
+ "default": "./dist/index.js",
19
+ "types": "./dist/index.d.ts"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md",
25
+ "LICENSE",
26
+ "CHANGELOG.md",
27
+ "docs/README.md",
28
+ "docs/API.md",
29
+ "docs/Config.md",
30
+ "docs/Concepts.md",
31
+ "docs/Architecture.md",
32
+ "docs/Validation.md",
33
+ "docs/FAQ.md",
34
+ "docs/Usage-Web.md",
35
+ "docs/Usage-ReactNative.md",
36
+ "docs/Usage-JSON.md",
37
+ "docs/CLI.md",
38
+ "docs/Exporters.md",
39
+ "docs/Tokens.md",
40
+ "docs/Diagnostics.md",
41
+ "docs/Alpha.md",
42
+ "docs/Overlays.md",
43
+ "docs/Text.md",
44
+ "docs/Why.md",
45
+ "docs/Migration.md",
46
+ "docs/spec.md",
47
+ "docs/_api-surface.md",
48
+ "docs/snippets/serialize-oklch.md"
49
+ ],
50
+ "license": "MIT",
51
+ "main": "dist/index.js",
52
+ "name": "@clhaas/palette-kit",
53
+ "packageManager": "pnpm@10.33.2",
54
+ "publishConfig": {
55
+ "access": "public"
56
+ },
57
+ "repository": {
58
+ "type": "git",
59
+ "url": "https://github.com/claushaas/palette-kit"
60
+ },
61
+ "scripts": {
62
+ "build": "tsc -p tsconfig.build.json",
63
+ "clean": "rm -rf dist",
64
+ "lint": "pnpm run lint:biome && pnpm run lint:md && pnpm run typecheck",
65
+ "lint:biome": "biome check --unsafe --write",
66
+ "lint:md": "markdownlint \"**/*.md\" --ignore node_modules --fix",
67
+ "prepublishOnly": "npm run build",
68
+ "test": "vitest run",
69
+ "test:watch": "vitest",
70
+ "typecheck": "tsc -p tsconfig.json --noEmit",
71
+ "update": "pnpm dlx npm-check-updates -i"
72
+ },
73
+ "type": "module",
74
+ "types": "dist/index.d.ts",
75
+ "version": "0.4.0"
54
76
  }
@@ -1,5 +0,0 @@
1
- import type { AlphaScale, ColorHex } from "../types.js";
2
- export declare function generateAlphaScale(base: ColorHex, _background: {
3
- light: ColorHex;
4
- dark: ColorHex;
5
- }): AlphaScale;
@@ -1,34 +0,0 @@
1
- import Color from "colorjs.io";
2
- const steps = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
3
- const alphaCurve = {
4
- 1: 0.05,
5
- 2: 0.1,
6
- 3: 0.15,
7
- 4: 0.2,
8
- 5: 0.3,
9
- 6: 0.4,
10
- 7: 0.5,
11
- 8: 0.6,
12
- 9: 0.7,
13
- 10: 0.8,
14
- 11: 0.9,
15
- 12: 0.95,
16
- };
17
- function mixWithAlpha(foreground, alpha) {
18
- const color = new Color(foreground).to("srgb");
19
- const [r, g, b] = color.coords;
20
- const hex = new Color({ space: "srgb", coords: [r, g, b], alpha }).toString({
21
- format: "hex",
22
- });
23
- return hex;
24
- }
25
- export function generateAlphaScale(base, _background) {
26
- const light = {};
27
- const dark = {};
28
- for (const step of steps) {
29
- const alpha = alphaCurve[step];
30
- light[step] = mixWithAlpha(base, alpha);
31
- dark[step] = mixWithAlpha(base, alpha);
32
- }
33
- return { light, dark };
34
- }
package/dist/cli.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/dist/cli.js DELETED
@@ -1,150 +0,0 @@
1
- #!/usr/bin/env node
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
- import { createRequire } from "node:module";
4
- import path from "node:path";
5
- import { pathToFileURL } from "node:url";
6
- import { createTheme } from "./createTheme.js";
7
- import { toTs, toTsWithMode } from "./exporters/toTs.js";
8
- const DEFAULT_CONFIG_FILES = [
9
- "palette.config.mjs",
10
- "palette.config.js",
11
- "palette.config.cjs",
12
- "palette.config.json",
13
- ];
14
- const args = process.argv.slice(2);
15
- const command = args[0];
16
- if (!command || command === "--help" || command === "-h") {
17
- printHelp();
18
- process.exit(0);
19
- }
20
- if (command !== "generate") {
21
- console.error(`Unknown command: ${command}`);
22
- printHelp();
23
- process.exit(1);
24
- }
25
- const options = parseArgs(args.slice(1));
26
- const configPath = resolveConfigPath(options.configPath);
27
- const outPath = path.resolve(process.cwd(), options.outPath ?? "src/theme.ts");
28
- const mode = options.mode;
29
- const config = await loadConfig(configPath);
30
- if (!config || typeof config !== "object") {
31
- console.error("Config must export a plain object with createTheme options.");
32
- process.exit(1);
33
- }
34
- if (!("neutral" in config) || !("accent" in config)) {
35
- console.error("Config must include at least `neutral` and `accent` sources.");
36
- process.exit(1);
37
- }
38
- const theme = createTheme(config);
39
- const ts = mode ? toTsWithMode(theme, mode) : toTs(theme);
40
- mkdirSync(path.dirname(outPath), { recursive: true });
41
- writeFileSync(outPath, ts);
42
- console.log(`Generated ${path.relative(process.cwd(), outPath)}`);
43
- function parseArgs(input) {
44
- const options = {};
45
- for (let i = 0; i < input.length; i += 1) {
46
- const arg = input[i];
47
- if (arg === "--config" || arg === "-c") {
48
- options.configPath = input[i + 1];
49
- i += 1;
50
- continue;
51
- }
52
- if (arg?.startsWith("--config=")) {
53
- options.configPath = arg.split("=")[1];
54
- continue;
55
- }
56
- if (arg === "--out" || arg === "-o") {
57
- options.outPath = input[i + 1];
58
- i += 1;
59
- continue;
60
- }
61
- if (arg?.startsWith("--out=")) {
62
- options.outPath = arg.split("=")[1];
63
- continue;
64
- }
65
- if (arg === "--mode" || arg === "-m") {
66
- const value = input[i + 1];
67
- if (!value) {
68
- console.error('Missing value for --mode. Use "srgb" or "p3".');
69
- process.exit(1);
70
- }
71
- if (value !== "srgb" && value !== "p3") {
72
- console.error(`Invalid mode: ${value}. Use "srgb" or "p3".`);
73
- process.exit(1);
74
- }
75
- options.mode = value;
76
- i += 1;
77
- continue;
78
- }
79
- if (arg?.startsWith("--mode=")) {
80
- const value = arg.split("=")[1];
81
- if (!value) {
82
- console.error('Missing value for --mode. Use "srgb" or "p3".');
83
- process.exit(1);
84
- }
85
- if (value !== "srgb" && value !== "p3") {
86
- console.error(`Invalid mode: ${value}. Use "srgb" or "p3".`);
87
- process.exit(1);
88
- }
89
- options.mode = value;
90
- continue;
91
- }
92
- if (arg === "--help" || arg === "-h") {
93
- printHelp();
94
- process.exit(0);
95
- }
96
- console.error(`Unknown argument: ${arg}`);
97
- printHelp();
98
- process.exit(1);
99
- }
100
- return options;
101
- }
102
- function resolveConfigPath(configPath) {
103
- if (configPath) {
104
- const resolved = path.resolve(process.cwd(), configPath);
105
- if (!existsSync(resolved)) {
106
- console.error(`Config not found: ${configPath}`);
107
- process.exit(1);
108
- }
109
- return resolved;
110
- }
111
- for (const filename of DEFAULT_CONFIG_FILES) {
112
- const candidate = path.resolve(process.cwd(), filename);
113
- if (existsSync(candidate)) {
114
- return candidate;
115
- }
116
- }
117
- console.error("No config file found. Expected one of:");
118
- for (const filename of DEFAULT_CONFIG_FILES) {
119
- console.error(` - ${filename}`);
120
- }
121
- process.exit(1);
122
- throw new Error("No config file found.");
123
- }
124
- async function loadConfig(filePath) {
125
- const ext = path.extname(filePath).toLowerCase();
126
- if (ext === ".json") {
127
- const raw = readFileSync(filePath, "utf8");
128
- return JSON.parse(raw);
129
- }
130
- if (ext === ".cjs") {
131
- const require = createRequire(import.meta.url);
132
- return require(filePath);
133
- }
134
- const module = await import(pathToFileURL(filePath).href);
135
- return (module.default ?? module.config ?? module.theme ?? module);
136
- }
137
- function printHelp() {
138
- console.log([
139
- "palette-kit generate [options]",
140
- "",
141
- "Options:",
142
- " -c, --config <file> Config file (default: palette.config.*)",
143
- " -o, --out <file> Output file (default: src/theme.ts)",
144
- " -m, --mode <srgb|p3> Export mode (default: theme as-is)",
145
- " -h, --help Show help",
146
- "",
147
- "Example:",
148
- " palette-kit generate --config palette.config.mjs --out src/theme.ts",
149
- ].join("\n"));
150
- }
@@ -1,2 +0,0 @@
1
- import type { ColorHex } from "../types.js";
2
- export declare function apcaContrast(foreground: ColorHex, background: ColorHex): number;
@@ -1,5 +0,0 @@
1
- import { calcAPCA } from "apca-w3";
2
- export function apcaContrast(foreground, background) {
3
- const contrast = Number(calcAPCA(foreground, background));
4
- return Number(contrast.toFixed(2));
5
- }
@@ -1,6 +0,0 @@
1
- import type { ColorHex } from "../types.js";
2
- export declare function onSolidTextTokens(background: ColorHex): {
3
- primary: ColorHex;
4
- secondary: ColorHex;
5
- disabled: ColorHex;
6
- };
@@ -1,28 +0,0 @@
1
- import { apcaContrast } from "./apca.js";
2
- const white = "#ffffff";
3
- const black = "#000000";
4
- const alphaLevels = {
5
- primary: 0.92,
6
- secondary: 0.72,
7
- disabled: 0.48,
8
- };
9
- function withAlpha(hex, alpha) {
10
- const normalized = hex.replace("#", "");
11
- const alphaHex = Math.round(alpha * 255)
12
- .toString(16)
13
- .padStart(2, "0");
14
- return `#${normalized}${alphaHex}`;
15
- }
16
- function chooseTextColor(background) {
17
- const whiteScore = Math.abs(apcaContrast(white, background));
18
- const blackScore = Math.abs(apcaContrast(black, background));
19
- return whiteScore >= blackScore ? white : black;
20
- }
21
- export function onSolidTextTokens(background) {
22
- const base = chooseTextColor(background);
23
- return {
24
- primary: withAlpha(base, alphaLevels.primary),
25
- secondary: withAlpha(base, alphaLevels.secondary),
26
- disabled: withAlpha(base, alphaLevels.disabled),
27
- };
28
- }
@@ -1,2 +0,0 @@
1
- import type { ColorHex } from "../types.js";
2
- export declare function adjustTextColor(foreground: ColorHex, background: ColorHex, target: number): ColorHex;
@@ -1,31 +0,0 @@
1
- import Color from "colorjs.io";
2
- import { compressToSrgb, oklchToHex } from "../engine/oklch.js";
3
- import { apcaContrast } from "./apca.js";
4
- function clamp(value, min, max) {
5
- return Math.min(max, Math.max(min, value));
6
- }
7
- function adjustLightness(oklch, background, target, maxIterations = 24) {
8
- const bg = new Color(background).to("oklch");
9
- const bgL = bg.coords[0] ?? 0;
10
- const direction = bgL > 0.5 ? -1 : 1;
11
- let current = { ...oklch };
12
- for (let i = 0; i < maxIterations; i += 1) {
13
- const contrast = Math.abs(apcaContrast(oklchToHex(current), background));
14
- if (contrast >= target) {
15
- return current;
16
- }
17
- current = {
18
- ...current,
19
- l: clamp(current.l + direction * 0.02, 0, 1),
20
- };
21
- }
22
- return current;
23
- }
24
- export function adjustTextColor(foreground, background, target) {
25
- const fg = new Color(foreground).to("oklch");
26
- const [l, c, h] = fg.coords;
27
- let candidate = { l: l ?? 0, c: c ?? 0, h: h ?? 0 };
28
- candidate = adjustLightness(candidate, background, target);
29
- candidate = compressToSrgb(candidate);
30
- return oklchToHex(candidate);
31
- }
@@ -1,38 +0,0 @@
1
- import type { GenerateScaleOptions } from "./generateScale.js";
2
- import type { ColorHex, ColorSource, Theme } from "./types.js";
3
- export type TokenOverrides = {
4
- light?: Record<string, ColorHex>;
5
- dark?: Record<string, ColorHex>;
6
- };
7
- export type CreateThemeOptions = {
8
- neutral: ColorSource;
9
- accent: ColorSource;
10
- semantic?: {
11
- success?: ColorSource;
12
- warning?: ColorSource;
13
- danger?: ColorSource;
14
- };
15
- extras?: Record<string, ColorSource>;
16
- tokens?: {
17
- preset?: "radix-like-ui";
18
- overrides?: TokenOverrides;
19
- };
20
- alpha?: {
21
- enabled?: boolean;
22
- background?: {
23
- light?: ColorHex;
24
- dark?: ColorHex;
25
- };
26
- };
27
- text?: {
28
- darkBase?: ColorHex;
29
- lightBase?: ColorHex;
30
- };
31
- contrast?: {
32
- textPrimary?: number;
33
- textSecondary?: number;
34
- };
35
- scale?: Omit<GenerateScaleOptions, "source" | "mode" | "p3">;
36
- p3?: boolean;
37
- };
38
- export declare function createTheme(options: CreateThemeOptions): Theme;
@@ -1,148 +0,0 @@
1
- import { generateAlphaScale } from "./alpha/generateAlphaScale.js";
2
- import { onSolidTextTokens } from "./contrast/onSolid.js";
3
- import { analyzeTheme } from "./diagnostics/analyzeTheme.js";
4
- import { generateScale } from "./generateScale.js";
5
- import { generateOverlayScale } from "./overlays/generateOverlayScale.js";
6
- import { generateTextScale } from "./text/generateTextScale.js";
7
- import { buildPresetTokens } from "./tokens/presetRadixLikeUi.js";
8
- export function createTheme(options) {
9
- const includeP3 = options.p3 ?? false;
10
- const scaleOptions = options.scale ?? {};
11
- const scales = {
12
- neutral: generateScale({ source: options.neutral, ...scaleOptions, p3: includeP3 }),
13
- accent: generateScale({ source: options.accent, ...scaleOptions, p3: includeP3 }),
14
- };
15
- if (options.semantic?.success) {
16
- scales.success = generateScale({
17
- source: options.semantic.success,
18
- ...scaleOptions,
19
- p3: includeP3,
20
- });
21
- }
22
- if (options.semantic?.warning) {
23
- scales.warning = generateScale({
24
- source: options.semantic.warning,
25
- ...scaleOptions,
26
- p3: includeP3,
27
- });
28
- }
29
- if (options.semantic?.danger) {
30
- scales.danger = generateScale({
31
- source: options.semantic.danger,
32
- ...scaleOptions,
33
- p3: includeP3,
34
- });
35
- }
36
- if (options.extras) {
37
- for (const [key, source] of Object.entries(options.extras)) {
38
- scales[key] = generateScale({ source, ...scaleOptions, p3: includeP3 });
39
- }
40
- }
41
- const preset = options.tokens?.preset ?? "radix-like-ui";
42
- const tokens = preset === "radix-like-ui" ? buildPresetTokens(scales) : { light: {}, dark: {} };
43
- const accentScale = scales.accent;
44
- const lightOnSolid = onSolidTextTokens(accentScale.light[9]);
45
- const darkOnSolid = onSolidTextTokens(accentScale.dark[9]);
46
- tokens.light["onSolid.primary"] = lightOnSolid.primary;
47
- tokens.light["onSolid.secondary"] = lightOnSolid.secondary;
48
- tokens.light["onSolid.disabled"] = lightOnSolid.disabled;
49
- tokens.dark["onSolid.primary"] = darkOnSolid.primary;
50
- tokens.dark["onSolid.secondary"] = darkOnSolid.secondary;
51
- tokens.dark["onSolid.disabled"] = darkOnSolid.disabled;
52
- const textScale = generateTextScale({
53
- darkBase: options.text?.darkBase,
54
- lightBase: options.text?.lightBase,
55
- });
56
- const darkTextSteps = {
57
- primary: 12,
58
- secondary: 10,
59
- tertiary: 9,
60
- disabled: 8,
61
- };
62
- const lightTextSteps = {
63
- primary: 1,
64
- secondary: 3,
65
- tertiary: 4,
66
- disabled: 5,
67
- };
68
- const midDarkTextSteps = {
69
- primary: 12,
70
- secondary: 11,
71
- };
72
- const midLightTextSteps = {
73
- primary: 1,
74
- secondary: 3,
75
- };
76
- const onBgLightMode = {
77
- light: { scale: "dark", steps: darkTextSteps },
78
- mid: { scale: "dark", steps: midDarkTextSteps },
79
- dark: { scale: "light", steps: lightTextSteps },
80
- };
81
- const onBgDarkMode = {
82
- light: { scale: "light", steps: lightTextSteps },
83
- mid: { scale: "light", steps: midLightTextSteps },
84
- dark: { scale: "dark", steps: darkTextSteps },
85
- };
86
- const applyOnBgTokens = (target, mapping) => {
87
- for (const [zone, config] of Object.entries(mapping)) {
88
- const scale = config.scale === "dark" ? textScale.dark : textScale.light;
89
- for (const [role, step] of Object.entries(config.steps)) {
90
- target[`text.onBg.${zone}.${role}`] = scale[step];
91
- }
92
- }
93
- };
94
- for (const [step, value] of Object.entries(textScale.dark)) {
95
- tokens.light[`text.dark.${step}`] = value;
96
- tokens.dark[`text.dark.${step}`] = value;
97
- }
98
- for (const [step, value] of Object.entries(textScale.light)) {
99
- tokens.light[`text.light.${step}`] = value;
100
- tokens.dark[`text.light.${step}`] = value;
101
- }
102
- for (const [key, step] of Object.entries(darkTextSteps)) {
103
- const token = `text.dark.${key}`;
104
- tokens.light[token] = textScale.dark[step];
105
- tokens.dark[token] = textScale.dark[step];
106
- }
107
- for (const [key, step] of Object.entries(lightTextSteps)) {
108
- const token = `text.light.${key}`;
109
- tokens.light[token] = textScale.light[step];
110
- tokens.dark[token] = textScale.light[step];
111
- }
112
- applyOnBgTokens(tokens.light, onBgLightMode);
113
- applyOnBgTokens(tokens.dark, onBgDarkMode);
114
- tokens.light["text.primary"] = tokens.light["text.onBg.light.primary"];
115
- tokens.light["text.secondary"] = tokens.light["text.onBg.light.secondary"];
116
- tokens.light["text.tertiary"] = tokens.light["text.onBg.light.tertiary"];
117
- tokens.light["text.disabled"] = tokens.light["text.onBg.light.disabled"];
118
- tokens.dark["text.primary"] = tokens.dark["text.onBg.light.primary"];
119
- tokens.dark["text.secondary"] = tokens.dark["text.onBg.light.secondary"];
120
- tokens.dark["text.tertiary"] = tokens.dark["text.onBg.light.tertiary"];
121
- tokens.dark["text.disabled"] = tokens.dark["text.onBg.light.disabled"];
122
- if (options.tokens?.overrides?.light) {
123
- Object.assign(tokens.light, options.tokens.overrides.light);
124
- }
125
- if (options.tokens?.overrides?.dark) {
126
- Object.assign(tokens.dark, options.tokens.overrides.dark);
127
- }
128
- let alpha;
129
- if (options.alpha?.enabled !== false) {
130
- const background = {
131
- light: options.alpha?.background?.light ?? "#ffffff",
132
- dark: options.alpha?.background?.dark ?? "#111111",
133
- };
134
- alpha = Object.fromEntries(Object.entries(scales).map(([slot, scale]) => [
135
- slot,
136
- generateAlphaScale(scale.light[9], background),
137
- ]));
138
- }
139
- const overlay = generateOverlayScale();
140
- const diagnostics = analyzeTheme({ scales, tokens, alpha, overlay });
141
- return {
142
- scales,
143
- tokens,
144
- alpha,
145
- overlay,
146
- diagnostics,
147
- };
148
- }
@@ -1,3 +0,0 @@
1
- import type { ColorHex, RadixSeedName } from "../types.js";
2
- export declare const radixSeeds: Record<RadixSeedName, ColorHex>;
3
- export declare const radixSeedNames: string[];
@@ -1,34 +0,0 @@
1
- export const radixSeeds = {
2
- amber: "#ffc53d",
3
- blue: "#0090ff",
4
- bronze: "#a18072",
5
- brown: "#ad7f58",
6
- crimson: "#e93d82",
7
- cyan: "#00a2c7",
8
- gold: "#978365",
9
- grass: "#46a758",
10
- gray: "#8d8d8d",
11
- green: "#30a46c",
12
- indigo: "#3e63dd",
13
- iris: "#5b5bd6",
14
- jade: "#29a383",
15
- lime: "#bdee63",
16
- mauve: "#8e8c99",
17
- mint: "#86ead4",
18
- olive: "#898e87",
19
- orange: "#f76b15",
20
- pink: "#d6409f",
21
- plum: "#ab4aba",
22
- purple: "#8e4ec6",
23
- red: "#e5484d",
24
- ruby: "#e54666",
25
- sage: "#868e8b",
26
- sand: "#8d8d86",
27
- sky: "#7ce2fe",
28
- slate: "#8b8d98",
29
- teal: "#12a594",
30
- tomato: "#e54d2e",
31
- violet: "#6e56cf",
32
- yellow: "#ffe629",
33
- };
34
- export const radixSeedNames = Object.keys(radixSeeds).sort();
@@ -1,2 +0,0 @@
1
- import type { Scale, ScaleDiagnostics } from "../types.js";
2
- export declare function analyzeScale(scale: Scale): ScaleDiagnostics;
@@ -1,7 +0,0 @@
1
- export function analyzeScale(scale) {
2
- return {
3
- outOfGamutCount: scale.meta?.outOfGamutCount ?? 0,
4
- outOfP3GamutCount: scale.meta?.outOfP3GamutCount ?? 0,
5
- anchorSteps: scale.meta?.anchorSteps,
6
- };
7
- }
@@ -1,2 +0,0 @@
1
- import type { Theme, ThemeDiagnostics } from "../types.js";
2
- export declare function analyzeTheme(theme: Theme): ThemeDiagnostics;