@mgcrea/react-native-tailwind 0.10.0 → 0.11.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 +30 -13
- package/dist/babel/config-loader.d.ts +12 -3
- package/dist/babel/config-loader.test.ts +14 -12
- package/dist/babel/config-loader.ts +41 -9
- package/dist/babel/index.cjs +50 -27
- package/dist/babel/plugin.d.ts +2 -1
- package/dist/babel/plugin.ts +11 -10
- package/dist/babel/utils/colorSchemeModifierProcessing.d.ts +3 -3
- package/dist/babel/utils/colorSchemeModifierProcessing.ts +4 -4
- package/dist/babel/utils/dynamicProcessing.d.ts +5 -5
- package/dist/babel/utils/dynamicProcessing.ts +11 -11
- package/dist/babel/utils/modifierProcessing.d.ts +3 -3
- package/dist/babel/utils/modifierProcessing.ts +5 -5
- package/dist/babel/utils/platformModifierProcessing.d.ts +3 -3
- package/dist/babel/utils/platformModifierProcessing.ts +4 -4
- package/dist/babel/utils/twProcessing.d.ts +3 -3
- package/dist/babel/utils/twProcessing.ts +6 -6
- package/dist/parser/index.d.ts +11 -4
- package/dist/parser/index.js +1 -1
- package/dist/parser/typography.d.ts +3 -1
- package/dist/parser/typography.js +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +3 -3
- package/dist/runtime.d.ts +8 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +3 -3
- package/dist/runtime.test.js +1 -1
- package/package.json +1 -1
- package/src/babel/config-loader.test.ts +14 -12
- package/src/babel/config-loader.ts +41 -9
- package/src/babel/plugin.ts +11 -10
- package/src/babel/utils/colorSchemeModifierProcessing.ts +4 -4
- package/src/babel/utils/dynamicProcessing.ts +11 -11
- package/src/babel/utils/modifierProcessing.ts +5 -5
- package/src/babel/utils/platformModifierProcessing.ts +4 -4
- package/src/babel/utils/twProcessing.ts +6 -6
- package/src/parser/index.ts +16 -8
- package/src/parser/typography.ts +14 -2
- package/src/runtime.test.ts +7 -7
- package/src/runtime.ts +37 -14
package/dist/runtime.test.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var _vitest=require("vitest");var _runtime=require("./runtime");(0,_vitest.describe)("runtime",function(){(0,_vitest.beforeEach)(function(){(0,_runtime.clearCache)();(0,_runtime.setConfig)({});});(0,_vitest.describe)("tw template tag",function(){(0,_vitest.it)("should parse static classes",function(){var result=(0,_runtime.tw)`m-4 p-2 bg-blue-500`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8,backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toBeUndefined();(0,_vitest.expect)(result==null?void 0:result.disabledStyle).toBeUndefined();});(0,_vitest.it)("should handle interpolated values",function(){var isActive=true;var result=(0,_runtime.tw)`m-4 ${isActive&&"bg-blue-500"}`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,backgroundColor:"#2b7fff"});});(0,_vitest.it)("should handle conditional classes",function(){var isLarge=true;var result=(0,_runtime.tw)`p-4 ${isLarge?"text-xl":"text-sm"}`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({padding:16,fontSize:20});});(0,_vitest.it)("should handle falsy values",function(){var result=(0,_runtime.tw)`m-4 ${false} ${null} ${undefined} p-2`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8});});(0,_vitest.it)("should preserve zero values in template literals",function(){var result=(0,_runtime.tw)`opacity-${0} m-4`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({opacity:0,margin:16});});(0,_vitest.it)("should preserve empty string values in template literals",function(){var result=(0,_runtime.tw)`m-4 ${""}p-2`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8});});(0,_vitest.it)("should handle mixed falsy and truthy numeric values",function(){var spacing=0;var result=(0,_runtime.tw)`m-${spacing} p-4`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:0,padding:16});});(0,_vitest.it)("should return empty style object for empty className",function(){var result=(0,_runtime.tw)``;(0,_vitest.expect)(result).toEqual({style:{}});});(0,_vitest.it)("should normalize whitespace",function(){var result=(0,_runtime.tw)`m-4 p-2 bg-blue-500`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8,backgroundColor:"#2b7fff"});});});(0,_vitest.describe)("twStyle function",function(){(0,_vitest.it)("should parse className string",function(){var result=(0,_runtime.twStyle)("m-4 p-2 bg-blue-500");(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8,backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toBeUndefined();});(0,_vitest.it)("should return undefined for empty string",function(){var result=(0,_runtime.twStyle)("");(0,_vitest.expect)(result).toBeUndefined();});(0,_vitest.it)("should normalize whitespace",function(){var result=(0,_runtime.twStyle)("m-4 p-2 bg-blue-500");(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8,backgroundColor:"#2b7fff"});});});(0,_vitest.describe)("setConfig",function(){(0,_vitest.it)("should set custom colors",function(){(0,_runtime.setConfig)({theme:{extend:{colors:{primary:"#007AFF",secondary:"#5856D6"}}}});var
|
|
1
|
+
var _vitest=require("vitest");var _runtime=require("./runtime");(0,_vitest.describe)("runtime",function(){(0,_vitest.beforeEach)(function(){(0,_runtime.clearCache)();(0,_runtime.setConfig)({});});(0,_vitest.describe)("tw template tag",function(){(0,_vitest.it)("should parse static classes",function(){var result=(0,_runtime.tw)`m-4 p-2 bg-blue-500`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8,backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toBeUndefined();(0,_vitest.expect)(result==null?void 0:result.disabledStyle).toBeUndefined();});(0,_vitest.it)("should handle interpolated values",function(){var isActive=true;var result=(0,_runtime.tw)`m-4 ${isActive&&"bg-blue-500"}`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,backgroundColor:"#2b7fff"});});(0,_vitest.it)("should handle conditional classes",function(){var isLarge=true;var result=(0,_runtime.tw)`p-4 ${isLarge?"text-xl":"text-sm"}`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({padding:16,fontSize:20});});(0,_vitest.it)("should handle falsy values",function(){var result=(0,_runtime.tw)`m-4 ${false} ${null} ${undefined} p-2`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8});});(0,_vitest.it)("should preserve zero values in template literals",function(){var result=(0,_runtime.tw)`opacity-${0} m-4`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({opacity:0,margin:16});});(0,_vitest.it)("should preserve empty string values in template literals",function(){var result=(0,_runtime.tw)`m-4 ${""}p-2`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8});});(0,_vitest.it)("should handle mixed falsy and truthy numeric values",function(){var spacing=0;var result=(0,_runtime.tw)`m-${spacing} p-4`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:0,padding:16});});(0,_vitest.it)("should return empty style object for empty className",function(){var result=(0,_runtime.tw)``;(0,_vitest.expect)(result).toEqual({style:{}});});(0,_vitest.it)("should normalize whitespace",function(){var result=(0,_runtime.tw)`m-4 p-2 bg-blue-500`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8,backgroundColor:"#2b7fff"});});});(0,_vitest.describe)("twStyle function",function(){(0,_vitest.it)("should parse className string",function(){var result=(0,_runtime.twStyle)("m-4 p-2 bg-blue-500");(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8,backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toBeUndefined();});(0,_vitest.it)("should return undefined for empty string",function(){var result=(0,_runtime.twStyle)("");(0,_vitest.expect)(result).toBeUndefined();});(0,_vitest.it)("should normalize whitespace",function(){var result=(0,_runtime.twStyle)("m-4 p-2 bg-blue-500");(0,_vitest.expect)(result==null?void 0:result.style).toEqual({margin:16,padding:8,backgroundColor:"#2b7fff"});});});(0,_vitest.describe)("setConfig",function(){(0,_vitest.it)("should set custom colors",function(){(0,_runtime.setConfig)({theme:{extend:{colors:{primary:"#007AFF",secondary:"#5856D6"}}}});var theme=(0,_runtime.getCustomTheme)();(0,_vitest.expect)(theme.colors).toEqual({primary:"#007AFF",secondary:"#5856D6"});});(0,_vitest.it)("should flatten nested colors",function(){(0,_runtime.setConfig)({theme:{extend:{colors:{brand:{light:"#FF6B6B",dark:"#CC0000"}}}}});var theme=(0,_runtime.getCustomTheme)();(0,_vitest.expect)(theme.colors).toEqual({"brand-light":"#FF6B6B","brand-dark":"#CC0000"});});(0,_vitest.it)("should handle mixed flat and nested colors",function(){(0,_runtime.setConfig)({theme:{extend:{colors:{primary:"#007AFF",brand:{light:"#FF6B6B",dark:"#CC0000"}}}}});var theme=(0,_runtime.getCustomTheme)();(0,_vitest.expect)(theme.colors).toEqual({primary:"#007AFF","brand-light":"#FF6B6B","brand-dark":"#CC0000"});});(0,_vitest.it)("should clear cache when config changes",function(){var style=(0,_runtime.tw)`bg-blue-500`;(0,_vitest.expect)(style).toBeDefined();(0,_vitest.expect)((0,_runtime.getCacheStats)().size).toBe(1);(0,_runtime.setConfig)({theme:{extend:{colors:{primary:"#007AFF"}}}});(0,_vitest.expect)((0,_runtime.getCacheStats)().size).toBe(0);});(0,_vitest.it)("should use custom colors in parsing",function(){(0,_runtime.setConfig)({theme:{extend:{colors:{primary:"#007AFF"}}}});var result=(0,_runtime.tw)`bg-primary`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({backgroundColor:"#007AFF"});});});(0,_vitest.describe)("cache",function(){(0,_vitest.it)("should cache parsed styles",function(){var result1=(0,_runtime.tw)`m-4 p-2`;var result2=(0,_runtime.tw)`m-4 p-2`;(0,_vitest.expect)(result1).toBe(result2);});(0,_vitest.it)("should track cache stats",function(){var style1=(0,_runtime.tw)`m-4`;var style2=(0,_runtime.tw)`p-2`;var style3=(0,_runtime.tw)`bg-blue-500`;(0,_vitest.expect)(style1).toBeDefined();(0,_vitest.expect)(style2).toBeDefined();(0,_vitest.expect)(style3).toBeDefined();var stats=(0,_runtime.getCacheStats)();(0,_vitest.expect)(stats.size).toBe(3);(0,_vitest.expect)(stats.keys).toContain("m-4");(0,_vitest.expect)(stats.keys).toContain("p-2");(0,_vitest.expect)(stats.keys).toContain("bg-blue-500");});(0,_vitest.it)("should clear cache",function(){var style1=(0,_runtime.tw)`m-4`;var style2=(0,_runtime.tw)`p-2`;(0,_vitest.expect)(style1).toBeDefined();(0,_vitest.expect)(style2).toBeDefined();(0,_vitest.expect)((0,_runtime.getCacheStats)().size).toBe(2);(0,_runtime.clearCache)();(0,_vitest.expect)((0,_runtime.getCacheStats)().size).toBe(0);});});(0,_vitest.describe)("state modifiers",function(){(0,_vitest.it)("should return activeStyle when active: modifier is used",function(){var result=(0,_runtime.tw)`bg-blue-500 active:bg-blue-700`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toEqual({backgroundColor:"#1447e6"});(0,_vitest.expect)(result==null?void 0:result.disabledStyle).toBeUndefined();});(0,_vitest.it)("should return disabledStyle when disabled: modifier is used",function(){var result=(0,_runtime.tw)`bg-blue-500 disabled:bg-gray-300`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.disabledStyle).toEqual({backgroundColor:"#d1d5dc"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toBeUndefined();});(0,_vitest.it)("should return both activeStyle and disabledStyle when both modifiers are used",function(){var result=(0,_runtime.tw)`bg-blue-500 active:bg-blue-700 disabled:bg-gray-300`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toEqual({backgroundColor:"#1447e6"});(0,_vitest.expect)(result==null?void 0:result.disabledStyle).toEqual({backgroundColor:"#d1d5dc"});});(0,_vitest.it)("should merge base and active styles with multiple properties",function(){var result=(0,_runtime.tw)`p-4 m-2 bg-blue-500 active:bg-blue-700 active:p-6`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({padding:16,margin:8,backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toEqual({backgroundColor:"#1447e6",padding:24});});(0,_vitest.it)("should handle only modifier classes (no base)",function(){var result=(0,_runtime.tw)`active:bg-blue-700`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toEqual({backgroundColor:"#1447e6"});});(0,_vitest.it)("should work with twStyle function",function(){var result=(0,_runtime.twStyle)("bg-blue-500 active:bg-blue-700");(0,_vitest.expect)(result==null?void 0:result.style).toEqual({backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toEqual({backgroundColor:"#1447e6"});});(0,_vitest.it)("should provide raw hex values for animations",function(){var _result$activeStyle;var result=(0,_runtime.tw)`bg-blue-500 active:bg-blue-700`;(0,_vitest.expect)(result==null?void 0:result.style.backgroundColor).toBe("#2b7fff");(0,_vitest.expect)(result==null||(_result$activeStyle=result.activeStyle)==null?void 0:_result$activeStyle.backgroundColor).toBe("#1447e6");});(0,_vitest.it)("should return focusStyle when focus: modifier is used",function(){var result=(0,_runtime.tw)`bg-blue-500 focus:bg-blue-800`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.focusStyle).toEqual({backgroundColor:"#193cb8"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toBeUndefined();(0,_vitest.expect)(result==null?void 0:result.disabledStyle).toBeUndefined();});(0,_vitest.it)("should return all three modifier styles when all are used",function(){var result=(0,_runtime.tw)`bg-blue-500 active:bg-blue-700 focus:bg-blue-800 disabled:bg-gray-300`;(0,_vitest.expect)(result==null?void 0:result.style).toEqual({backgroundColor:"#2b7fff"});(0,_vitest.expect)(result==null?void 0:result.activeStyle).toEqual({backgroundColor:"#1447e6"});(0,_vitest.expect)(result==null?void 0:result.focusStyle).toEqual({backgroundColor:"#193cb8"});(0,_vitest.expect)(result==null?void 0:result.disabledStyle).toEqual({backgroundColor:"#d1d5dc"});});});});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mgcrea/react-native-tailwind",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
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,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
-
import {
|
|
3
|
+
import { extractCustomTheme, findTailwindConfig, loadTailwindConfig } from "./config-loader";
|
|
4
4
|
|
|
5
5
|
// Mock fs
|
|
6
6
|
vi.mock("fs");
|
|
@@ -115,15 +115,15 @@ describe("config-loader", () => {
|
|
|
115
115
|
});
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
describe("
|
|
119
|
-
it("should return empty
|
|
118
|
+
describe("extractCustomTheme", () => {
|
|
119
|
+
it("should return empty theme when no config found", () => {
|
|
120
120
|
vi.spyOn(fs, "existsSync").mockReturnValue(false);
|
|
121
121
|
|
|
122
|
-
const result =
|
|
123
|
-
expect(result).toEqual({});
|
|
122
|
+
const result = extractCustomTheme("/project/src/file.ts");
|
|
123
|
+
expect(result).toEqual({ colors: {}, fontFamily: {} });
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
-
it("should return empty
|
|
126
|
+
it("should return empty theme when config has no theme", () => {
|
|
127
127
|
const configPath = "/project/tailwind.config.js";
|
|
128
128
|
|
|
129
129
|
vi.spyOn(fs, "existsSync").mockImplementation((filepath) => filepath === configPath);
|
|
@@ -131,22 +131,24 @@ describe("config-loader", () => {
|
|
|
131
131
|
|
|
132
132
|
// loadTailwindConfig will be called, but we've already tested it
|
|
133
133
|
// For integration, we'd need to mock the entire flow
|
|
134
|
-
const result =
|
|
134
|
+
const result = extractCustomTheme("/project/src/file.ts");
|
|
135
135
|
|
|
136
136
|
// Without actual config loading, this returns empty
|
|
137
|
-
expect(result).toEqual({});
|
|
137
|
+
expect(result).toEqual({ colors: {}, fontFamily: {} });
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
-
it("should extract colors from theme.extend
|
|
140
|
+
it("should extract colors and fontFamily from theme.extend", () => {
|
|
141
141
|
// This would require complex mocking of the entire require flow
|
|
142
|
-
// Testing the logic: theme.extend
|
|
142
|
+
// Testing the logic: theme.extend is preferred
|
|
143
143
|
const colors = { brand: { light: "#fff", dark: "#000" } };
|
|
144
|
+
const fontFamily = { sans: ['"SF Pro"'], custom: ['"Custom Font"'] };
|
|
144
145
|
const theme = {
|
|
145
|
-
extend: { colors },
|
|
146
|
+
extend: { colors, fontFamily },
|
|
146
147
|
};
|
|
147
148
|
|
|
148
|
-
// If we had the config, we'd flatten the colors
|
|
149
|
+
// If we had the config, we'd flatten the colors and convert fontFamily
|
|
149
150
|
expect(theme.extend.colors).toEqual(colors);
|
|
151
|
+
expect(theme.extend.fontFamily).toEqual(fontFamily);
|
|
150
152
|
});
|
|
151
153
|
});
|
|
152
154
|
});
|
|
@@ -13,8 +13,10 @@ export type TailwindConfig = {
|
|
|
13
13
|
theme?: {
|
|
14
14
|
extend?: {
|
|
15
15
|
colors?: Record<string, string | Record<string, string>>;
|
|
16
|
+
fontFamily?: Record<string, string | string[]>;
|
|
16
17
|
};
|
|
17
18
|
colors?: Record<string, string | Record<string, string>>;
|
|
19
|
+
fontFamily?: Record<string, string | string[]>;
|
|
18
20
|
};
|
|
19
21
|
};
|
|
20
22
|
|
|
@@ -82,23 +84,31 @@ export function loadTailwindConfig(configPath: string): TailwindConfig | null {
|
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
/**
|
|
85
|
-
*
|
|
86
|
-
* Prefers theme.extend.colors over theme.colors to avoid overriding defaults
|
|
87
|
+
* Custom theme configuration extracted from tailwind.config
|
|
87
88
|
*/
|
|
88
|
-
export
|
|
89
|
+
export type CustomTheme = {
|
|
90
|
+
colors: Record<string, string>;
|
|
91
|
+
fontFamily: Record<string, string>;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Extract all custom theme extensions from tailwind config
|
|
96
|
+
* Prefers theme.extend.* over theme.* to avoid overriding defaults
|
|
97
|
+
*/
|
|
98
|
+
export function extractCustomTheme(filename: string): CustomTheme {
|
|
89
99
|
const projectDir = path.dirname(filename);
|
|
90
100
|
const configPath = findTailwindConfig(projectDir);
|
|
91
101
|
|
|
92
102
|
if (!configPath) {
|
|
93
|
-
return {};
|
|
103
|
+
return { colors: {}, fontFamily: {} };
|
|
94
104
|
}
|
|
95
105
|
|
|
96
106
|
const config = loadTailwindConfig(configPath);
|
|
97
107
|
if (!config?.theme) {
|
|
98
|
-
return {};
|
|
108
|
+
return { colors: {}, fontFamily: {} };
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
//
|
|
111
|
+
// Extract colors
|
|
102
112
|
/* v8 ignore next 5 */
|
|
103
113
|
if (config.theme.colors && !config.theme.extend?.colors && process.env.NODE_ENV !== "production") {
|
|
104
114
|
console.warn(
|
|
@@ -106,9 +116,31 @@ export function extractCustomColors(filename: string): Record<string, string> {
|
|
|
106
116
|
"Use theme.extend.colors to add custom colors while keeping defaults.",
|
|
107
117
|
);
|
|
108
118
|
}
|
|
109
|
-
|
|
110
|
-
// Prefer theme.extend.colors
|
|
111
119
|
const colors = config.theme.extend?.colors ?? config.theme.colors ?? {};
|
|
112
120
|
|
|
113
|
-
|
|
121
|
+
// Extract fontFamily
|
|
122
|
+
/* v8 ignore next 5 */
|
|
123
|
+
if (config.theme.fontFamily && !config.theme.extend?.fontFamily && process.env.NODE_ENV !== "production") {
|
|
124
|
+
console.warn(
|
|
125
|
+
"[react-native-tailwind] Using theme.fontFamily will override all default font families. " +
|
|
126
|
+
"Use theme.extend.fontFamily to add custom fonts while keeping defaults.",
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
const fontFamily = config.theme.extend?.fontFamily ?? config.theme.fontFamily ?? {};
|
|
130
|
+
|
|
131
|
+
// Convert fontFamily values to strings (take first value if array)
|
|
132
|
+
const fontFamilyResult: Record<string, string> = {};
|
|
133
|
+
for (const [key, value] of Object.entries(fontFamily)) {
|
|
134
|
+
if (Array.isArray(value)) {
|
|
135
|
+
// Take first font in the array (React Native doesn't support font stacks)
|
|
136
|
+
fontFamilyResult[key] = value[0];
|
|
137
|
+
} else {
|
|
138
|
+
fontFamilyResult[key] = value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
colors: flattenColors(colors),
|
|
144
|
+
fontFamily: fontFamilyResult,
|
|
145
|
+
};
|
|
114
146
|
}
|
package/src/babel/plugin.ts
CHANGED
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
} from "../parser/index.js";
|
|
19
19
|
import type { StyleObject } from "../types/core.js";
|
|
20
20
|
import { generateStyleKey } from "../utils/styleKey.js";
|
|
21
|
-
import {
|
|
21
|
+
import type { CustomTheme } from "./config-loader.js";
|
|
22
|
+
import { extractCustomTheme } from "./config-loader.js";
|
|
22
23
|
|
|
23
24
|
// Import utility functions
|
|
24
25
|
import type { SchemeModifierConfig } from "../types/config.js";
|
|
@@ -99,7 +100,7 @@ type PluginState = PluginPass & {
|
|
|
99
100
|
hasColorSchemeImport: boolean;
|
|
100
101
|
needsColorSchemeImport: boolean;
|
|
101
102
|
colorSchemeVariableName: string;
|
|
102
|
-
|
|
103
|
+
customTheme: CustomTheme;
|
|
103
104
|
schemeModifierConfig: SchemeModifierConfig;
|
|
104
105
|
supportedAttributes: Set<string>;
|
|
105
106
|
attributePatterns: RegExp[];
|
|
@@ -231,8 +232,8 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
231
232
|
state.hasTwImport = false;
|
|
232
233
|
state.functionComponentsNeedingColorScheme = new Set();
|
|
233
234
|
|
|
234
|
-
// Load custom
|
|
235
|
-
state.
|
|
235
|
+
// Load custom theme from tailwind.config.*
|
|
236
|
+
state.customTheme = extractCustomTheme(state.file.opts.filename ?? "");
|
|
236
237
|
|
|
237
238
|
// Use scheme modifier config from plugin options
|
|
238
239
|
state.schemeModifierConfig = schemeModifierConfig;
|
|
@@ -480,7 +481,7 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
480
481
|
// Expand scheme: into dark: and light:
|
|
481
482
|
const expanded = expandSchemeModifier(
|
|
482
483
|
modifier,
|
|
483
|
-
state.
|
|
484
|
+
state.customTheme.colors ?? {},
|
|
484
485
|
state.schemeModifierConfig.darkSuffix,
|
|
485
486
|
state.schemeModifierConfig.lightSuffix,
|
|
486
487
|
);
|
|
@@ -507,7 +508,7 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
507
508
|
|
|
508
509
|
if (componentSupport?.supportedModifiers.includes("placeholder")) {
|
|
509
510
|
const placeholderClasses = placeholderModifiers.map((m) => m.baseClass).join(" ");
|
|
510
|
-
const placeholderColor = parsePlaceholderClasses(placeholderClasses, state.
|
|
511
|
+
const placeholderColor = parsePlaceholderClasses(placeholderClasses, state.customTheme.colors);
|
|
511
512
|
|
|
512
513
|
if (placeholderColor) {
|
|
513
514
|
// Add or merge placeholderTextColor prop
|
|
@@ -561,7 +562,7 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
561
562
|
// Add base classes
|
|
562
563
|
if (hasBaseClasses) {
|
|
563
564
|
const baseClassName = baseClasses.join(" ");
|
|
564
|
-
const baseStyleObject = parseClassName(baseClassName, state.
|
|
565
|
+
const baseStyleObject = parseClassName(baseClassName, state.customTheme);
|
|
565
566
|
const baseStyleKey = generateStyleKey(baseClassName);
|
|
566
567
|
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
567
568
|
styleArrayElements.push(
|
|
@@ -611,7 +612,7 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
611
612
|
}
|
|
612
613
|
|
|
613
614
|
const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
614
|
-
const modifierStyleObject = parseClassName(modifierClassNames, state.
|
|
615
|
+
const modifierStyleObject = parseClassName(modifierClassNames, state.customTheme);
|
|
615
616
|
const modifierStyleKey = generateStyleKey(`${modifierType}_${modifierClassNames}`);
|
|
616
617
|
state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
|
|
617
618
|
|
|
@@ -653,7 +654,7 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
653
654
|
// Add base classes
|
|
654
655
|
if (hasBaseClasses) {
|
|
655
656
|
const baseClassName = baseClasses.join(" ");
|
|
656
|
-
const baseStyleObject = parseClassName(baseClassName, state.
|
|
657
|
+
const baseStyleObject = parseClassName(baseClassName, state.customTheme);
|
|
657
658
|
const baseStyleKey = generateStyleKey(baseClassName);
|
|
658
659
|
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
659
660
|
styleExpressions.push(
|
|
@@ -815,7 +816,7 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
815
816
|
return;
|
|
816
817
|
}
|
|
817
818
|
|
|
818
|
-
const styleObject = parseClassName(classNameForStyle, state.
|
|
819
|
+
const styleObject = parseClassName(classNameForStyle, state.customTheme);
|
|
819
820
|
const styleKey = generateStyleKey(classNameForStyle);
|
|
820
821
|
state.styleRegistry.set(styleKey, styleObject);
|
|
821
822
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type * as BabelTypes from "@babel/types";
|
|
6
|
-
import type { ColorSchemeModifierType, ParsedModifier } from "../../parser/index.js";
|
|
6
|
+
import type { ColorSchemeModifierType, CustomTheme, ParsedModifier } from "../../parser/index.js";
|
|
7
7
|
import type { StyleObject } from "../../types/core.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -12,7 +12,7 @@ import type { StyleObject } from "../../types/core.js";
|
|
|
12
12
|
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
13
13
|
export interface ColorSchemeModifierProcessingState {
|
|
14
14
|
styleRegistry: Map<string, StyleObject>;
|
|
15
|
-
|
|
15
|
+
customTheme: CustomTheme;
|
|
16
16
|
stylesIdentifier: string;
|
|
17
17
|
needsColorSchemeImport: boolean;
|
|
18
18
|
colorSchemeVariableName: string;
|
|
@@ -38,7 +38,7 @@ export interface ColorSchemeModifierProcessingState {
|
|
|
38
38
|
export function processColorSchemeModifiers(
|
|
39
39
|
colorSchemeModifiers: ParsedModifier[],
|
|
40
40
|
state: ColorSchemeModifierProcessingState,
|
|
41
|
-
parseClassName: (className: string,
|
|
41
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
42
42
|
generateStyleKey: (className: string) => string,
|
|
43
43
|
t: typeof BabelTypes,
|
|
44
44
|
): BabelTypes.Expression[] {
|
|
@@ -65,7 +65,7 @@ export function processColorSchemeModifiers(
|
|
|
65
65
|
for (const [scheme, modifiers] of modifiersByScheme) {
|
|
66
66
|
// Parse all classes for this color scheme together
|
|
67
67
|
const classNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
68
|
-
const styleObject = parseClassName(classNames, state.
|
|
68
|
+
const styleObject = parseClassName(classNames, state.customTheme);
|
|
69
69
|
const styleKey = generateStyleKey(`${scheme}_${classNames}`);
|
|
70
70
|
|
|
71
71
|
// Register style in the registry
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { NodePath } from "@babel/core";
|
|
6
6
|
import type * as BabelTypes from "@babel/types";
|
|
7
|
-
import type { ParsedModifier } from "../../parser/index.js";
|
|
7
|
+
import type { CustomTheme, ParsedModifier } from "../../parser/index.js";
|
|
8
8
|
import type { SchemeModifierConfig } from "../../types/config.js";
|
|
9
9
|
import type { StyleObject } from "../../types/core.js";
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ import type { StyleObject } from "../../types/core.js";
|
|
|
14
14
|
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
15
15
|
export interface DynamicProcessingState {
|
|
16
16
|
styleRegistry: Map<string, StyleObject>;
|
|
17
|
-
|
|
17
|
+
customTheme: CustomTheme;
|
|
18
18
|
schemeModifierConfig: SchemeModifierConfig;
|
|
19
19
|
stylesIdentifier: string;
|
|
20
20
|
needsPlatformImport: boolean;
|
|
@@ -37,7 +37,7 @@ export type SplitModifierClassesFn = (className: string) => {
|
|
|
37
37
|
export type ProcessPlatformModifiersFn = (
|
|
38
38
|
modifiers: ParsedModifier[],
|
|
39
39
|
state: DynamicProcessingState,
|
|
40
|
-
parseClassName: (className: string,
|
|
40
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
41
41
|
generateStyleKey: (className: string) => string,
|
|
42
42
|
t: typeof BabelTypes,
|
|
43
43
|
) => BabelTypes.Expression;
|
|
@@ -48,7 +48,7 @@ export type ProcessPlatformModifiersFn = (
|
|
|
48
48
|
export type ProcessColorSchemeModifiersFn = (
|
|
49
49
|
modifiers: ParsedModifier[],
|
|
50
50
|
state: DynamicProcessingState,
|
|
51
|
-
parseClassName: (className: string,
|
|
51
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
52
52
|
generateStyleKey: (className: string) => string,
|
|
53
53
|
t: typeof BabelTypes,
|
|
54
54
|
) => BabelTypes.Expression[];
|
|
@@ -85,7 +85,7 @@ export type DynamicExpressionResult = {
|
|
|
85
85
|
export function processDynamicExpression(
|
|
86
86
|
expression: BabelTypes.Expression,
|
|
87
87
|
state: DynamicProcessingState,
|
|
88
|
-
parseClassName: (className: string,
|
|
88
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
89
89
|
generateStyleKey: (className: string) => string,
|
|
90
90
|
splitModifierClasses: SplitModifierClassesFn,
|
|
91
91
|
processPlatformModifiers: ProcessPlatformModifiersFn,
|
|
@@ -164,7 +164,7 @@ export function processDynamicExpression(
|
|
|
164
164
|
function processTemplateLiteral(
|
|
165
165
|
node: BabelTypes.TemplateLiteral,
|
|
166
166
|
state: DynamicProcessingState,
|
|
167
|
-
parseClassName: (className: string,
|
|
167
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
168
168
|
generateStyleKey: (className: string) => string,
|
|
169
169
|
splitModifierClasses: SplitModifierClassesFn,
|
|
170
170
|
processPlatformModifiers: ProcessPlatformModifiersFn,
|
|
@@ -262,7 +262,7 @@ function processTemplateLiteral(
|
|
|
262
262
|
function processConditionalExpression(
|
|
263
263
|
node: BabelTypes.ConditionalExpression,
|
|
264
264
|
state: DynamicProcessingState,
|
|
265
|
-
parseClassName: (className: string,
|
|
265
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
266
266
|
generateStyleKey: (className: string) => string,
|
|
267
267
|
splitModifierClasses: SplitModifierClassesFn,
|
|
268
268
|
processPlatformModifiers: ProcessPlatformModifiersFn,
|
|
@@ -325,7 +325,7 @@ function processConditionalExpression(
|
|
|
325
325
|
function processLogicalExpression(
|
|
326
326
|
node: BabelTypes.LogicalExpression,
|
|
327
327
|
state: DynamicProcessingState,
|
|
328
|
-
parseClassName: (className: string,
|
|
328
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
329
329
|
generateStyleKey: (className: string) => string,
|
|
330
330
|
splitModifierClasses: SplitModifierClassesFn,
|
|
331
331
|
processPlatformModifiers: ProcessPlatformModifiersFn,
|
|
@@ -376,7 +376,7 @@ function processLogicalExpression(
|
|
|
376
376
|
function processStringOrExpressionHelper(
|
|
377
377
|
node: BabelTypes.StringLiteral | BabelTypes.Expression,
|
|
378
378
|
state: DynamicProcessingState,
|
|
379
|
-
parseClassName: (className: string,
|
|
379
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
380
380
|
generateStyleKey: (className: string) => string,
|
|
381
381
|
splitModifierClasses: SplitModifierClassesFn,
|
|
382
382
|
processPlatformModifiers: ProcessPlatformModifiersFn,
|
|
@@ -405,7 +405,7 @@ function processStringOrExpressionHelper(
|
|
|
405
405
|
// Expand scheme: into dark: and light:
|
|
406
406
|
const expanded = expandSchemeModifier(
|
|
407
407
|
modifier,
|
|
408
|
-
state.
|
|
408
|
+
state.customTheme.colors ?? {},
|
|
409
409
|
state.schemeModifierConfig.darkSuffix ?? "-dark",
|
|
410
410
|
state.schemeModifierConfig.lightSuffix ?? "-light",
|
|
411
411
|
);
|
|
@@ -425,7 +425,7 @@ function processStringOrExpressionHelper(
|
|
|
425
425
|
// Process base classes
|
|
426
426
|
if (baseClasses.length > 0) {
|
|
427
427
|
const baseClassName = baseClasses.join(" ");
|
|
428
|
-
const styleObject = parseClassName(baseClassName, state.
|
|
428
|
+
const styleObject = parseClassName(baseClassName, state.customTheme);
|
|
429
429
|
const styleKey = generateStyleKey(baseClassName);
|
|
430
430
|
state.styleRegistry.set(styleKey, styleObject);
|
|
431
431
|
styleElements.push(t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey)));
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type * as BabelTypes from "@babel/types";
|
|
6
|
-
import type { ModifierType, ParsedModifier } from "../../parser/index.js";
|
|
6
|
+
import type { CustomTheme, ModifierType, ParsedModifier } from "../../parser/index.js";
|
|
7
7
|
import type { StyleObject } from "../../types/core.js";
|
|
8
8
|
import { getStatePropertyForModifier } from "./componentSupport.js";
|
|
9
9
|
|
|
@@ -13,7 +13,7 @@ import { getStatePropertyForModifier } from "./componentSupport.js";
|
|
|
13
13
|
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
14
14
|
export interface ModifierProcessingState {
|
|
15
15
|
styleRegistry: Map<string, StyleObject>;
|
|
16
|
-
|
|
16
|
+
customTheme: CustomTheme;
|
|
17
17
|
stylesIdentifier: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -24,7 +24,7 @@ export interface ModifierProcessingState {
|
|
|
24
24
|
export function processStaticClassNameWithModifiers(
|
|
25
25
|
className: string,
|
|
26
26
|
state: ModifierProcessingState,
|
|
27
|
-
parseClassName: (className: string,
|
|
27
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
28
28
|
generateStyleKey: (className: string) => string,
|
|
29
29
|
splitModifierClasses: (className: string) => { baseClasses: string[]; modifierClasses: ParsedModifier[] },
|
|
30
30
|
t: typeof BabelTypes,
|
|
@@ -35,7 +35,7 @@ export function processStaticClassNameWithModifiers(
|
|
|
35
35
|
let baseStyleExpression: BabelTypes.Node | null = null;
|
|
36
36
|
if (baseClasses.length > 0) {
|
|
37
37
|
const baseClassName = baseClasses.join(" ");
|
|
38
|
-
const baseStyleObject = parseClassName(baseClassName, state.
|
|
38
|
+
const baseStyleObject = parseClassName(baseClassName, state.customTheme);
|
|
39
39
|
const baseStyleKey = generateStyleKey(baseClassName);
|
|
40
40
|
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
41
41
|
baseStyleExpression = t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey));
|
|
@@ -66,7 +66,7 @@ export function processStaticClassNameWithModifiers(
|
|
|
66
66
|
for (const [modifierType, modifiers] of modifiersByType) {
|
|
67
67
|
// Parse all modifier classes together
|
|
68
68
|
const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
69
|
-
const modifierStyleObject = parseClassName(modifierClassNames, state.
|
|
69
|
+
const modifierStyleObject = parseClassName(modifierClassNames, state.customTheme);
|
|
70
70
|
const modifierStyleKey = generateStyleKey(`${modifierType}_${modifierClassNames}`);
|
|
71
71
|
state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
|
|
72
72
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type * as BabelTypes from "@babel/types";
|
|
6
|
-
import type { ParsedModifier, PlatformModifierType } from "../../parser/index.js";
|
|
6
|
+
import type { CustomTheme, ParsedModifier, PlatformModifierType } from "../../parser/index.js";
|
|
7
7
|
import type { StyleObject } from "../../types/core.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -12,7 +12,7 @@ import type { StyleObject } from "../../types/core.js";
|
|
|
12
12
|
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
13
13
|
export interface PlatformModifierProcessingState {
|
|
14
14
|
styleRegistry: Map<string, StyleObject>;
|
|
15
|
-
|
|
15
|
+
customTheme: CustomTheme;
|
|
16
16
|
stylesIdentifier: string;
|
|
17
17
|
needsPlatformImport: boolean;
|
|
18
18
|
}
|
|
@@ -34,7 +34,7 @@ export interface PlatformModifierProcessingState {
|
|
|
34
34
|
export function processPlatformModifiers(
|
|
35
35
|
platformModifiers: ParsedModifier[],
|
|
36
36
|
state: PlatformModifierProcessingState,
|
|
37
|
-
parseClassName: (className: string,
|
|
37
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
38
38
|
generateStyleKey: (className: string) => string,
|
|
39
39
|
t: typeof BabelTypes,
|
|
40
40
|
): BabelTypes.Expression {
|
|
@@ -61,7 +61,7 @@ export function processPlatformModifiers(
|
|
|
61
61
|
for (const [platform, modifiers] of modifiersByPlatform) {
|
|
62
62
|
// Parse all classes for this platform together
|
|
63
63
|
const classNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
64
|
-
const styleObject = parseClassName(classNames, state.
|
|
64
|
+
const styleObject = parseClassName(classNames, state.customTheme);
|
|
65
65
|
const styleKey = generateStyleKey(`${platform}_${classNames}`);
|
|
66
66
|
|
|
67
67
|
// Register style in the registry
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { NodePath } from "@babel/core";
|
|
6
6
|
import type * as BabelTypes from "@babel/types";
|
|
7
|
-
import type { ModifierType, ParsedModifier } from "../../parser/index.js";
|
|
7
|
+
import type { CustomTheme, ModifierType, ParsedModifier } from "../../parser/index.js";
|
|
8
8
|
import { expandSchemeModifier, isSchemeModifier } from "../../parser/index.js";
|
|
9
9
|
import type { SchemeModifierConfig } from "../../types/config.js";
|
|
10
10
|
import type { StyleObject } from "../../types/core.js";
|
|
@@ -15,7 +15,7 @@ import type { StyleObject } from "../../types/core.js";
|
|
|
15
15
|
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
16
16
|
export interface TwProcessingState {
|
|
17
17
|
styleRegistry: Map<string, StyleObject>;
|
|
18
|
-
|
|
18
|
+
customTheme: CustomTheme;
|
|
19
19
|
schemeModifierConfig: SchemeModifierConfig;
|
|
20
20
|
stylesIdentifier: string;
|
|
21
21
|
}
|
|
@@ -28,7 +28,7 @@ export function processTwCall(
|
|
|
28
28
|
className: string,
|
|
29
29
|
path: NodePath,
|
|
30
30
|
state: TwProcessingState,
|
|
31
|
-
parseClassName: (className: string,
|
|
31
|
+
parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
|
|
32
32
|
generateStyleKey: (className: string) => string,
|
|
33
33
|
splitModifierClasses: (className: string) => { baseClasses: string[]; modifierClasses: ParsedModifier[] },
|
|
34
34
|
t: typeof BabelTypes,
|
|
@@ -42,7 +42,7 @@ export function processTwCall(
|
|
|
42
42
|
// Expand scheme: into dark: and light:
|
|
43
43
|
const expanded = expandSchemeModifier(
|
|
44
44
|
modifier,
|
|
45
|
-
state.
|
|
45
|
+
state.customTheme.colors ?? {},
|
|
46
46
|
state.schemeModifierConfig.darkSuffix ?? "-dark",
|
|
47
47
|
state.schemeModifierConfig.lightSuffix ?? "-light",
|
|
48
48
|
);
|
|
@@ -59,7 +59,7 @@ export function processTwCall(
|
|
|
59
59
|
// Parse and add base styles
|
|
60
60
|
if (baseClasses.length > 0) {
|
|
61
61
|
const baseClassName = baseClasses.join(" ");
|
|
62
|
-
const baseStyleObject = parseClassName(baseClassName, state.
|
|
62
|
+
const baseStyleObject = parseClassName(baseClassName, state.customTheme);
|
|
63
63
|
const baseStyleKey = generateStyleKey(baseClassName);
|
|
64
64
|
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
65
65
|
|
|
@@ -89,7 +89,7 @@ export function processTwCall(
|
|
|
89
89
|
// Add modifier styles
|
|
90
90
|
for (const [modifierType, modifiers] of modifiersByType) {
|
|
91
91
|
const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
92
|
-
const modifierStyleObject = parseClassName(modifierClassNames, state.
|
|
92
|
+
const modifierStyleObject = parseClassName(modifierClassNames, state.customTheme);
|
|
93
93
|
const modifierStyleKey = generateStyleKey(`${modifierType}_${modifierClassNames}`);
|
|
94
94
|
state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
|
|
95
95
|
|
package/src/parser/index.ts
CHANGED
|
@@ -14,18 +14,26 @@ import { parseSpacing } from "./spacing";
|
|
|
14
14
|
import { parseTransform } from "./transforms";
|
|
15
15
|
import { parseTypography } from "./typography";
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Custom theme configuration (subset of tailwind.config theme extensions)
|
|
19
|
+
*/
|
|
20
|
+
export type CustomTheme = {
|
|
21
|
+
colors?: Record<string, string>;
|
|
22
|
+
fontFamily?: Record<string, string>;
|
|
23
|
+
};
|
|
24
|
+
|
|
17
25
|
/**
|
|
18
26
|
* Parse a className string and return a React Native style object
|
|
19
27
|
* @param className - Space-separated class names
|
|
20
|
-
* @param
|
|
28
|
+
* @param customTheme - Optional custom theme from tailwind.config
|
|
21
29
|
* @returns React Native style object
|
|
22
30
|
*/
|
|
23
|
-
export function parseClassName(className: string,
|
|
31
|
+
export function parseClassName(className: string, customTheme?: CustomTheme): StyleObject {
|
|
24
32
|
const classes = className.split(/\s+/).filter(Boolean);
|
|
25
33
|
const style: StyleObject = {};
|
|
26
34
|
|
|
27
35
|
for (const cls of classes) {
|
|
28
|
-
const parsedStyle = parseClass(cls,
|
|
36
|
+
const parsedStyle = parseClass(cls, customTheme);
|
|
29
37
|
Object.assign(style, parsedStyle);
|
|
30
38
|
}
|
|
31
39
|
|
|
@@ -35,19 +43,19 @@ export function parseClassName(className: string, customColors?: Record<string,
|
|
|
35
43
|
/**
|
|
36
44
|
* Parse a single class name
|
|
37
45
|
* @param cls - Single class name
|
|
38
|
-
* @param
|
|
46
|
+
* @param customTheme - Optional custom theme from tailwind.config
|
|
39
47
|
* @returns React Native style object
|
|
40
48
|
*/
|
|
41
|
-
export function parseClass(cls: string,
|
|
49
|
+
export function parseClass(cls: string, customTheme?: CustomTheme): StyleObject {
|
|
42
50
|
// Try each parser in order
|
|
43
51
|
// Note: parseBorder must come before parseColor to avoid border-[3px] being parsed as a color
|
|
44
|
-
// parseColor
|
|
52
|
+
// parseColor and parseTypography get custom theme, others don't need it
|
|
45
53
|
const parsers: Array<(cls: string) => StyleObject | null> = [
|
|
46
54
|
parseSpacing,
|
|
47
55
|
parseBorder,
|
|
48
|
-
(cls: string) => parseColor(cls,
|
|
56
|
+
(cls: string) => parseColor(cls, customTheme?.colors),
|
|
49
57
|
parseLayout,
|
|
50
|
-
parseTypography,
|
|
58
|
+
(cls: string) => parseTypography(cls, customTheme?.fontFamily),
|
|
51
59
|
parseSizing,
|
|
52
60
|
parseShadow,
|
|
53
61
|
parseAspectRatio,
|
package/src/parser/typography.ts
CHANGED
|
@@ -164,8 +164,20 @@ function parseArbitraryLineHeight(value: string): number | null {
|
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
166
|
* Parse typography classes
|
|
167
|
+
* @param cls - Class name to parse
|
|
168
|
+
* @param customFontFamily - Optional custom fontFamily from tailwind.config
|
|
167
169
|
*/
|
|
168
|
-
export function parseTypography(cls: string): StyleObject | null {
|
|
170
|
+
export function parseTypography(cls: string, customFontFamily?: Record<string, string>): StyleObject | null {
|
|
171
|
+
// Merge custom fontFamily with defaults (custom takes precedence)
|
|
172
|
+
const fontFamilyMap = customFontFamily
|
|
173
|
+
? {
|
|
174
|
+
...FONT_FAMILY_MAP,
|
|
175
|
+
...Object.fromEntries(
|
|
176
|
+
Object.entries(customFontFamily).map(([key, value]) => [`font-${key}`, { fontFamily: value }]),
|
|
177
|
+
),
|
|
178
|
+
}
|
|
179
|
+
: FONT_FAMILY_MAP;
|
|
180
|
+
|
|
169
181
|
// Font size: text-base, text-lg, text-[18px], etc.
|
|
170
182
|
if (cls.startsWith("text-")) {
|
|
171
183
|
const sizeKey = cls.substring(5);
|
|
@@ -202,7 +214,7 @@ export function parseTypography(cls: string): StyleObject | null {
|
|
|
202
214
|
|
|
203
215
|
// Try each lookup table in order
|
|
204
216
|
return (
|
|
205
|
-
|
|
217
|
+
fontFamilyMap[cls] ??
|
|
206
218
|
FONT_WEIGHT_MAP[cls] ??
|
|
207
219
|
FONT_STYLE_MAP[cls] ??
|
|
208
220
|
TEXT_ALIGN_MAP[cls] ??
|