@mgcrea/react-native-tailwind 0.4.0 → 0.5.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.
Files changed (71) hide show
  1. package/README.md +527 -136
  2. package/dist/babel/index.cjs +767 -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 +22 -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 +4 -3
  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 +192 -0
  64. package/src/parser/shadows.ts +84 -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 +1 -3
  71. package/dist/react-native.d.js +0 -1
@@ -34,6 +34,49 @@ __export(index_exports, {
34
34
  });
35
35
  module.exports = __toCommonJS(index_exports);
36
36
 
37
+ // src/parser/aspectRatio.ts
38
+ var ASPECT_RATIO_PRESETS = {
39
+ "aspect-auto": void 0,
40
+ // Remove aspect ratio
41
+ "aspect-square": 1,
42
+ // 1:1
43
+ "aspect-video": 16 / 9
44
+ // 16:9
45
+ };
46
+ function parseArbitraryAspectRatio(value) {
47
+ const match = value.match(/^\[(\d+)\/(\d+)\]$/);
48
+ if (match) {
49
+ const numerator = Number.parseInt(match[1], 10);
50
+ const denominator = Number.parseInt(match[2], 10);
51
+ if (denominator === 0) {
52
+ if (process.env.NODE_ENV !== "production") {
53
+ console.warn(`[react-native-tailwind] Invalid aspect ratio: ${value}. Denominator cannot be zero.`);
54
+ }
55
+ return null;
56
+ }
57
+ return numerator / denominator;
58
+ }
59
+ return null;
60
+ }
61
+ function parseAspectRatio(cls) {
62
+ if (!cls.startsWith("aspect-")) {
63
+ return null;
64
+ }
65
+ if (cls in ASPECT_RATIO_PRESETS) {
66
+ const aspectRatio2 = ASPECT_RATIO_PRESETS[cls];
67
+ if (aspectRatio2 === void 0) {
68
+ return {};
69
+ }
70
+ return { aspectRatio: aspectRatio2 };
71
+ }
72
+ const arbitraryValue = cls.substring(7);
73
+ const aspectRatio = parseArbitraryAspectRatio(arbitraryValue);
74
+ if (aspectRatio !== null) {
75
+ return { aspectRatio };
76
+ }
77
+ return null;
78
+ }
79
+
37
80
  // src/parser/borders.ts
38
81
  var BORDER_WIDTH_SCALE = {
39
82
  "": 1,
@@ -53,7 +96,58 @@ var BORDER_RADIUS_SCALE = {
53
96
  "3xl": 24,
54
97
  full: 9999
55
98
  };
99
+ var BORDER_WIDTH_PROP_MAP = {
100
+ t: "borderTopWidth",
101
+ r: "borderRightWidth",
102
+ b: "borderBottomWidth",
103
+ l: "borderLeftWidth"
104
+ };
105
+ var BORDER_RADIUS_CORNER_MAP = {
106
+ tl: "borderTopLeftRadius",
107
+ tr: "borderTopRightRadius",
108
+ bl: "borderBottomLeftRadius",
109
+ br: "borderBottomRightRadius"
110
+ };
111
+ var BORDER_RADIUS_SIDE_MAP = {
112
+ t: ["borderTopLeftRadius", "borderTopRightRadius"],
113
+ r: ["borderTopRightRadius", "borderBottomRightRadius"],
114
+ b: ["borderBottomLeftRadius", "borderBottomRightRadius"],
115
+ l: ["borderTopLeftRadius", "borderBottomLeftRadius"]
116
+ };
117
+ function parseArbitraryBorderWidth(value) {
118
+ const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
119
+ if (pxMatch) {
120
+ return parseInt(pxMatch[1], 10);
121
+ }
122
+ if (value.startsWith("[") && value.endsWith("]")) {
123
+ if (process.env.NODE_ENV !== "production") {
124
+ console.warn(
125
+ `[react-native-tailwind] Unsupported arbitrary border width value: ${value}. Only px values are supported (e.g., [8px] or [8]).`
126
+ );
127
+ }
128
+ return null;
129
+ }
130
+ return null;
131
+ }
132
+ function parseArbitraryBorderRadius(value) {
133
+ const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
134
+ if (pxMatch) {
135
+ return parseInt(pxMatch[1], 10);
136
+ }
137
+ if (value.startsWith("[") && value.endsWith("]")) {
138
+ if (process.env.NODE_ENV !== "production") {
139
+ console.warn(
140
+ `[react-native-tailwind] Unsupported arbitrary border radius value: ${value}. Only px values are supported (e.g., [12px] or [12]).`
141
+ );
142
+ }
143
+ return null;
144
+ }
145
+ return null;
146
+ }
56
147
  function parseBorder(cls) {
148
+ if (cls === "border-solid") return { borderStyle: "solid" };
149
+ if (cls === "border-dotted") return { borderStyle: "dotted" };
150
+ if (cls === "border-dashed") return { borderStyle: "dashed" };
57
151
  if (cls.startsWith("border-")) {
58
152
  return parseBorderWidth(cls);
59
153
  }
@@ -63,42 +157,25 @@ function parseBorder(cls) {
63
157
  if (cls.startsWith("rounded")) {
64
158
  return parseBorderRadius(cls);
65
159
  }
66
- if (cls === "border-solid") return { borderStyle: "solid" };
67
- if (cls === "border-dotted") return { borderStyle: "dotted" };
68
- if (cls === "border-dashed") return { borderStyle: "dashed" };
69
160
  return null;
70
161
  }
71
162
  function parseBorderWidth(cls) {
72
- const allArbMatch = cls.match(/^border-\[(\d+)(?:px)?\]$/);
73
- if (allArbMatch) {
74
- return { borderWidth: parseInt(allArbMatch[1], 10) };
75
- }
76
- const dirArbMatch = cls.match(/^border-([trbl])-\[(\d+)(?:px)?\]$/);
77
- if (dirArbMatch) {
78
- const dir = dirArbMatch[1];
79
- const value = parseInt(dirArbMatch[2], 10);
80
- const propMap = {
81
- t: "borderTopWidth",
82
- r: "borderRightWidth",
83
- b: "borderBottomWidth",
84
- l: "borderLeftWidth"
85
- };
86
- return { [propMap[dir]]: value };
87
- }
88
- const dirMatch = cls.match(/^border-([trbl])-?(\d*)$/);
163
+ const dirMatch = cls.match(/^border-([trbl])(?:-(.+))?$/);
89
164
  if (dirMatch) {
90
165
  const dir = dirMatch[1];
91
- const scaleKey = dirMatch[2] || "";
92
- const value = BORDER_WIDTH_SCALE[scaleKey];
93
- if (typeof value === "number") {
94
- const propMap = {
95
- t: "borderTopWidth",
96
- r: "borderRightWidth",
97
- b: "borderBottomWidth",
98
- l: "borderLeftWidth"
99
- };
100
- return { [propMap[dir]]: value };
166
+ const valueStr = dirMatch[2] || "";
167
+ if (valueStr.startsWith("[")) {
168
+ const arbitraryValue = parseArbitraryBorderWidth(valueStr);
169
+ if (arbitraryValue !== null) {
170
+ return { [BORDER_WIDTH_PROP_MAP[dir]]: arbitraryValue };
171
+ }
172
+ return null;
173
+ }
174
+ const scaleValue = BORDER_WIDTH_SCALE[valueStr];
175
+ if (scaleValue !== void 0) {
176
+ return { [BORDER_WIDTH_PROP_MAP[dir]]: scaleValue };
101
177
  }
178
+ return null;
102
179
  }
103
180
  const allMatch = cls.match(/^border-(\d+)$/);
104
181
  if (allMatch) {
@@ -107,78 +184,76 @@ function parseBorderWidth(cls) {
107
184
  return { borderWidth: value };
108
185
  }
109
186
  }
187
+ const allArbMatch = cls.match(/^border-(\[.+\])$/);
188
+ if (allArbMatch) {
189
+ const arbitraryValue = parseArbitraryBorderWidth(allArbMatch[1]);
190
+ if (arbitraryValue !== null) {
191
+ return { borderWidth: arbitraryValue };
192
+ }
193
+ }
110
194
  return null;
111
195
  }
112
196
  function parseBorderRadius(cls) {
113
- const allArbMatch = cls.match(/^rounded-\[(\d+)(?:px)?\]$/);
114
- if (allArbMatch) {
115
- return { borderRadius: parseInt(allArbMatch[1], 10) };
116
- }
117
- const cornerArbMatch = cls.match(/^rounded-(tl|tr|bl|br)-\[(\d+)(?:px)?\]$/);
118
- if (cornerArbMatch) {
119
- const corner = cornerArbMatch[1];
120
- const value = parseInt(cornerArbMatch[2], 10);
121
- const propMap = {
122
- tl: "borderTopLeftRadius",
123
- tr: "borderTopRightRadius",
124
- bl: "borderBottomLeftRadius",
125
- br: "borderBottomRightRadius"
126
- };
127
- return { [propMap[corner]]: value };
128
- }
129
- const sideArbMatch = cls.match(/^rounded-([trbl])-\[(\d+)(?:px)?\]$/);
130
- if (sideArbMatch) {
131
- const side = sideArbMatch[1];
132
- const value = parseInt(sideArbMatch[2], 10);
133
- const propMap = {
134
- t: ["borderTopLeftRadius", "borderTopRightRadius"],
135
- r: ["borderTopRightRadius", "borderBottomRightRadius"],
136
- b: ["borderBottomLeftRadius", "borderBottomRightRadius"],
137
- l: ["borderTopLeftRadius", "borderBottomLeftRadius"]
138
- };
139
- const result = {};
140
- propMap[side].forEach((prop) => result[prop] = value);
141
- return result;
142
- }
143
- const allMatch = cls.match(/^rounded(-\w+)?$/);
144
- if (allMatch) {
145
- const scaleKey = allMatch[1] ? allMatch[1].substring(1) : "";
146
- const value = BORDER_RADIUS_SCALE[scaleKey];
147
- if (value !== void 0) {
148
- return { borderRadius: value };
197
+ const withoutPrefix = cls.substring(7);
198
+ if (withoutPrefix === "") {
199
+ return { borderRadius: BORDER_RADIUS_SCALE[""] };
200
+ }
201
+ if (!withoutPrefix.startsWith("-")) {
202
+ return null;
203
+ }
204
+ const rest = withoutPrefix.substring(1);
205
+ if (rest === "") {
206
+ return null;
207
+ }
208
+ const cornerMatch = rest.match(/^(tl|tr|bl|br)(?:-(.+))?$/);
209
+ if (cornerMatch) {
210
+ const corner = cornerMatch[1];
211
+ const valueStr = cornerMatch[2] || "";
212
+ if (valueStr.startsWith("[")) {
213
+ const arbitraryValue = parseArbitraryBorderRadius(valueStr);
214
+ if (arbitraryValue !== null) {
215
+ return { [BORDER_RADIUS_CORNER_MAP[corner]]: arbitraryValue };
216
+ }
217
+ return null;
218
+ }
219
+ const scaleValue2 = BORDER_RADIUS_SCALE[valueStr];
220
+ if (scaleValue2 !== void 0) {
221
+ return { [BORDER_RADIUS_CORNER_MAP[corner]]: scaleValue2 };
149
222
  }
223
+ return null;
150
224
  }
151
- const sideMatch = cls.match(/^rounded-([trbl])(?:-(\w+))?$/);
225
+ const sideMatch = rest.match(/^([trbl])(?:-(.+))?$/);
152
226
  if (sideMatch) {
153
227
  const side = sideMatch[1];
154
- const scaleKey = sideMatch[2] || "";
155
- const value = BORDER_RADIUS_SCALE[scaleKey];
228
+ const valueStr = sideMatch[2] || "";
229
+ let value;
230
+ if (valueStr.startsWith("[")) {
231
+ const arbitraryValue = parseArbitraryBorderRadius(valueStr);
232
+ if (arbitraryValue !== null) {
233
+ value = arbitraryValue;
234
+ } else {
235
+ return null;
236
+ }
237
+ } else {
238
+ value = BORDER_RADIUS_SCALE[valueStr];
239
+ }
156
240
  if (value !== void 0) {
157
- const propMap = {
158
- t: ["borderTopLeftRadius", "borderTopRightRadius"],
159
- r: ["borderTopRightRadius", "borderBottomRightRadius"],
160
- b: ["borderBottomLeftRadius", "borderBottomRightRadius"],
161
- l: ["borderTopLeftRadius", "borderBottomLeftRadius"]
162
- };
163
241
  const result = {};
164
- propMap[side].forEach((prop) => result[prop] = value);
242
+ BORDER_RADIUS_SIDE_MAP[side].forEach((prop) => result[prop] = value);
165
243
  return result;
166
244
  }
245
+ return null;
167
246
  }
168
- const cornerMatch = cls.match(/^rounded-(tl|tr|bl|br)(?:-(\w+))?$/);
169
- if (cornerMatch) {
170
- const corner = cornerMatch[1];
171
- const scaleKey = cornerMatch[2] || "";
172
- const value = BORDER_RADIUS_SCALE[scaleKey];
173
- if (value !== void 0) {
174
- const propMap = {
175
- tl: "borderTopLeftRadius",
176
- tr: "borderTopRightRadius",
177
- bl: "borderBottomLeftRadius",
178
- br: "borderBottomRightRadius"
179
- };
180
- return { [propMap[corner]]: value };
247
+ if (rest.startsWith("[")) {
248
+ const arbitraryValue = parseArbitraryBorderRadius(rest);
249
+ if (arbitraryValue !== null) {
250
+ return { borderRadius: arbitraryValue };
181
251
  }
252
+ return null;
253
+ }
254
+ const scaleValue = BORDER_RADIUS_SCALE[rest];
255
+ if (scaleValue !== void 0) {
256
+ return { borderRadius: scaleValue };
182
257
  }
183
258
  return null;
184
259
  }
@@ -289,27 +364,86 @@ var COLORS = {
289
364
  black: "#000000",
290
365
  transparent: "transparent"
291
366
  };
367
+ function applyOpacity(hex, opacity) {
368
+ if (hex === "transparent") {
369
+ return "transparent";
370
+ }
371
+ const cleanHex = hex.replace(/^#/, "");
372
+ const fullHex = cleanHex.length === 3 ? cleanHex.split("").map((char) => char + char).join("") : cleanHex;
373
+ const alpha = Math.round(opacity / 100 * 255);
374
+ const alphaHex = alpha.toString(16).padStart(2, "0").toUpperCase();
375
+ return `#${fullHex.toUpperCase()}${alphaHex}`;
376
+ }
377
+ function parseArbitraryColor(value) {
378
+ const hexMatch = value.match(/^\[#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\]$/);
379
+ if (hexMatch) {
380
+ const hex = hexMatch[1];
381
+ if (hex.length === 3) {
382
+ const expanded = hex.split("").map((char) => char + char).join("");
383
+ return `#${expanded}`;
384
+ }
385
+ return `#${hex}`;
386
+ }
387
+ if (value.startsWith("[") && value.endsWith("]")) {
388
+ if (process.env.NODE_ENV !== "production") {
389
+ console.warn(
390
+ `[react-native-tailwind] Unsupported arbitrary color value: ${value}. Only hex colors are supported (e.g., [#ff0000], [#f00], or [#ff0000aa]).`
391
+ );
392
+ }
393
+ return null;
394
+ }
395
+ return null;
396
+ }
292
397
  function parseColor(cls, customColors) {
293
398
  const getColor = (key) => {
294
399
  return customColors?.[key] ?? COLORS[key];
295
400
  };
401
+ const parseColorWithOpacity = (colorKey) => {
402
+ const opacityMatch = colorKey.match(/^(.+)\/(\d+)$/);
403
+ if (opacityMatch) {
404
+ const baseColorKey = opacityMatch[1];
405
+ const opacity = Number.parseInt(opacityMatch[2], 10);
406
+ if (opacity < 0 || opacity > 100) {
407
+ if (process.env.NODE_ENV !== "production") {
408
+ console.warn(
409
+ `[react-native-tailwind] Invalid opacity value: ${opacity}. Opacity must be between 0 and 100.`
410
+ );
411
+ }
412
+ return null;
413
+ }
414
+ const arbitraryColor2 = parseArbitraryColor(baseColorKey);
415
+ if (arbitraryColor2 !== null) {
416
+ return applyOpacity(arbitraryColor2, opacity);
417
+ }
418
+ const color = getColor(baseColorKey);
419
+ if (color) {
420
+ return applyOpacity(color, opacity);
421
+ }
422
+ return null;
423
+ }
424
+ const arbitraryColor = parseArbitraryColor(colorKey);
425
+ if (arbitraryColor !== null) {
426
+ return arbitraryColor;
427
+ }
428
+ return getColor(colorKey) ?? null;
429
+ };
296
430
  if (cls.startsWith("bg-")) {
297
431
  const colorKey = cls.substring(3);
298
- const color = getColor(colorKey);
432
+ const color = parseColorWithOpacity(colorKey);
299
433
  if (color) {
300
434
  return { backgroundColor: color };
301
435
  }
302
436
  }
303
437
  if (cls.startsWith("text-")) {
304
438
  const colorKey = cls.substring(5);
305
- const color = getColor(colorKey);
439
+ const color = parseColorWithOpacity(colorKey);
306
440
  if (color) {
307
441
  return { color };
308
442
  }
309
443
  }
310
444
  if (cls.startsWith("border-") && !cls.match(/^border-[0-9]/)) {
311
445
  const colorKey = cls.substring(7);
312
- const color = getColor(colorKey);
446
+ const color = parseColorWithOpacity(colorKey);
313
447
  if (color) {
314
448
  return { borderColor: color };
315
449
  }
@@ -384,10 +518,166 @@ var OVERFLOW_MAP = {
384
518
  "overflow-visible": { overflow: "visible" },
385
519
  "overflow-scroll": { overflow: "scroll" }
386
520
  };
521
+ var Z_INDEX_SCALE = {
522
+ 0: 0,
523
+ 10: 10,
524
+ 20: 20,
525
+ 30: 30,
526
+ 40: 40,
527
+ 50: 50,
528
+ auto: 0
529
+ // React Native doesn't have 'auto', default to 0
530
+ };
531
+ var INSET_SCALE = {
532
+ 0: 0,
533
+ 0.5: 2,
534
+ 1: 4,
535
+ 1.5: 6,
536
+ 2: 8,
537
+ 2.5: 10,
538
+ 3: 12,
539
+ 3.5: 14,
540
+ 4: 16,
541
+ 5: 20,
542
+ 6: 24,
543
+ 8: 32,
544
+ 10: 40,
545
+ 12: 48,
546
+ 16: 64,
547
+ 20: 80,
548
+ 24: 96
549
+ };
387
550
  function parseLayout(cls) {
551
+ if (cls.startsWith("z-")) {
552
+ const zKey = cls.substring(2);
553
+ const zValue = Z_INDEX_SCALE[zKey];
554
+ if (zValue !== void 0) {
555
+ return { zIndex: zValue };
556
+ }
557
+ }
558
+ if (cls.startsWith("top-")) {
559
+ const topKey = cls.substring(4);
560
+ if (topKey === "auto") {
561
+ return {};
562
+ }
563
+ const topValue = INSET_SCALE[topKey];
564
+ if (topValue !== void 0) {
565
+ return { top: topValue };
566
+ }
567
+ }
568
+ if (cls.startsWith("right-")) {
569
+ const rightKey = cls.substring(6);
570
+ if (rightKey === "auto") {
571
+ return {};
572
+ }
573
+ const rightValue = INSET_SCALE[rightKey];
574
+ if (rightValue !== void 0) {
575
+ return { right: rightValue };
576
+ }
577
+ }
578
+ if (cls.startsWith("bottom-")) {
579
+ const bottomKey = cls.substring(7);
580
+ if (bottomKey === "auto") {
581
+ return {};
582
+ }
583
+ const bottomValue = INSET_SCALE[bottomKey];
584
+ if (bottomValue !== void 0) {
585
+ return { bottom: bottomValue };
586
+ }
587
+ }
588
+ if (cls.startsWith("left-")) {
589
+ const leftKey = cls.substring(5);
590
+ if (leftKey === "auto") {
591
+ return {};
592
+ }
593
+ const leftValue = INSET_SCALE[leftKey];
594
+ if (leftValue !== void 0) {
595
+ return { left: leftValue };
596
+ }
597
+ }
598
+ if (cls.startsWith("inset-")) {
599
+ const insetKey = cls.substring(6);
600
+ const insetValue = INSET_SCALE[insetKey];
601
+ if (insetValue !== void 0) {
602
+ return { top: insetValue, right: insetValue, bottom: insetValue, left: insetValue };
603
+ }
604
+ }
605
+ if (cls.startsWith("inset-x-")) {
606
+ const insetKey = cls.substring(8);
607
+ const insetValue = INSET_SCALE[insetKey];
608
+ if (insetValue !== void 0) {
609
+ return { left: insetValue, right: insetValue };
610
+ }
611
+ }
612
+ if (cls.startsWith("inset-y-")) {
613
+ const insetKey = cls.substring(8);
614
+ const insetValue = INSET_SCALE[insetKey];
615
+ if (insetValue !== void 0) {
616
+ return { top: insetValue, bottom: insetValue };
617
+ }
618
+ }
388
619
  return DISPLAY_MAP[cls] ?? FLEX_DIRECTION_MAP[cls] ?? FLEX_WRAP_MAP[cls] ?? FLEX_MAP[cls] ?? GROW_SHRINK_MAP[cls] ?? JUSTIFY_CONTENT_MAP[cls] ?? ALIGN_ITEMS_MAP[cls] ?? ALIGN_SELF_MAP[cls] ?? ALIGN_CONTENT_MAP[cls] ?? POSITION_MAP[cls] ?? OVERFLOW_MAP[cls] ?? null;
389
620
  }
390
621
 
622
+ // src/parser/shadows.ts
623
+ var SHADOW_SCALE = {
624
+ "shadow-sm": {
625
+ shadowColor: "#000000",
626
+ shadowOffset: { width: 0, height: 1 },
627
+ shadowOpacity: 0.05,
628
+ shadowRadius: 1,
629
+ elevation: 1
630
+ },
631
+ shadow: {
632
+ shadowColor: "#000000",
633
+ shadowOffset: { width: 0, height: 1 },
634
+ shadowOpacity: 0.1,
635
+ shadowRadius: 2,
636
+ elevation: 2
637
+ },
638
+ "shadow-md": {
639
+ shadowColor: "#000000",
640
+ shadowOffset: { width: 0, height: 3 },
641
+ shadowOpacity: 0.15,
642
+ shadowRadius: 4,
643
+ elevation: 4
644
+ },
645
+ "shadow-lg": {
646
+ shadowColor: "#000000",
647
+ shadowOffset: { width: 0, height: 6 },
648
+ shadowOpacity: 0.2,
649
+ shadowRadius: 8,
650
+ elevation: 8
651
+ },
652
+ "shadow-xl": {
653
+ shadowColor: "#000000",
654
+ shadowOffset: { width: 0, height: 10 },
655
+ shadowOpacity: 0.25,
656
+ shadowRadius: 12,
657
+ elevation: 12
658
+ },
659
+ "shadow-2xl": {
660
+ shadowColor: "#000000",
661
+ shadowOffset: { width: 0, height: 20 },
662
+ shadowOpacity: 0.3,
663
+ shadowRadius: 24,
664
+ elevation: 16
665
+ },
666
+ "shadow-none": {
667
+ shadowColor: "transparent",
668
+ shadowOffset: { width: 0, height: 0 },
669
+ shadowOpacity: 0,
670
+ shadowRadius: 0,
671
+ elevation: 0
672
+ }
673
+ };
674
+ function parseShadow(cls) {
675
+ if (cls in SHADOW_SCALE) {
676
+ return SHADOW_SCALE[cls];
677
+ }
678
+ return null;
679
+ }
680
+
391
681
  // src/parser/sizing.ts
392
682
  var SIZE_SCALE = {
393
683
  0: 0,
@@ -599,131 +889,99 @@ var SPACING_SCALE = {
599
889
  80: 320,
600
890
  96: 384
601
891
  };
602
- function parseSpacing(cls) {
603
- if (cls.startsWith("m-") || cls.startsWith("m")) {
604
- return parseMargin(cls);
605
- }
606
- if (cls.startsWith("p-") || cls.startsWith("p")) {
607
- return parsePadding(cls);
892
+ function parseArbitrarySpacing(value) {
893
+ const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
894
+ if (pxMatch) {
895
+ return parseInt(pxMatch[1], 10);
608
896
  }
609
- if (cls.startsWith("gap-")) {
610
- return parseGap(cls);
897
+ if (value.startsWith("[") && value.endsWith("]")) {
898
+ if (process.env.NODE_ENV !== "production") {
899
+ console.warn(
900
+ `[react-native-tailwind] Unsupported arbitrary spacing value: ${value}. Only px values are supported (e.g., [16px] or [16]).`
901
+ );
902
+ }
903
+ return null;
611
904
  }
612
905
  return null;
613
906
  }
614
- function parseMargin(cls) {
615
- const allMatch = cls.match(/^m-(\d+(?:\.\d+)?)$/);
616
- if (allMatch) {
617
- const value = SPACING_SCALE[allMatch[1]];
618
- if (value !== void 0) {
619
- return { margin: value };
907
+ function parseSpacing(cls) {
908
+ const marginMatch = cls.match(/^m([xytrbls]?)-(.+)$/);
909
+ if (marginMatch) {
910
+ const [, dir, valueStr] = marginMatch;
911
+ const arbitraryValue = parseArbitrarySpacing(valueStr);
912
+ if (arbitraryValue !== null) {
913
+ return getMarginStyle(dir, arbitraryValue);
620
914
  }
621
- }
622
- const xMatch = cls.match(/^mx-(\d+(?:\.\d+)?)$/);
623
- if (xMatch) {
624
- const value = SPACING_SCALE[xMatch[1]];
625
- if (value !== void 0) {
626
- return { marginHorizontal: value };
915
+ const scaleValue = SPACING_SCALE[valueStr];
916
+ if (scaleValue !== void 0) {
917
+ return getMarginStyle(dir, scaleValue);
627
918
  }
628
919
  }
629
- const yMatch = cls.match(/^my-(\d+(?:\.\d+)?)$/);
630
- if (yMatch) {
631
- const value = SPACING_SCALE[yMatch[1]];
632
- if (value !== void 0) {
633
- return { marginVertical: value };
920
+ const paddingMatch = cls.match(/^p([xytrbls]?)-(.+)$/);
921
+ if (paddingMatch) {
922
+ const [, dir, valueStr] = paddingMatch;
923
+ const arbitraryValue = parseArbitrarySpacing(valueStr);
924
+ if (arbitraryValue !== null) {
925
+ return getPaddingStyle(dir, arbitraryValue);
634
926
  }
635
- }
636
- const tMatch = cls.match(/^mt-(\d+(?:\.\d+)?)$/);
637
- if (tMatch) {
638
- const value = SPACING_SCALE[tMatch[1]];
639
- if (value !== void 0) {
640
- return { marginTop: value };
927
+ const scaleValue = SPACING_SCALE[valueStr];
928
+ if (scaleValue !== void 0) {
929
+ return getPaddingStyle(dir, scaleValue);
641
930
  }
642
931
  }
643
- const rMatch = cls.match(/^mr-(\d+(?:\.\d+)?)$/);
644
- if (rMatch) {
645
- const value = SPACING_SCALE[rMatch[1]];
646
- if (value !== void 0) {
647
- return { marginRight: value };
932
+ const gapMatch = cls.match(/^gap-(.+)$/);
933
+ if (gapMatch) {
934
+ const valueStr = gapMatch[1];
935
+ const arbitraryValue = parseArbitrarySpacing(valueStr);
936
+ if (arbitraryValue !== null) {
937
+ return { gap: arbitraryValue };
648
938
  }
649
- }
650
- const bMatch = cls.match(/^mb-(\d+(?:\.\d+)?)$/);
651
- if (bMatch) {
652
- const value = SPACING_SCALE[bMatch[1]];
653
- if (value !== void 0) {
654
- return { marginBottom: value };
939
+ const scaleValue = SPACING_SCALE[valueStr];
940
+ if (scaleValue !== void 0) {
941
+ return { gap: scaleValue };
655
942
  }
656
943
  }
657
- const lMatch = cls.match(/^ml-(\d+(?:\.\d+)?)$/);
658
- if (lMatch) {
659
- const value = SPACING_SCALE[lMatch[1]];
660
- if (value !== void 0) {
944
+ return null;
945
+ }
946
+ function getMarginStyle(dir, value) {
947
+ switch (dir) {
948
+ case "":
949
+ return { margin: value };
950
+ case "x":
951
+ return { marginHorizontal: value };
952
+ case "y":
953
+ return { marginVertical: value };
954
+ case "t":
955
+ return { marginTop: value };
956
+ case "r":
957
+ return { marginRight: value };
958
+ case "b":
959
+ return { marginBottom: value };
960
+ case "l":
661
961
  return { marginLeft: value };
662
- }
962
+ default:
963
+ return {};
663
964
  }
664
- return null;
665
965
  }
666
- function parsePadding(cls) {
667
- const allMatch = cls.match(/^p-(\d+(?:\.\d+)?)$/);
668
- if (allMatch) {
669
- const value = SPACING_SCALE[allMatch[1]];
670
- if (value !== void 0) {
966
+ function getPaddingStyle(dir, value) {
967
+ switch (dir) {
968
+ case "":
671
969
  return { padding: value };
672
- }
673
- }
674
- const xMatch = cls.match(/^px-(\d+(?:\.\d+)?)$/);
675
- if (xMatch) {
676
- const value = SPACING_SCALE[xMatch[1]];
677
- if (value !== void 0) {
970
+ case "x":
678
971
  return { paddingHorizontal: value };
679
- }
680
- }
681
- const yMatch = cls.match(/^py-(\d+(?:\.\d+)?)$/);
682
- if (yMatch) {
683
- const value = SPACING_SCALE[yMatch[1]];
684
- if (value !== void 0) {
972
+ case "y":
685
973
  return { paddingVertical: value };
686
- }
687
- }
688
- const tMatch = cls.match(/^pt-(\d+(?:\.\d+)?)$/);
689
- if (tMatch) {
690
- const value = SPACING_SCALE[tMatch[1]];
691
- if (value !== void 0) {
974
+ case "t":
692
975
  return { paddingTop: value };
693
- }
694
- }
695
- const rMatch = cls.match(/^pr-(\d+(?:\.\d+)?)$/);
696
- if (rMatch) {
697
- const value = SPACING_SCALE[rMatch[1]];
698
- if (value !== void 0) {
976
+ case "r":
699
977
  return { paddingRight: value };
700
- }
701
- }
702
- const bMatch = cls.match(/^pb-(\d+(?:\.\d+)?)$/);
703
- if (bMatch) {
704
- const value = SPACING_SCALE[bMatch[1]];
705
- if (value !== void 0) {
978
+ case "b":
706
979
  return { paddingBottom: value };
707
- }
708
- }
709
- const lMatch = cls.match(/^pl-(\d+(?:\.\d+)?)$/);
710
- if (lMatch) {
711
- const value = SPACING_SCALE[lMatch[1]];
712
- if (value !== void 0) {
980
+ case "l":
713
981
  return { paddingLeft: value };
714
- }
982
+ default:
983
+ return {};
715
984
  }
716
- return null;
717
- }
718
- function parseGap(cls) {
719
- const match = cls.match(/^gap-(\d+(?:\.\d+)?)$/);
720
- if (match) {
721
- const value = SPACING_SCALE[match[1]];
722
- if (value !== void 0) {
723
- return { gap: value };
724
- }
725
- }
726
- return null;
727
985
  }
728
986
 
729
987
  // src/parser/typography.ts
@@ -742,99 +1000,142 @@ var FONT_SIZES = {
742
1000
  "8xl": 96,
743
1001
  "9xl": 128
744
1002
  };
1003
+ var FONT_WEIGHT_MAP = {
1004
+ "font-thin": { fontWeight: "100" },
1005
+ "font-extralight": { fontWeight: "200" },
1006
+ "font-light": { fontWeight: "300" },
1007
+ "font-normal": { fontWeight: "400" },
1008
+ "font-medium": { fontWeight: "500" },
1009
+ "font-semibold": { fontWeight: "600" },
1010
+ "font-bold": { fontWeight: "700" },
1011
+ "font-extrabold": { fontWeight: "800" },
1012
+ "font-black": { fontWeight: "900" }
1013
+ };
1014
+ var FONT_STYLE_MAP = {
1015
+ italic: { fontStyle: "italic" },
1016
+ "not-italic": { fontStyle: "normal" }
1017
+ };
1018
+ var TEXT_ALIGN_MAP = {
1019
+ "text-left": { textAlign: "left" },
1020
+ "text-center": { textAlign: "center" },
1021
+ "text-right": { textAlign: "right" },
1022
+ "text-justify": { textAlign: "justify" }
1023
+ };
1024
+ var TEXT_DECORATION_MAP = {
1025
+ underline: { textDecorationLine: "underline" },
1026
+ "line-through": { textDecorationLine: "line-through" },
1027
+ "no-underline": { textDecorationLine: "none" }
1028
+ };
1029
+ var TEXT_TRANSFORM_MAP = {
1030
+ uppercase: { textTransform: "uppercase" },
1031
+ lowercase: { textTransform: "lowercase" },
1032
+ capitalize: { textTransform: "capitalize" },
1033
+ "normal-case": { textTransform: "none" }
1034
+ };
1035
+ var LINE_HEIGHT_MAP = {
1036
+ "leading-none": { lineHeight: 16 },
1037
+ "leading-tight": { lineHeight: 20 },
1038
+ "leading-snug": { lineHeight: 22 },
1039
+ "leading-normal": { lineHeight: 24 },
1040
+ "leading-relaxed": { lineHeight: 28 },
1041
+ "leading-loose": { lineHeight: 32 }
1042
+ };
1043
+ var TRACKING_MAP = {
1044
+ "tracking-tighter": { letterSpacing: -0.8 },
1045
+ "tracking-tight": { letterSpacing: -0.4 },
1046
+ "tracking-normal": { letterSpacing: 0 },
1047
+ "tracking-wide": { letterSpacing: 0.4 },
1048
+ "tracking-wider": { letterSpacing: 0.8 },
1049
+ "tracking-widest": { letterSpacing: 1.6 }
1050
+ };
1051
+ function parseArbitraryFontSize(value) {
1052
+ const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
1053
+ if (pxMatch) {
1054
+ return parseInt(pxMatch[1], 10);
1055
+ }
1056
+ if (value.startsWith("[") && value.endsWith("]")) {
1057
+ if (process.env.NODE_ENV !== "production") {
1058
+ console.warn(
1059
+ `[react-native-tailwind] Unsupported arbitrary font size value: ${value}. Only px values are supported (e.g., [18px] or [18]).`
1060
+ );
1061
+ }
1062
+ return null;
1063
+ }
1064
+ return null;
1065
+ }
1066
+ function parseArbitraryLineHeight(value) {
1067
+ const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
1068
+ if (pxMatch) {
1069
+ return parseInt(pxMatch[1], 10);
1070
+ }
1071
+ if (value.startsWith("[") && value.endsWith("]")) {
1072
+ if (process.env.NODE_ENV !== "production") {
1073
+ console.warn(
1074
+ `[react-native-tailwind] Unsupported arbitrary line height value: ${value}. Only px values are supported (e.g., [24px] or [24]).`
1075
+ );
1076
+ }
1077
+ return null;
1078
+ }
1079
+ return null;
1080
+ }
745
1081
  function parseTypography(cls) {
746
1082
  if (cls.startsWith("text-")) {
747
1083
  const sizeKey = cls.substring(5);
1084
+ const arbitraryValue = parseArbitraryFontSize(sizeKey);
1085
+ if (arbitraryValue !== null) {
1086
+ return { fontSize: arbitraryValue };
1087
+ }
748
1088
  const fontSize = FONT_SIZES[sizeKey];
749
1089
  if (fontSize !== void 0) {
750
1090
  return { fontSize };
751
1091
  }
752
1092
  }
753
- if (cls === "font-thin") {
754
- return { fontWeight: "100" };
755
- }
756
- if (cls === "font-extralight") {
757
- return { fontWeight: "200" };
758
- }
759
- if (cls === "font-light") {
760
- return { fontWeight: "300" };
761
- }
762
- if (cls === "font-normal") {
763
- return { fontWeight: "400" };
764
- }
765
- if (cls === "font-medium") {
766
- return { fontWeight: "500" };
767
- }
768
- if (cls === "font-semibold") {
769
- return { fontWeight: "600" };
770
- }
771
- if (cls === "font-bold") {
772
- return { fontWeight: "700" };
773
- }
774
- if (cls === "font-extrabold") {
775
- return { fontWeight: "800" };
776
- }
777
- if (cls === "font-black") {
778
- return { fontWeight: "900" };
779
- }
780
- if (cls === "italic") {
781
- return { fontStyle: "italic" };
782
- }
783
- if (cls === "not-italic") {
784
- return { fontStyle: "normal" };
785
- }
786
- if (cls === "text-left") {
787
- return { textAlign: "left" };
788
- }
789
- if (cls === "text-center") {
790
- return { textAlign: "center" };
791
- }
792
- if (cls === "text-right") {
793
- return { textAlign: "right" };
794
- }
795
- if (cls === "text-justify") {
796
- return { textAlign: "justify" };
797
- }
798
- if (cls === "underline") {
799
- return { textDecorationLine: "underline" };
800
- }
801
- if (cls === "line-through") {
802
- return { textDecorationLine: "line-through" };
803
- }
804
- if (cls === "no-underline") {
805
- return { textDecorationLine: "none" };
806
- }
807
- if (cls === "uppercase") {
808
- return { textTransform: "uppercase" };
809
- }
810
- if (cls === "lowercase") {
811
- return { textTransform: "lowercase" };
812
- }
813
- if (cls === "capitalize") {
814
- return { textTransform: "capitalize" };
815
- }
816
- if (cls === "normal-case") {
817
- return { textTransform: "none" };
818
- }
819
- if (cls === "leading-none") {
820
- return { lineHeight: 16 };
1093
+ if (cls.startsWith("leading-")) {
1094
+ const heightKey = cls.substring(8);
1095
+ const arbitraryValue = parseArbitraryLineHeight(heightKey);
1096
+ if (arbitraryValue !== null) {
1097
+ return { lineHeight: arbitraryValue };
1098
+ }
821
1099
  }
822
- if (cls === "leading-tight") {
823
- return { lineHeight: 20 };
1100
+ return FONT_WEIGHT_MAP[cls] ?? FONT_STYLE_MAP[cls] ?? TEXT_ALIGN_MAP[cls] ?? TEXT_DECORATION_MAP[cls] ?? TEXT_TRANSFORM_MAP[cls] ?? LINE_HEIGHT_MAP[cls] ?? TRACKING_MAP[cls] ?? null;
1101
+ }
1102
+
1103
+ // src/parser/modifiers.ts
1104
+ var SUPPORTED_MODIFIERS = ["active", "hover", "focus", "disabled"];
1105
+ function parseModifier(cls) {
1106
+ const colonIndex = cls.indexOf(":");
1107
+ if (colonIndex === -1) {
1108
+ return null;
824
1109
  }
825
- if (cls === "leading-snug") {
826
- return { lineHeight: 22 };
1110
+ const potentialModifier = cls.slice(0, colonIndex);
1111
+ const baseClass = cls.slice(colonIndex + 1);
1112
+ if (!SUPPORTED_MODIFIERS.includes(potentialModifier)) {
1113
+ return null;
827
1114
  }
828
- if (cls === "leading-normal") {
829
- return { lineHeight: 24 };
1115
+ if (baseClass.includes(":")) {
1116
+ return null;
830
1117
  }
831
- if (cls === "leading-relaxed") {
832
- return { lineHeight: 28 };
1118
+ if (!baseClass) {
1119
+ return null;
833
1120
  }
834
- if (cls === "leading-loose") {
835
- return { lineHeight: 32 };
1121
+ return {
1122
+ modifier: potentialModifier,
1123
+ baseClass
1124
+ };
1125
+ }
1126
+ function splitModifierClasses(className) {
1127
+ const classes = className.trim().split(/\s+/).filter(Boolean);
1128
+ const baseClasses = [];
1129
+ const modifierClasses = [];
1130
+ for (const cls of classes) {
1131
+ const parsed = parseModifier(cls);
1132
+ if (parsed) {
1133
+ modifierClasses.push(parsed);
1134
+ } else {
1135
+ baseClasses.push(cls);
1136
+ }
836
1137
  }
837
- return null;
1138
+ return { baseClasses, modifierClasses };
838
1139
  }
839
1140
 
840
1141
  // src/parser/index.ts
@@ -850,11 +1151,13 @@ function parseClassName(className, customColors) {
850
1151
  function parseClass(cls, customColors) {
851
1152
  const parsers = [
852
1153
  parseSpacing,
1154
+ parseBorder,
853
1155
  (cls2) => parseColor(cls2, customColors),
854
1156
  parseLayout,
855
1157
  parseTypography,
856
- parseBorder,
857
- parseSizing
1158
+ parseSizing,
1159
+ parseShadow,
1160
+ parseAspectRatio
858
1161
  ];
859
1162
  for (const parser of parsers) {
860
1163
  const result = parser(cls);
@@ -953,12 +1256,16 @@ function extractCustomColors(filename) {
953
1256
  var STYLES_IDENTIFIER = "_twStyles";
954
1257
  var SUPPORTED_CLASS_ATTRIBUTES = [
955
1258
  "className",
1259
+ "containerClassName",
956
1260
  "contentContainerClassName",
957
1261
  "columnWrapperClassName",
958
1262
  "ListHeaderComponentClassName",
959
1263
  "ListFooterComponentClassName"
960
1264
  ];
961
1265
  function getTargetStyleProp(attributeName) {
1266
+ if (attributeName === "containerClassName") {
1267
+ return "containerStyle";
1268
+ }
962
1269
  if (attributeName === "contentContainerClassName") {
963
1270
  return "contentContainerStyle";
964
1271
  }
@@ -973,6 +1280,33 @@ function getTargetStyleProp(attributeName) {
973
1280
  }
974
1281
  return "style";
975
1282
  }
1283
+ function getComponentModifierSupport(jsxElement, t) {
1284
+ if (!t.isJSXOpeningElement(jsxElement)) {
1285
+ return null;
1286
+ }
1287
+ const name = jsxElement.name;
1288
+ let componentName = null;
1289
+ if (t.isJSXIdentifier(name)) {
1290
+ componentName = name.name;
1291
+ }
1292
+ if (t.isJSXMemberExpression(name)) {
1293
+ const property = name.property;
1294
+ if (t.isJSXIdentifier(property)) {
1295
+ componentName = property.name;
1296
+ }
1297
+ }
1298
+ if (!componentName) {
1299
+ return null;
1300
+ }
1301
+ switch (componentName) {
1302
+ case "Pressable":
1303
+ return { component: "Pressable", supportedModifiers: ["active", "hover", "focus", "disabled"] };
1304
+ case "TextInput":
1305
+ return { component: "TextInput", supportedModifiers: ["focus", "disabled"] };
1306
+ default:
1307
+ return null;
1308
+ }
1309
+ }
976
1310
  function processDynamicExpression(expression, state, t) {
977
1311
  if (t.isTemplateLiteral(expression)) {
978
1312
  return processTemplateLiteral(expression, state, t);
@@ -1069,6 +1403,77 @@ function processStringOrExpression(node, state, t) {
1069
1403
  }
1070
1404
  return null;
1071
1405
  }
1406
+ function processStaticClassNameWithModifiers(className, state, t) {
1407
+ const { baseClasses, modifierClasses } = splitModifierClasses(className);
1408
+ let baseStyleExpression = null;
1409
+ if (baseClasses.length > 0) {
1410
+ const baseClassName = baseClasses.join(" ");
1411
+ const baseStyleObject = parseClassName2(baseClassName, state.customColors);
1412
+ const baseStyleKey = generateStyleKey2(baseClassName);
1413
+ state.styleRegistry.set(baseStyleKey, baseStyleObject);
1414
+ baseStyleExpression = t.memberExpression(t.identifier(STYLES_IDENTIFIER), t.identifier(baseStyleKey));
1415
+ }
1416
+ const modifiersByType = /* @__PURE__ */ new Map();
1417
+ for (const mod of modifierClasses) {
1418
+ if (!modifiersByType.has(mod.modifier)) {
1419
+ modifiersByType.set(mod.modifier, []);
1420
+ }
1421
+ const modGroup = modifiersByType.get(mod.modifier);
1422
+ if (modGroup) {
1423
+ modGroup.push(mod);
1424
+ }
1425
+ }
1426
+ const styleArrayElements = [];
1427
+ if (baseStyleExpression) {
1428
+ styleArrayElements.push(baseStyleExpression);
1429
+ }
1430
+ for (const [modifierType, modifiers] of modifiersByType) {
1431
+ const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
1432
+ const modifierStyleObject = parseClassName2(modifierClassNames, state.customColors);
1433
+ const modifierStyleKey = generateStyleKey2(`${modifierType}_${modifierClassNames}`);
1434
+ state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
1435
+ const stateProperty = getStatePropertyForModifier(modifierType);
1436
+ const conditionalExpression = t.logicalExpression(
1437
+ "&&",
1438
+ t.identifier(stateProperty),
1439
+ t.memberExpression(t.identifier(STYLES_IDENTIFIER), t.identifier(modifierStyleKey))
1440
+ );
1441
+ styleArrayElements.push(conditionalExpression);
1442
+ }
1443
+ if (styleArrayElements.length === 1) {
1444
+ return styleArrayElements[0];
1445
+ }
1446
+ return t.arrayExpression(styleArrayElements);
1447
+ }
1448
+ function getStatePropertyForModifier(modifier) {
1449
+ switch (modifier) {
1450
+ case "active":
1451
+ return "pressed";
1452
+ case "hover":
1453
+ return "hovered";
1454
+ case "focus":
1455
+ return "focused";
1456
+ case "disabled":
1457
+ return "disabled";
1458
+ default:
1459
+ return "pressed";
1460
+ }
1461
+ }
1462
+ function createStyleFunction(styleExpression, modifierTypes, t) {
1463
+ const paramProperties = [];
1464
+ const usedStateProps = /* @__PURE__ */ new Set();
1465
+ for (const modifierType of modifierTypes) {
1466
+ const stateProperty = getStatePropertyForModifier(modifierType);
1467
+ if (!usedStateProps.has(stateProperty)) {
1468
+ usedStateProps.add(stateProperty);
1469
+ paramProperties.push(
1470
+ t.objectProperty(t.identifier(stateProperty), t.identifier(stateProperty), false, true)
1471
+ );
1472
+ }
1473
+ }
1474
+ const param = t.objectPattern(paramProperties);
1475
+ return t.arrowFunctionExpression([param], styleExpression);
1476
+ }
1072
1477
  function reactNativeTailwindBabelPlugin({
1073
1478
  types: t
1074
1479
  }) {
@@ -1126,6 +1531,69 @@ function reactNativeTailwindBabelPlugin({
1126
1531
  return;
1127
1532
  }
1128
1533
  state.hasClassNames = true;
1534
+ const { baseClasses, modifierClasses } = splitModifierClasses(className);
1535
+ if (modifierClasses.length > 0) {
1536
+ const jsxOpeningElement = path2.parent;
1537
+ const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
1538
+ if (componentSupport) {
1539
+ const usedModifiers = Array.from(new Set(modifierClasses.map((m) => m.modifier)));
1540
+ const unsupportedModifiers = usedModifiers.filter(
1541
+ (mod) => !componentSupport.supportedModifiers.includes(mod)
1542
+ );
1543
+ if (unsupportedModifiers.length > 0) {
1544
+ if (process.env.NODE_ENV !== "production") {
1545
+ console.warn(
1546
+ `[react-native-tailwind] Modifiers (${unsupportedModifiers.map((m) => `${m}:`).join(", ")}) are not supported on ${componentSupport.component} component at ${state.file.opts.filename ?? "unknown"}. Supported modifiers: ${componentSupport.supportedModifiers.join(", ")}`
1547
+ );
1548
+ }
1549
+ const supportedModifierClasses = modifierClasses.filter(
1550
+ (m) => componentSupport.supportedModifiers.includes(m.modifier)
1551
+ );
1552
+ if (supportedModifierClasses.length === 0) {
1553
+ } else {
1554
+ const filteredClassName = baseClasses.join(" ") + " " + supportedModifierClasses.map((m) => `${m.modifier}:${m.baseClass}`).join(" ");
1555
+ const styleExpression = processStaticClassNameWithModifiers(
1556
+ filteredClassName.trim(),
1557
+ state,
1558
+ t
1559
+ );
1560
+ const modifierTypes = Array.from(new Set(supportedModifierClasses.map((m) => m.modifier)));
1561
+ const styleFunctionExpression = createStyleFunction(styleExpression, modifierTypes, t);
1562
+ const parent2 = path2.parent;
1563
+ const styleAttribute2 = parent2.attributes.find(
1564
+ (attr) => t.isJSXAttribute(attr) && attr.name.name === targetStyleProp
1565
+ );
1566
+ if (styleAttribute2) {
1567
+ mergeStyleFunctionAttribute(path2, styleAttribute2, styleFunctionExpression, t);
1568
+ } else {
1569
+ replaceWithStyleFunctionAttribute(path2, styleFunctionExpression, targetStyleProp, t);
1570
+ }
1571
+ return;
1572
+ }
1573
+ } else {
1574
+ const styleExpression = processStaticClassNameWithModifiers(className, state, t);
1575
+ const modifierTypes = usedModifiers;
1576
+ const styleFunctionExpression = createStyleFunction(styleExpression, modifierTypes, t);
1577
+ const parent2 = path2.parent;
1578
+ const styleAttribute2 = parent2.attributes.find(
1579
+ (attr) => t.isJSXAttribute(attr) && attr.name.name === targetStyleProp
1580
+ );
1581
+ if (styleAttribute2) {
1582
+ mergeStyleFunctionAttribute(path2, styleAttribute2, styleFunctionExpression, t);
1583
+ } else {
1584
+ replaceWithStyleFunctionAttribute(path2, styleFunctionExpression, targetStyleProp, t);
1585
+ }
1586
+ return;
1587
+ }
1588
+ } else {
1589
+ if (process.env.NODE_ENV !== "production") {
1590
+ const usedModifiers = Array.from(new Set(modifierClasses.map((m) => m.modifier)));
1591
+ console.warn(
1592
+ `[react-native-tailwind] Modifiers (${usedModifiers.map((m) => `${m}:`).join(", ")}) can only be used on compatible components (Pressable, TextInput). Found on unsupported element at ${state.file.opts.filename ?? "unknown"}`
1593
+ );
1594
+ }
1595
+ }
1596
+ }
1129
1597
  const styleObject = parseClassName2(className, state.customColors);
1130
1598
  const styleKey = generateStyleKey2(className);
1131
1599
  state.styleRegistry.set(styleKey, styleObject);
@@ -1219,6 +1687,31 @@ function mergeDynamicStyleAttribute(classNamePath, styleAttribute, result, t) {
1219
1687
  styleAttribute.value = t.jsxExpressionContainer(styleArray);
1220
1688
  classNamePath.remove();
1221
1689
  }
1690
+ function replaceWithStyleFunctionAttribute(classNamePath, styleFunctionExpression, targetStyleProp, t) {
1691
+ const styleAttribute = t.jsxAttribute(
1692
+ t.jsxIdentifier(targetStyleProp),
1693
+ t.jsxExpressionContainer(styleFunctionExpression)
1694
+ );
1695
+ classNamePath.replaceWith(styleAttribute);
1696
+ }
1697
+ function mergeStyleFunctionAttribute(classNamePath, styleAttribute, styleFunctionExpression, t) {
1698
+ const existingStyle = styleAttribute.value.expression;
1699
+ if (t.isArrowFunctionExpression(existingStyle) || t.isFunctionExpression(existingStyle)) {
1700
+ const paramIdentifier = t.identifier("_state");
1701
+ const newFunctionCall = t.callExpression(styleFunctionExpression, [paramIdentifier]);
1702
+ const existingFunctionCall = t.callExpression(existingStyle, [paramIdentifier]);
1703
+ const mergedArray = t.arrayExpression([newFunctionCall, existingFunctionCall]);
1704
+ const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
1705
+ styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
1706
+ } else {
1707
+ const paramIdentifier = t.identifier("_state");
1708
+ const functionCall = t.callExpression(styleFunctionExpression, [paramIdentifier]);
1709
+ const mergedArray = t.arrayExpression([functionCall, existingStyle]);
1710
+ const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
1711
+ styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
1712
+ }
1713
+ classNamePath.remove();
1714
+ }
1222
1715
  function injectStyles(path2, styleRegistry, t) {
1223
1716
  const styleProperties = [];
1224
1717
  for (const [key, styleObject] of styleRegistry) {