@mgcrea/react-native-tailwind 0.12.1 → 0.13.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 (82) hide show
  1. package/README.md +29 -2014
  2. package/dist/babel/index.cjs +1462 -1155
  3. package/dist/babel/plugin/componentScope.d.ts +26 -0
  4. package/dist/babel/plugin/componentScope.ts +87 -0
  5. package/dist/babel/plugin/state.d.ts +119 -0
  6. package/dist/babel/plugin/state.ts +177 -0
  7. package/dist/babel/plugin/visitors/className.d.ts +11 -0
  8. package/{src/babel/plugin.test.ts → dist/babel/plugin/visitors/className.test.ts} +74 -674
  9. package/dist/babel/plugin/visitors/className.ts +624 -0
  10. package/dist/babel/plugin/visitors/className.windowDimensions.test.ts +406 -0
  11. package/dist/babel/plugin/visitors/imports.d.ts +11 -0
  12. package/dist/babel/plugin/visitors/imports.test.ts +88 -0
  13. package/dist/babel/plugin/visitors/imports.ts +101 -0
  14. package/dist/babel/plugin/visitors/program.d.ts +15 -0
  15. package/dist/babel/plugin/visitors/program.test.ts +325 -0
  16. package/dist/babel/plugin/visitors/program.ts +99 -0
  17. package/dist/babel/plugin/visitors/tw.d.ts +16 -0
  18. package/dist/babel/plugin/visitors/tw.test.ts +620 -0
  19. package/dist/babel/plugin/visitors/tw.ts +148 -0
  20. package/dist/babel/plugin.d.ts +3 -96
  21. package/dist/babel/plugin.test.ts +470 -0
  22. package/dist/babel/plugin.ts +28 -963
  23. package/dist/babel/utils/colorSchemeModifierProcessing.ts +11 -0
  24. package/dist/babel/utils/componentSupport.test.ts +20 -7
  25. package/dist/babel/utils/componentSupport.ts +2 -0
  26. package/dist/babel/utils/modifierProcessing.ts +21 -0
  27. package/dist/babel/utils/platformModifierProcessing.ts +11 -0
  28. package/dist/babel/utils/styleInjection.d.ts +15 -0
  29. package/dist/babel/utils/styleInjection.ts +115 -0
  30. package/dist/babel/utils/twProcessing.ts +11 -0
  31. package/dist/babel/utils/windowDimensionsProcessing.d.ts +56 -0
  32. package/dist/babel/utils/windowDimensionsProcessing.ts +121 -0
  33. package/dist/components/TouchableOpacity.d.ts +35 -0
  34. package/dist/components/TouchableOpacity.js +1 -0
  35. package/dist/components/index.d.ts +3 -0
  36. package/dist/components/index.js +1 -0
  37. package/dist/config/markers.d.ts +5 -0
  38. package/dist/config/markers.js +1 -0
  39. package/dist/index.d.ts +2 -5
  40. package/dist/index.js +1 -1
  41. package/dist/parser/borders.d.ts +3 -1
  42. package/dist/parser/borders.js +1 -1
  43. package/dist/parser/borders.test.js +1 -1
  44. package/dist/parser/colors.js +1 -1
  45. package/dist/parser/colors.test.js +1 -1
  46. package/dist/parser/index.js +1 -1
  47. package/dist/parser/sizing.js +1 -1
  48. package/dist/runtime.cjs +1 -1
  49. package/dist/runtime.cjs.map +4 -4
  50. package/dist/runtime.js +1 -1
  51. package/dist/runtime.js.map +4 -4
  52. package/package.json +1 -1
  53. package/src/babel/plugin/componentScope.ts +87 -0
  54. package/src/babel/plugin/state.ts +177 -0
  55. package/src/babel/plugin/visitors/className.test.ts +1312 -0
  56. package/src/babel/plugin/visitors/className.ts +624 -0
  57. package/src/babel/plugin/visitors/className.windowDimensions.test.ts +406 -0
  58. package/src/babel/plugin/visitors/imports.test.ts +88 -0
  59. package/src/babel/plugin/visitors/imports.ts +101 -0
  60. package/src/babel/plugin/visitors/program.test.ts +325 -0
  61. package/src/babel/plugin/visitors/program.ts +99 -0
  62. package/src/babel/plugin/visitors/tw.test.ts +620 -0
  63. package/src/babel/plugin/visitors/tw.ts +148 -0
  64. package/src/babel/plugin.ts +28 -963
  65. package/src/babel/utils/colorSchemeModifierProcessing.ts +11 -0
  66. package/src/babel/utils/componentSupport.test.ts +20 -7
  67. package/src/babel/utils/componentSupport.ts +2 -0
  68. package/src/babel/utils/modifierProcessing.ts +21 -0
  69. package/src/babel/utils/platformModifierProcessing.ts +11 -0
  70. package/src/babel/utils/styleInjection.ts +115 -0
  71. package/src/babel/utils/twProcessing.ts +11 -0
  72. package/src/babel/utils/windowDimensionsProcessing.ts +121 -0
  73. package/src/components/TouchableOpacity.tsx +71 -0
  74. package/src/components/index.ts +3 -0
  75. package/src/config/markers.ts +5 -0
  76. package/src/index.ts +4 -5
  77. package/src/parser/borders.test.ts +58 -0
  78. package/src/parser/borders.ts +18 -3
  79. package/src/parser/colors.test.ts +249 -0
  80. package/src/parser/colors.ts +38 -0
  81. package/src/parser/index.ts +2 -2
  82. package/src/parser/sizing.ts +11 -0
@@ -391,3 +391,252 @@ describe("parseColor - opacity modifiers", () => {
391
391
  });
392
392
  });
393
393
  });
394
+
395
+ describe("parseColor - directional border colors", () => {
396
+ it("should parse directional border colors with preset values", () => {
397
+ expect(parseColor("border-t-red-500")).toEqual({ borderTopColor: COLORS["red-500"] });
398
+ expect(parseColor("border-r-blue-500")).toEqual({ borderRightColor: COLORS["blue-500"] });
399
+ expect(parseColor("border-b-green-500")).toEqual({ borderBottomColor: COLORS["green-500"] });
400
+ expect(parseColor("border-l-yellow-500")).toEqual({ borderLeftColor: COLORS["yellow-500"] });
401
+ });
402
+
403
+ it("should parse directional border colors with basic values", () => {
404
+ expect(parseColor("border-t-white")).toEqual({ borderTopColor: "#FFFFFF" });
405
+ expect(parseColor("border-r-black")).toEqual({ borderRightColor: "#000000" });
406
+ expect(parseColor("border-b-transparent")).toEqual({ borderBottomColor: "transparent" });
407
+ expect(parseColor("border-l-white")).toEqual({ borderLeftColor: "#FFFFFF" });
408
+ });
409
+
410
+ it("should parse directional border colors with arbitrary 6-digit hex values", () => {
411
+ expect(parseColor("border-t-[#ff0000]")).toEqual({ borderTopColor: "#ff0000" });
412
+ expect(parseColor("border-r-[#3B82F6]")).toEqual({ borderRightColor: "#3B82F6" });
413
+ expect(parseColor("border-b-[#00ff00]")).toEqual({ borderBottomColor: "#00ff00" });
414
+ expect(parseColor("border-l-[#cccccc]")).toEqual({ borderLeftColor: "#cccccc" });
415
+ });
416
+
417
+ it("should parse directional border colors with arbitrary 3-digit hex values", () => {
418
+ expect(parseColor("border-t-[#f00]")).toEqual({ borderTopColor: "#ff0000" });
419
+ expect(parseColor("border-r-[#abc]")).toEqual({ borderRightColor: "#aabbcc" });
420
+ expect(parseColor("border-b-[#123]")).toEqual({ borderBottomColor: "#112233" });
421
+ expect(parseColor("border-l-[#999]")).toEqual({ borderLeftColor: "#999999" });
422
+ });
423
+
424
+ it("should parse directional border colors with arbitrary 8-digit hex values (with alpha)", () => {
425
+ expect(parseColor("border-t-[#ff0000aa]")).toEqual({ borderTopColor: "#ff0000aa" });
426
+ expect(parseColor("border-r-[#0000FF50]")).toEqual({ borderRightColor: "#0000FF50" });
427
+ expect(parseColor("border-b-[#00FF0080]")).toEqual({ borderBottomColor: "#00FF0080" });
428
+ expect(parseColor("border-l-[#FFFFFF00]")).toEqual({ borderLeftColor: "#FFFFFF00" });
429
+ });
430
+
431
+ it("should parse directional border colors with opacity modifiers", () => {
432
+ expect(parseColor("border-t-red-500/50")).toEqual({
433
+ borderTopColor: applyOpacity(COLORS["red-500"], 50),
434
+ });
435
+ expect(parseColor("border-r-blue-500/80")).toEqual({
436
+ borderRightColor: applyOpacity(COLORS["blue-500"], 80),
437
+ });
438
+ expect(parseColor("border-b-green-500/30")).toEqual({
439
+ borderBottomColor: applyOpacity(COLORS["green-500"], 30),
440
+ });
441
+ expect(parseColor("border-l-black/25")).toEqual({
442
+ borderLeftColor: applyOpacity(COLORS.black, 25),
443
+ });
444
+ });
445
+
446
+ it("should parse directional border colors with arbitrary hex and opacity", () => {
447
+ expect(parseColor("border-t-[#ff0000]/50")).toEqual({ borderTopColor: "#FF000080" });
448
+ expect(parseColor("border-r-[#3B82F6]/80")).toEqual({ borderRightColor: "#3B82F6CC" });
449
+ expect(parseColor("border-b-[#abc]/60")).toEqual({ borderBottomColor: "#AABBCC99" });
450
+ expect(parseColor("border-l-[#000]/100")).toEqual({ borderLeftColor: "#000000FF" });
451
+ });
452
+
453
+ it("should parse directional border colors with custom colors", () => {
454
+ const customColors = {
455
+ "brand-primary": "#FF6B6B",
456
+ "brand-secondary": "#4ECDC4",
457
+ accent: "#FFE66D",
458
+ };
459
+
460
+ expect(parseColor("border-t-brand-primary", customColors)).toEqual({
461
+ borderTopColor: "#FF6B6B",
462
+ });
463
+ expect(parseColor("border-r-brand-secondary", customColors)).toEqual({
464
+ borderRightColor: "#4ECDC4",
465
+ });
466
+ expect(parseColor("border-b-accent", customColors)).toEqual({ borderBottomColor: "#FFE66D" });
467
+ expect(parseColor("border-l-brand-primary", customColors)).toEqual({
468
+ borderLeftColor: "#FF6B6B",
469
+ });
470
+ });
471
+
472
+ it("should parse directional border colors with custom colors and opacity", () => {
473
+ const customColors = { "brand-primary": "#FF6B6B" };
474
+ expect(parseColor("border-t-brand-primary/50", customColors)).toEqual({
475
+ borderTopColor: "#FF6B6B80",
476
+ });
477
+ expect(parseColor("border-l-brand-primary/75", customColors)).toEqual({
478
+ borderLeftColor: "#FF6B6BBF",
479
+ });
480
+ });
481
+
482
+ it("should not match border width classes", () => {
483
+ // These should be handled by parseBorder
484
+ expect(parseColor("border-t-2")).toBeNull();
485
+ expect(parseColor("border-r-4")).toBeNull();
486
+ expect(parseColor("border-b-8")).toBeNull();
487
+ expect(parseColor("border-l-0")).toBeNull();
488
+ });
489
+
490
+ it("should not match border width arbitrary values", () => {
491
+ // These should be handled by parseBorder
492
+ expect(parseColor("border-t-[3px]")).toBeNull();
493
+ expect(parseColor("border-r-[8px]")).toBeNull();
494
+ expect(parseColor("border-b-[5]")).toBeNull();
495
+ expect(parseColor("border-l-[10px]")).toBeNull();
496
+ });
497
+
498
+ it("should return null for invalid directional border color values", () => {
499
+ expect(parseColor("border-t-invalid")).toBeNull();
500
+ expect(parseColor("border-r-notacolor")).toBeNull();
501
+ expect(parseColor("border-b-xyz")).toBeNull();
502
+ expect(parseColor("border-l-wrongcolor")).toBeNull();
503
+ });
504
+
505
+ it("should handle all directions with same color", () => {
506
+ const color = COLORS["blue-500"];
507
+ expect(parseColor("border-t-blue-500")).toEqual({ borderTopColor: color });
508
+ expect(parseColor("border-r-blue-500")).toEqual({ borderRightColor: color });
509
+ expect(parseColor("border-b-blue-500")).toEqual({ borderBottomColor: color });
510
+ expect(parseColor("border-l-blue-500")).toEqual({ borderLeftColor: color });
511
+ });
512
+
513
+ it("should handle all color families for directional borders", () => {
514
+ const families = ["gray", "red", "blue", "green", "yellow", "purple", "pink", "orange", "indigo"];
515
+ families.forEach((family) => {
516
+ expect(parseColor(`border-t-${family}-500`)).toBeTruthy();
517
+ expect(parseColor(`border-r-${family}-500`)).toBeTruthy();
518
+ expect(parseColor(`border-b-${family}-500`)).toBeTruthy();
519
+ expect(parseColor(`border-l-${family}-500`)).toBeTruthy();
520
+ });
521
+ });
522
+
523
+ it("should handle directional borders with all opacity levels", () => {
524
+ expect(parseColor("border-t-black/0")).toEqual({ borderTopColor: "#00000000" });
525
+ expect(parseColor("border-t-black/25")).toEqual({ borderTopColor: "#00000040" });
526
+ expect(parseColor("border-t-black/50")).toEqual({ borderTopColor: "#00000080" });
527
+ expect(parseColor("border-t-black/75")).toEqual({ borderTopColor: "#000000BF" });
528
+ expect(parseColor("border-t-black/100")).toEqual({ borderTopColor: "#000000FF" });
529
+ });
530
+ });
531
+
532
+ describe("parseColor - border-x and border-y colors", () => {
533
+ it("should parse border-x colors (horizontal: left + right)", () => {
534
+ expect(parseColor("border-x-red-500")).toEqual({
535
+ borderLeftColor: COLORS["red-500"],
536
+ borderRightColor: COLORS["red-500"],
537
+ });
538
+ expect(parseColor("border-x-blue-500")).toEqual({
539
+ borderLeftColor: COLORS["blue-500"],
540
+ borderRightColor: COLORS["blue-500"],
541
+ });
542
+ });
543
+
544
+ it("should parse border-y colors (vertical: top + bottom)", () => {
545
+ expect(parseColor("border-y-green-500")).toEqual({
546
+ borderTopColor: COLORS["green-500"],
547
+ borderBottomColor: COLORS["green-500"],
548
+ });
549
+ expect(parseColor("border-y-yellow-500")).toEqual({
550
+ borderTopColor: COLORS["yellow-500"],
551
+ borderBottomColor: COLORS["yellow-500"],
552
+ });
553
+ });
554
+
555
+ it("should parse border-x with basic colors", () => {
556
+ expect(parseColor("border-x-white")).toEqual({
557
+ borderLeftColor: "#FFFFFF",
558
+ borderRightColor: "#FFFFFF",
559
+ });
560
+ expect(parseColor("border-x-black")).toEqual({
561
+ borderLeftColor: "#000000",
562
+ borderRightColor: "#000000",
563
+ });
564
+ });
565
+
566
+ it("should parse border-y with basic colors", () => {
567
+ expect(parseColor("border-y-white")).toEqual({
568
+ borderTopColor: "#FFFFFF",
569
+ borderBottomColor: "#FFFFFF",
570
+ });
571
+ expect(parseColor("border-y-transparent")).toEqual({
572
+ borderTopColor: "transparent",
573
+ borderBottomColor: "transparent",
574
+ });
575
+ });
576
+
577
+ it("should parse border-x with opacity", () => {
578
+ expect(parseColor("border-x-red-500/50")).toEqual({
579
+ borderLeftColor: applyOpacity(COLORS["red-500"], 50),
580
+ borderRightColor: applyOpacity(COLORS["red-500"], 50),
581
+ });
582
+ });
583
+
584
+ it("should parse border-y with opacity", () => {
585
+ expect(parseColor("border-y-blue-500/80")).toEqual({
586
+ borderTopColor: applyOpacity(COLORS["blue-500"], 80),
587
+ borderBottomColor: applyOpacity(COLORS["blue-500"], 80),
588
+ });
589
+ });
590
+
591
+ it("should parse border-x with arbitrary hex colors", () => {
592
+ expect(parseColor("border-x-[#ff0000]")).toEqual({
593
+ borderLeftColor: "#ff0000",
594
+ borderRightColor: "#ff0000",
595
+ });
596
+ expect(parseColor("border-x-[#abc]")).toEqual({
597
+ borderLeftColor: "#aabbcc",
598
+ borderRightColor: "#aabbcc",
599
+ });
600
+ });
601
+
602
+ it("should parse border-y with arbitrary hex colors", () => {
603
+ expect(parseColor("border-y-[#00ff00]")).toEqual({
604
+ borderTopColor: "#00ff00",
605
+ borderBottomColor: "#00ff00",
606
+ });
607
+ expect(parseColor("border-y-[#123]")).toEqual({
608
+ borderTopColor: "#112233",
609
+ borderBottomColor: "#112233",
610
+ });
611
+ });
612
+
613
+ it("should parse border-x with custom colors", () => {
614
+ const customColors = { "brand-primary": "#FF6B6B" };
615
+ expect(parseColor("border-x-brand-primary", customColors)).toEqual({
616
+ borderLeftColor: "#FF6B6B",
617
+ borderRightColor: "#FF6B6B",
618
+ });
619
+ });
620
+
621
+ it("should parse border-y with custom colors", () => {
622
+ const customColors = { accent: "#FFE66D" };
623
+ expect(parseColor("border-y-accent", customColors)).toEqual({
624
+ borderTopColor: "#FFE66D",
625
+ borderBottomColor: "#FFE66D",
626
+ });
627
+ });
628
+
629
+ it("should not match border-x/border-y width classes", () => {
630
+ expect(parseColor("border-x-2")).toBeNull();
631
+ expect(parseColor("border-y-4")).toBeNull();
632
+ expect(parseColor("border-x-0")).toBeNull();
633
+ expect(parseColor("border-y-8")).toBeNull();
634
+ });
635
+
636
+ it("should not match border-x/border-y arbitrary width values", () => {
637
+ expect(parseColor("border-x-[3px]")).toBeNull();
638
+ expect(parseColor("border-y-[5px]")).toBeNull();
639
+ expect(parseColor("border-x-[10]")).toBeNull();
640
+ expect(parseColor("border-y-[8px]")).toBeNull();
641
+ });
642
+ });
@@ -178,5 +178,43 @@ export function parseColor(cls: string, customColors?: Record<string, string>):
178
178
  }
179
179
  }
180
180
 
181
+ // Directional border colors: border-t-red-500, border-l-blue-500/50, border-r-[#ff0000]
182
+ const dirBorderMatch = cls.match(/^border-([trblxy])-(.+)$/);
183
+ if (dirBorderMatch) {
184
+ const dir = dirBorderMatch[1];
185
+ const colorKey = dirBorderMatch[2];
186
+
187
+ // Skip arbitrary values that don't look like colors (e.g., border-t-[3px] is width)
188
+ if (colorKey.startsWith("[") && !colorKey.startsWith("[#")) {
189
+ return null;
190
+ }
191
+
192
+ const color = parseColorWithOpacity(colorKey);
193
+ if (color) {
194
+ // Map direction to React Native property/properties
195
+ // x and y apply to multiple sides (RN doesn't have borderHorizontalColor/borderVerticalColor)
196
+ if (dir === "x") {
197
+ return {
198
+ borderLeftColor: color,
199
+ borderRightColor: color,
200
+ };
201
+ }
202
+ if (dir === "y") {
203
+ return {
204
+ borderTopColor: color,
205
+ borderBottomColor: color,
206
+ };
207
+ }
208
+
209
+ const propMap: Record<string, string> = {
210
+ t: "borderTopColor",
211
+ r: "borderRightColor",
212
+ b: "borderBottomColor",
213
+ l: "borderLeftColor",
214
+ };
215
+ return { [propMap[dir]]: color };
216
+ }
217
+ }
218
+
181
219
  return null;
182
220
  }
@@ -50,10 +50,10 @@ export function parseClassName(className: string, customTheme?: CustomTheme): St
50
50
  export function parseClass(cls: string, customTheme?: CustomTheme): StyleObject {
51
51
  // Try each parser in order
52
52
  // Note: parseBorder must come before parseColor to avoid border-[3px] being parsed as a color
53
- // parseColor and parseTypography get custom theme, others don't need it
53
+ // parseBorder, parseColor and parseTypography get custom theme
54
54
  const parsers: Array<(cls: string) => StyleObject | null> = [
55
55
  parseSpacing,
56
- parseBorder,
56
+ (cls: string) => parseBorder(cls, customTheme?.colors),
57
57
  (cls: string) => parseColor(cls, customTheme?.colors),
58
58
  parseLayout,
59
59
  (cls: string) => parseTypography(cls, customTheme?.fontFamily, customTheme?.fontSize),
@@ -2,6 +2,7 @@
2
2
  * Sizing utilities (width, height, min/max)
3
3
  */
4
4
 
5
+ import { RUNTIME_DIMENSIONS_MARKER } from "../config/markers";
5
6
  import type { StyleObject } from "../types";
6
7
 
7
8
  // Size scale (in pixels/percentages)
@@ -100,6 +101,11 @@ export function parseSizing(cls: string): StyleObject | null {
100
101
  if (cls.startsWith("w-")) {
101
102
  const sizeKey = cls.substring(2);
102
103
 
104
+ // Screen width (requires runtime hook)
105
+ if (sizeKey === "screen") {
106
+ return { width: `${RUNTIME_DIMENSIONS_MARKER}width}}` } as StyleObject;
107
+ }
108
+
103
109
  // Arbitrary values: w-[123px], w-[50%]
104
110
  const arbitrarySize = parseArbitrarySize(sizeKey);
105
111
  if (arbitrarySize !== null) {
@@ -128,6 +134,11 @@ export function parseSizing(cls: string): StyleObject | null {
128
134
  if (cls.startsWith("h-")) {
129
135
  const sizeKey = cls.substring(2);
130
136
 
137
+ // Screen height (requires runtime hook)
138
+ if (sizeKey === "screen") {
139
+ return { height: `${RUNTIME_DIMENSIONS_MARKER}height}}` } as StyleObject;
140
+ }
141
+
131
142
  // Arbitrary values: h-[123px], h-[50%]
132
143
  const arbitrarySize = parseArbitrarySize(sizeKey);
133
144
  if (arbitrarySize !== null) {