@mgcrea/react-native-tailwind 0.9.0 → 0.9.1
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 +28 -13
- package/dist/babel/plugin.d.ts +2 -1
- package/dist/babel/plugin.test.ts +86 -0
- package/dist/babel/plugin.ts +7 -4
- package/dist/babel/utils/styleInjection.d.ts +1 -1
- package/dist/babel/utils/styleInjection.ts +24 -7
- package/dist/parser/aspectRatio.js +1 -1
- package/dist/parser/aspectRatio.test.js +1 -1
- 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 +3 -3
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +3 -3
- package/dist/runtime.test.js +1 -1
- package/package.json +2 -3
- package/src/babel/plugin.test.ts +86 -0
- package/src/babel/plugin.ts +7 -4
- package/src/babel/utils/styleInjection.ts +24 -7
- package/src/parser/aspectRatio.test.ts +25 -2
- package/src/parser/aspectRatio.ts +3 -3
- package/src/parser/spacing.test.ts +63 -0
- package/src/parser/spacing.ts +10 -6
- package/src/runtime.test.ts +27 -0
- package/src/runtime.ts +2 -1
- package/dist/babel/index.test.ts +0 -481
- package/dist/config/palettes.d.ts +0 -302
- package/dist/config/palettes.js +0 -1
- package/dist/parser/__snapshots__/aspectRatio.test.js.snap +0 -9
- package/dist/parser/__snapshots__/borders.test.js.snap +0 -23
- package/dist/parser/__snapshots__/colors.test.js.snap +0 -251
- package/dist/parser/__snapshots__/shadows.test.js.snap +0 -76
- package/dist/parser/__snapshots__/sizing.test.js.snap +0 -61
- package/dist/parser/__snapshots__/spacing.test.js.snap +0 -40
- package/dist/parser/__snapshots__/transforms.test.js.snap +0 -58
- package/dist/parser/__snapshots__/typography.test.js.snap +0 -30
- package/dist/parser/aspectRatio.test.d.ts +0 -1
- package/dist/parser/borders.test.d.ts +0 -1
- package/dist/parser/colors.test.d.ts +0 -1
- package/dist/parser/layout.test.d.ts +0 -1
- package/dist/parser/modifiers.test.d.ts +0 -1
- package/dist/parser/shadows.test.d.ts +0 -1
- package/dist/parser/sizing.test.d.ts +0 -1
- package/dist/parser/spacing.test.d.ts +0 -1
- package/dist/parser/typography.test.d.ts +0 -1
- package/dist/types.d.ts +0 -42
- package/dist/types.js +0 -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 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 colors=(0,_runtime.getCustomColors)();(0,_vitest.expect)(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 colors=(0,_runtime.getCustomColors)();(0,_vitest.expect)(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 colors=(0,_runtime.getCustomColors)();(0,_vitest.expect)(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"});});});});
|
|
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 colors=(0,_runtime.getCustomColors)();(0,_vitest.expect)(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 colors=(0,_runtime.getCustomColors)();(0,_vitest.expect)(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 colors=(0,_runtime.getCustomColors)();(0,_vitest.expect)(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.9.
|
|
3
|
+
"version": "0.9.1",
|
|
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",
|
|
@@ -29,10 +29,9 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
|
-
"*.podspec",
|
|
33
32
|
"src",
|
|
34
33
|
"dist",
|
|
35
|
-
"
|
|
34
|
+
"README.md"
|
|
36
35
|
],
|
|
37
36
|
"scripts": {
|
|
38
37
|
"dev": "cd example; npm run dev",
|
package/src/babel/plugin.test.ts
CHANGED
|
@@ -721,3 +721,89 @@ describe("Babel plugin - platform modifier transformation", () => {
|
|
|
721
721
|
expect(output).not.toMatch(/(?<!_ios|_android|_web)_p_8:/);
|
|
722
722
|
});
|
|
723
723
|
});
|
|
724
|
+
|
|
725
|
+
describe("Babel plugin - import injection", () => {
|
|
726
|
+
it("should not add StyleSheet import to files without className usage", () => {
|
|
727
|
+
const input = `
|
|
728
|
+
import { View, Text } from 'react-native';
|
|
729
|
+
|
|
730
|
+
function MyComponent() {
|
|
731
|
+
return <View><Text>Hello</Text></View>;
|
|
732
|
+
}
|
|
733
|
+
`;
|
|
734
|
+
|
|
735
|
+
const output = transform(input, undefined, true);
|
|
736
|
+
|
|
737
|
+
// Should not mutate the import by adding StyleSheet
|
|
738
|
+
// Count occurrences of "StyleSheet" in output
|
|
739
|
+
const styleSheetCount = (output.match(/StyleSheet/g) ?? []).length;
|
|
740
|
+
expect(styleSheetCount).toBe(0);
|
|
741
|
+
|
|
742
|
+
// Should not have _twStyles definition
|
|
743
|
+
expect(output).not.toContain("_twStyles");
|
|
744
|
+
expect(output).not.toContain("StyleSheet.create");
|
|
745
|
+
|
|
746
|
+
// Original imports should remain unchanged
|
|
747
|
+
expect(output).toContain("View");
|
|
748
|
+
expect(output).toContain("Text");
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
it("should add StyleSheet import only when className is used", () => {
|
|
752
|
+
const input = `
|
|
753
|
+
import { View } from 'react-native';
|
|
754
|
+
|
|
755
|
+
function MyComponent() {
|
|
756
|
+
return <View className="m-4 p-2" />;
|
|
757
|
+
}
|
|
758
|
+
`;
|
|
759
|
+
|
|
760
|
+
const output = transform(input, undefined, true);
|
|
761
|
+
|
|
762
|
+
// Should have StyleSheet import (both single and double quotes)
|
|
763
|
+
expect(output).toMatch(/import.*StyleSheet.*from ['"]react-native['"]|require\(['"]react-native['"]\)/);
|
|
764
|
+
|
|
765
|
+
// Should have _twStyles definition
|
|
766
|
+
expect(output).toContain("_twStyles");
|
|
767
|
+
expect(output).toContain("StyleSheet.create");
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
it("should add Platform import only when platform modifiers are used", () => {
|
|
771
|
+
const input = `
|
|
772
|
+
import { View } from 'react-native';
|
|
773
|
+
|
|
774
|
+
function MyComponent() {
|
|
775
|
+
return <View className="ios:m-4 android:m-2" />;
|
|
776
|
+
}
|
|
777
|
+
`;
|
|
778
|
+
|
|
779
|
+
const output = transform(input, undefined, true);
|
|
780
|
+
|
|
781
|
+
// Should have Platform import
|
|
782
|
+
expect(output).toContain("Platform");
|
|
783
|
+
|
|
784
|
+
// Should have StyleSheet import too
|
|
785
|
+
expect(output).toContain("StyleSheet");
|
|
786
|
+
|
|
787
|
+
// Should use Platform.select
|
|
788
|
+
expect(output).toContain("Platform.select");
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
it("should not add Platform import without platform modifiers", () => {
|
|
792
|
+
const input = `
|
|
793
|
+
import { View } from 'react-native';
|
|
794
|
+
|
|
795
|
+
function MyComponent() {
|
|
796
|
+
return <View className="m-4 p-2" />;
|
|
797
|
+
}
|
|
798
|
+
`;
|
|
799
|
+
|
|
800
|
+
const output = transform(input, undefined, true);
|
|
801
|
+
|
|
802
|
+
// Should not have Platform import
|
|
803
|
+
const platformCount = (output.match(/Platform/g) ?? []).length;
|
|
804
|
+
expect(platformCount).toBe(0);
|
|
805
|
+
|
|
806
|
+
// Should still have StyleSheet
|
|
807
|
+
expect(output).toContain("StyleSheet");
|
|
808
|
+
});
|
|
809
|
+
});
|
package/src/babel/plugin.ts
CHANGED
|
@@ -76,6 +76,8 @@ type PluginState = PluginPass & {
|
|
|
76
76
|
// Track tw/twStyle imports from main package
|
|
77
77
|
twImportNames: Set<string>; // e.g., ['tw', 'twStyle'] or ['tw as customTw']
|
|
78
78
|
hasTwImport: boolean;
|
|
79
|
+
// Track react-native import path for conditional StyleSheet/Platform injection
|
|
80
|
+
reactNativeImportPath?: NodePath<BabelTypes.ImportDeclaration>;
|
|
79
81
|
};
|
|
80
82
|
|
|
81
83
|
// Default identifier for the generated StyleSheet constant
|
|
@@ -161,17 +163,18 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
161
163
|
return false;
|
|
162
164
|
});
|
|
163
165
|
|
|
166
|
+
// Only track if imports exist - don't mutate yet
|
|
167
|
+
// Actual import injection happens in Program.exit only if needed
|
|
164
168
|
if (hasStyleSheet) {
|
|
165
169
|
state.hasStyleSheetImport = true;
|
|
166
|
-
} else {
|
|
167
|
-
// Add StyleSheet to existing import
|
|
168
|
-
node.specifiers.push(t.importSpecifier(t.identifier("StyleSheet"), t.identifier("StyleSheet")));
|
|
169
|
-
state.hasStyleSheetImport = true;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
if (hasPlatform) {
|
|
173
173
|
state.hasPlatformImport = true;
|
|
174
174
|
}
|
|
175
|
+
|
|
176
|
+
// Store reference to the react-native import for later modification if needed
|
|
177
|
+
state.reactNativeImportPath = path;
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
// Track tw/twStyle imports from main package (for compile-time transformation)
|
|
@@ -7,16 +7,33 @@ import type * as BabelTypes from "@babel/types";
|
|
|
7
7
|
import type { StyleObject } from "../../types/core.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Add StyleSheet import to the file
|
|
10
|
+
* Add StyleSheet import to the file or merge with existing react-native import
|
|
11
11
|
*/
|
|
12
12
|
export function addStyleSheetImport(path: NodePath<BabelTypes.Program>, t: typeof BabelTypes): void {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
// Check if there's already a react-native import
|
|
14
|
+
const body = path.node.body;
|
|
15
|
+
let reactNativeImport: BabelTypes.ImportDeclaration | null = null;
|
|
16
|
+
|
|
17
|
+
for (const statement of body) {
|
|
18
|
+
if (t.isImportDeclaration(statement) && statement.source.value === "react-native") {
|
|
19
|
+
reactNativeImport = statement;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
if (reactNativeImport) {
|
|
25
|
+
// Add StyleSheet to existing react-native import
|
|
26
|
+
reactNativeImport.specifiers.push(
|
|
27
|
+
t.importSpecifier(t.identifier("StyleSheet"), t.identifier("StyleSheet")),
|
|
28
|
+
);
|
|
29
|
+
} else {
|
|
30
|
+
// Create new react-native import with StyleSheet
|
|
31
|
+
const importDeclaration = t.importDeclaration(
|
|
32
|
+
[t.importSpecifier(t.identifier("StyleSheet"), t.identifier("StyleSheet"))],
|
|
33
|
+
t.stringLiteral("react-native"),
|
|
34
|
+
);
|
|
35
|
+
path.unshiftContainer("body", importDeclaration);
|
|
36
|
+
}
|
|
20
37
|
}
|
|
21
38
|
|
|
22
39
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { ASPECT_RATIO_PRESETS, parseAspectRatio } from "./aspectRatio";
|
|
3
|
+
import { parseClassName } from "./index";
|
|
3
4
|
|
|
4
5
|
describe("ASPECT_RATIO_PRESETS", () => {
|
|
5
6
|
it("should export aspect ratio presets", () => {
|
|
@@ -29,8 +30,8 @@ describe("parseAspectRatio - preset values", () => {
|
|
|
29
30
|
});
|
|
30
31
|
|
|
31
32
|
it("should parse aspect-auto", () => {
|
|
32
|
-
// aspect-auto removes the aspect ratio constraint
|
|
33
|
-
expect(parseAspectRatio("aspect-auto")).toEqual({});
|
|
33
|
+
// aspect-auto removes the aspect ratio constraint by explicitly setting to undefined
|
|
34
|
+
expect(parseAspectRatio("aspect-auto")).toEqual({ aspectRatio: undefined });
|
|
34
35
|
});
|
|
35
36
|
});
|
|
36
37
|
|
|
@@ -131,6 +132,28 @@ describe("parseAspectRatio - type validation", () => {
|
|
|
131
132
|
});
|
|
132
133
|
});
|
|
133
134
|
|
|
135
|
+
describe("parseAspectRatio - override behavior", () => {
|
|
136
|
+
it("should allow aspect-auto to override previously set aspect ratios", () => {
|
|
137
|
+
// This tests the fix for issue #3 - aspect-auto must explicitly set aspectRatio: undefined
|
|
138
|
+
// to override previous aspect ratio values when using Object.assign
|
|
139
|
+
const result = parseClassName("aspect-square aspect-auto");
|
|
140
|
+
expect(result).toEqual({ aspectRatio: undefined });
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("should allow aspect ratios to override aspect-auto", () => {
|
|
144
|
+
const result = parseClassName("aspect-auto aspect-square");
|
|
145
|
+
expect(result).toEqual({ aspectRatio: 1 });
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("should apply last aspect ratio in sequence", () => {
|
|
149
|
+
const result = parseClassName("aspect-square aspect-video aspect-auto");
|
|
150
|
+
expect(result).toEqual({ aspectRatio: undefined });
|
|
151
|
+
|
|
152
|
+
const result2 = parseClassName("aspect-auto aspect-square aspect-video");
|
|
153
|
+
expect(result2).toEqual({ aspectRatio: 16 / 9 });
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
134
157
|
describe("parseAspectRatio - comprehensive coverage", () => {
|
|
135
158
|
it("should parse all preset variants without errors", () => {
|
|
136
159
|
const presets = ["aspect-auto", "aspect-square", "aspect-video"];
|
|
@@ -52,10 +52,10 @@ export function parseAspectRatio(cls: string): StyleObject | null {
|
|
|
52
52
|
// Check for preset values
|
|
53
53
|
if (cls in ASPECT_RATIO_PRESETS) {
|
|
54
54
|
const aspectRatio = ASPECT_RATIO_PRESETS[cls];
|
|
55
|
-
// aspect-auto removes the aspect ratio constraint by
|
|
56
|
-
//
|
|
55
|
+
// aspect-auto removes the aspect ratio constraint by explicitly setting to undefined
|
|
56
|
+
// This ensures it overrides any previously set aspectRatio in Object.assign
|
|
57
57
|
if (aspectRatio === undefined) {
|
|
58
|
-
return {};
|
|
58
|
+
return { aspectRatio: undefined };
|
|
59
59
|
}
|
|
60
60
|
return { aspectRatio };
|
|
61
61
|
}
|
|
@@ -60,6 +60,69 @@ describe("parseSpacing - margin", () => {
|
|
|
60
60
|
});
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
describe("parseSpacing - negative margin", () => {
|
|
64
|
+
it("should parse negative margin all sides", () => {
|
|
65
|
+
expect(parseSpacing("-m-0")).toEqual({ margin: -0 }); // JavaScript -0 is distinct from +0
|
|
66
|
+
expect(parseSpacing("-m-4")).toEqual({ margin: -16 });
|
|
67
|
+
expect(parseSpacing("-m-8")).toEqual({ margin: -32 });
|
|
68
|
+
expect(parseSpacing("-m-96")).toEqual({ margin: -384 });
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should parse negative margin with fractional values", () => {
|
|
72
|
+
expect(parseSpacing("-m-0.5")).toEqual({ margin: -2 });
|
|
73
|
+
expect(parseSpacing("-m-1.5")).toEqual({ margin: -6 });
|
|
74
|
+
expect(parseSpacing("-m-2.5")).toEqual({ margin: -10 });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should parse negative margin horizontal", () => {
|
|
78
|
+
expect(parseSpacing("-mx-4")).toEqual({ marginHorizontal: -16 });
|
|
79
|
+
expect(parseSpacing("-mx-8")).toEqual({ marginHorizontal: -32 });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("should parse negative margin vertical", () => {
|
|
83
|
+
expect(parseSpacing("-my-4")).toEqual({ marginVertical: -16 });
|
|
84
|
+
expect(parseSpacing("-my-8")).toEqual({ marginVertical: -32 });
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should parse negative margin directional", () => {
|
|
88
|
+
expect(parseSpacing("-mt-4")).toEqual({ marginTop: -16 });
|
|
89
|
+
expect(parseSpacing("-mr-4")).toEqual({ marginRight: -16 });
|
|
90
|
+
expect(parseSpacing("-mb-4")).toEqual({ marginBottom: -16 });
|
|
91
|
+
expect(parseSpacing("-ml-4")).toEqual({ marginLeft: -16 });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("should parse negative margin with arbitrary values", () => {
|
|
95
|
+
expect(parseSpacing("-m-[16px]")).toEqual({ margin: -16 });
|
|
96
|
+
expect(parseSpacing("-m-[16]")).toEqual({ margin: -16 });
|
|
97
|
+
expect(parseSpacing("-m-[100px]")).toEqual({ margin: -100 });
|
|
98
|
+
expect(parseSpacing("-m-[100]")).toEqual({ margin: -100 });
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should parse negative margin directional with arbitrary values", () => {
|
|
102
|
+
expect(parseSpacing("-mt-[24px]")).toEqual({ marginTop: -24 });
|
|
103
|
+
expect(parseSpacing("-mr-[32]")).toEqual({ marginRight: -32 });
|
|
104
|
+
expect(parseSpacing("-mb-[16px]")).toEqual({ marginBottom: -16 });
|
|
105
|
+
expect(parseSpacing("-ml-[48]")).toEqual({ marginLeft: -48 });
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should parse negative margin horizontal/vertical with arbitrary values", () => {
|
|
109
|
+
expect(parseSpacing("-mx-[20px]")).toEqual({ marginHorizontal: -20 });
|
|
110
|
+
expect(parseSpacing("-my-[30]")).toEqual({ marginVertical: -30 });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should not parse negative padding (invalid)", () => {
|
|
114
|
+
expect(parseSpacing("-p-4")).toBeNull();
|
|
115
|
+
expect(parseSpacing("-px-4")).toBeNull();
|
|
116
|
+
expect(parseSpacing("-pt-4")).toBeNull();
|
|
117
|
+
expect(parseSpacing("-p-[16px]")).toBeNull();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("should not parse negative gap (invalid)", () => {
|
|
121
|
+
expect(parseSpacing("-gap-4")).toBeNull();
|
|
122
|
+
expect(parseSpacing("-gap-[16px]")).toBeNull();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
63
126
|
describe("parseSpacing - padding", () => {
|
|
64
127
|
it("should parse padding all sides", () => {
|
|
65
128
|
expect(parseSpacing("p-0")).toEqual({ padding: 0 });
|
package/src/parser/spacing.ts
CHANGED
|
@@ -69,24 +69,28 @@ function parseArbitrarySpacing(value: string): number | null {
|
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
71
|
* Parse spacing classes (margin, padding, gap)
|
|
72
|
-
* Examples: m-4, mx-2, mt-8, p-4, px-2, pt-8, gap-4, m-[16px]
|
|
72
|
+
* Examples: m-4, mx-2, mt-8, p-4, px-2, pt-8, gap-4, m-[16px], -m-4, -mt-[10px]
|
|
73
73
|
*/
|
|
74
74
|
export function parseSpacing(cls: string): StyleObject | null {
|
|
75
|
-
// Margin: m-4, mx-2, mt-8, m-[16px], etc.
|
|
76
|
-
|
|
75
|
+
// Margin: m-4, mx-2, mt-8, m-[16px], -m-4, -mt-2, etc.
|
|
76
|
+
// Supports negative values for margins (but not padding or gap)
|
|
77
|
+
const marginMatch = cls.match(/^(-?)m([xytrbls]?)-(.+)$/);
|
|
77
78
|
if (marginMatch) {
|
|
78
|
-
const [, dir, valueStr] = marginMatch;
|
|
79
|
+
const [, negativePrefix, dir, valueStr] = marginMatch;
|
|
80
|
+
const isNegative = negativePrefix === "-";
|
|
79
81
|
|
|
80
82
|
// Try arbitrary value first
|
|
81
83
|
const arbitraryValue = parseArbitrarySpacing(valueStr);
|
|
82
84
|
if (arbitraryValue !== null) {
|
|
83
|
-
|
|
85
|
+
const finalValue = isNegative ? -arbitraryValue : arbitraryValue;
|
|
86
|
+
return getMarginStyle(dir, finalValue);
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
// Try preset scale
|
|
87
90
|
const scaleValue = SPACING_SCALE[valueStr];
|
|
88
91
|
if (scaleValue !== undefined) {
|
|
89
|
-
|
|
92
|
+
const finalValue = isNegative ? -scaleValue : scaleValue;
|
|
93
|
+
return getMarginStyle(dir, finalValue);
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
96
|
|
package/src/runtime.test.ts
CHANGED
|
@@ -45,6 +45,33 @@ describe("runtime", () => {
|
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
+
it("should preserve zero values in template literals", () => {
|
|
49
|
+
// Issue #1 fix: 0 should be treated as valid value, not filtered out
|
|
50
|
+
const result = tw`opacity-${0} m-4`;
|
|
51
|
+
expect(result?.style).toEqual({
|
|
52
|
+
opacity: 0,
|
|
53
|
+
margin: 16,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should preserve empty string values in template literals", () => {
|
|
58
|
+
// Empty strings should be preserved (even though they don't contribute to className)
|
|
59
|
+
const result = tw`m-4 ${""}p-2`;
|
|
60
|
+
expect(result?.style).toEqual({
|
|
61
|
+
margin: 16,
|
|
62
|
+
padding: 8,
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should handle mixed falsy and truthy numeric values", () => {
|
|
67
|
+
const spacing = 0;
|
|
68
|
+
const result = tw`m-${spacing} p-4`;
|
|
69
|
+
expect(result?.style).toEqual({
|
|
70
|
+
margin: 0,
|
|
71
|
+
padding: 16,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
48
75
|
it("should return empty style object for empty className", () => {
|
|
49
76
|
const result = tw``;
|
|
50
77
|
expect(result).toEqual({ style: {} });
|
package/src/runtime.ts
CHANGED
|
@@ -211,8 +211,9 @@ export function tw<T extends NativeStyle = NativeStyle>(
|
|
|
211
211
|
const className = strings.reduce((acc, str, i) => {
|
|
212
212
|
const value = values[i];
|
|
213
213
|
// Handle falsy values (false, null, undefined) - don't add them
|
|
214
|
+
// Note: 0 and empty string are preserved as they may be valid values
|
|
214
215
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
215
|
-
const valueStr = value ? String(value) : "";
|
|
216
|
+
const valueStr = value != null && value !== false ? String(value) : "";
|
|
216
217
|
return acc + str + valueStr;
|
|
217
218
|
}, "");
|
|
218
219
|
|