oklchtohex 0.1.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.
package/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # oklchtohex
2
+
3
+ `oklchtohex` helps teams using Tailwind v4 convert `oklch(...)` colors into HEX.
4
+
5
+ This is useful when:
6
+ - clients compare implementation colors against Figma tokens shown in HEX
7
+ - QA wants quick visual checks from DevTools
8
+ - you want an optional HEX-only CSS artifact at build time
9
+
10
+ ## Why this approach
11
+
12
+ A build-time package is the most practical fix:
13
+ - no Tailwind fork required
14
+ - works for any CSS output (including generated Tailwind files)
15
+ - can run in CI and produce a deterministic `*.hex.css` artifact
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm i -D oklchtohex
21
+ ```
22
+
23
+ ## CLI usage
24
+
25
+ Convert one value:
26
+
27
+ ```bash
28
+ npx oklchtohex --value "oklch(70.4% 0.191 22.216)"
29
+ ```
30
+
31
+ Convert a CSS file and write to a new file:
32
+
33
+ ```bash
34
+ npx oklchtohex ./dist/app.css -o ./dist/app.hex.css
35
+ ```
36
+
37
+ Print transformed CSS to stdout:
38
+
39
+ ```bash
40
+ npx oklchtohex ./dist/app.css --stdout
41
+ ```
42
+
43
+ ### Options
44
+
45
+ - `--gamut fit|clip`
46
+ `clip` (default) hard-clamps channels; `fit` reduces chroma to stay in sRGB.
47
+ - `--alpha auto|always|never`
48
+ defaults to `auto`.
49
+ - `--upper`
50
+ outputs uppercase HEX.
51
+
52
+ When converting Tailwind CSS, known default variables like `--color-red-500` are replaced with the exact Tailwind HEX palette value first. Unknown variables and raw `oklch(...)` values use functional conversion.
53
+
54
+ ## Tailwind v4 integration (Inspect Element workflow)
55
+
56
+ ```json
57
+ {
58
+ "scripts": {
59
+ "build:css": "tailwindcss -i ./src/input.css -o ./dist/tailwind.css",
60
+ "build:css:hex": "oklchtohex ./dist/tailwind.css -o ./dist/tailwind.css",
61
+ "build": "npm run build:css && npm run build:css:hex"
62
+ }
63
+ }
64
+ ```
65
+
66
+ This rewrites Tailwind output in-place, so your existing HTML `<link>` remains unchanged and DevTools "Styles" pane shows HEX declarations.
67
+
68
+ If you want two files instead, output to `./dist/tailwind.hex.css` and link that file.
69
+
70
+ Note: some browsers still show `rgb(...)` in the "Computed" pane. The "Styles" pane reflects your source declaration format.
71
+
72
+ ## JS API
73
+
74
+ ```js
75
+ import { oklchToHex, replaceOklchInText } from "oklchtohex";
76
+
77
+ const hex = oklchToHex("oklch(70.4% 0.191 22.216)");
78
+ const css = replaceOklchInText("color: oklch(70.4% 0.191 22.216);");
79
+ ```
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "oklchtohex",
3
+ "version": "0.1.0",
4
+ "description": "Convert OKLCH colors to HEX and rewrite CSS at build time.",
5
+ "type": "module",
6
+ "main": "./src/converter.js",
7
+ "exports": {
8
+ ".": "./src/converter.js"
9
+ },
10
+ "bin": {
11
+ "oklchtohex": "./src/cli.js"
12
+ },
13
+ "files": [
14
+ "src",
15
+ "README.md"
16
+ ],
17
+ "scripts": {
18
+ "check": "node ./src/cli.js --help"
19
+ },
20
+ "keywords": [
21
+ "oklch",
22
+ "hex",
23
+ "tailwind",
24
+ "tailwindcss",
25
+ "color",
26
+ "converter"
27
+ ],
28
+ "author": "",
29
+ "license": "MIT",
30
+ "engines": {
31
+ "node": ">=18"
32
+ }
33
+ }
package/src/cli.js ADDED
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import process from "node:process";
6
+ import { oklchToHex, replaceOklchInText } from "./converter.js";
7
+
8
+ function printHelp() {
9
+ const help = `
10
+ oklchtohex
11
+
12
+ Convert OKLCH values to HEX, or rewrite an entire CSS file.
13
+
14
+ Usage:
15
+ oklchtohex --value "oklch(70.4% 0.191 22.216)"
16
+ oklchtohex ./dist/app.css -o ./dist/app.hex.css
17
+ oklchtohex ./dist/app.css --stdout
18
+
19
+ Options:
20
+ --value <oklch> Convert a single OKLCH value to HEX
21
+ -o, --output <file> Output file path for transformed CSS
22
+ --stdout Print transformed CSS to stdout
23
+ --gamut <fit|clip> Gamut strategy (default: clip)
24
+ --alpha <auto|always|never>
25
+ Include alpha in HEX (default: auto)
26
+ --upper Uppercase HEX output
27
+ -h, --help Show this help text
28
+ `;
29
+ process.stdout.write(help);
30
+ }
31
+
32
+ function parseArgs(argv) {
33
+ const parsed = {
34
+ input: undefined,
35
+ output: undefined,
36
+ value: undefined,
37
+ stdout: false,
38
+ gamut: "clip",
39
+ includeAlpha: "auto",
40
+ uppercase: false,
41
+ help: false
42
+ };
43
+
44
+ for (let i = 0; i < argv.length; i += 1) {
45
+ const arg = argv[i];
46
+
47
+ if (arg === "-h" || arg === "--help") {
48
+ parsed.help = true;
49
+ continue;
50
+ }
51
+ if (arg === "--value") {
52
+ parsed.value = argv[i + 1];
53
+ i += 1;
54
+ continue;
55
+ }
56
+ if (arg === "-o" || arg === "--output") {
57
+ parsed.output = argv[i + 1];
58
+ i += 1;
59
+ continue;
60
+ }
61
+ if (arg === "--stdout") {
62
+ parsed.stdout = true;
63
+ continue;
64
+ }
65
+ if (arg === "--gamut") {
66
+ parsed.gamut = argv[i + 1];
67
+ i += 1;
68
+ continue;
69
+ }
70
+ if (arg === "--alpha") {
71
+ parsed.includeAlpha = argv[i + 1];
72
+ i += 1;
73
+ continue;
74
+ }
75
+ if (arg === "--upper") {
76
+ parsed.uppercase = true;
77
+ continue;
78
+ }
79
+ if (!arg.startsWith("-") && !parsed.input) {
80
+ parsed.input = arg;
81
+ continue;
82
+ }
83
+
84
+ throw new Error(`Unknown argument: ${arg}`);
85
+ }
86
+
87
+ return parsed;
88
+ }
89
+
90
+ function normalizeIncludeAlpha(value) {
91
+ if (!value || value === "auto") {
92
+ return "auto";
93
+ }
94
+ if (value === "always") {
95
+ return true;
96
+ }
97
+ if (value === "never") {
98
+ return false;
99
+ }
100
+ throw new Error(`Invalid --alpha value: ${value}`);
101
+ }
102
+
103
+ function normalizeGamut(value) {
104
+ if (value === "fit" || value === "clip") {
105
+ return value;
106
+ }
107
+ throw new Error(`Invalid --gamut value: ${value}`);
108
+ }
109
+
110
+ async function run() {
111
+ const args = parseArgs(process.argv.slice(2));
112
+ if (args.help) {
113
+ printHelp();
114
+ return;
115
+ }
116
+
117
+ const options = {
118
+ gamut: normalizeGamut(args.gamut),
119
+ includeAlpha: normalizeIncludeAlpha(args.includeAlpha),
120
+ uppercase: args.uppercase
121
+ };
122
+
123
+ if (args.value) {
124
+ const hex = oklchToHex(args.value, options);
125
+ process.stdout.write(`${hex}\n`);
126
+ return;
127
+ }
128
+
129
+ if (!args.input) {
130
+ throw new Error("Missing input. Provide --value or a CSS file path.");
131
+ }
132
+
133
+ const inputPath = path.resolve(process.cwd(), args.input);
134
+ const css = await fs.readFile(inputPath, "utf8");
135
+ const transformed = replaceOklchInText(css, options);
136
+
137
+ if (args.stdout || !args.output) {
138
+ process.stdout.write(transformed);
139
+ if (!transformed.endsWith("\n")) {
140
+ process.stdout.write("\n");
141
+ }
142
+ return;
143
+ }
144
+
145
+ const outputPath = path.resolve(process.cwd(), args.output);
146
+ await fs.writeFile(outputPath, transformed, "utf8");
147
+ }
148
+
149
+ run().catch((error) => {
150
+ process.stderr.write(`${error.message}\n`);
151
+ process.exit(1);
152
+ });
@@ -0,0 +1,243 @@
1
+ import { getTailwindDefaultHexForVar } from "./tailwind-default-hex.js";
2
+ const OKLCH_REGEX = /oklch\(([^)]*)\)/gi;
3
+
4
+ function clamp(value, min, max) {
5
+ return Math.min(max, Math.max(min, value));
6
+ }
7
+
8
+ function parseNumericToken(token) {
9
+ const value = Number.parseFloat(token);
10
+ if (Number.isNaN(value)) {
11
+ throw new Error(`Invalid numeric token: "${token}"`);
12
+ }
13
+ return value;
14
+ }
15
+
16
+ function parseLightness(token) {
17
+ const trimmed = token.trim().toLowerCase();
18
+ if (trimmed.endsWith("%")) {
19
+ return clamp(parseNumericToken(trimmed.slice(0, -1)) / 100, 0, 1);
20
+ }
21
+
22
+ const value = parseNumericToken(trimmed);
23
+ if (value > 1 && value <= 100) {
24
+ return clamp(value / 100, 0, 1);
25
+ }
26
+ return clamp(value, 0, 1);
27
+ }
28
+
29
+ function parseHue(token) {
30
+ const trimmed = token.trim().toLowerCase();
31
+ if (trimmed.endsWith("deg")) {
32
+ return parseNumericToken(trimmed.slice(0, -3));
33
+ }
34
+ if (trimmed.endsWith("rad")) {
35
+ return (parseNumericToken(trimmed.slice(0, -3)) * 180) / Math.PI;
36
+ }
37
+ if (trimmed.endsWith("turn")) {
38
+ return parseNumericToken(trimmed.slice(0, -4)) * 360;
39
+ }
40
+ return parseNumericToken(trimmed);
41
+ }
42
+
43
+ function parseAlpha(token) {
44
+ if (typeof token !== "string") {
45
+ return 1;
46
+ }
47
+
48
+ const trimmed = token.trim().toLowerCase();
49
+ if (trimmed.endsWith("%")) {
50
+ return clamp(parseNumericToken(trimmed.slice(0, -1)) / 100, 0, 1);
51
+ }
52
+ return clamp(parseNumericToken(trimmed), 0, 1);
53
+ }
54
+
55
+ function normalizeHueDegrees(hue) {
56
+ const normalized = hue % 360;
57
+ return normalized < 0 ? normalized + 360 : normalized;
58
+ }
59
+
60
+ export function parseOklch(input) {
61
+ if (typeof input !== "string") {
62
+ throw new Error("parseOklch expects a string like oklch(70% 0.2 30)");
63
+ }
64
+
65
+ const trimmed = input.trim();
66
+ const lower = trimmed.toLowerCase();
67
+ if (!lower.startsWith("oklch(") || !lower.endsWith(")")) {
68
+ throw new Error(`Invalid OKLCH function: "${input}"`);
69
+ }
70
+
71
+ const inner = trimmed.slice(trimmed.indexOf("(") + 1, -1).trim();
72
+ const slashIndex = inner.indexOf("/");
73
+ const colorPart = slashIndex === -1 ? inner : inner.slice(0, slashIndex).trim();
74
+ const alphaPart = slashIndex === -1 ? undefined : inner.slice(slashIndex + 1).trim();
75
+
76
+ const parts = colorPart
77
+ .replace(/,/g, " ")
78
+ .split(/\s+/)
79
+ .filter(Boolean);
80
+
81
+ if (parts.length < 3) {
82
+ throw new Error(`Invalid OKLCH channels: "${input}"`);
83
+ }
84
+
85
+ const l = parseLightness(parts[0]);
86
+ const c = Math.max(0, parseNumericToken(parts[1]));
87
+ const h = normalizeHueDegrees(parseHue(parts[2]));
88
+ const alpha = parseAlpha(alphaPart);
89
+
90
+ return { l, c, h, alpha };
91
+ }
92
+
93
+ function oklabToLinearSrgb(l, a, b) {
94
+ const l_ = l + 0.3963377774 * a + 0.2158037573 * b;
95
+ const m_ = l - 0.1055613458 * a - 0.0638541728 * b;
96
+ const s_ = l - 0.0894841775 * a - 1.291485548 * b;
97
+
98
+ const l3 = l_ * l_ * l_;
99
+ const m3 = m_ * m_ * m_;
100
+ const s3 = s_ * s_ * s_;
101
+
102
+ return {
103
+ r: +4.0767416621 * l3 - 3.3077115913 * m3 + 0.2309699292 * s3,
104
+ g: -1.2684380046 * l3 + 2.6097574011 * m3 - 0.3413193965 * s3,
105
+ b: -0.0041960863 * l3 - 0.7034186147 * m3 + 1.707614701 * s3
106
+ };
107
+ }
108
+
109
+ function oklchToLinearSrgb(l, c, hDegrees) {
110
+ const radians = (hDegrees * Math.PI) / 180;
111
+ const a = c * Math.cos(radians);
112
+ const b = c * Math.sin(radians);
113
+ return oklabToLinearSrgb(l, a, b);
114
+ }
115
+
116
+ function isInSrgbGamut(linearRgb) {
117
+ return (
118
+ linearRgb.r >= 0 &&
119
+ linearRgb.r <= 1 &&
120
+ linearRgb.g >= 0 &&
121
+ linearRgb.g <= 1 &&
122
+ linearRgb.b >= 0 &&
123
+ linearRgb.b <= 1
124
+ );
125
+ }
126
+
127
+ function fitChromaToSrgb(l, c, h) {
128
+ const initial = oklchToLinearSrgb(l, c, h);
129
+ if (isInSrgbGamut(initial)) {
130
+ return c;
131
+ }
132
+
133
+ let low = 0;
134
+ let high = c;
135
+ for (let i = 0; i < 24; i += 1) {
136
+ const mid = (low + high) / 2;
137
+ const rgb = oklchToLinearSrgb(l, mid, h);
138
+ if (isInSrgbGamut(rgb)) {
139
+ low = mid;
140
+ } else {
141
+ high = mid;
142
+ }
143
+ }
144
+ return low;
145
+ }
146
+
147
+ function linearToSrgbChannel(channel) {
148
+ if (channel <= 0.0031308) {
149
+ return 12.92 * channel;
150
+ }
151
+ return 1.055 * channel ** (1 / 2.4) - 0.055;
152
+ }
153
+
154
+ function channelToHex(channel) {
155
+ const clamped = clamp(channel, 0, 1);
156
+ const byte = Math.round(clamped * 255);
157
+ return byte.toString(16).padStart(2, "0");
158
+ }
159
+
160
+ function normalizeInput(input) {
161
+ if (typeof input === "string") {
162
+ return parseOklch(input);
163
+ }
164
+ if (input && typeof input === "object") {
165
+ if (
166
+ typeof input.l === "number" &&
167
+ typeof input.c === "number" &&
168
+ typeof input.h === "number"
169
+ ) {
170
+ return {
171
+ l: clamp(input.l, 0, 1),
172
+ c: Math.max(0, input.c),
173
+ h: normalizeHueDegrees(input.h),
174
+ alpha: clamp(input.alpha ?? 1, 0, 1)
175
+ };
176
+ }
177
+ }
178
+ throw new Error("Input must be an OKLCH string or { l, c, h, alpha } object");
179
+ }
180
+
181
+ export function oklchToHex(input, options = {}) {
182
+ const { gamut = "clip", includeAlpha = "auto", uppercase = false } = options;
183
+ const parsed = normalizeInput(input);
184
+
185
+ const c =
186
+ gamut === "fit"
187
+ ? fitChromaToSrgb(parsed.l, parsed.c, parsed.h)
188
+ : parsed.c;
189
+
190
+ const linear = oklchToLinearSrgb(parsed.l, c, parsed.h);
191
+ const r = linearToSrgbChannel(linear.r);
192
+ const g = linearToSrgbChannel(linear.g);
193
+ const b = linearToSrgbChannel(linear.b);
194
+
195
+ let hex = `#${channelToHex(r)}${channelToHex(g)}${channelToHex(b)}`;
196
+ const shouldIncludeAlpha =
197
+ includeAlpha === true || includeAlpha === "always" || (includeAlpha === "auto" && parsed.alpha < 1);
198
+
199
+ if (shouldIncludeAlpha) {
200
+ hex += channelToHex(parsed.alpha);
201
+ }
202
+
203
+ return uppercase ? hex.toUpperCase() : hex;
204
+ }
205
+
206
+ function replaceTailwindDefaultColorVariables(text) {
207
+ const declarationRegex =
208
+ /(--color-[a-z]+-\d{2,3})(\s*:\s*)oklch\(([^)]*)\)/gi;
209
+
210
+ return text.replace(
211
+ declarationRegex,
212
+ (fullMatch, variableName, separator) => {
213
+ const mappedHex = getTailwindDefaultHexForVar(variableName.toLowerCase());
214
+ if (!mappedHex) {
215
+ return fullMatch;
216
+ }
217
+ return `${variableName}${separator}${mappedHex}`;
218
+ }
219
+ );
220
+ }
221
+
222
+ export function replaceOklchInText(text, options = {}) {
223
+ if (typeof text !== "string") {
224
+ throw new Error("replaceOklchInText expects a string");
225
+ }
226
+ const { onError = "preserve", ...convertOptions } = options;
227
+ const withMappedTailwindDefaults = replaceTailwindDefaultColorVariables(text);
228
+
229
+ return withMappedTailwindDefaults.replace(OKLCH_REGEX, (match) => {
230
+ try {
231
+ return oklchToHex(match, convertOptions);
232
+ } catch (error) {
233
+ if (onError === "throw") {
234
+ throw error;
235
+ }
236
+ return match;
237
+ }
238
+ });
239
+ }
240
+
241
+ export function convertTailwindCssToHex(css, options = {}) {
242
+ return replaceOklchInText(css, options);
243
+ }
@@ -0,0 +1,300 @@
1
+ const TAILWIND_HEX_COLORS = {
2
+ slate: {
3
+ 50: "#f8fafc",
4
+ 100: "#f1f5f9",
5
+ 200: "#e2e8f0",
6
+ 300: "#cbd5e1",
7
+ 400: "#94a3b8",
8
+ 500: "#64748b",
9
+ 600: "#475569",
10
+ 700: "#334155",
11
+ 800: "#1e293b",
12
+ 900: "#0f172a",
13
+ 950: "#020617"
14
+ },
15
+ gray: {
16
+ 50: "#f9fafb",
17
+ 100: "#f3f4f6",
18
+ 200: "#e5e7eb",
19
+ 300: "#d1d5db",
20
+ 400: "#9ca3af",
21
+ 500: "#6b7280",
22
+ 600: "#4b5563",
23
+ 700: "#374151",
24
+ 800: "#1f2937",
25
+ 900: "#111827",
26
+ 950: "#030712"
27
+ },
28
+ zinc: {
29
+ 50: "#fafafa",
30
+ 100: "#f4f4f5",
31
+ 200: "#e4e4e7",
32
+ 300: "#d4d4d8",
33
+ 400: "#a1a1aa",
34
+ 500: "#71717a",
35
+ 600: "#52525b",
36
+ 700: "#3f3f46",
37
+ 800: "#27272a",
38
+ 900: "#18181b",
39
+ 950: "#09090b"
40
+ },
41
+ neutral: {
42
+ 50: "#fafafa",
43
+ 100: "#f5f5f5",
44
+ 200: "#e5e5e5",
45
+ 300: "#d4d4d4",
46
+ 400: "#a3a3a3",
47
+ 500: "#737373",
48
+ 600: "#525252",
49
+ 700: "#404040",
50
+ 800: "#262626",
51
+ 900: "#171717",
52
+ 950: "#0a0a0a"
53
+ },
54
+ stone: {
55
+ 50: "#fafaf9",
56
+ 100: "#f5f5f4",
57
+ 200: "#e7e5e4",
58
+ 300: "#d6d3d1",
59
+ 400: "#a8a29e",
60
+ 500: "#78716c",
61
+ 600: "#57534e",
62
+ 700: "#44403c",
63
+ 800: "#292524",
64
+ 900: "#1c1917",
65
+ 950: "#0c0a09"
66
+ },
67
+ red: {
68
+ 50: "#fef2f2",
69
+ 100: "#fee2e2",
70
+ 200: "#fecaca",
71
+ 300: "#fca5a5",
72
+ 400: "#f87171",
73
+ 500: "#ef4444",
74
+ 600: "#dc2626",
75
+ 700: "#b91c1c",
76
+ 800: "#991b1b",
77
+ 900: "#7f1d1d",
78
+ 950: "#450a0a"
79
+ },
80
+ orange: {
81
+ 50: "#fff7ed",
82
+ 100: "#ffedd5",
83
+ 200: "#fed7aa",
84
+ 300: "#fdba74",
85
+ 400: "#fb923c",
86
+ 500: "#f97316",
87
+ 600: "#ea580c",
88
+ 700: "#c2410c",
89
+ 800: "#9a3412",
90
+ 900: "#7c2d12",
91
+ 950: "#431407"
92
+ },
93
+ amber: {
94
+ 50: "#fffbeb",
95
+ 100: "#fef3c7",
96
+ 200: "#fde68a",
97
+ 300: "#fcd34d",
98
+ 400: "#fbbf24",
99
+ 500: "#f59e0b",
100
+ 600: "#d97706",
101
+ 700: "#b45309",
102
+ 800: "#92400e",
103
+ 900: "#78350f",
104
+ 950: "#451a03"
105
+ },
106
+ yellow: {
107
+ 50: "#fefce8",
108
+ 100: "#fef9c3",
109
+ 200: "#fef08a",
110
+ 300: "#fde047",
111
+ 400: "#facc15",
112
+ 500: "#eab308",
113
+ 600: "#ca8a04",
114
+ 700: "#a16207",
115
+ 800: "#854d0e",
116
+ 900: "#713f12",
117
+ 950: "#422006"
118
+ },
119
+ lime: {
120
+ 50: "#f7fee7",
121
+ 100: "#ecfccb",
122
+ 200: "#d9f99d",
123
+ 300: "#bef264",
124
+ 400: "#a3e635",
125
+ 500: "#84cc16",
126
+ 600: "#65a30d",
127
+ 700: "#4d7c0f",
128
+ 800: "#3f6212",
129
+ 900: "#365314",
130
+ 950: "#1a2e05"
131
+ },
132
+ green: {
133
+ 50: "#f0fdf4",
134
+ 100: "#dcfce7",
135
+ 200: "#bbf7d0",
136
+ 300: "#86efac",
137
+ 400: "#4ade80",
138
+ 500: "#22c55e",
139
+ 600: "#16a34a",
140
+ 700: "#15803d",
141
+ 800: "#166534",
142
+ 900: "#14532d",
143
+ 950: "#052e16"
144
+ },
145
+ emerald: {
146
+ 50: "#ecfdf5",
147
+ 100: "#d1fae5",
148
+ 200: "#a7f3d0",
149
+ 300: "#6ee7b7",
150
+ 400: "#34d399",
151
+ 500: "#10b981",
152
+ 600: "#059669",
153
+ 700: "#047857",
154
+ 800: "#065f46",
155
+ 900: "#064e3b",
156
+ 950: "#022c22"
157
+ },
158
+ teal: {
159
+ 50: "#f0fdfa",
160
+ 100: "#ccfbf1",
161
+ 200: "#99f6e4",
162
+ 300: "#5eead4",
163
+ 400: "#2dd4bf",
164
+ 500: "#14b8a6",
165
+ 600: "#0d9488",
166
+ 700: "#0f766e",
167
+ 800: "#115e59",
168
+ 900: "#134e4a",
169
+ 950: "#042f2e"
170
+ },
171
+ cyan: {
172
+ 50: "#ecfeff",
173
+ 100: "#cffafe",
174
+ 200: "#a5f3fc",
175
+ 300: "#67e8f9",
176
+ 400: "#22d3ee",
177
+ 500: "#06b6d4",
178
+ 600: "#0891b2",
179
+ 700: "#0e7490",
180
+ 800: "#155e75",
181
+ 900: "#164e63",
182
+ 950: "#083344"
183
+ },
184
+ sky: {
185
+ 50: "#f0f9ff",
186
+ 100: "#e0f2fe",
187
+ 200: "#bae6fd",
188
+ 300: "#7dd3fc",
189
+ 400: "#38bdf8",
190
+ 500: "#0ea5e9",
191
+ 600: "#0284c7",
192
+ 700: "#0369a1",
193
+ 800: "#075985",
194
+ 900: "#0c4a6e",
195
+ 950: "#082f49"
196
+ },
197
+ blue: {
198
+ 50: "#eff6ff",
199
+ 100: "#dbeafe",
200
+ 200: "#bfdbfe",
201
+ 300: "#93c5fd",
202
+ 400: "#60a5fa",
203
+ 500: "#3b82f6",
204
+ 600: "#2563eb",
205
+ 700: "#1d4ed8",
206
+ 800: "#1e40af",
207
+ 900: "#1e3a8a",
208
+ 950: "#172554"
209
+ },
210
+ indigo: {
211
+ 50: "#eef2ff",
212
+ 100: "#e0e7ff",
213
+ 200: "#c7d2fe",
214
+ 300: "#a5b4fc",
215
+ 400: "#818cf8",
216
+ 500: "#6366f1",
217
+ 600: "#4f46e5",
218
+ 700: "#4338ca",
219
+ 800: "#3730a3",
220
+ 900: "#312e81",
221
+ 950: "#1e1b4b"
222
+ },
223
+ violet: {
224
+ 50: "#f5f3ff",
225
+ 100: "#ede9fe",
226
+ 200: "#ddd6fe",
227
+ 300: "#c4b5fd",
228
+ 400: "#a78bfa",
229
+ 500: "#8b5cf6",
230
+ 600: "#7c3aed",
231
+ 700: "#6d28d9",
232
+ 800: "#5b21b6",
233
+ 900: "#4c1d95",
234
+ 950: "#2e1065"
235
+ },
236
+ purple: {
237
+ 50: "#faf5ff",
238
+ 100: "#f3e8ff",
239
+ 200: "#e9d5ff",
240
+ 300: "#d8b4fe",
241
+ 400: "#c084fc",
242
+ 500: "#a855f7",
243
+ 600: "#9333ea",
244
+ 700: "#7e22ce",
245
+ 800: "#6b21a8",
246
+ 900: "#581c87",
247
+ 950: "#3b0764"
248
+ },
249
+ fuchsia: {
250
+ 50: "#fdf4ff",
251
+ 100: "#fae8ff",
252
+ 200: "#f5d0fe",
253
+ 300: "#f0abfc",
254
+ 400: "#e879f9",
255
+ 500: "#d946ef",
256
+ 600: "#c026d3",
257
+ 700: "#a21caf",
258
+ 800: "#86198f",
259
+ 900: "#701a75",
260
+ 950: "#4a044e"
261
+ },
262
+ pink: {
263
+ 50: "#fdf2f8",
264
+ 100: "#fce7f3",
265
+ 200: "#fbcfe8",
266
+ 300: "#f9a8d4",
267
+ 400: "#f472b6",
268
+ 500: "#ec4899",
269
+ 600: "#db2777",
270
+ 700: "#be185d",
271
+ 800: "#9d174d",
272
+ 900: "#831843",
273
+ 950: "#500724"
274
+ },
275
+ rose: {
276
+ 50: "#fff1f2",
277
+ 100: "#ffe4e6",
278
+ 200: "#fecdd3",
279
+ 300: "#fda4af",
280
+ 400: "#fb7185",
281
+ 500: "#f43f5e",
282
+ 600: "#e11d48",
283
+ 700: "#be123c",
284
+ 800: "#9f1239",
285
+ 900: "#881337",
286
+ 950: "#4c0519"
287
+ }
288
+ };
289
+
290
+ const TAILWIND_HEX_COLOR_MAP = new Map();
291
+
292
+ for (const [family, scale] of Object.entries(TAILWIND_HEX_COLORS)) {
293
+ for (const [step, hex] of Object.entries(scale)) {
294
+ TAILWIND_HEX_COLOR_MAP.set(`--color-${family}-${step}`, hex);
295
+ }
296
+ }
297
+
298
+ export function getTailwindDefaultHexForVar(variableName) {
299
+ return TAILWIND_HEX_COLOR_MAP.get(variableName) ?? null;
300
+ }