@mgcrea/react-native-tailwind 0.4.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 +443 -13
  2. package/dist/babel/index.cjs +804 -274
  3. package/dist/babel/index.d.ts +2 -1
  4. package/dist/babel/index.ts +319 -16
  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 +319 -16
  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
@@ -26,10 +26,93 @@ export const BORDER_RADIUS_SCALE: Record<string, number> = {
26
26
  full: 9999,
27
27
  };
28
28
 
29
+ /**
30
+ * Property mapping for border width directions
31
+ */
32
+ const BORDER_WIDTH_PROP_MAP: Record<string, string> = {
33
+ t: "borderTopWidth",
34
+ r: "borderRightWidth",
35
+ b: "borderBottomWidth",
36
+ l: "borderLeftWidth",
37
+ };
38
+
39
+ /**
40
+ * Property mapping for border radius corners
41
+ */
42
+ const BORDER_RADIUS_CORNER_MAP: Record<string, string> = {
43
+ tl: "borderTopLeftRadius",
44
+ tr: "borderTopRightRadius",
45
+ bl: "borderBottomLeftRadius",
46
+ br: "borderBottomRightRadius",
47
+ };
48
+
49
+ /**
50
+ * Property mapping for border radius sides (returns array of properties)
51
+ */
52
+ const BORDER_RADIUS_SIDE_MAP: Record<string, string[]> = {
53
+ t: ["borderTopLeftRadius", "borderTopRightRadius"],
54
+ r: ["borderTopRightRadius", "borderBottomRightRadius"],
55
+ b: ["borderBottomLeftRadius", "borderBottomRightRadius"],
56
+ l: ["borderTopLeftRadius", "borderBottomLeftRadius"],
57
+ };
58
+
59
+ /**
60
+ * Parse arbitrary border width value: [8px], [4]
61
+ * Returns number for px values, null for unsupported formats
62
+ */
63
+ function parseArbitraryBorderWidth(value: string): number | null {
64
+ // Match: [8px] or [8] (pixels only)
65
+ const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
66
+ if (pxMatch) {
67
+ return parseInt(pxMatch[1], 10);
68
+ }
69
+
70
+ // Warn about unsupported formats
71
+ if (value.startsWith("[") && value.endsWith("]")) {
72
+ if (process.env.NODE_ENV !== "production") {
73
+ console.warn(
74
+ `[react-native-tailwind] Unsupported arbitrary border width value: ${value}. Only px values are supported (e.g., [8px] or [8]).`,
75
+ );
76
+ }
77
+ return null;
78
+ }
79
+
80
+ return null;
81
+ }
82
+
83
+ /**
84
+ * Parse arbitrary border radius value: [12px], [8]
85
+ * Returns number for px values, null for unsupported formats
86
+ */
87
+ function parseArbitraryBorderRadius(value: string): number | null {
88
+ // Match: [12px] or [12] (pixels only)
89
+ const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
90
+ if (pxMatch) {
91
+ return parseInt(pxMatch[1], 10);
92
+ }
93
+
94
+ // Warn about unsupported formats
95
+ if (value.startsWith("[") && value.endsWith("]")) {
96
+ if (process.env.NODE_ENV !== "production") {
97
+ console.warn(
98
+ `[react-native-tailwind] Unsupported arbitrary border radius value: ${value}. Only px values are supported (e.g., [12px] or [12]).`,
99
+ );
100
+ }
101
+ return null;
102
+ }
103
+
104
+ return null;
105
+ }
106
+
29
107
  /**
30
108
  * Parse border classes
31
109
  */
32
110
  export function parseBorder(cls: string): StyleObject | null {
111
+ // Border style (must come before parseBorderWidth)
112
+ if (cls === "border-solid") return { borderStyle: "solid" };
113
+ if (cls === "border-dotted") return { borderStyle: "dotted" };
114
+ if (cls === "border-dashed") return { borderStyle: "dashed" };
115
+
33
116
  // Border width (border-0, border-t, border-[8px], etc.)
34
117
  if (cls.startsWith("border-")) {
35
118
  return parseBorderWidth(cls);
@@ -44,11 +127,6 @@ export function parseBorder(cls: string): StyleObject | null {
44
127
  return parseBorderRadius(cls);
45
128
  }
46
129
 
47
- // Border style
48
- if (cls === "border-solid") return { borderStyle: "solid" };
49
- if (cls === "border-dotted") return { borderStyle: "dotted" };
50
- if (cls === "border-dashed") return { borderStyle: "dashed" };
51
-
52
130
  return null;
53
131
  }
54
132
 
@@ -56,45 +134,31 @@ export function parseBorder(cls: string): StyleObject | null {
56
134
  * Parse border width classes
57
135
  */
58
136
  function parseBorderWidth(cls: string): StyleObject | null {
59
- // All borders with arbitrary values: border-[8px]
60
- const allArbMatch = cls.match(/^border-\[(\d+)(?:px)?\]$/);
61
- if (allArbMatch) {
62
- return { borderWidth: parseInt(allArbMatch[1], 10) };
63
- }
64
-
65
- // Directional borders with arbitrary values: border-t-[8px]
66
- const dirArbMatch = cls.match(/^border-([trbl])-\[(\d+)(?:px)?\]$/);
67
- if (dirArbMatch) {
68
- const dir = dirArbMatch[1];
69
- const value = parseInt(dirArbMatch[2], 10);
70
- const propMap: Record<string, string> = {
71
- t: "borderTopWidth",
72
- r: "borderRightWidth",
73
- b: "borderBottomWidth",
74
- l: "borderLeftWidth",
75
- };
76
- return { [propMap[dir]]: value };
77
- }
78
-
79
- // Preset directional borders: border-t-0, border-t-2, etc.
80
- const dirMatch = cls.match(/^border-([trbl])-?(\d*)$/);
137
+ // Directional borders: border-t, border-t-2, border-t-[8px]
138
+ const dirMatch = cls.match(/^border-([trbl])(?:-(.+))?$/);
81
139
  if (dirMatch) {
82
140
  const dir = dirMatch[1];
83
- const scaleKey = dirMatch[2] || ""; // empty string for border-t
84
- const value = BORDER_WIDTH_SCALE[scaleKey];
85
-
86
- if (typeof value === "number") {
87
- const propMap: Record<string, string> = {
88
- t: "borderTopWidth",
89
- r: "borderRightWidth",
90
- b: "borderBottomWidth",
91
- l: "borderLeftWidth",
92
- };
93
- return { [propMap[dir]]: value };
141
+ const valueStr = dirMatch[2] || ""; // empty string for border-t
142
+
143
+ // Try arbitrary value first (if it starts with [)
144
+ if (valueStr.startsWith("[")) {
145
+ const arbitraryValue = parseArbitraryBorderWidth(valueStr);
146
+ if (arbitraryValue !== null) {
147
+ return { [BORDER_WIDTH_PROP_MAP[dir]]: arbitraryValue };
148
+ }
149
+ return null;
94
150
  }
151
+
152
+ // Try preset scale
153
+ const scaleValue = BORDER_WIDTH_SCALE[valueStr];
154
+ if (scaleValue !== undefined) {
155
+ return { [BORDER_WIDTH_PROP_MAP[dir]]: scaleValue };
156
+ }
157
+
158
+ return null;
95
159
  }
96
160
 
97
- // Preset all borders: border-0, border-2, etc.
161
+ // All borders with preset values: border-0, border-2, border-4, border-8
98
162
  const allMatch = cls.match(/^border-(\d+)$/);
99
163
  if (allMatch) {
100
164
  const value = BORDER_WIDTH_SCALE[allMatch[1]];
@@ -103,6 +167,15 @@ function parseBorderWidth(cls: string): StyleObject | null {
103
167
  }
104
168
  }
105
169
 
170
+ // All borders with arbitrary values: border-[8px]
171
+ const allArbMatch = cls.match(/^border-(\[.+\])$/);
172
+ if (allArbMatch) {
173
+ const arbitraryValue = parseArbitraryBorderWidth(allArbMatch[1]);
174
+ if (arbitraryValue !== null) {
175
+ return { borderWidth: arbitraryValue };
176
+ }
177
+ }
178
+
106
179
  return null;
107
180
  }
108
181
 
@@ -110,88 +183,94 @@ function parseBorderWidth(cls: string): StyleObject | null {
110
183
  * Parse border radius classes
111
184
  */
112
185
  function parseBorderRadius(cls: string): StyleObject | null {
113
- // All corners with arbitrary values: rounded-[12px]
114
- const allArbMatch = cls.match(/^rounded-\[(\d+)(?:px)?\]$/);
115
- if (allArbMatch) {
116
- return { borderRadius: parseInt(allArbMatch[1], 10) };
117
- }
118
-
119
- // Specific corners with arbitrary values: rounded-tl-[8px]
120
- const cornerArbMatch = cls.match(/^rounded-(tl|tr|bl|br)-\[(\d+)(?:px)?\]$/);
121
- if (cornerArbMatch) {
122
- const corner = cornerArbMatch[1];
123
- const value = parseInt(cornerArbMatch[2], 10);
124
- const propMap: Record<string, string> = {
125
- tl: "borderTopLeftRadius",
126
- tr: "borderTopRightRadius",
127
- bl: "borderBottomLeftRadius",
128
- br: "borderBottomRightRadius",
129
- };
130
- return { [propMap[corner]]: value };
131
- }
132
-
133
- // Sides with arbitrary values: rounded-t-[8px]
134
- const sideArbMatch = cls.match(/^rounded-([trbl])-\[(\d+)(?:px)?\]$/);
135
- if (sideArbMatch) {
136
- const side = sideArbMatch[1];
137
- const value = parseInt(sideArbMatch[2], 10);
138
- const propMap: Record<string, string[]> = {
139
- t: ["borderTopLeftRadius", "borderTopRightRadius"],
140
- r: ["borderTopRightRadius", "borderBottomRightRadius"],
141
- b: ["borderBottomLeftRadius", "borderBottomRightRadius"],
142
- l: ["borderTopLeftRadius", "borderBottomLeftRadius"],
143
- };
144
- const result: StyleObject = {};
145
- propMap[side].forEach((prop) => (result[prop] = value));
146
- return result;
147
- }
148
-
149
- // All corners with preset values: rounded, rounded-lg, etc.
150
- const allMatch = cls.match(/^rounded(-\w+)?$/);
151
- if (allMatch) {
152
- const scaleKey = allMatch[1] ? allMatch[1].substring(1) : ""; // remove leading dash
153
- const value = BORDER_RADIUS_SCALE[scaleKey];
154
- if (value !== undefined) {
155
- return { borderRadius: value };
186
+ // Remove "rounded" prefix for easier parsing
187
+ const withoutPrefix = cls.substring(7); // "rounded".length = 7
188
+
189
+ // Handle "rounded" by itself
190
+ if (withoutPrefix === "") {
191
+ return { borderRadius: BORDER_RADIUS_SCALE[""] };
192
+ }
193
+
194
+ // Must start with "-" after "rounded"
195
+ if (!withoutPrefix.startsWith("-")) {
196
+ return null;
197
+ }
198
+
199
+ const rest = withoutPrefix.substring(1); // Remove leading "-"
200
+
201
+ // Handle "rounded-" (just dash, no content)
202
+ if (rest === "") {
203
+ return null;
204
+ }
205
+
206
+ // Specific corners: rounded-tl, rounded-tl-lg, rounded-tl-[8px]
207
+ const cornerMatch = rest.match(/^(tl|tr|bl|br)(?:-(.+))?$/);
208
+ if (cornerMatch) {
209
+ const corner = cornerMatch[1];
210
+ const valueStr = cornerMatch[2] || ""; // empty string for rounded-tl
211
+
212
+ // Try arbitrary value first
213
+ if (valueStr.startsWith("[")) {
214
+ const arbitraryValue = parseArbitraryBorderRadius(valueStr);
215
+ if (arbitraryValue !== null) {
216
+ return { [BORDER_RADIUS_CORNER_MAP[corner]]: arbitraryValue };
217
+ }
218
+ return null;
156
219
  }
220
+
221
+ // Try preset scale
222
+ const scaleValue = BORDER_RADIUS_SCALE[valueStr];
223
+ if (scaleValue !== undefined) {
224
+ return { [BORDER_RADIUS_CORNER_MAP[corner]]: scaleValue };
225
+ }
226
+
227
+ return null;
157
228
  }
158
229
 
159
- // Sides with preset values: rounded-t, rounded-t-lg, etc.
160
- const sideMatch = cls.match(/^rounded-([trbl])(?:-(\w+))?$/);
230
+ // Sides: rounded-t, rounded-t-lg, rounded-t-[8px]
231
+ const sideMatch = rest.match(/^([trbl])(?:-(.+))?$/);
161
232
  if (sideMatch) {
162
233
  const side = sideMatch[1];
163
- const scaleKey = sideMatch[2] || ""; // empty string for rounded-t
164
- const value = BORDER_RADIUS_SCALE[scaleKey];
234
+ const valueStr = sideMatch[2] || ""; // empty string for rounded-t
235
+
236
+ let value: number | undefined;
237
+
238
+ // Try arbitrary value first
239
+ if (valueStr.startsWith("[")) {
240
+ const arbitraryValue = parseArbitraryBorderRadius(valueStr);
241
+ if (arbitraryValue !== null) {
242
+ value = arbitraryValue;
243
+ } else {
244
+ return null;
245
+ }
246
+ } else {
247
+ // Try preset scale
248
+ value = BORDER_RADIUS_SCALE[valueStr];
249
+ }
165
250
 
166
251
  if (value !== undefined) {
167
- const propMap: Record<string, string[]> = {
168
- t: ["borderTopLeftRadius", "borderTopRightRadius"],
169
- r: ["borderTopRightRadius", "borderBottomRightRadius"],
170
- b: ["borderBottomLeftRadius", "borderBottomRightRadius"],
171
- l: ["borderTopLeftRadius", "borderBottomLeftRadius"],
172
- };
173
252
  const result: StyleObject = {};
174
- propMap[side].forEach((prop) => (result[prop] = value));
253
+ BORDER_RADIUS_SIDE_MAP[side].forEach((prop) => (result[prop] = value));
175
254
  return result;
176
255
  }
177
- }
178
256
 
179
- // Specific corners with preset values: rounded-tl, rounded-tl-lg, etc.
180
- const cornerMatch = cls.match(/^rounded-(tl|tr|bl|br)(?:-(\w+))?$/);
181
- if (cornerMatch) {
182
- const corner = cornerMatch[1];
183
- const scaleKey = cornerMatch[2] || "";
184
- const value = BORDER_RADIUS_SCALE[scaleKey];
257
+ return null;
258
+ }
185
259
 
186
- if (value !== undefined) {
187
- const propMap: Record<string, string> = {
188
- tl: "borderTopLeftRadius",
189
- tr: "borderTopRightRadius",
190
- bl: "borderBottomLeftRadius",
191
- br: "borderBottomRightRadius",
192
- };
193
- return { [propMap[corner]]: value };
260
+ // All corners with preset values: rounded-lg, rounded-xl, etc.
261
+ // Or arbitrary values: rounded-[12px]
262
+ if (rest.startsWith("[")) {
263
+ const arbitraryValue = parseArbitraryBorderRadius(rest);
264
+ if (arbitraryValue !== null) {
265
+ return { borderRadius: arbitraryValue };
194
266
  }
267
+ return null;
268
+ }
269
+
270
+ // Preset scale
271
+ const scaleValue = BORDER_RADIUS_SCALE[rest];
272
+ if (scaleValue !== undefined) {
273
+ return { borderRadius: scaleValue };
195
274
  }
196
275
 
197
276
  return null;