@mgcrea/react-native-tailwind 0.15.3 → 0.15.4
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/dist/babel/index.cjs +45 -10
- package/dist/parser/colors.d.ts +2 -1
- package/dist/parser/colors.js +1 -1
- package/dist/parser/colors.test.js +1 -1
- package/dist/parser/index.js +1 -1
- package/dist/parser/shadows.d.ts +7 -2
- package/dist/parser/shadows.js +1 -1
- package/dist/parser/shadows.test.js +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +4 -4
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +4 -4
- package/dist/utils/colorUtils.d.ts +30 -0
- package/dist/utils/colorUtils.js +1 -0
- package/dist/utils/colorUtils.test.js +1 -0
- package/package.json +1 -1
- package/src/parser/colors.test.ts +1 -16
- package/src/parser/colors.ts +15 -77
- package/src/parser/index.ts +1 -1
- package/src/parser/shadows.test.ts +109 -2
- package/src/parser/shadows.ts +20 -4
- package/src/utils/colorUtils.test.ts +193 -0
- package/src/utils/colorUtils.ts +115 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared color utilities for parsing and manipulating colors
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Tailwind color palette (flattened from config) with basic colors
|
|
6
|
+
*/
|
|
7
|
+
export declare const COLORS: Record<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* Apply opacity to hex color by appending alpha channel
|
|
10
|
+
* @param hex - Hex color string (e.g., "#ff0000", "#f00", or "transparent")
|
|
11
|
+
* @param opacity - Opacity value 0-100 (e.g., 50 for 50%)
|
|
12
|
+
* @returns 8-digit hex with alpha (e.g., "#FF000080") or transparent
|
|
13
|
+
*/
|
|
14
|
+
export declare function applyOpacity(hex: string, opacity: number): string;
|
|
15
|
+
/**
|
|
16
|
+
* Parse arbitrary color value: [#ff0000], [#f00], [#FF0000AA]
|
|
17
|
+
* Supports 3-digit, 6-digit, and 8-digit (with alpha) hex colors
|
|
18
|
+
* @param value - Arbitrary value string like "[#ff0000]"
|
|
19
|
+
* @returns Hex string if valid, null otherwise (preserves input case)
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseArbitraryColor(value: string): string | null;
|
|
22
|
+
/**
|
|
23
|
+
* Parse a color value with optional opacity modifier
|
|
24
|
+
* Handles preset colors, custom colors, arbitrary hex values, and opacity modifiers
|
|
25
|
+
*
|
|
26
|
+
* @param colorKey - Color key like "red-500", "red-500/50", "[#ff0000]", "[#ff0000]/80"
|
|
27
|
+
* @param customColors - Optional custom colors from tailwind.config
|
|
28
|
+
* @returns Hex color string or null if invalid
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseColorValue(colorKey: string, customColors?: Record<string, string>): string | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:true});exports.COLORS=void 0;exports.applyOpacity=applyOpacity;exports.parseArbitraryColor=parseArbitraryColor;exports.parseColorValue=parseColorValue;var _tailwind=require("../config/tailwind");var _flattenColors=require("./flattenColors");var COLORS=exports.COLORS=Object.assign({},(0,_flattenColors.flattenColors)(_tailwind.TAILWIND_COLORS),{white:"#FFFFFF",black:"#000000",transparent:"transparent"});function applyOpacity(hex,opacity){if(hex==="transparent"){return"transparent";}var cleanHex=hex.replace(/^#/,"");var fullHex=cleanHex.length===3?cleanHex.split("").map(function(char){return char+char;}).join(""):cleanHex;var alpha=Math.round(opacity/100*255);var alphaHex=alpha.toString(16).padStart(2,"0").toUpperCase();return`#${fullHex.toUpperCase()}${alphaHex}`;}function parseArbitraryColor(value){var hexMatch=value.match(/^\[#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\]$/);if(hexMatch){var hex=hexMatch[1];if(hex.length===3){var expanded=hex.split("").map(function(char){return char+char;}).join("");return`#${expanded}`;}return`#${hex}`;}return null;}function parseColorValue(colorKey,customColors){var _getColor;var getColor=function getColor(key){var _customColors$key;return(_customColors$key=customColors==null?void 0:customColors[key])!=null?_customColors$key:COLORS[key];};var opacityMatch=colorKey.match(/^(.+)\/(\d+)$/);if(opacityMatch){var baseColorKey=opacityMatch[1];var opacity=Number.parseInt(opacityMatch[2],10);if(opacity<0||opacity>100){return null;}var _arbitraryColor=parseArbitraryColor(baseColorKey);if(_arbitraryColor!==null){return applyOpacity(_arbitraryColor,opacity);}var color=getColor(baseColorKey);if(color){return applyOpacity(color,opacity);}return null;}var arbitraryColor=parseArbitraryColor(colorKey);if(arbitraryColor!==null){return arbitraryColor;}return(_getColor=getColor(colorKey))!=null?_getColor:null;}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var _vitest=require("vitest");var _colorUtils=require("./colorUtils");(0,_vitest.describe)("COLORS",function(){(0,_vitest.it)("should include basic colors",function(){(0,_vitest.expect)(_colorUtils.COLORS.white).toBe("#FFFFFF");(0,_vitest.expect)(_colorUtils.COLORS.black).toBe("#000000");(0,_vitest.expect)(_colorUtils.COLORS.transparent).toBe("transparent");});(0,_vitest.it)("should include flattened Tailwind colors",function(){(0,_vitest.expect)(_colorUtils.COLORS["red-500"]).toBeDefined();(0,_vitest.expect)(_colorUtils.COLORS["blue-500"]).toBeDefined();(0,_vitest.expect)(_colorUtils.COLORS["green-500"]).toBeDefined();(0,_vitest.expect)(_colorUtils.COLORS["gray-100"]).toBeDefined();(0,_vitest.expect)(_colorUtils.COLORS["gray-900"]).toBeDefined();});});(0,_vitest.describe)("applyOpacity",function(){(0,_vitest.it)("should apply opacity to 6-digit hex colors",function(){(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#ff0000",50)).toBe("#FF000080");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#00ff00",100)).toBe("#00FF00FF");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#0000ff",0)).toBe("#0000FF00");});(0,_vitest.it)("should apply opacity to 3-digit hex colors",function(){(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#f00",50)).toBe("#FF000080");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#0f0",25)).toBe("#00FF0040");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#00f",75)).toBe("#0000FFBF");});(0,_vitest.it)("should handle various opacity values",function(){(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#000000",0)).toBe("#00000000");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#000000",25)).toBe("#00000040");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#000000",50)).toBe("#00000080");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#000000",75)).toBe("#000000BF");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#000000",80)).toBe("#000000CC");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#000000",100)).toBe("#000000FF");});(0,_vitest.it)("should return transparent unchanged",function(){(0,_vitest.expect)((0,_colorUtils.applyOpacity)("transparent",50)).toBe("transparent");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("transparent",0)).toBe("transparent");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("transparent",100)).toBe("transparent");});(0,_vitest.it)("should uppercase the output",function(){(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#aabbcc",50)).toBe("#AABBCC80");(0,_vitest.expect)((0,_colorUtils.applyOpacity)("#AbCdEf",50)).toBe("#ABCDEF80");});});(0,_vitest.describe)("parseArbitraryColor",function(){(0,_vitest.it)("should parse 6-digit hex colors",function(){(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#ff0000]")).toBe("#ff0000");(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#00ff00]")).toBe("#00ff00");(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#0000ff]")).toBe("#0000ff");(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#AABBCC]")).toBe("#AABBCC");});(0,_vitest.it)("should parse and expand 3-digit hex colors",function(){(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#f00]")).toBe("#ff0000");(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#0f0]")).toBe("#00ff00");(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#00f]")).toBe("#0000ff");(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#ABC]")).toBe("#AABBCC");});(0,_vitest.it)("should parse 8-digit hex colors (with alpha)",function(){(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#ff000080]")).toBe("#ff000080");(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#00ff00cc]")).toBe("#00ff00cc");(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#AABBCCDD]")).toBe("#AABBCCDD");});(0,_vitest.it)("should preserve input case",function(){(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#aabbcc]")).toBe("#aabbcc");(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#AABBCC]")).toBe("#AABBCC");(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#AaBbCc]")).toBe("#AaBbCc");});(0,_vitest.it)("should return null for invalid formats",function(){(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#gg0000]")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#ff00]")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[#ff00000]")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[ff0000]")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("#ff0000")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[rgb(255,0,0)]")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseArbitraryColor)("[]")).toBeNull();});});(0,_vitest.describe)("parseColorValue",function(){(0,_vitest.describe)("preset colors",function(){(0,_vitest.it)("should parse preset color names",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("red-500")).toBe(_colorUtils.COLORS["red-500"]);(0,_vitest.expect)((0,_colorUtils.parseColorValue)("blue-800")).toBe(_colorUtils.COLORS["blue-800"]);(0,_vitest.expect)((0,_colorUtils.parseColorValue)("green-600")).toBe(_colorUtils.COLORS["green-600"]);});(0,_vitest.it)("should parse basic colors",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("black")).toBe("#000000");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("white")).toBe("#FFFFFF");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("transparent")).toBe("transparent");});(0,_vitest.it)("should return null for invalid color names",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("notacolor")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseColorValue)("red-999")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseColorValue)("foobar-500")).toBeNull();});});(0,_vitest.describe)("arbitrary colors",function(){(0,_vitest.it)("should parse arbitrary hex colors",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#ff0000]")).toBe("#ff0000");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#00ff00]")).toBe("#00ff00");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#0000ff]")).toBe("#0000ff");});(0,_vitest.it)("should parse 3-digit arbitrary hex colors",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#f00]")).toBe("#ff0000");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#0f0]")).toBe("#00ff00");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#00f]")).toBe("#0000ff");});(0,_vitest.it)("should parse 8-digit arbitrary hex colors",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#ff000080]")).toBe("#ff000080");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#00ff00cc]")).toBe("#00ff00cc");});});(0,_vitest.describe)("opacity modifier",function(){(0,_vitest.it)("should apply opacity to preset colors",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("red-500/50")).toBe((0,_colorUtils.applyOpacity)(_colorUtils.COLORS["red-500"],50));(0,_vitest.expect)((0,_colorUtils.parseColorValue)("blue-800/80")).toBe((0,_colorUtils.applyOpacity)(_colorUtils.COLORS["blue-800"],80));(0,_vitest.expect)((0,_colorUtils.parseColorValue)("black/25")).toBe((0,_colorUtils.applyOpacity)("#000000",25));});(0,_vitest.it)("should apply opacity to arbitrary colors",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#ff0000]/50")).toBe("#FF000080");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#00ff00]/25")).toBe("#00FF0040");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("[#0000ff]/80")).toBe("#0000FFCC");});(0,_vitest.it)("should handle edge opacity values",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("red-500/0")).toBe((0,_colorUtils.applyOpacity)(_colorUtils.COLORS["red-500"],0));(0,_vitest.expect)((0,_colorUtils.parseColorValue)("red-500/100")).toBe((0,_colorUtils.applyOpacity)(_colorUtils.COLORS["red-500"],100));});(0,_vitest.it)("should return null for invalid opacity values",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("red-500/101")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseColorValue)("red-500/-1")).toBeNull();(0,_vitest.expect)((0,_colorUtils.parseColorValue)("red-500/abc")).toBeNull();});(0,_vitest.it)("should keep transparent unchanged with opacity",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("transparent/50")).toBe("transparent");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("transparent/0")).toBe("transparent");});});(0,_vitest.describe)("custom colors",function(){var customColors={brand:"#FF5733","brand-primary":"#3498DB","brand-secondary":"#2ECC71"};(0,_vitest.it)("should parse custom colors",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("brand",customColors)).toBe("#FF5733");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("brand-primary",customColors)).toBe("#3498DB");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("brand-secondary",customColors)).toBe("#2ECC71");});(0,_vitest.it)("should apply opacity to custom colors",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("brand/50",customColors)).toBe("#FF573380");(0,_vitest.expect)((0,_colorUtils.parseColorValue)("brand-primary/80",customColors)).toBe("#3498DBCC");});(0,_vitest.it)("should still support preset colors with custom colors",function(){(0,_vitest.expect)((0,_colorUtils.parseColorValue)("red-500",customColors)).toBe(_colorUtils.COLORS["red-500"]);(0,_vitest.expect)((0,_colorUtils.parseColorValue)("blue-800/50",customColors)).toBe((0,_colorUtils.applyOpacity)(_colorUtils.COLORS["blue-800"],50));});(0,_vitest.it)("should allow custom colors to override presets",function(){var overrideColors={"red-500":"#CUSTOM1"};(0,_vitest.expect)((0,_colorUtils.parseColorValue)("red-500",overrideColors)).toBe("#CUSTOM1");});});});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mgcrea/react-native-tailwind",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.4",
|
|
4
4
|
"description": "Compile-time Tailwind CSS for React Native with zero runtime overhead",
|
|
5
5
|
"author": "Olivier Louvignes <olivier@mgcrea.io> (https://github.com/mgcrea)",
|
|
6
6
|
"homepage": "https://github.com/mgcrea/react-native-tailwind#readme",
|
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { COLORS, parseColor } from "./colors";
|
|
3
|
-
|
|
4
|
-
// Helper to apply opacity to hex color for testing
|
|
5
|
-
function applyOpacity(hex: string, opacity: number): string {
|
|
6
|
-
if (hex === "transparent") return "transparent";
|
|
7
|
-
const cleanHex = hex.replace(/^#/, "");
|
|
8
|
-
const fullHex =
|
|
9
|
-
cleanHex.length === 3
|
|
10
|
-
? cleanHex
|
|
11
|
-
.split("")
|
|
12
|
-
.map((char) => char + char)
|
|
13
|
-
.join("")
|
|
14
|
-
: cleanHex;
|
|
15
|
-
const alpha = Math.round((opacity / 100) * 255);
|
|
16
|
-
const alphaHex = alpha.toString(16).padStart(2, "0").toUpperCase();
|
|
17
|
-
return `#${fullHex.toUpperCase()}${alphaHex}`;
|
|
18
|
-
}
|
|
3
|
+
import { applyOpacity } from "../utils/colorUtils";
|
|
19
4
|
|
|
20
5
|
describe("COLORS", () => {
|
|
21
6
|
it("should export complete color palette", () => {
|
package/src/parser/colors.ts
CHANGED
|
@@ -2,85 +2,11 @@
|
|
|
2
2
|
* Color utilities (background, text, border colors)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { TAILWIND_COLORS } from "../config/tailwind";
|
|
6
5
|
import type { StyleObject } from "../types";
|
|
7
|
-
import {
|
|
6
|
+
import { COLORS, applyOpacity, parseArbitraryColor } from "../utils/colorUtils";
|
|
8
7
|
|
|
9
|
-
//
|
|
10
|
-
export
|
|
11
|
-
...flattenColors(TAILWIND_COLORS),
|
|
12
|
-
// Add basic colors
|
|
13
|
-
white: "#FFFFFF",
|
|
14
|
-
black: "#000000",
|
|
15
|
-
transparent: "transparent",
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Apply opacity to hex color by appending alpha channel
|
|
20
|
-
* @param hex - Hex color string (e.g., "#ff0000", "#f00", or "transparent")
|
|
21
|
-
* @param opacity - Opacity value 0-100 (e.g., 50 for 50%)
|
|
22
|
-
* @returns 8-digit hex with alpha (e.g., "#FF000080") or rgba for special colors
|
|
23
|
-
*/
|
|
24
|
-
function applyOpacity(hex: string, opacity: number): string {
|
|
25
|
-
// Handle transparent specially
|
|
26
|
-
if (hex === "transparent") {
|
|
27
|
-
return "transparent";
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Remove # if present
|
|
31
|
-
const cleanHex = hex.replace(/^#/, "");
|
|
32
|
-
|
|
33
|
-
// Expand 3-digit hex to 6-digit: #abc -> #aabbcc
|
|
34
|
-
const fullHex =
|
|
35
|
-
cleanHex.length === 3
|
|
36
|
-
? cleanHex
|
|
37
|
-
.split("")
|
|
38
|
-
.map((char) => char + char)
|
|
39
|
-
.join("")
|
|
40
|
-
: cleanHex;
|
|
41
|
-
|
|
42
|
-
// Convert opacity percentage (0-100) to hex (00-FF)
|
|
43
|
-
const alpha = Math.round((opacity / 100) * 255);
|
|
44
|
-
const alphaHex = alpha.toString(16).padStart(2, "0").toUpperCase();
|
|
45
|
-
|
|
46
|
-
// Return 8-digit hex: #RRGGBBAA
|
|
47
|
-
return `#${fullHex.toUpperCase()}${alphaHex}`;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Parse arbitrary color value: [#ff0000], [#f00], [#FF0000AA]
|
|
52
|
-
* Supports 3-digit, 6-digit, and 8-digit (with alpha) hex colors
|
|
53
|
-
* Returns hex string if valid, null otherwise
|
|
54
|
-
*/
|
|
55
|
-
function parseArbitraryColor(value: string): string | null {
|
|
56
|
-
// Match: [#rgb], [#rrggbb], or [#rrggbbaa]
|
|
57
|
-
const hexMatch = value.match(/^\[#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\]$/);
|
|
58
|
-
if (hexMatch) {
|
|
59
|
-
const hex = hexMatch[1];
|
|
60
|
-
// Expand 3-digit hex to 6-digit: #abc -> #aabbcc
|
|
61
|
-
if (hex.length === 3) {
|
|
62
|
-
const expanded = hex
|
|
63
|
-
.split("")
|
|
64
|
-
.map((char) => char + char)
|
|
65
|
-
.join("");
|
|
66
|
-
return `#${expanded}`;
|
|
67
|
-
}
|
|
68
|
-
return `#${hex}`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Warn about unsupported formats
|
|
72
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
73
|
-
/* v8 ignore next 5 */
|
|
74
|
-
if (process.env.NODE_ENV !== "production") {
|
|
75
|
-
console.warn(
|
|
76
|
-
`[react-native-tailwind] Unsupported arbitrary color value: ${value}. Only hex colors are supported (e.g., [#ff0000], [#f00], or [#ff0000aa]).`,
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
return null;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
8
|
+
// Re-export COLORS for backward compatibility and tests
|
|
9
|
+
export { COLORS };
|
|
84
10
|
|
|
85
11
|
/**
|
|
86
12
|
* Parse color classes (background, text, border)
|
|
@@ -93,6 +19,7 @@ export function parseColor(cls: string, customColors?: Record<string, string>):
|
|
|
93
19
|
};
|
|
94
20
|
|
|
95
21
|
// Helper to parse color with optional opacity modifier
|
|
22
|
+
// Uses internal implementation to preserve warnings for invalid arbitrary colors
|
|
96
23
|
const parseColorWithOpacity = (colorKey: string): string | null => {
|
|
97
24
|
// Check for opacity modifier: blue-500/50
|
|
98
25
|
const opacityMatch = colorKey.match(/^(.+)\/(\d+)$/);
|
|
@@ -133,6 +60,17 @@ export function parseColor(cls: string, customColors?: Record<string, string>):
|
|
|
133
60
|
return arbitraryColor;
|
|
134
61
|
}
|
|
135
62
|
|
|
63
|
+
// Check for unsupported arbitrary format and warn
|
|
64
|
+
if (colorKey.startsWith("[") && colorKey.endsWith("]")) {
|
|
65
|
+
/* v8 ignore next 5 */
|
|
66
|
+
if (process.env.NODE_ENV !== "production") {
|
|
67
|
+
console.warn(
|
|
68
|
+
`[react-native-tailwind] Unsupported arbitrary color value: ${colorKey}. Only hex colors are supported (e.g., [#ff0000], [#f00], or [#ff0000aa]).`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
136
74
|
// Try preset/custom colors
|
|
137
75
|
return getColor(colorKey) ?? null;
|
|
138
76
|
};
|
package/src/parser/index.ts
CHANGED
|
@@ -60,7 +60,7 @@ export function parseClass(cls: string, customTheme?: CustomTheme): StyleObject
|
|
|
60
60
|
(cls: string) => parseLayout(cls, customTheme?.spacing),
|
|
61
61
|
(cls: string) => parseTypography(cls, customTheme?.fontFamily, customTheme?.fontSize),
|
|
62
62
|
(cls: string) => parseSizing(cls, customTheme?.spacing),
|
|
63
|
-
parseShadow,
|
|
63
|
+
(cls: string) => parseShadow(cls, customTheme?.colors),
|
|
64
64
|
parseAspectRatio,
|
|
65
65
|
(cls: string) => parseTransform(cls, customTheme?.spacing),
|
|
66
66
|
];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { SHADOW_SCALE, parseShadow } from "./shadows";
|
|
2
|
+
import { SHADOW_COLORS, SHADOW_SCALE, parseShadow } from "./shadows";
|
|
3
|
+
import { applyOpacity } from "../utils/colorUtils";
|
|
3
4
|
|
|
4
5
|
describe("SHADOW_SCALE", () => {
|
|
5
6
|
it("should export complete shadow scale", () => {
|
|
@@ -138,7 +139,7 @@ describe("parseShadow - shadow properties (Android)", () => {
|
|
|
138
139
|
|
|
139
140
|
describe("parseShadow - invalid classes", () => {
|
|
140
141
|
it("should return null for invalid shadow classes", () => {
|
|
141
|
-
expect(parseShadow("shadow-
|
|
142
|
+
expect(parseShadow("shadow-invalidcolor")).toBeNull();
|
|
142
143
|
expect(parseShadow("shadows")).toBeNull();
|
|
143
144
|
expect(parseShadow("shadow-")).toBeNull();
|
|
144
145
|
expect(parseShadow("shadow-small")).toBeNull();
|
|
@@ -190,3 +191,109 @@ describe("parseShadow - comprehensive coverage", () => {
|
|
|
190
191
|
expect(parseShadow("shadow-MD")).toBeNull();
|
|
191
192
|
});
|
|
192
193
|
});
|
|
194
|
+
|
|
195
|
+
describe("parseShadow - shadow colors", () => {
|
|
196
|
+
it("should parse shadow color with preset colors", () => {
|
|
197
|
+
expect(parseShadow("shadow-red-500")).toEqual({ shadowColor: SHADOW_COLORS["red-500"] });
|
|
198
|
+
expect(parseShadow("shadow-blue-800")).toEqual({ shadowColor: SHADOW_COLORS["blue-800"] });
|
|
199
|
+
expect(parseShadow("shadow-green-600")).toEqual({ shadowColor: SHADOW_COLORS["green-600"] });
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("should parse shadow color with basic colors", () => {
|
|
203
|
+
expect(parseShadow("shadow-black")).toEqual({ shadowColor: SHADOW_COLORS.black });
|
|
204
|
+
expect(parseShadow("shadow-white")).toEqual({ shadowColor: SHADOW_COLORS.white });
|
|
205
|
+
expect(parseShadow("shadow-transparent")).toEqual({ shadowColor: "transparent" });
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("should parse shadow color with opacity modifier", () => {
|
|
209
|
+
expect(parseShadow("shadow-red-500/50")).toEqual({
|
|
210
|
+
shadowColor: applyOpacity(SHADOW_COLORS["red-500"], 50),
|
|
211
|
+
});
|
|
212
|
+
expect(parseShadow("shadow-blue-800/80")).toEqual({
|
|
213
|
+
shadowColor: applyOpacity(SHADOW_COLORS["blue-800"], 80),
|
|
214
|
+
});
|
|
215
|
+
expect(parseShadow("shadow-black/25")).toEqual({
|
|
216
|
+
shadowColor: applyOpacity(SHADOW_COLORS.black, 25),
|
|
217
|
+
});
|
|
218
|
+
expect(parseShadow("shadow-white/0")).toEqual({
|
|
219
|
+
shadowColor: applyOpacity(SHADOW_COLORS.white, 0),
|
|
220
|
+
});
|
|
221
|
+
expect(parseShadow("shadow-green-500/100")).toEqual({
|
|
222
|
+
shadowColor: applyOpacity(SHADOW_COLORS["green-500"], 100),
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("should parse shadow color with arbitrary hex values", () => {
|
|
227
|
+
expect(parseShadow("shadow-[#ff0000]")).toEqual({ shadowColor: "#ff0000" });
|
|
228
|
+
expect(parseShadow("shadow-[#00ff00]")).toEqual({ shadowColor: "#00ff00" });
|
|
229
|
+
expect(parseShadow("shadow-[#0000ff]")).toEqual({ shadowColor: "#0000ff" });
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("should parse shadow color with 3-digit hex values", () => {
|
|
233
|
+
expect(parseShadow("shadow-[#f00]")).toEqual({ shadowColor: "#ff0000" });
|
|
234
|
+
expect(parseShadow("shadow-[#0f0]")).toEqual({ shadowColor: "#00ff00" });
|
|
235
|
+
expect(parseShadow("shadow-[#00f]")).toEqual({ shadowColor: "#0000ff" });
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("should parse shadow color with arbitrary hex and opacity", () => {
|
|
239
|
+
// When opacity is applied, the color is uppercased for consistency
|
|
240
|
+
expect(parseShadow("shadow-[#ff0000]/50")).toEqual({ shadowColor: "#FF000080" });
|
|
241
|
+
expect(parseShadow("shadow-[#00ff00]/25")).toEqual({ shadowColor: "#00FF0040" });
|
|
242
|
+
expect(parseShadow("shadow-[#0000ff]/80")).toEqual({ shadowColor: "#0000FFCC" });
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("should parse shadow color with 8-digit hex (with alpha)", () => {
|
|
246
|
+
expect(parseShadow("shadow-[#ff000080]")).toEqual({ shadowColor: "#ff000080" });
|
|
247
|
+
expect(parseShadow("shadow-[#00ff00cc]")).toEqual({ shadowColor: "#00ff00cc" });
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("should handle transparent with opacity modifier", () => {
|
|
251
|
+
// Transparent should remain transparent even with opacity
|
|
252
|
+
expect(parseShadow("shadow-transparent/50")).toEqual({ shadowColor: "transparent" });
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("should return null for invalid opacity values", () => {
|
|
256
|
+
expect(parseShadow("shadow-red-500/101")).toBeNull();
|
|
257
|
+
expect(parseShadow("shadow-red-500/-1")).toBeNull();
|
|
258
|
+
expect(parseShadow("shadow-red-500/abc")).toBeNull();
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("should return null for invalid color names", () => {
|
|
262
|
+
expect(parseShadow("shadow-notacolor")).toBeNull();
|
|
263
|
+
expect(parseShadow("shadow-foobar-500")).toBeNull();
|
|
264
|
+
expect(parseShadow("shadow-red-999")).toBeNull();
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
describe("parseShadow - shadow colors with custom colors", () => {
|
|
269
|
+
const customColors = {
|
|
270
|
+
brand: "#FF5733",
|
|
271
|
+
"brand-primary": "#3498DB",
|
|
272
|
+
"brand-secondary": "#2ECC71",
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
it("should parse shadow with custom colors", () => {
|
|
276
|
+
expect(parseShadow("shadow-brand", customColors)).toEqual({ shadowColor: "#FF5733" });
|
|
277
|
+
expect(parseShadow("shadow-brand-primary", customColors)).toEqual({ shadowColor: "#3498DB" });
|
|
278
|
+
expect(parseShadow("shadow-brand-secondary", customColors)).toEqual({ shadowColor: "#2ECC71" });
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("should parse shadow with custom colors and opacity", () => {
|
|
282
|
+
expect(parseShadow("shadow-brand/50", customColors)).toEqual({ shadowColor: "#FF573380" });
|
|
283
|
+
expect(parseShadow("shadow-brand-primary/80", customColors)).toEqual({ shadowColor: "#3498DBCC" });
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it("should still support preset colors with custom colors", () => {
|
|
287
|
+
expect(parseShadow("shadow-red-500", customColors)).toEqual({ shadowColor: SHADOW_COLORS["red-500"] });
|
|
288
|
+
expect(parseShadow("shadow-blue-800/50", customColors)).toEqual({
|
|
289
|
+
shadowColor: applyOpacity(SHADOW_COLORS["blue-800"], 50),
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it("should allow custom colors to override presets", () => {
|
|
294
|
+
const overrideColors = {
|
|
295
|
+
"red-500": "#CUSTOM1",
|
|
296
|
+
};
|
|
297
|
+
expect(parseShadow("shadow-red-500", overrideColors)).toEqual({ shadowColor: "#CUSTOM1" });
|
|
298
|
+
});
|
|
299
|
+
});
|
package/src/parser/shadows.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { StyleObject } from "../types";
|
|
7
|
+
import { COLORS, parseColorValue } from "../utils/colorUtils";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Shadow scale definitions combining iOS and Android properties
|
|
@@ -68,17 +69,32 @@ const SHADOW_SCALE: Record<string, StyleObject> = {
|
|
|
68
69
|
|
|
69
70
|
/**
|
|
70
71
|
* Parse shadow classes
|
|
72
|
+
* Supports shadow size presets (shadow-sm, shadow-md, etc.) and
|
|
73
|
+
* shadow colors (shadow-red-500, shadow-blue-800/50, shadow-[#ff0000]/80)
|
|
74
|
+
*
|
|
71
75
|
* @param cls - Class name to parse
|
|
76
|
+
* @param customColors - Optional custom colors from tailwind.config
|
|
72
77
|
* @returns Style object or null if not a shadow class
|
|
73
78
|
*/
|
|
74
|
-
export function parseShadow(cls: string): StyleObject | null {
|
|
75
|
-
// Check if it's a shadow
|
|
79
|
+
export function parseShadow(cls: string, customColors?: Record<string, string>): StyleObject | null {
|
|
80
|
+
// Check if it's a shadow size preset
|
|
76
81
|
if (cls in SHADOW_SCALE) {
|
|
77
82
|
return SHADOW_SCALE[cls];
|
|
78
83
|
}
|
|
79
84
|
|
|
85
|
+
// Check for shadow color: shadow-red-500, shadow-red-500/50, shadow-[#ff0000]/80
|
|
86
|
+
if (cls.startsWith("shadow-")) {
|
|
87
|
+
const colorPart = cls.substring(7); // Remove "shadow-"
|
|
88
|
+
|
|
89
|
+
// Parse the color value using shared utility
|
|
90
|
+
const shadowColor = parseColorValue(colorPart, customColors);
|
|
91
|
+
if (shadowColor) {
|
|
92
|
+
return { shadowColor };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
80
96
|
return null;
|
|
81
97
|
}
|
|
82
98
|
|
|
83
|
-
// Export shadow scale for testing/advanced usage
|
|
84
|
-
export { SHADOW_SCALE };
|
|
99
|
+
// Export shadow scale and colors for testing/advanced usage
|
|
100
|
+
export { SHADOW_SCALE, COLORS as SHADOW_COLORS };
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { COLORS, applyOpacity, parseArbitraryColor, parseColorValue } from "./colorUtils";
|
|
3
|
+
|
|
4
|
+
describe("COLORS", () => {
|
|
5
|
+
it("should include basic colors", () => {
|
|
6
|
+
expect(COLORS.white).toBe("#FFFFFF");
|
|
7
|
+
expect(COLORS.black).toBe("#000000");
|
|
8
|
+
expect(COLORS.transparent).toBe("transparent");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("should include flattened Tailwind colors", () => {
|
|
12
|
+
expect(COLORS["red-500"]).toBeDefined();
|
|
13
|
+
expect(COLORS["blue-500"]).toBeDefined();
|
|
14
|
+
expect(COLORS["green-500"]).toBeDefined();
|
|
15
|
+
expect(COLORS["gray-100"]).toBeDefined();
|
|
16
|
+
expect(COLORS["gray-900"]).toBeDefined();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("applyOpacity", () => {
|
|
21
|
+
it("should apply opacity to 6-digit hex colors", () => {
|
|
22
|
+
expect(applyOpacity("#ff0000", 50)).toBe("#FF000080");
|
|
23
|
+
expect(applyOpacity("#00ff00", 100)).toBe("#00FF00FF");
|
|
24
|
+
expect(applyOpacity("#0000ff", 0)).toBe("#0000FF00");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should apply opacity to 3-digit hex colors", () => {
|
|
28
|
+
expect(applyOpacity("#f00", 50)).toBe("#FF000080");
|
|
29
|
+
expect(applyOpacity("#0f0", 25)).toBe("#00FF0040");
|
|
30
|
+
expect(applyOpacity("#00f", 75)).toBe("#0000FFBF");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should handle various opacity values", () => {
|
|
34
|
+
expect(applyOpacity("#000000", 0)).toBe("#00000000");
|
|
35
|
+
expect(applyOpacity("#000000", 25)).toBe("#00000040");
|
|
36
|
+
expect(applyOpacity("#000000", 50)).toBe("#00000080");
|
|
37
|
+
expect(applyOpacity("#000000", 75)).toBe("#000000BF");
|
|
38
|
+
expect(applyOpacity("#000000", 80)).toBe("#000000CC");
|
|
39
|
+
expect(applyOpacity("#000000", 100)).toBe("#000000FF");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should return transparent unchanged", () => {
|
|
43
|
+
expect(applyOpacity("transparent", 50)).toBe("transparent");
|
|
44
|
+
expect(applyOpacity("transparent", 0)).toBe("transparent");
|
|
45
|
+
expect(applyOpacity("transparent", 100)).toBe("transparent");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should uppercase the output", () => {
|
|
49
|
+
expect(applyOpacity("#aabbcc", 50)).toBe("#AABBCC80");
|
|
50
|
+
expect(applyOpacity("#AbCdEf", 50)).toBe("#ABCDEF80");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("parseArbitraryColor", () => {
|
|
55
|
+
it("should parse 6-digit hex colors", () => {
|
|
56
|
+
expect(parseArbitraryColor("[#ff0000]")).toBe("#ff0000");
|
|
57
|
+
expect(parseArbitraryColor("[#00ff00]")).toBe("#00ff00");
|
|
58
|
+
expect(parseArbitraryColor("[#0000ff]")).toBe("#0000ff");
|
|
59
|
+
expect(parseArbitraryColor("[#AABBCC]")).toBe("#AABBCC");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should parse and expand 3-digit hex colors", () => {
|
|
63
|
+
expect(parseArbitraryColor("[#f00]")).toBe("#ff0000");
|
|
64
|
+
expect(parseArbitraryColor("[#0f0]")).toBe("#00ff00");
|
|
65
|
+
expect(parseArbitraryColor("[#00f]")).toBe("#0000ff");
|
|
66
|
+
expect(parseArbitraryColor("[#ABC]")).toBe("#AABBCC");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should parse 8-digit hex colors (with alpha)", () => {
|
|
70
|
+
expect(parseArbitraryColor("[#ff000080]")).toBe("#ff000080");
|
|
71
|
+
expect(parseArbitraryColor("[#00ff00cc]")).toBe("#00ff00cc");
|
|
72
|
+
expect(parseArbitraryColor("[#AABBCCDD]")).toBe("#AABBCCDD");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should preserve input case", () => {
|
|
76
|
+
expect(parseArbitraryColor("[#aabbcc]")).toBe("#aabbcc");
|
|
77
|
+
expect(parseArbitraryColor("[#AABBCC]")).toBe("#AABBCC");
|
|
78
|
+
expect(parseArbitraryColor("[#AaBbCc]")).toBe("#AaBbCc");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should return null for invalid formats", () => {
|
|
82
|
+
expect(parseArbitraryColor("[#gg0000]")).toBeNull();
|
|
83
|
+
expect(parseArbitraryColor("[#ff00]")).toBeNull();
|
|
84
|
+
expect(parseArbitraryColor("[#ff00000]")).toBeNull();
|
|
85
|
+
expect(parseArbitraryColor("[ff0000]")).toBeNull();
|
|
86
|
+
expect(parseArbitraryColor("#ff0000")).toBeNull();
|
|
87
|
+
expect(parseArbitraryColor("[rgb(255,0,0)]")).toBeNull();
|
|
88
|
+
expect(parseArbitraryColor("")).toBeNull();
|
|
89
|
+
expect(parseArbitraryColor("[]")).toBeNull();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("parseColorValue", () => {
|
|
94
|
+
describe("preset colors", () => {
|
|
95
|
+
it("should parse preset color names", () => {
|
|
96
|
+
expect(parseColorValue("red-500")).toBe(COLORS["red-500"]);
|
|
97
|
+
expect(parseColorValue("blue-800")).toBe(COLORS["blue-800"]);
|
|
98
|
+
expect(parseColorValue("green-600")).toBe(COLORS["green-600"]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should parse basic colors", () => {
|
|
102
|
+
expect(parseColorValue("black")).toBe("#000000");
|
|
103
|
+
expect(parseColorValue("white")).toBe("#FFFFFF");
|
|
104
|
+
expect(parseColorValue("transparent")).toBe("transparent");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should return null for invalid color names", () => {
|
|
108
|
+
expect(parseColorValue("notacolor")).toBeNull();
|
|
109
|
+
expect(parseColorValue("red-999")).toBeNull();
|
|
110
|
+
expect(parseColorValue("foobar-500")).toBeNull();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("arbitrary colors", () => {
|
|
115
|
+
it("should parse arbitrary hex colors", () => {
|
|
116
|
+
expect(parseColorValue("[#ff0000]")).toBe("#ff0000");
|
|
117
|
+
expect(parseColorValue("[#00ff00]")).toBe("#00ff00");
|
|
118
|
+
expect(parseColorValue("[#0000ff]")).toBe("#0000ff");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should parse 3-digit arbitrary hex colors", () => {
|
|
122
|
+
expect(parseColorValue("[#f00]")).toBe("#ff0000");
|
|
123
|
+
expect(parseColorValue("[#0f0]")).toBe("#00ff00");
|
|
124
|
+
expect(parseColorValue("[#00f]")).toBe("#0000ff");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should parse 8-digit arbitrary hex colors", () => {
|
|
128
|
+
expect(parseColorValue("[#ff000080]")).toBe("#ff000080");
|
|
129
|
+
expect(parseColorValue("[#00ff00cc]")).toBe("#00ff00cc");
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe("opacity modifier", () => {
|
|
134
|
+
it("should apply opacity to preset colors", () => {
|
|
135
|
+
expect(parseColorValue("red-500/50")).toBe(applyOpacity(COLORS["red-500"], 50));
|
|
136
|
+
expect(parseColorValue("blue-800/80")).toBe(applyOpacity(COLORS["blue-800"], 80));
|
|
137
|
+
expect(parseColorValue("black/25")).toBe(applyOpacity("#000000", 25));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should apply opacity to arbitrary colors", () => {
|
|
141
|
+
expect(parseColorValue("[#ff0000]/50")).toBe("#FF000080");
|
|
142
|
+
expect(parseColorValue("[#00ff00]/25")).toBe("#00FF0040");
|
|
143
|
+
expect(parseColorValue("[#0000ff]/80")).toBe("#0000FFCC");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should handle edge opacity values", () => {
|
|
147
|
+
expect(parseColorValue("red-500/0")).toBe(applyOpacity(COLORS["red-500"], 0));
|
|
148
|
+
expect(parseColorValue("red-500/100")).toBe(applyOpacity(COLORS["red-500"], 100));
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should return null for invalid opacity values", () => {
|
|
152
|
+
expect(parseColorValue("red-500/101")).toBeNull();
|
|
153
|
+
expect(parseColorValue("red-500/-1")).toBeNull();
|
|
154
|
+
expect(parseColorValue("red-500/abc")).toBeNull();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("should keep transparent unchanged with opacity", () => {
|
|
158
|
+
expect(parseColorValue("transparent/50")).toBe("transparent");
|
|
159
|
+
expect(parseColorValue("transparent/0")).toBe("transparent");
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe("custom colors", () => {
|
|
164
|
+
const customColors = {
|
|
165
|
+
brand: "#FF5733",
|
|
166
|
+
"brand-primary": "#3498DB",
|
|
167
|
+
"brand-secondary": "#2ECC71",
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
it("should parse custom colors", () => {
|
|
171
|
+
expect(parseColorValue("brand", customColors)).toBe("#FF5733");
|
|
172
|
+
expect(parseColorValue("brand-primary", customColors)).toBe("#3498DB");
|
|
173
|
+
expect(parseColorValue("brand-secondary", customColors)).toBe("#2ECC71");
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("should apply opacity to custom colors", () => {
|
|
177
|
+
expect(parseColorValue("brand/50", customColors)).toBe("#FF573380");
|
|
178
|
+
expect(parseColorValue("brand-primary/80", customColors)).toBe("#3498DBCC");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("should still support preset colors with custom colors", () => {
|
|
182
|
+
expect(parseColorValue("red-500", customColors)).toBe(COLORS["red-500"]);
|
|
183
|
+
expect(parseColorValue("blue-800/50", customColors)).toBe(applyOpacity(COLORS["blue-800"], 50));
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("should allow custom colors to override presets", () => {
|
|
187
|
+
const overrideColors = {
|
|
188
|
+
"red-500": "#CUSTOM1",
|
|
189
|
+
};
|
|
190
|
+
expect(parseColorValue("red-500", overrideColors)).toBe("#CUSTOM1");
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|