@mgcrea/react-native-tailwind 0.3.0 → 0.5.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.
Files changed (71) hide show
  1. package/README.md +459 -39
  2. package/dist/babel/index.cjs +810 -279
  3. package/dist/babel/index.d.ts +2 -1
  4. package/dist/babel/index.ts +328 -22
  5. package/dist/components/Pressable.d.ts +32 -0
  6. package/dist/components/Pressable.js +1 -0
  7. package/dist/components/TextInput.d.ts +56 -0
  8. package/dist/components/TextInput.js +1 -0
  9. package/dist/index.d.ts +9 -2
  10. package/dist/index.js +1 -1
  11. package/dist/parser/aspectRatio.d.ts +16 -0
  12. package/dist/parser/aspectRatio.js +1 -0
  13. package/dist/parser/aspectRatio.test.d.ts +1 -0
  14. package/dist/parser/aspectRatio.test.js +1 -0
  15. package/dist/parser/borders.js +1 -1
  16. package/dist/parser/borders.test.d.ts +1 -0
  17. package/dist/parser/borders.test.js +1 -0
  18. package/dist/parser/colors.d.ts +1 -0
  19. package/dist/parser/colors.js +1 -1
  20. package/dist/parser/colors.test.d.ts +1 -0
  21. package/dist/parser/colors.test.js +1 -0
  22. package/dist/parser/index.d.ts +4 -0
  23. package/dist/parser/index.js +1 -1
  24. package/dist/parser/layout.d.ts +2 -0
  25. package/dist/parser/layout.js +1 -1
  26. package/dist/parser/layout.test.d.ts +1 -0
  27. package/dist/parser/layout.test.js +1 -0
  28. package/dist/parser/modifiers.d.ts +47 -0
  29. package/dist/parser/modifiers.js +1 -0
  30. package/dist/parser/modifiers.test.d.ts +1 -0
  31. package/dist/parser/modifiers.test.js +1 -0
  32. package/dist/parser/shadows.d.ts +26 -0
  33. package/dist/parser/shadows.js +1 -0
  34. package/dist/parser/shadows.test.d.ts +1 -0
  35. package/dist/parser/shadows.test.js +1 -0
  36. package/dist/parser/sizing.test.d.ts +1 -0
  37. package/dist/parser/sizing.test.js +1 -0
  38. package/dist/parser/spacing.d.ts +1 -1
  39. package/dist/parser/spacing.js +1 -1
  40. package/dist/parser/spacing.test.d.ts +1 -0
  41. package/dist/parser/spacing.test.js +1 -0
  42. package/dist/parser/typography.d.ts +2 -1
  43. package/dist/parser/typography.js +1 -1
  44. package/dist/parser/typography.test.d.ts +1 -0
  45. package/dist/parser/typography.test.js +1 -0
  46. package/dist/types.d.ts +5 -2
  47. package/package.json +7 -6
  48. package/src/babel/index.ts +328 -22
  49. package/src/components/Pressable.tsx +46 -0
  50. package/src/components/TextInput.tsx +90 -0
  51. package/src/index.ts +20 -2
  52. package/src/parser/aspectRatio.test.ts +191 -0
  53. package/src/parser/aspectRatio.ts +73 -0
  54. package/src/parser/borders.test.ts +329 -0
  55. package/src/parser/borders.ts +187 -108
  56. package/src/parser/colors.test.ts +335 -0
  57. package/src/parser/colors.ts +117 -6
  58. package/src/parser/index.ts +13 -2
  59. package/src/parser/layout.test.ts +459 -0
  60. package/src/parser/layout.ts +128 -0
  61. package/src/parser/modifiers.test.ts +375 -0
  62. package/src/parser/modifiers.ts +104 -0
  63. package/src/parser/shadows.test.ts +201 -0
  64. package/src/parser/shadows.ts +133 -0
  65. package/src/parser/sizing.test.ts +256 -0
  66. package/src/parser/spacing.test.ts +226 -0
  67. package/src/parser/spacing.ts +93 -138
  68. package/src/parser/typography.test.ts +221 -0
  69. package/src/parser/typography.ts +143 -112
  70. package/src/types.ts +2 -2
  71. package/dist/react-native.d.js +0 -1
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Shadow and elevation utilities for React Native
3
+ * iOS uses shadow* properties, Android uses elevation
4
+ */
5
+
6
+ import { Platform } from "react-native";
7
+ import type { StyleObject } from "../types";
8
+
9
+ /**
10
+ * Shadow scale definitions (raw values, not platform-specific)
11
+ * Based on Tailwind CSS shadow scale, adapted for React Native
12
+ */
13
+ const SHADOW_DEFINITIONS = {
14
+ "shadow-sm": {
15
+ ios: {
16
+ shadowColor: "#000000",
17
+ shadowOffset: { width: 0, height: 1 },
18
+ shadowOpacity: 0.05,
19
+ shadowRadius: 1,
20
+ },
21
+ android: {
22
+ elevation: 1,
23
+ },
24
+ },
25
+ shadow: {
26
+ ios: {
27
+ shadowColor: "#000000",
28
+ shadowOffset: { width: 0, height: 1 },
29
+ shadowOpacity: 0.1,
30
+ shadowRadius: 2,
31
+ },
32
+ android: {
33
+ elevation: 2,
34
+ },
35
+ },
36
+ "shadow-md": {
37
+ ios: {
38
+ shadowColor: "#000000",
39
+ shadowOffset: { width: 0, height: 3 },
40
+ shadowOpacity: 0.15,
41
+ shadowRadius: 4,
42
+ },
43
+ android: {
44
+ elevation: 4,
45
+ },
46
+ },
47
+ "shadow-lg": {
48
+ ios: {
49
+ shadowColor: "#000000",
50
+ shadowOffset: { width: 0, height: 6 },
51
+ shadowOpacity: 0.2,
52
+ shadowRadius: 8,
53
+ },
54
+ android: {
55
+ elevation: 8,
56
+ },
57
+ },
58
+ "shadow-xl": {
59
+ ios: {
60
+ shadowColor: "#000000",
61
+ shadowOffset: { width: 0, height: 10 },
62
+ shadowOpacity: 0.25,
63
+ shadowRadius: 12,
64
+ },
65
+ android: {
66
+ elevation: 12,
67
+ },
68
+ },
69
+ "shadow-2xl": {
70
+ ios: {
71
+ shadowColor: "#000000",
72
+ shadowOffset: { width: 0, height: 20 },
73
+ shadowOpacity: 0.3,
74
+ shadowRadius: 24,
75
+ },
76
+ android: {
77
+ elevation: 16,
78
+ },
79
+ },
80
+ "shadow-none": {
81
+ ios: {
82
+ shadowColor: "transparent",
83
+ shadowOffset: { width: 0, height: 0 },
84
+ shadowOpacity: 0,
85
+ shadowRadius: 0,
86
+ },
87
+ android: {
88
+ elevation: 0,
89
+ },
90
+ },
91
+ } as const;
92
+
93
+ /**
94
+ * Helper function to build the shadow scale using Platform.select()
95
+ * This allows tests to rebuild the scale after changing the platform mock
96
+ */
97
+ function buildShadowScale(): Record<string, StyleObject> {
98
+ const scale: Record<string, StyleObject> = {};
99
+ for (const [key, value] of Object.entries(SHADOW_DEFINITIONS)) {
100
+ scale[key] = Platform.select<StyleObject>(value as never);
101
+ }
102
+ return scale;
103
+ }
104
+
105
+ /**
106
+ * Computed shadow scale using Platform.select()
107
+ * This is evaluated at module load time for production use
108
+ */
109
+ let SHADOW_SCALE = buildShadowScale();
110
+
111
+ /**
112
+ * Rebuild the shadow scale (useful for testing with platform mocks)
113
+ */
114
+ export function rebuildShadowScale() {
115
+ SHADOW_SCALE = buildShadowScale();
116
+ }
117
+
118
+ /**
119
+ * Parse shadow classes
120
+ * @param cls - Class name to parse
121
+ * @returns Style object or null if not a shadow class
122
+ */
123
+ export function parseShadow(cls: string): StyleObject | null {
124
+ // Check if it's a shadow class
125
+ if (cls in SHADOW_SCALE) {
126
+ return SHADOW_SCALE[cls];
127
+ }
128
+
129
+ return null;
130
+ }
131
+
132
+ // Export shadow scale and builder for testing/advanced usage
133
+ export { buildShadowScale, SHADOW_SCALE };
@@ -0,0 +1,256 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { SIZE_PERCENTAGES, SIZE_SCALE, parseSizing } from "./sizing";
3
+
4
+ describe("SIZE_SCALE", () => {
5
+ it("should export complete size scale", () => {
6
+ expect(SIZE_SCALE).toMatchSnapshot();
7
+ });
8
+ });
9
+
10
+ describe("SIZE_PERCENTAGES", () => {
11
+ it("should export complete percentage sizes", () => {
12
+ expect(SIZE_PERCENTAGES).toMatchSnapshot();
13
+ });
14
+ });
15
+
16
+ describe("parseSizing - width", () => {
17
+ it("should parse width with numeric values", () => {
18
+ expect(parseSizing("w-0")).toEqual({ width: 0 });
19
+ expect(parseSizing("w-4")).toEqual({ width: 16 });
20
+ expect(parseSizing("w-8")).toEqual({ width: 32 });
21
+ expect(parseSizing("w-96")).toEqual({ width: 384 });
22
+ });
23
+
24
+ it("should parse width with fractional values", () => {
25
+ expect(parseSizing("w-0.5")).toEqual({ width: 2 });
26
+ expect(parseSizing("w-1.5")).toEqual({ width: 6 });
27
+ expect(parseSizing("w-2.5")).toEqual({ width: 10 });
28
+ });
29
+
30
+ it("should parse width with percentage values", () => {
31
+ expect(parseSizing("w-full")).toEqual({ width: "100%" });
32
+ expect(parseSizing("w-1/2")).toEqual({ width: "50%" });
33
+ expect(parseSizing("w-1/3")).toEqual({ width: "33.333333%" });
34
+ expect(parseSizing("w-2/3")).toEqual({ width: "66.666667%" });
35
+ expect(parseSizing("w-1/4")).toEqual({ width: "25%" });
36
+ expect(parseSizing("w-3/4")).toEqual({ width: "75%" });
37
+ });
38
+
39
+ it("should parse width with special values", () => {
40
+ expect(parseSizing("w-auto")).toEqual({ width: "auto" });
41
+ });
42
+
43
+ it("should parse width with arbitrary pixel values", () => {
44
+ expect(parseSizing("w-[123px]")).toEqual({ width: 123 });
45
+ expect(parseSizing("w-[123]")).toEqual({ width: 123 });
46
+ expect(parseSizing("w-[350px]")).toEqual({ width: 350 });
47
+ });
48
+
49
+ it("should parse width with arbitrary percentage values", () => {
50
+ expect(parseSizing("w-[50%]")).toEqual({ width: "50%" });
51
+ expect(parseSizing("w-[33.333%]")).toEqual({ width: "33.333%" });
52
+ expect(parseSizing("w-[85%]")).toEqual({ width: "85%" });
53
+ });
54
+ });
55
+
56
+ describe("parseSizing - height", () => {
57
+ it("should parse height with numeric values", () => {
58
+ expect(parseSizing("h-0")).toEqual({ height: 0 });
59
+ expect(parseSizing("h-4")).toEqual({ height: 16 });
60
+ expect(parseSizing("h-8")).toEqual({ height: 32 });
61
+ expect(parseSizing("h-96")).toEqual({ height: 384 });
62
+ });
63
+
64
+ it("should parse height with fractional values", () => {
65
+ expect(parseSizing("h-0.5")).toEqual({ height: 2 });
66
+ expect(parseSizing("h-1.5")).toEqual({ height: 6 });
67
+ expect(parseSizing("h-2.5")).toEqual({ height: 10 });
68
+ });
69
+
70
+ it("should parse height with percentage values", () => {
71
+ expect(parseSizing("h-full")).toEqual({ height: "100%" });
72
+ expect(parseSizing("h-1/2")).toEqual({ height: "50%" });
73
+ expect(parseSizing("h-1/3")).toEqual({ height: "33.333333%" });
74
+ expect(parseSizing("h-2/3")).toEqual({ height: "66.666667%" });
75
+ });
76
+
77
+ it("should parse height with special values", () => {
78
+ expect(parseSizing("h-auto")).toEqual({ height: "auto" });
79
+ });
80
+
81
+ it("should parse height with arbitrary values", () => {
82
+ expect(parseSizing("h-[200px]")).toEqual({ height: 200 });
83
+ expect(parseSizing("h-[75%]")).toEqual({ height: "75%" });
84
+ });
85
+ });
86
+
87
+ describe("parseSizing - min width", () => {
88
+ it("should parse min-width with numeric values", () => {
89
+ expect(parseSizing("min-w-0")).toEqual({ minWidth: 0 });
90
+ expect(parseSizing("min-w-4")).toEqual({ minWidth: 16 });
91
+ expect(parseSizing("min-w-8")).toEqual({ minWidth: 32 });
92
+ });
93
+
94
+ it("should parse min-width with percentage values", () => {
95
+ expect(parseSizing("min-w-full")).toEqual({ minWidth: "100%" });
96
+ expect(parseSizing("min-w-1/2")).toEqual({ minWidth: "50%" });
97
+ });
98
+
99
+ it("should parse min-width with arbitrary values", () => {
100
+ expect(parseSizing("min-w-[200px]")).toEqual({ minWidth: 200 });
101
+ expect(parseSizing("min-w-[50%]")).toEqual({ minWidth: "50%" });
102
+ });
103
+ });
104
+
105
+ describe("parseSizing - min height", () => {
106
+ it("should parse min-height with numeric values", () => {
107
+ expect(parseSizing("min-h-0")).toEqual({ minHeight: 0 });
108
+ expect(parseSizing("min-h-4")).toEqual({ minHeight: 16 });
109
+ expect(parseSizing("min-h-8")).toEqual({ minHeight: 32 });
110
+ });
111
+
112
+ it("should parse min-height with percentage values", () => {
113
+ expect(parseSizing("min-h-full")).toEqual({ minHeight: "100%" });
114
+ expect(parseSizing("min-h-1/2")).toEqual({ minHeight: "50%" });
115
+ });
116
+
117
+ it("should parse min-height with arbitrary values", () => {
118
+ expect(parseSizing("min-h-[150px]")).toEqual({ minHeight: 150 });
119
+ expect(parseSizing("min-h-[40%]")).toEqual({ minHeight: "40%" });
120
+ });
121
+ });
122
+
123
+ describe("parseSizing - max width", () => {
124
+ it("should parse max-width with numeric values", () => {
125
+ expect(parseSizing("max-w-0")).toEqual({ maxWidth: 0 });
126
+ expect(parseSizing("max-w-4")).toEqual({ maxWidth: 16 });
127
+ expect(parseSizing("max-w-8")).toEqual({ maxWidth: 32 });
128
+ });
129
+
130
+ it("should parse max-width with percentage values", () => {
131
+ expect(parseSizing("max-w-full")).toEqual({ maxWidth: "100%" });
132
+ expect(parseSizing("max-w-1/2")).toEqual({ maxWidth: "50%" });
133
+ });
134
+
135
+ it("should parse max-width with arbitrary values", () => {
136
+ expect(parseSizing("max-w-[500px]")).toEqual({ maxWidth: 500 });
137
+ expect(parseSizing("max-w-[80%]")).toEqual({ maxWidth: "80%" });
138
+ });
139
+ });
140
+
141
+ describe("parseSizing - max height", () => {
142
+ it("should parse max-height with numeric values", () => {
143
+ expect(parseSizing("max-h-0")).toEqual({ maxHeight: 0 });
144
+ expect(parseSizing("max-h-4")).toEqual({ maxHeight: 16 });
145
+ expect(parseSizing("max-h-8")).toEqual({ maxHeight: 32 });
146
+ });
147
+
148
+ it("should parse max-height with percentage values", () => {
149
+ expect(parseSizing("max-h-full")).toEqual({ maxHeight: "100%" });
150
+ expect(parseSizing("max-h-1/2")).toEqual({ maxHeight: "50%" });
151
+ });
152
+
153
+ it("should parse max-height with arbitrary values", () => {
154
+ expect(parseSizing("max-h-[300px]")).toEqual({ maxHeight: 300 });
155
+ expect(parseSizing("max-h-[90%]")).toEqual({ maxHeight: "90%" });
156
+ });
157
+ });
158
+
159
+ describe("parseSizing - edge cases", () => {
160
+ it("should return null for invalid classes", () => {
161
+ expect(parseSizing("invalid")).toBeNull();
162
+ expect(parseSizing("w")).toBeNull();
163
+ expect(parseSizing("h")).toBeNull();
164
+ expect(parseSizing("width-4")).toBeNull();
165
+ expect(parseSizing("height-4")).toBeNull();
166
+ });
167
+
168
+ it("should return null for invalid size values", () => {
169
+ expect(parseSizing("w-invalid")).toBeNull();
170
+ expect(parseSizing("h-999")).toBeNull();
171
+ expect(parseSizing("min-w-abc")).toBeNull();
172
+ });
173
+
174
+ it("should return null for arbitrary values with unsupported units", () => {
175
+ expect(parseSizing("w-[16rem]")).toBeNull();
176
+ expect(parseSizing("h-[2em]")).toBeNull();
177
+ expect(parseSizing("max-w-[50vh]")).toBeNull();
178
+ expect(parseSizing("min-h-[100vw]")).toBeNull();
179
+ });
180
+
181
+ it("should return null for malformed arbitrary values", () => {
182
+ expect(parseSizing("w-[16")).toBeNull();
183
+ expect(parseSizing("h-16]")).toBeNull();
184
+ expect(parseSizing("min-w-[]")).toBeNull();
185
+ });
186
+
187
+ it("should handle edge case size values", () => {
188
+ expect(parseSizing("w-0")).toEqual({ width: 0 });
189
+ expect(parseSizing("h-0")).toEqual({ height: 0 });
190
+ expect(parseSizing("min-w-0")).toEqual({ minWidth: 0 });
191
+ expect(parseSizing("max-h-0")).toEqual({ maxHeight: 0 });
192
+ });
193
+
194
+ it("should not match partial class names", () => {
195
+ expect(parseSizing("tw-4")).toBeNull();
196
+ expect(parseSizing("width-4")).toBeNull();
197
+ expect(parseSizing("height-4")).toBeNull();
198
+ });
199
+ });
200
+
201
+ describe("parseSizing - comprehensive coverage", () => {
202
+ it("should parse all width variants with same value", () => {
203
+ const value = 16;
204
+ expect(parseSizing("w-4")).toEqual({ width: value });
205
+ expect(parseSizing("min-w-4")).toEqual({ minWidth: value });
206
+ expect(parseSizing("max-w-4")).toEqual({ maxWidth: value });
207
+ });
208
+
209
+ it("should parse all height variants with same value", () => {
210
+ const value = 16;
211
+ expect(parseSizing("h-4")).toEqual({ height: value });
212
+ expect(parseSizing("min-h-4")).toEqual({ minHeight: value });
213
+ expect(parseSizing("max-h-4")).toEqual({ maxHeight: value });
214
+ });
215
+
216
+ it("should handle large size values", () => {
217
+ expect(parseSizing("w-96")).toEqual({ width: 384 });
218
+ expect(parseSizing("h-96")).toEqual({ height: 384 });
219
+ expect(parseSizing("max-w-96")).toEqual({ maxWidth: 384 });
220
+ });
221
+
222
+ it("should handle arbitrary values across all width variants", () => {
223
+ expect(parseSizing("w-[123px]")).toEqual({ width: 123 });
224
+ expect(parseSizing("min-w-[123px]")).toEqual({ minWidth: 123 });
225
+ expect(parseSizing("max-w-[123px]")).toEqual({ maxWidth: 123 });
226
+ });
227
+
228
+ it("should handle arbitrary values across all height variants", () => {
229
+ expect(parseSizing("h-[200px]")).toEqual({ height: 200 });
230
+ expect(parseSizing("min-h-[200px]")).toEqual({ minHeight: 200 });
231
+ expect(parseSizing("max-h-[200px]")).toEqual({ maxHeight: 200 });
232
+ });
233
+
234
+ it("should handle arbitrary percentage values across all variants", () => {
235
+ expect(parseSizing("w-[75%]")).toEqual({ width: "75%" });
236
+ expect(parseSizing("h-[60%]")).toEqual({ height: "60%" });
237
+ expect(parseSizing("min-w-[25%]")).toEqual({ minWidth: "25%" });
238
+ expect(parseSizing("max-h-[90%]")).toEqual({ maxHeight: "90%" });
239
+ });
240
+
241
+ it("should handle all fractional percentage variants", () => {
242
+ expect(parseSizing("w-1/5")).toEqual({ width: "20%" });
243
+ expect(parseSizing("w-2/5")).toEqual({ width: "40%" });
244
+ expect(parseSizing("w-3/5")).toEqual({ width: "60%" });
245
+ expect(parseSizing("w-4/5")).toEqual({ width: "80%" });
246
+ expect(parseSizing("w-1/6")).toEqual({ width: "16.666667%" });
247
+ expect(parseSizing("w-5/6")).toEqual({ width: "83.333333%" });
248
+ });
249
+
250
+ it("should handle special values consistently", () => {
251
+ expect(parseSizing("w-auto")).toEqual({ width: "auto" });
252
+ expect(parseSizing("h-auto")).toEqual({ height: "auto" });
253
+ expect(parseSizing("w-full")).toEqual({ width: "100%" });
254
+ expect(parseSizing("h-full")).toEqual({ height: "100%" });
255
+ });
256
+ });
@@ -0,0 +1,226 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { SPACING_SCALE, parseSpacing } from "./spacing";
3
+
4
+ describe("SPACING_SCALE", () => {
5
+ it("should export complete spacing scale", () => {
6
+ expect(SPACING_SCALE).toMatchSnapshot();
7
+ });
8
+ });
9
+
10
+ describe("parseSpacing - margin", () => {
11
+ it("should parse margin all sides", () => {
12
+ expect(parseSpacing("m-0")).toEqual({ margin: 0 });
13
+ expect(parseSpacing("m-4")).toEqual({ margin: 16 });
14
+ expect(parseSpacing("m-8")).toEqual({ margin: 32 });
15
+ expect(parseSpacing("m-96")).toEqual({ margin: 384 });
16
+ });
17
+
18
+ it("should parse margin with fractional values", () => {
19
+ expect(parseSpacing("m-0.5")).toEqual({ margin: 2 });
20
+ expect(parseSpacing("m-1.5")).toEqual({ margin: 6 });
21
+ expect(parseSpacing("m-2.5")).toEqual({ margin: 10 });
22
+ });
23
+
24
+ it("should parse margin horizontal", () => {
25
+ expect(parseSpacing("mx-0")).toEqual({ marginHorizontal: 0 });
26
+ expect(parseSpacing("mx-4")).toEqual({ marginHorizontal: 16 });
27
+ expect(parseSpacing("mx-8")).toEqual({ marginHorizontal: 32 });
28
+ });
29
+
30
+ it("should parse margin vertical", () => {
31
+ expect(parseSpacing("my-0")).toEqual({ marginVertical: 0 });
32
+ expect(parseSpacing("my-4")).toEqual({ marginVertical: 16 });
33
+ expect(parseSpacing("my-8")).toEqual({ marginVertical: 32 });
34
+ });
35
+
36
+ it("should parse margin directional", () => {
37
+ expect(parseSpacing("mt-4")).toEqual({ marginTop: 16 });
38
+ expect(parseSpacing("mr-4")).toEqual({ marginRight: 16 });
39
+ expect(parseSpacing("mb-4")).toEqual({ marginBottom: 16 });
40
+ expect(parseSpacing("ml-4")).toEqual({ marginLeft: 16 });
41
+ });
42
+
43
+ it("should parse margin with arbitrary values", () => {
44
+ expect(parseSpacing("m-[16px]")).toEqual({ margin: 16 });
45
+ expect(parseSpacing("m-[16]")).toEqual({ margin: 16 });
46
+ expect(parseSpacing("m-[100px]")).toEqual({ margin: 100 });
47
+ expect(parseSpacing("m-[100]")).toEqual({ margin: 100 });
48
+ });
49
+
50
+ it("should parse margin directional with arbitrary values", () => {
51
+ expect(parseSpacing("mt-[24px]")).toEqual({ marginTop: 24 });
52
+ expect(parseSpacing("mr-[32]")).toEqual({ marginRight: 32 });
53
+ expect(parseSpacing("mb-[16px]")).toEqual({ marginBottom: 16 });
54
+ expect(parseSpacing("ml-[48]")).toEqual({ marginLeft: 48 });
55
+ });
56
+
57
+ it("should parse margin horizontal/vertical with arbitrary values", () => {
58
+ expect(parseSpacing("mx-[20px]")).toEqual({ marginHorizontal: 20 });
59
+ expect(parseSpacing("my-[30]")).toEqual({ marginVertical: 30 });
60
+ });
61
+ });
62
+
63
+ describe("parseSpacing - padding", () => {
64
+ it("should parse padding all sides", () => {
65
+ expect(parseSpacing("p-0")).toEqual({ padding: 0 });
66
+ expect(parseSpacing("p-4")).toEqual({ padding: 16 });
67
+ expect(parseSpacing("p-8")).toEqual({ padding: 32 });
68
+ expect(parseSpacing("p-96")).toEqual({ padding: 384 });
69
+ });
70
+
71
+ it("should parse padding with fractional values", () => {
72
+ expect(parseSpacing("p-0.5")).toEqual({ padding: 2 });
73
+ expect(parseSpacing("p-1.5")).toEqual({ padding: 6 });
74
+ expect(parseSpacing("p-2.5")).toEqual({ padding: 10 });
75
+ });
76
+
77
+ it("should parse padding horizontal", () => {
78
+ expect(parseSpacing("px-0")).toEqual({ paddingHorizontal: 0 });
79
+ expect(parseSpacing("px-4")).toEqual({ paddingHorizontal: 16 });
80
+ expect(parseSpacing("px-8")).toEqual({ paddingHorizontal: 32 });
81
+ });
82
+
83
+ it("should parse padding vertical", () => {
84
+ expect(parseSpacing("py-0")).toEqual({ paddingVertical: 0 });
85
+ expect(parseSpacing("py-4")).toEqual({ paddingVertical: 16 });
86
+ expect(parseSpacing("py-8")).toEqual({ paddingVertical: 32 });
87
+ });
88
+
89
+ it("should parse padding directional", () => {
90
+ expect(parseSpacing("pt-4")).toEqual({ paddingTop: 16 });
91
+ expect(parseSpacing("pr-4")).toEqual({ paddingRight: 16 });
92
+ expect(parseSpacing("pb-4")).toEqual({ paddingBottom: 16 });
93
+ expect(parseSpacing("pl-4")).toEqual({ paddingLeft: 16 });
94
+ });
95
+
96
+ it("should parse padding with arbitrary values", () => {
97
+ expect(parseSpacing("p-[16px]")).toEqual({ padding: 16 });
98
+ expect(parseSpacing("p-[16]")).toEqual({ padding: 16 });
99
+ expect(parseSpacing("p-[100px]")).toEqual({ padding: 100 });
100
+ expect(parseSpacing("p-[100]")).toEqual({ padding: 100 });
101
+ });
102
+
103
+ it("should parse padding directional with arbitrary values", () => {
104
+ expect(parseSpacing("pt-[24px]")).toEqual({ paddingTop: 24 });
105
+ expect(parseSpacing("pr-[32]")).toEqual({ paddingRight: 32 });
106
+ expect(parseSpacing("pb-[16px]")).toEqual({ paddingBottom: 16 });
107
+ expect(parseSpacing("pl-[48]")).toEqual({ paddingLeft: 48 });
108
+ });
109
+
110
+ it("should parse padding horizontal/vertical with arbitrary values", () => {
111
+ expect(parseSpacing("px-[20px]")).toEqual({ paddingHorizontal: 20 });
112
+ expect(parseSpacing("py-[30]")).toEqual({ paddingVertical: 30 });
113
+ });
114
+ });
115
+
116
+ describe("parseSpacing - gap", () => {
117
+ it("should parse gap", () => {
118
+ expect(parseSpacing("gap-0")).toEqual({ gap: 0 });
119
+ expect(parseSpacing("gap-4")).toEqual({ gap: 16 });
120
+ expect(parseSpacing("gap-8")).toEqual({ gap: 32 });
121
+ expect(parseSpacing("gap-96")).toEqual({ gap: 384 });
122
+ });
123
+
124
+ it("should parse gap with fractional values", () => {
125
+ expect(parseSpacing("gap-0.5")).toEqual({ gap: 2 });
126
+ expect(parseSpacing("gap-1.5")).toEqual({ gap: 6 });
127
+ expect(parseSpacing("gap-2.5")).toEqual({ gap: 10 });
128
+ });
129
+
130
+ it("should parse gap with arbitrary values", () => {
131
+ expect(parseSpacing("gap-[16px]")).toEqual({ gap: 16 });
132
+ expect(parseSpacing("gap-[16]")).toEqual({ gap: 16 });
133
+ expect(parseSpacing("gap-[100px]")).toEqual({ gap: 100 });
134
+ expect(parseSpacing("gap-[100]")).toEqual({ gap: 100 });
135
+ });
136
+ });
137
+
138
+ describe("parseSpacing - edge cases", () => {
139
+ it("should return null for invalid classes", () => {
140
+ expect(parseSpacing("invalid")).toBeNull();
141
+ expect(parseSpacing("m")).toBeNull();
142
+ expect(parseSpacing("p")).toBeNull();
143
+ expect(parseSpacing("margin-4")).toBeNull();
144
+ expect(parseSpacing("padding-4")).toBeNull();
145
+ });
146
+
147
+ it("should return null for invalid spacing values", () => {
148
+ expect(parseSpacing("m-invalid")).toBeNull();
149
+ expect(parseSpacing("p-999")).toBeNull();
150
+ expect(parseSpacing("gap-abc")).toBeNull();
151
+ });
152
+
153
+ it("should return null for arbitrary values with unsupported units", () => {
154
+ expect(parseSpacing("m-[16rem]")).toBeNull();
155
+ expect(parseSpacing("p-[2em]")).toBeNull();
156
+ expect(parseSpacing("gap-[50%]")).toBeNull();
157
+ });
158
+
159
+ it("should return null for malformed arbitrary values", () => {
160
+ expect(parseSpacing("m-[16")).toBeNull();
161
+ expect(parseSpacing("p-16]")).toBeNull();
162
+ expect(parseSpacing("gap-[]")).toBeNull();
163
+ });
164
+
165
+ it("should handle edge case spacing values", () => {
166
+ expect(parseSpacing("m-0")).toEqual({ margin: 0 });
167
+ expect(parseSpacing("p-0")).toEqual({ padding: 0 });
168
+ expect(parseSpacing("gap-0")).toEqual({ gap: 0 });
169
+ });
170
+
171
+ it("should not match partial class names", () => {
172
+ expect(parseSpacing("sm-4")).toBeNull();
173
+ expect(parseSpacing("margin-4")).toBeNull();
174
+ expect(parseSpacing("padding-4")).toBeNull();
175
+ });
176
+ });
177
+
178
+ describe("parseSpacing - comprehensive coverage", () => {
179
+ it("should parse all margin directions with same value", () => {
180
+ const value = 16;
181
+ expect(parseSpacing("m-4")).toEqual({ margin: value });
182
+ expect(parseSpacing("mx-4")).toEqual({ marginHorizontal: value });
183
+ expect(parseSpacing("my-4")).toEqual({ marginVertical: value });
184
+ expect(parseSpacing("mt-4")).toEqual({ marginTop: value });
185
+ expect(parseSpacing("mr-4")).toEqual({ marginRight: value });
186
+ expect(parseSpacing("mb-4")).toEqual({ marginBottom: value });
187
+ expect(parseSpacing("ml-4")).toEqual({ marginLeft: value });
188
+ });
189
+
190
+ it("should parse all padding directions with same value", () => {
191
+ const value = 16;
192
+ expect(parseSpacing("p-4")).toEqual({ padding: value });
193
+ expect(parseSpacing("px-4")).toEqual({ paddingHorizontal: value });
194
+ expect(parseSpacing("py-4")).toEqual({ paddingVertical: value });
195
+ expect(parseSpacing("pt-4")).toEqual({ paddingTop: value });
196
+ expect(parseSpacing("pr-4")).toEqual({ paddingRight: value });
197
+ expect(parseSpacing("pb-4")).toEqual({ paddingBottom: value });
198
+ expect(parseSpacing("pl-4")).toEqual({ paddingLeft: value });
199
+ });
200
+
201
+ it("should handle large spacing values", () => {
202
+ expect(parseSpacing("m-96")).toEqual({ margin: 384 });
203
+ expect(parseSpacing("p-96")).toEqual({ padding: 384 });
204
+ expect(parseSpacing("gap-96")).toEqual({ gap: 384 });
205
+ });
206
+
207
+ it("should handle arbitrary values across all margin directions", () => {
208
+ expect(parseSpacing("m-[50px]")).toEqual({ margin: 50 });
209
+ expect(parseSpacing("mx-[50px]")).toEqual({ marginHorizontal: 50 });
210
+ expect(parseSpacing("my-[50px]")).toEqual({ marginVertical: 50 });
211
+ expect(parseSpacing("mt-[50px]")).toEqual({ marginTop: 50 });
212
+ expect(parseSpacing("mr-[50px]")).toEqual({ marginRight: 50 });
213
+ expect(parseSpacing("mb-[50px]")).toEqual({ marginBottom: 50 });
214
+ expect(parseSpacing("ml-[50px]")).toEqual({ marginLeft: 50 });
215
+ });
216
+
217
+ it("should handle arbitrary values across all padding directions", () => {
218
+ expect(parseSpacing("p-[50px]")).toEqual({ padding: 50 });
219
+ expect(parseSpacing("px-[50px]")).toEqual({ paddingHorizontal: 50 });
220
+ expect(parseSpacing("py-[50px]")).toEqual({ paddingVertical: 50 });
221
+ expect(parseSpacing("pt-[50px]")).toEqual({ paddingTop: 50 });
222
+ expect(parseSpacing("pr-[50px]")).toEqual({ paddingRight: 50 });
223
+ expect(parseSpacing("pb-[50px]")).toEqual({ paddingBottom: 50 });
224
+ expect(parseSpacing("pl-[50px]")).toEqual({ paddingLeft: 50 });
225
+ });
226
+ });