@mgcrea/react-native-tailwind 0.11.1 → 0.12.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/dist/babel/index.cjs +189 -20
- package/dist/babel/plugin.test.ts +498 -0
- package/dist/babel/plugin.ts +55 -16
- package/dist/babel/utils/twProcessing.d.ts +8 -1
- package/dist/babel/utils/twProcessing.ts +212 -4
- package/dist/parser/spacing.d.ts +1 -1
- package/dist/parser/spacing.js +1 -1
- package/dist/parser/spacing.test.js +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +2 -2
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +2 -2
- package/dist/runtime.test.js +1 -1
- package/dist/types/runtime.d.ts +8 -1
- package/package.json +1 -1
- package/src/babel/plugin.test.ts +498 -0
- package/src/babel/plugin.ts +55 -16
- package/src/babel/utils/twProcessing.ts +212 -4
- package/src/parser/spacing.test.ts +62 -0
- package/src/parser/spacing.ts +7 -7
- package/src/runtime.test.ts +4 -1
- package/src/types/runtime.ts +8 -1
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 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
|
|
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`;var style=Array.isArray(result==null?void 0:result.style)?result.style.find(function(s){return s!==false;}):result==null?void 0:result.style;(0,_vitest.expect)(style&&typeof style==="object"&&"backgroundColor"in style?style.backgroundColor:undefined).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/dist/types/runtime.d.ts
CHANGED
|
@@ -5,11 +5,18 @@ import type { ImageStyle, TextStyle, ViewStyle } from "react-native";
|
|
|
5
5
|
export type NativeStyle = ViewStyle | TextStyle | ImageStyle;
|
|
6
6
|
/**
|
|
7
7
|
* Return type for tw/twStyle functions with separate style properties for modifiers
|
|
8
|
+
* When color-scheme modifiers (dark:, light:) are present, style becomes an array with runtime conditionals
|
|
9
|
+
* When platform modifiers (ios:, android:, web:) are present, style becomes an array with Platform.select()
|
|
8
10
|
*/
|
|
9
11
|
export type TwStyle<T extends NativeStyle = NativeStyle> = {
|
|
10
|
-
style: T
|
|
12
|
+
style: T | Array<T | false>;
|
|
11
13
|
activeStyle?: T;
|
|
12
14
|
focusStyle?: T;
|
|
13
15
|
disabledStyle?: T;
|
|
14
16
|
placeholderStyle?: TextStyle;
|
|
17
|
+
lightStyle?: T;
|
|
18
|
+
darkStyle?: T;
|
|
19
|
+
iosStyle?: T;
|
|
20
|
+
androidStyle?: T;
|
|
21
|
+
webStyle?: T;
|
|
15
22
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mgcrea/react-native-tailwind",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.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",
|
package/src/babel/plugin.test.ts
CHANGED
|
@@ -334,6 +334,89 @@ describe("Babel plugin - className transformation (existing behavior)", () => {
|
|
|
334
334
|
// Should not have className in output
|
|
335
335
|
expect(output).not.toContain("className");
|
|
336
336
|
});
|
|
337
|
+
|
|
338
|
+
it('should transform className={"..."} (string literal in expression container)', () => {
|
|
339
|
+
const input = `
|
|
340
|
+
import { View } from 'react-native';
|
|
341
|
+
export function Component() {
|
|
342
|
+
return <View className={"flex-row items-center justify-start"} />;
|
|
343
|
+
}
|
|
344
|
+
`;
|
|
345
|
+
|
|
346
|
+
const output = transform(input, undefined, true);
|
|
347
|
+
|
|
348
|
+
// Should have StyleSheet
|
|
349
|
+
expect(output).toContain("StyleSheet.create");
|
|
350
|
+
expect(output).toContain("_twStyles");
|
|
351
|
+
|
|
352
|
+
// Should replace className with style
|
|
353
|
+
expect(output).not.toContain("className");
|
|
354
|
+
expect(output).toContain("style:");
|
|
355
|
+
|
|
356
|
+
// Should have the expected style keys
|
|
357
|
+
expect(output).toContain("_flex_row_items_center_justify_start");
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('should transform className={"..."} with modifiers', () => {
|
|
361
|
+
const input = `
|
|
362
|
+
import { Pressable } from 'react-native';
|
|
363
|
+
export function Component() {
|
|
364
|
+
return <Pressable className={"bg-blue-500 active:bg-blue-700 p-4"} />;
|
|
365
|
+
}
|
|
366
|
+
`;
|
|
367
|
+
|
|
368
|
+
const output = transform(input, undefined, true);
|
|
369
|
+
|
|
370
|
+
// Should have StyleSheet with both base and active styles
|
|
371
|
+
expect(output).toContain("_bg_blue_500_p_4");
|
|
372
|
+
expect(output).toContain("_active_bg_blue_700");
|
|
373
|
+
|
|
374
|
+
// Should have style function for active modifier (Pressable uses 'pressed' parameter)
|
|
375
|
+
expect(output).toMatch(/(pressed|_state)/);
|
|
376
|
+
|
|
377
|
+
// Should not have className in output
|
|
378
|
+
expect(output).not.toContain("className");
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('should transform className={"..."} with platform modifiers', () => {
|
|
382
|
+
const input = `
|
|
383
|
+
import { View } from 'react-native';
|
|
384
|
+
export function Component() {
|
|
385
|
+
return <View className={"p-4 ios:p-6 android:p-8"} />;
|
|
386
|
+
}
|
|
387
|
+
`;
|
|
388
|
+
|
|
389
|
+
const output = transform(input, undefined, true);
|
|
390
|
+
|
|
391
|
+
// Should have Platform import
|
|
392
|
+
expect(output).toContain("Platform");
|
|
393
|
+
expect(output).toMatch(/from ['"]react-native['"]/); // Match both single and double quotes
|
|
394
|
+
|
|
395
|
+
// Should have Platform.select
|
|
396
|
+
expect(output).toContain("Platform.select");
|
|
397
|
+
|
|
398
|
+
// Should have platform-specific styles
|
|
399
|
+
expect(output).toContain("_ios_p_6");
|
|
400
|
+
expect(output).toContain("_android_p_8");
|
|
401
|
+
|
|
402
|
+
// Should not have className in output
|
|
403
|
+
expect(output).not.toContain("className");
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it('should handle empty className={""}', () => {
|
|
407
|
+
const input = `
|
|
408
|
+
import { View } from 'react-native';
|
|
409
|
+
export function Component() {
|
|
410
|
+
return <View className={""} />;
|
|
411
|
+
}
|
|
412
|
+
`;
|
|
413
|
+
|
|
414
|
+
const output = transform(input, undefined, true);
|
|
415
|
+
|
|
416
|
+
// Should remove empty className attribute entirely
|
|
417
|
+
expect(output).not.toContain("className");
|
|
418
|
+
expect(output).not.toContain("style=");
|
|
419
|
+
});
|
|
337
420
|
});
|
|
338
421
|
|
|
339
422
|
describe("Babel plugin - placeholder: modifier transformation", () => {
|
|
@@ -1250,6 +1333,34 @@ describe("Babel plugin - custom color scheme hook import", () => {
|
|
|
1250
1333
|
expect(output).not.toContain("_twColorScheme = useTheme()");
|
|
1251
1334
|
});
|
|
1252
1335
|
|
|
1336
|
+
it("should not treat type-only imports as having the hook", () => {
|
|
1337
|
+
const input = `
|
|
1338
|
+
import React from 'react';
|
|
1339
|
+
import { View } from 'react-native';
|
|
1340
|
+
import type { useColorScheme } from 'react-native';
|
|
1341
|
+
|
|
1342
|
+
export function Component() {
|
|
1343
|
+
return <View className="dark:bg-gray-900" />;
|
|
1344
|
+
}
|
|
1345
|
+
`;
|
|
1346
|
+
|
|
1347
|
+
const output = transform(input, undefined, true);
|
|
1348
|
+
|
|
1349
|
+
// Should add a VALUE import for useColorScheme (type import doesn't count)
|
|
1350
|
+
expect(output).toMatch(/import\s+\{[^}]*useColorScheme[^}]*\}\s+from\s+['"]react-native['"]/);
|
|
1351
|
+
|
|
1352
|
+
// Should inject the hook
|
|
1353
|
+
expect(output).toContain("_twColorScheme = useColorScheme()");
|
|
1354
|
+
|
|
1355
|
+
// Should have both type-only and value imports in output
|
|
1356
|
+
// (TypeScript preset keeps type imports for type checking)
|
|
1357
|
+
const colorSchemeMatches = output.match(/useColorScheme/g);
|
|
1358
|
+
expect(colorSchemeMatches).toBeTruthy();
|
|
1359
|
+
if (colorSchemeMatches) {
|
|
1360
|
+
expect(colorSchemeMatches.length).toBeGreaterThanOrEqual(2); // At least in import and hook call
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
|
|
1253
1364
|
it("should handle both type-only and aliased imports together", () => {
|
|
1254
1365
|
const input = `
|
|
1255
1366
|
import React from 'react';
|
|
@@ -1412,3 +1523,390 @@ describe("Babel plugin - scheme: modifier", () => {
|
|
|
1412
1523
|
expect(output).toContain("_twColorScheme === 'light'");
|
|
1413
1524
|
});
|
|
1414
1525
|
});
|
|
1526
|
+
|
|
1527
|
+
describe("Babel plugin - color scheme modifiers in tw/twStyle", () => {
|
|
1528
|
+
it("should transform tw with dark: modifier inside component", () => {
|
|
1529
|
+
const input = `
|
|
1530
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1531
|
+
|
|
1532
|
+
function MyComponent() {
|
|
1533
|
+
const styles = tw\`bg-white dark:bg-gray-900\`;
|
|
1534
|
+
return null;
|
|
1535
|
+
}
|
|
1536
|
+
`;
|
|
1537
|
+
|
|
1538
|
+
const output = transform(input);
|
|
1539
|
+
|
|
1540
|
+
// Should inject useColorScheme hook
|
|
1541
|
+
expect(output).toContain("useColorScheme");
|
|
1542
|
+
expect(output).toContain("_twColorScheme");
|
|
1543
|
+
|
|
1544
|
+
// Should generate style array with conditionals
|
|
1545
|
+
expect(output).toContain("style: [");
|
|
1546
|
+
expect(output).toContain('_twColorScheme === "dark"');
|
|
1547
|
+
expect(output).toContain("_twStyles._dark_bg_gray_900");
|
|
1548
|
+
expect(output).toContain("_twStyles._bg_white");
|
|
1549
|
+
|
|
1550
|
+
// Should have StyleSheet.create
|
|
1551
|
+
expect(output).toContain("StyleSheet.create");
|
|
1552
|
+
});
|
|
1553
|
+
|
|
1554
|
+
it("should transform twStyle with light: modifier inside component", () => {
|
|
1555
|
+
const input = `
|
|
1556
|
+
import { twStyle } from '@mgcrea/react-native-tailwind';
|
|
1557
|
+
|
|
1558
|
+
export const MyComponent = () => {
|
|
1559
|
+
const buttonStyles = twStyle('text-gray-900 light:text-gray-100');
|
|
1560
|
+
return null;
|
|
1561
|
+
};
|
|
1562
|
+
`;
|
|
1563
|
+
|
|
1564
|
+
const output = transform(input);
|
|
1565
|
+
|
|
1566
|
+
// Should inject useColorScheme hook
|
|
1567
|
+
expect(output).toContain("useColorScheme");
|
|
1568
|
+
expect(output).toContain("_twColorScheme");
|
|
1569
|
+
|
|
1570
|
+
// Should generate style array with conditionals
|
|
1571
|
+
expect(output).toContain("style: [");
|
|
1572
|
+
expect(output).toContain('_twColorScheme === "light"');
|
|
1573
|
+
expect(output).toContain("_twStyles._light_text_gray_100");
|
|
1574
|
+
expect(output).toContain("_twStyles._text_gray_900");
|
|
1575
|
+
});
|
|
1576
|
+
|
|
1577
|
+
it("should transform tw with both dark: and light: modifiers", () => {
|
|
1578
|
+
const input = `
|
|
1579
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1580
|
+
|
|
1581
|
+
function MyComponent() {
|
|
1582
|
+
const styles = tw\`bg-blue-500 dark:bg-blue-900 light:bg-blue-100\`;
|
|
1583
|
+
return null;
|
|
1584
|
+
}
|
|
1585
|
+
`;
|
|
1586
|
+
|
|
1587
|
+
const output = transform(input);
|
|
1588
|
+
|
|
1589
|
+
// Should have both conditionals
|
|
1590
|
+
expect(output).toContain('_twColorScheme === "dark"');
|
|
1591
|
+
expect(output).toContain('_twColorScheme === "light"');
|
|
1592
|
+
expect(output).toContain("_twStyles._dark_bg_blue_900");
|
|
1593
|
+
expect(output).toContain("_twStyles._light_bg_blue_100");
|
|
1594
|
+
expect(output).toContain("_twStyles._bg_blue_500");
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
it("should combine color scheme modifiers with state modifiers", () => {
|
|
1598
|
+
const input = `
|
|
1599
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1600
|
+
|
|
1601
|
+
function MyComponent() {
|
|
1602
|
+
const styles = tw\`bg-white dark:bg-gray-900 active:bg-blue-500\`;
|
|
1603
|
+
return null;
|
|
1604
|
+
}
|
|
1605
|
+
`;
|
|
1606
|
+
|
|
1607
|
+
const output = transform(input);
|
|
1608
|
+
|
|
1609
|
+
// Should have color scheme conditionals in style array
|
|
1610
|
+
expect(output).toContain("style: [");
|
|
1611
|
+
expect(output).toContain('_twColorScheme === "dark"');
|
|
1612
|
+
|
|
1613
|
+
// Should have activeStyle property (separate from color scheme)
|
|
1614
|
+
expect(output).toContain("activeStyle:");
|
|
1615
|
+
expect(output).toContain("_twStyles._active_bg_blue_500");
|
|
1616
|
+
});
|
|
1617
|
+
|
|
1618
|
+
it("should warn if tw with color scheme modifiers used outside component", () => {
|
|
1619
|
+
const consoleWarnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
1620
|
+
|
|
1621
|
+
const input = `
|
|
1622
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1623
|
+
|
|
1624
|
+
const globalStyles = tw\`bg-white dark:bg-gray-900\`;
|
|
1625
|
+
`;
|
|
1626
|
+
|
|
1627
|
+
const output = transform(input);
|
|
1628
|
+
|
|
1629
|
+
// Should warn about usage outside component
|
|
1630
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
1631
|
+
expect.stringContaining("Color scheme modifiers (dark:, light:) in tw/twStyle calls"),
|
|
1632
|
+
);
|
|
1633
|
+
|
|
1634
|
+
// Should not inject hook (no component scope)
|
|
1635
|
+
expect(output).not.toContain("useColorScheme");
|
|
1636
|
+
|
|
1637
|
+
// Should still generate styles but without runtime conditionals
|
|
1638
|
+
expect(output).toContain("_twStyles");
|
|
1639
|
+
|
|
1640
|
+
consoleWarnSpy.mockRestore();
|
|
1641
|
+
});
|
|
1642
|
+
|
|
1643
|
+
it("should handle tw with only dark: modifier (no base class)", () => {
|
|
1644
|
+
const input = `
|
|
1645
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1646
|
+
|
|
1647
|
+
function MyComponent() {
|
|
1648
|
+
const styles = tw\`dark:bg-gray-900\`;
|
|
1649
|
+
return null;
|
|
1650
|
+
}
|
|
1651
|
+
`;
|
|
1652
|
+
|
|
1653
|
+
const output = transform(input);
|
|
1654
|
+
|
|
1655
|
+
// Should still generate style array
|
|
1656
|
+
expect(output).toContain("style: [");
|
|
1657
|
+
expect(output).toContain('_twColorScheme === "dark"');
|
|
1658
|
+
expect(output).toContain("_twStyles._dark_bg_gray_900");
|
|
1659
|
+
});
|
|
1660
|
+
|
|
1661
|
+
it("should work with custom color scheme hook import", () => {
|
|
1662
|
+
const input = `
|
|
1663
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1664
|
+
import { useTheme } from '@react-navigation/native';
|
|
1665
|
+
|
|
1666
|
+
function MyComponent() {
|
|
1667
|
+
const styles = tw\`bg-white dark:bg-gray-900\`;
|
|
1668
|
+
return null;
|
|
1669
|
+
}
|
|
1670
|
+
`;
|
|
1671
|
+
|
|
1672
|
+
const options: PluginOptions = {
|
|
1673
|
+
colorScheme: {
|
|
1674
|
+
importFrom: "@react-navigation/native",
|
|
1675
|
+
importName: "useTheme",
|
|
1676
|
+
},
|
|
1677
|
+
};
|
|
1678
|
+
|
|
1679
|
+
const output = transform(input, options);
|
|
1680
|
+
|
|
1681
|
+
// Should use existing import (not duplicate)
|
|
1682
|
+
const themeImportCount = (output.match(/useTheme/g) ?? []).length;
|
|
1683
|
+
// Should appear in import statement and hook call
|
|
1684
|
+
expect(themeImportCount).toBeGreaterThanOrEqual(2);
|
|
1685
|
+
|
|
1686
|
+
// Should call the custom hook
|
|
1687
|
+
expect(output).toContain("useTheme()");
|
|
1688
|
+
});
|
|
1689
|
+
|
|
1690
|
+
it("should generate both style array and darkStyle/lightStyle properties", () => {
|
|
1691
|
+
const input = `
|
|
1692
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1693
|
+
|
|
1694
|
+
function MyComponent() {
|
|
1695
|
+
const styles = tw\`bg-white dark:bg-gray-900 light:bg-gray-50\`;
|
|
1696
|
+
return null;
|
|
1697
|
+
}
|
|
1698
|
+
`;
|
|
1699
|
+
|
|
1700
|
+
const output = transform(input);
|
|
1701
|
+
|
|
1702
|
+
// Should have runtime conditional in style array
|
|
1703
|
+
expect(output).toContain("style: [");
|
|
1704
|
+
expect(output).toContain('_twColorScheme === "dark"');
|
|
1705
|
+
expect(output).toContain('_twColorScheme === "light"');
|
|
1706
|
+
|
|
1707
|
+
// Should ALSO have darkStyle and lightStyle properties for manual access
|
|
1708
|
+
expect(output).toContain("darkStyle:");
|
|
1709
|
+
expect(output).toContain("lightStyle:");
|
|
1710
|
+
expect(output).toContain("_twStyles._dark_bg_gray_900");
|
|
1711
|
+
expect(output).toContain("_twStyles._light_bg_gray_50");
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1714
|
+
it("should allow accessing raw color values from darkStyle/lightStyle", () => {
|
|
1715
|
+
const input = `
|
|
1716
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1717
|
+
|
|
1718
|
+
function MyComponent() {
|
|
1719
|
+
const btnStyles = tw\`bg-blue-500 dark:bg-blue-900\`;
|
|
1720
|
+
// User can access raw hex for Reanimated
|
|
1721
|
+
const darkBgColor = btnStyles.darkStyle?.backgroundColor;
|
|
1722
|
+
return null;
|
|
1723
|
+
}
|
|
1724
|
+
`;
|
|
1725
|
+
|
|
1726
|
+
const output = transform(input);
|
|
1727
|
+
|
|
1728
|
+
// Should have darkStyle property available
|
|
1729
|
+
expect(output).toContain("darkStyle:");
|
|
1730
|
+
expect(output).toContain("_twStyles._dark_bg_blue_900");
|
|
1731
|
+
|
|
1732
|
+
// The actual usage line should be preserved (TypeScript/Babel doesn't remove it)
|
|
1733
|
+
expect(output).toContain("btnStyles.darkStyle");
|
|
1734
|
+
});
|
|
1735
|
+
|
|
1736
|
+
// Platform modifier tests for tw/twStyle
|
|
1737
|
+
it("should transform tw with ios: modifier", () => {
|
|
1738
|
+
const input = `
|
|
1739
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1740
|
+
|
|
1741
|
+
function MyComponent() {
|
|
1742
|
+
const styles = tw\`bg-white ios:p-6\`;
|
|
1743
|
+
return null;
|
|
1744
|
+
}
|
|
1745
|
+
`;
|
|
1746
|
+
|
|
1747
|
+
const output = transform(input);
|
|
1748
|
+
|
|
1749
|
+
// Should add Platform import
|
|
1750
|
+
expect(output).toContain("Platform");
|
|
1751
|
+
expect(output).toContain('from "react-native"');
|
|
1752
|
+
|
|
1753
|
+
// Should generate style array with Platform.select()
|
|
1754
|
+
expect(output).toContain("style: [");
|
|
1755
|
+
expect(output).toContain("Platform.select");
|
|
1756
|
+
expect(output).toContain("ios:");
|
|
1757
|
+
expect(output).toContain("_twStyles._ios_p_6");
|
|
1758
|
+
expect(output).toContain("_twStyles._bg_white");
|
|
1759
|
+
|
|
1760
|
+
// Should have StyleSheet.create
|
|
1761
|
+
expect(output).toContain("StyleSheet.create");
|
|
1762
|
+
});
|
|
1763
|
+
|
|
1764
|
+
it("should transform twStyle with android: modifier", () => {
|
|
1765
|
+
const input = `
|
|
1766
|
+
import { twStyle } from '@mgcrea/react-native-tailwind';
|
|
1767
|
+
|
|
1768
|
+
export const MyComponent = () => {
|
|
1769
|
+
const buttonStyles = twStyle('bg-blue-500 android:p-8');
|
|
1770
|
+
return null;
|
|
1771
|
+
};
|
|
1772
|
+
`;
|
|
1773
|
+
|
|
1774
|
+
const output = transform(input);
|
|
1775
|
+
|
|
1776
|
+
// Should add Platform import
|
|
1777
|
+
expect(output).toContain("Platform");
|
|
1778
|
+
|
|
1779
|
+
// Should generate style array with Platform.select()
|
|
1780
|
+
expect(output).toContain("style: [");
|
|
1781
|
+
expect(output).toContain("Platform.select");
|
|
1782
|
+
expect(output).toContain("android:");
|
|
1783
|
+
expect(output).toContain("_twStyles._android_p_8");
|
|
1784
|
+
expect(output).toContain("_twStyles._bg_blue_500");
|
|
1785
|
+
});
|
|
1786
|
+
|
|
1787
|
+
it("should transform tw with multiple platform modifiers", () => {
|
|
1788
|
+
const input = `
|
|
1789
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1790
|
+
|
|
1791
|
+
function MyComponent() {
|
|
1792
|
+
const styles = tw\`bg-white ios:p-6 android:p-8 web:p-4\`;
|
|
1793
|
+
return null;
|
|
1794
|
+
}
|
|
1795
|
+
`;
|
|
1796
|
+
|
|
1797
|
+
const output = transform(input);
|
|
1798
|
+
|
|
1799
|
+
// Should generate Platform.select() with all platforms
|
|
1800
|
+
expect(output).toContain("Platform.select");
|
|
1801
|
+
expect(output).toContain("ios:");
|
|
1802
|
+
expect(output).toContain("android:");
|
|
1803
|
+
expect(output).toContain("web:");
|
|
1804
|
+
expect(output).toContain("_twStyles._ios_p_6");
|
|
1805
|
+
expect(output).toContain("_twStyles._android_p_8");
|
|
1806
|
+
expect(output).toContain("_twStyles._web_p_4");
|
|
1807
|
+
});
|
|
1808
|
+
|
|
1809
|
+
it("should combine platform modifiers with color-scheme modifiers", () => {
|
|
1810
|
+
const input = `
|
|
1811
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1812
|
+
|
|
1813
|
+
function MyComponent() {
|
|
1814
|
+
const styles = tw\`bg-white ios:p-6 dark:bg-gray-900\`;
|
|
1815
|
+
return null;
|
|
1816
|
+
}
|
|
1817
|
+
`;
|
|
1818
|
+
|
|
1819
|
+
const output = transform(input);
|
|
1820
|
+
|
|
1821
|
+
// Should have both Platform and useColorScheme
|
|
1822
|
+
expect(output).toContain("Platform");
|
|
1823
|
+
expect(output).toContain("useColorScheme");
|
|
1824
|
+
expect(output).toContain("_twColorScheme");
|
|
1825
|
+
|
|
1826
|
+
// Should have both conditionals in style array
|
|
1827
|
+
expect(output).toContain("Platform.select");
|
|
1828
|
+
expect(output).toContain('_twColorScheme === "dark"');
|
|
1829
|
+
});
|
|
1830
|
+
|
|
1831
|
+
it("should generate iosStyle/androidStyle/webStyle properties for manual access", () => {
|
|
1832
|
+
const input = `
|
|
1833
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1834
|
+
|
|
1835
|
+
function MyComponent() {
|
|
1836
|
+
const styles = tw\`bg-white ios:p-6 android:p-8 web:p-4\`;
|
|
1837
|
+
return null;
|
|
1838
|
+
}
|
|
1839
|
+
`;
|
|
1840
|
+
|
|
1841
|
+
const output = transform(input);
|
|
1842
|
+
|
|
1843
|
+
// Should have separate platform style properties
|
|
1844
|
+
expect(output).toContain("iosStyle:");
|
|
1845
|
+
expect(output).toContain("_twStyles._ios_p_6");
|
|
1846
|
+
expect(output).toContain("androidStyle:");
|
|
1847
|
+
expect(output).toContain("_twStyles._android_p_8");
|
|
1848
|
+
expect(output).toContain("webStyle:");
|
|
1849
|
+
expect(output).toContain("_twStyles._web_p_4");
|
|
1850
|
+
|
|
1851
|
+
// Should also have runtime Platform.select() in style array
|
|
1852
|
+
expect(output).toContain("Platform.select");
|
|
1853
|
+
});
|
|
1854
|
+
|
|
1855
|
+
it("should work with only platform modifiers (no base class)", () => {
|
|
1856
|
+
const input = `
|
|
1857
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1858
|
+
|
|
1859
|
+
function MyComponent() {
|
|
1860
|
+
const styles = tw\`ios:p-6 android:p-8\`;
|
|
1861
|
+
return null;
|
|
1862
|
+
}
|
|
1863
|
+
`;
|
|
1864
|
+
|
|
1865
|
+
const output = transform(input);
|
|
1866
|
+
|
|
1867
|
+
// Should generate Platform.select() even without base classes
|
|
1868
|
+
expect(output).toContain("Platform.select");
|
|
1869
|
+
expect(output).toContain("_twStyles._ios_p_6");
|
|
1870
|
+
expect(output).toContain("_twStyles._android_p_8");
|
|
1871
|
+
});
|
|
1872
|
+
|
|
1873
|
+
it("should allow accessing platform-specific styles manually", () => {
|
|
1874
|
+
const input = `
|
|
1875
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1876
|
+
|
|
1877
|
+
function MyComponent() {
|
|
1878
|
+
const btnStyles = tw\`bg-blue-500 ios:p-6\`;
|
|
1879
|
+
const iosPadding = btnStyles.iosStyle;
|
|
1880
|
+
return null;
|
|
1881
|
+
}
|
|
1882
|
+
`;
|
|
1883
|
+
|
|
1884
|
+
const output = transform(input);
|
|
1885
|
+
|
|
1886
|
+
// Should have iosStyle property available
|
|
1887
|
+
expect(output).toContain("iosStyle:");
|
|
1888
|
+
expect(output).toContain("_twStyles._ios_p_6");
|
|
1889
|
+
|
|
1890
|
+
// The actual usage line should be preserved
|
|
1891
|
+
expect(output).toContain("btnStyles.iosStyle");
|
|
1892
|
+
});
|
|
1893
|
+
|
|
1894
|
+
it("should combine state modifiers with platform modifiers", () => {
|
|
1895
|
+
const input = `
|
|
1896
|
+
import { tw } from '@mgcrea/react-native-tailwind';
|
|
1897
|
+
|
|
1898
|
+
function MyComponent() {
|
|
1899
|
+
const styles = tw\`bg-white active:bg-blue-500 ios:p-6\`;
|
|
1900
|
+
return null;
|
|
1901
|
+
}
|
|
1902
|
+
`;
|
|
1903
|
+
|
|
1904
|
+
const output = transform(input);
|
|
1905
|
+
|
|
1906
|
+
// Should have both activeStyle and platform modifiers
|
|
1907
|
+
expect(output).toContain("activeStyle:");
|
|
1908
|
+
expect(output).toContain("_twStyles._active_bg_blue_500");
|
|
1909
|
+
expect(output).toContain("Platform.select");
|
|
1910
|
+
expect(output).toContain("_twStyles._ios_p_6");
|
|
1911
|
+
});
|
|
1912
|
+
});
|