@mgcrea/react-native-tailwind 0.5.1 → 0.6.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.
package/README.md CHANGED
@@ -858,6 +858,108 @@ Use `aspect-[width/height]` for custom ratios:
858
858
 
859
859
  > **Note:** The aspect ratio is calculated as `width / height`. When combined with `w-full`, the height will be automatically calculated to maintain the ratio.
860
860
 
861
+ ### Transforms
862
+
863
+ Apply 2D and 3D transformations to views with React Native's transform API. All transforms compile to optimized transform arrays at build time:
864
+
865
+ **Scale:**
866
+
867
+ - `scale-{value}` — Scale uniformly (both X and Y)
868
+ - `scale-x-{value}`, `scale-y-{value}` — Scale on specific axis
869
+ - **Values:** `0`, `50`, `75`, `90`, `95`, `100`, `105`, `110`, `125`, `150`, `200`
870
+ - **Arbitrary:** `scale-[1.23]`, `scale-x-[0.5]`, `scale-y-[2.5]`
871
+
872
+ **Rotate:**
873
+
874
+ - `rotate-{degrees}`, `-rotate-{degrees}` — Rotate in 2D
875
+ - `rotate-x-{degrees}`, `rotate-y-{degrees}`, `rotate-z-{degrees}` — Rotate on specific axis
876
+ - **Values:** `0`, `1`, `2`, `3`, `6`, `12`, `45`, `90`, `180`
877
+ - **Arbitrary:** `rotate-[37deg]`, `-rotate-[15deg]`, `rotate-x-[30deg]`
878
+
879
+ **Translate:**
880
+
881
+ - `translate-x-{spacing}`, `translate-y-{spacing}` — Move on specific axis
882
+ - `-translate-x-{spacing}`, `-translate-y-{spacing}` — Negative translation
883
+ - **Values:** Uses spacing scale (same as `m-*`, `p-*`)
884
+ - **Arbitrary:** `translate-x-[50px]`, `translate-y-[100px]`, `translate-x-[50%]`
885
+
886
+ **Skew:**
887
+
888
+ - `skew-x-{degrees}`, `skew-y-{degrees}` — Skew on specific axis
889
+ - `-skew-x-{degrees}`, `-skew-y-{degrees}` — Negative skew
890
+ - **Values:** `0`, `1`, `2`, `3`, `6`, `12`
891
+ - **Arbitrary:** `skew-x-[15deg]`, `-skew-y-[8deg]`
892
+
893
+ **Perspective:**
894
+
895
+ - `perspective-{value}` — Apply perspective transformation
896
+ - **Values:** `0`, `100`, `200`, `300`, `400`, `500`, `600`, `700`, `800`, `900`, `1000`
897
+ - **Arbitrary:** `perspective-[1500]`, `perspective-[2000]`
898
+
899
+ **Examples:**
900
+
901
+ ```tsx
902
+ // Scale
903
+ <View className="scale-110 p-4">
904
+ {/* 110% scale (1.1x larger) */}
905
+ <Text>Scaled content</Text>
906
+ </View>
907
+
908
+ // Rotate
909
+ <View className="rotate-45 w-16 h-16 bg-blue-500" />
910
+
911
+ // Translate
912
+ <View className="translate-x-4 translate-y-2 bg-red-500 p-4">
913
+ {/* Moved 16px right, 8px down */}
914
+ </View>
915
+
916
+ // Arbitrary values
917
+ <View className="scale-[1.23] w-16 h-16 bg-green-500" />
918
+ <View className="rotate-[37deg] w-16 h-16 bg-purple-500" />
919
+ <View className="translate-x-[50px] bg-orange-500 p-4" />
920
+
921
+ // Negative values
922
+ <View className="-rotate-45 w-16 h-16 bg-pink-500" />
923
+ <View className="-translate-x-4 -translate-y-2 bg-indigo-500 p-4" />
924
+
925
+ // 3D rotation
926
+ <View className="rotate-x-45 w-16 h-16 bg-yellow-500" />
927
+ <View className="rotate-y-30 w-16 h-16 bg-teal-500" />
928
+
929
+ // Skew
930
+ <View className="skew-x-6 w-16 h-16 bg-cyan-500" />
931
+
932
+ // Perspective
933
+ <View className="perspective-500">
934
+ <View className="rotate-x-45 w-16 h-16 bg-blue-500" />
935
+ </View>
936
+ ```
937
+
938
+ **Multiple Transforms Limitation:**
939
+
940
+ Due to the current architecture, multiple transform classes on the same element will overwrite each other. For example:
941
+
942
+ ```tsx
943
+ // ❌ Only rotate-45 will apply (overwrites scale-110)
944
+ <View className="scale-110 rotate-45 w-16 h-16 bg-blue-500" />
945
+
946
+ // ✅ Workaround: Use nested Views for multiple transforms
947
+ <View className="scale-110">
948
+ <View className="rotate-45">
949
+ <View className="w-16 h-16 bg-blue-500" />
950
+ </View>
951
+ </View>
952
+ ```
953
+
954
+ This limitation exists because the current parser architecture uses `Object.assign()` which overwrites the `transform` property when multiple transform classes are present. This will be addressed in a future update by modifying the Babel plugin to detect multiple transform classes and generate style arrays.
955
+
956
+ **What's Not Supported:**
957
+
958
+ - `transform-origin` — Not available in React Native (transforms always use center as origin)
959
+ - Multiple transforms on one element — Use nested Views (see workaround above)
960
+
961
+ > **Note:** All transform parsing happens at compile-time with zero runtime overhead. Each transform compiles to a React Native transform array: `transform: [{ scale: 1.1 }]`, `transform: [{ rotate: '45deg' }]`, etc.
962
+
861
963
  ### Sizing
862
964
 
863
965
  - `w-{size}`, `h-{size}` — Width/height
@@ -889,6 +991,12 @@ Use arbitrary values for custom sizes, spacing, and borders not in the preset sc
889
991
  - **Sizing:** `w-[...]`, `h-[...]`, `min-w-[...]`, `min-h-[...]`, `max-w-[...]`, `max-h-[...]` (px and %)
890
992
  - **Border width:** `border-[...]`, `border-t-[...]`, `border-r-[...]`, `border-b-[...]`, `border-l-[...]` (px only)
891
993
  - **Border radius:** `rounded-[...]`, `rounded-t-[...]`, `rounded-tl-[...]`, etc. (px only)
994
+ - **Transforms:**
995
+ - **Scale:** `scale-[...]`, `scale-x-[...]`, `scale-y-[...]` (number only, e.g., `[1.23]`)
996
+ - **Rotate:** `rotate-[...]`, `rotate-x-[...]`, `rotate-y-[...]`, `rotate-z-[...]` (deg only, e.g., `[37deg]`)
997
+ - **Translate:** `translate-x-[...]`, `translate-y-[...]` (px or %, e.g., `[50px]` or `[50%]`)
998
+ - **Skew:** `skew-x-[...]`, `skew-y-[...]` (deg only, e.g., `[15deg]`)
999
+ - **Perspective:** `perspective-[...]` (number only, e.g., `[1500]`)
892
1000
 
893
1001
  **Formats:**
894
1002
 
@@ -429,6 +429,9 @@ function parseColor(cls, customColors) {
429
429
  };
430
430
  if (cls.startsWith("bg-")) {
431
431
  const colorKey = cls.substring(3);
432
+ if (colorKey.startsWith("[") && !colorKey.startsWith("[#")) {
433
+ return null;
434
+ }
432
435
  const color = parseColorWithOpacity(colorKey);
433
436
  if (color) {
434
437
  return { backgroundColor: color };
@@ -436,6 +439,9 @@ function parseColor(cls, customColors) {
436
439
  }
437
440
  if (cls.startsWith("text-")) {
438
441
  const colorKey = cls.substring(5);
442
+ if (colorKey.startsWith("[") && !colorKey.startsWith("[#")) {
443
+ return null;
444
+ }
439
445
  const color = parseColorWithOpacity(colorKey);
440
446
  if (color) {
441
447
  return { color };
@@ -443,6 +449,9 @@ function parseColor(cls, customColors) {
443
449
  }
444
450
  if (cls.startsWith("border-") && !cls.match(/^border-[0-9]/)) {
445
451
  const colorKey = cls.substring(7);
452
+ if (colorKey.startsWith("[") && !colorKey.startsWith("[#")) {
453
+ return null;
454
+ }
446
455
  const color = parseColorWithOpacity(colorKey);
447
456
  if (color) {
448
457
  return { borderColor: color };
@@ -452,6 +461,40 @@ function parseColor(cls, customColors) {
452
461
  }
453
462
 
454
463
  // src/parser/layout.ts
464
+ function parseArbitraryInset(value) {
465
+ const pxMatch = value.match(/^\[(-?\d+)(?:px)?\]$/);
466
+ if (pxMatch) {
467
+ return parseInt(pxMatch[1], 10);
468
+ }
469
+ const percentMatch = value.match(/^\[(-?\d+(?:\.\d+)?)%\]$/);
470
+ if (percentMatch) {
471
+ return `${percentMatch[1]}%`;
472
+ }
473
+ if (value.startsWith("[") && value.endsWith("]")) {
474
+ if (process.env.NODE_ENV !== "production") {
475
+ console.warn(
476
+ `[react-native-tailwind] Unsupported arbitrary inset unit: ${value}. Only px and % are supported.`
477
+ );
478
+ }
479
+ return null;
480
+ }
481
+ return null;
482
+ }
483
+ function parseArbitraryZIndex(value) {
484
+ const zMatch = value.match(/^\[(-?\d+)\]$/);
485
+ if (zMatch) {
486
+ return parseInt(zMatch[1], 10);
487
+ }
488
+ if (value.startsWith("[") && value.endsWith("]")) {
489
+ if (process.env.NODE_ENV !== "production") {
490
+ console.warn(
491
+ `[react-native-tailwind] Invalid arbitrary z-index: ${value}. Only integers are supported.`
492
+ );
493
+ }
494
+ return null;
495
+ }
496
+ return null;
497
+ }
455
498
  var DISPLAY_MAP = {
456
499
  flex: { display: "flex" },
457
500
  hidden: { display: "none" }
@@ -550,6 +593,10 @@ var INSET_SCALE = {
550
593
  function parseLayout(cls) {
551
594
  if (cls.startsWith("z-")) {
552
595
  const zKey = cls.substring(2);
596
+ const arbitraryZ = parseArbitraryZIndex(zKey);
597
+ if (arbitraryZ !== null) {
598
+ return { zIndex: arbitraryZ };
599
+ }
553
600
  const zValue = Z_INDEX_SCALE[zKey];
554
601
  if (zValue !== void 0) {
555
602
  return { zIndex: zValue };
@@ -560,6 +607,10 @@ function parseLayout(cls) {
560
607
  if (topKey === "auto") {
561
608
  return {};
562
609
  }
610
+ const arbitraryTop = parseArbitraryInset(topKey);
611
+ if (arbitraryTop !== null) {
612
+ return { top: arbitraryTop };
613
+ }
563
614
  const topValue = INSET_SCALE[topKey];
564
615
  if (topValue !== void 0) {
565
616
  return { top: topValue };
@@ -570,6 +621,10 @@ function parseLayout(cls) {
570
621
  if (rightKey === "auto") {
571
622
  return {};
572
623
  }
624
+ const arbitraryRight = parseArbitraryInset(rightKey);
625
+ if (arbitraryRight !== null) {
626
+ return { right: arbitraryRight };
627
+ }
573
628
  const rightValue = INSET_SCALE[rightKey];
574
629
  if (rightValue !== void 0) {
575
630
  return { right: rightValue };
@@ -580,6 +635,10 @@ function parseLayout(cls) {
580
635
  if (bottomKey === "auto") {
581
636
  return {};
582
637
  }
638
+ const arbitraryBottom = parseArbitraryInset(bottomKey);
639
+ if (arbitraryBottom !== null) {
640
+ return { bottom: arbitraryBottom };
641
+ }
583
642
  const bottomValue = INSET_SCALE[bottomKey];
584
643
  if (bottomValue !== void 0) {
585
644
  return { bottom: bottomValue };
@@ -590,20 +649,21 @@ function parseLayout(cls) {
590
649
  if (leftKey === "auto") {
591
650
  return {};
592
651
  }
652
+ const arbitraryLeft = parseArbitraryInset(leftKey);
653
+ if (arbitraryLeft !== null) {
654
+ return { left: arbitraryLeft };
655
+ }
593
656
  const leftValue = INSET_SCALE[leftKey];
594
657
  if (leftValue !== void 0) {
595
658
  return { left: leftValue };
596
659
  }
597
660
  }
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
661
  if (cls.startsWith("inset-x-")) {
606
662
  const insetKey = cls.substring(8);
663
+ const arbitraryInset = parseArbitraryInset(insetKey);
664
+ if (arbitraryInset !== null) {
665
+ return { left: arbitraryInset, right: arbitraryInset };
666
+ }
607
667
  const insetValue = INSET_SCALE[insetKey];
608
668
  if (insetValue !== void 0) {
609
669
  return { left: insetValue, right: insetValue };
@@ -611,11 +671,26 @@ function parseLayout(cls) {
611
671
  }
612
672
  if (cls.startsWith("inset-y-")) {
613
673
  const insetKey = cls.substring(8);
674
+ const arbitraryInset = parseArbitraryInset(insetKey);
675
+ if (arbitraryInset !== null) {
676
+ return { top: arbitraryInset, bottom: arbitraryInset };
677
+ }
614
678
  const insetValue = INSET_SCALE[insetKey];
615
679
  if (insetValue !== void 0) {
616
680
  return { top: insetValue, bottom: insetValue };
617
681
  }
618
682
  }
683
+ if (cls.startsWith("inset-")) {
684
+ const insetKey = cls.substring(6);
685
+ const arbitraryInset = parseArbitraryInset(insetKey);
686
+ if (arbitraryInset !== null) {
687
+ return { top: arbitraryInset, right: arbitraryInset, bottom: arbitraryInset, left: arbitraryInset };
688
+ }
689
+ const insetValue = INSET_SCALE[insetKey];
690
+ if (insetValue !== void 0) {
691
+ return { top: insetValue, right: insetValue, bottom: insetValue, left: insetValue };
692
+ }
693
+ }
619
694
  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;
620
695
  }
621
696
 
@@ -984,6 +1059,284 @@ function getPaddingStyle(dir, value) {
984
1059
  }
985
1060
  }
986
1061
 
1062
+ // src/parser/transforms.ts
1063
+ var SCALE_MAP = {
1064
+ 0: 0,
1065
+ 50: 0.5,
1066
+ 75: 0.75,
1067
+ 90: 0.9,
1068
+ 95: 0.95,
1069
+ 100: 1,
1070
+ 105: 1.05,
1071
+ 110: 1.1,
1072
+ 125: 1.25,
1073
+ 150: 1.5,
1074
+ 200: 2
1075
+ };
1076
+ var ROTATE_MAP = {
1077
+ 0: 0,
1078
+ 1: 1,
1079
+ 2: 2,
1080
+ 3: 3,
1081
+ 6: 6,
1082
+ 12: 12,
1083
+ 45: 45,
1084
+ 90: 90,
1085
+ 180: 180
1086
+ };
1087
+ var SKEW_MAP = {
1088
+ 0: 0,
1089
+ 1: 1,
1090
+ 2: 2,
1091
+ 3: 3,
1092
+ 6: 6,
1093
+ 12: 12
1094
+ };
1095
+ var PERSPECTIVE_SCALE = {
1096
+ 0: 0,
1097
+ 100: 100,
1098
+ 200: 200,
1099
+ 300: 300,
1100
+ 400: 400,
1101
+ 500: 500,
1102
+ 600: 600,
1103
+ 700: 700,
1104
+ 800: 800,
1105
+ 900: 900,
1106
+ 1e3: 1e3
1107
+ };
1108
+ function parseArbitraryScale(value) {
1109
+ const scaleMatch = value.match(/^\[(-?\d+(?:\.\d+)?)\]$/);
1110
+ if (scaleMatch) {
1111
+ return parseFloat(scaleMatch[1]);
1112
+ }
1113
+ if (value.startsWith("[") && value.endsWith("]")) {
1114
+ if (process.env.NODE_ENV !== "production") {
1115
+ console.warn(
1116
+ `[react-native-tailwind] Invalid arbitrary scale value: ${value}. Only numbers are supported (e.g., [1.5], [0.75]).`
1117
+ );
1118
+ }
1119
+ return null;
1120
+ }
1121
+ return null;
1122
+ }
1123
+ function parseArbitraryRotation(value) {
1124
+ const rotateMatch = value.match(/^\[(-?\d+(?:\.\d+)?)deg\]$/);
1125
+ if (rotateMatch) {
1126
+ return `${rotateMatch[1]}deg`;
1127
+ }
1128
+ if (value.startsWith("[") && value.endsWith("]")) {
1129
+ if (process.env.NODE_ENV !== "production") {
1130
+ console.warn(
1131
+ `[react-native-tailwind] Invalid arbitrary rotation value: ${value}. Only deg unit is supported (e.g., [45deg], [-15deg]).`
1132
+ );
1133
+ }
1134
+ return null;
1135
+ }
1136
+ return null;
1137
+ }
1138
+ function parseArbitraryTranslation(value) {
1139
+ const pxMatch = value.match(/^\[(-?\d+)(?:px)?\]$/);
1140
+ if (pxMatch) {
1141
+ return parseInt(pxMatch[1], 10);
1142
+ }
1143
+ const percentMatch = value.match(/^\[(-?\d+(?:\.\d+)?)%\]$/);
1144
+ if (percentMatch) {
1145
+ return `${percentMatch[1]}%`;
1146
+ }
1147
+ if (value.startsWith("[") && value.endsWith("]")) {
1148
+ if (process.env.NODE_ENV !== "production") {
1149
+ console.warn(
1150
+ `[react-native-tailwind] Unsupported arbitrary translation unit: ${value}. Only px and % are supported.`
1151
+ );
1152
+ }
1153
+ return null;
1154
+ }
1155
+ return null;
1156
+ }
1157
+ function parseArbitraryPerspective(value) {
1158
+ const perspectiveMatch = value.match(/^\[(-?\d+)\]$/);
1159
+ if (perspectiveMatch) {
1160
+ return parseInt(perspectiveMatch[1], 10);
1161
+ }
1162
+ if (value.startsWith("[") && value.endsWith("]")) {
1163
+ if (process.env.NODE_ENV !== "production") {
1164
+ console.warn(
1165
+ `[react-native-tailwind] Invalid arbitrary perspective value: ${value}. Only integers are supported (e.g., [1500]).`
1166
+ );
1167
+ }
1168
+ return null;
1169
+ }
1170
+ return null;
1171
+ }
1172
+ function parseTransform(cls) {
1173
+ if (cls.startsWith("origin-")) {
1174
+ if (process.env.NODE_ENV !== "production") {
1175
+ console.warn(
1176
+ `[react-native-tailwind] transform-origin is not supported in React Native. Class "${cls}" will be ignored.`
1177
+ );
1178
+ }
1179
+ return null;
1180
+ }
1181
+ if (cls.startsWith("scale-")) {
1182
+ const scaleKey = cls.substring(6);
1183
+ const arbitraryScale = parseArbitraryScale(scaleKey);
1184
+ if (arbitraryScale !== null) {
1185
+ return { transform: [{ scale: arbitraryScale }] };
1186
+ }
1187
+ const scaleValue = SCALE_MAP[scaleKey];
1188
+ if (scaleValue !== void 0) {
1189
+ return { transform: [{ scale: scaleValue }] };
1190
+ }
1191
+ }
1192
+ if (cls.startsWith("scale-x-")) {
1193
+ const scaleKey = cls.substring(8);
1194
+ const arbitraryScale = parseArbitraryScale(scaleKey);
1195
+ if (arbitraryScale !== null) {
1196
+ return { transform: [{ scaleX: arbitraryScale }] };
1197
+ }
1198
+ const scaleValue = SCALE_MAP[scaleKey];
1199
+ if (scaleValue !== void 0) {
1200
+ return { transform: [{ scaleX: scaleValue }] };
1201
+ }
1202
+ }
1203
+ if (cls.startsWith("scale-y-")) {
1204
+ const scaleKey = cls.substring(8);
1205
+ const arbitraryScale = parseArbitraryScale(scaleKey);
1206
+ if (arbitraryScale !== null) {
1207
+ return { transform: [{ scaleY: arbitraryScale }] };
1208
+ }
1209
+ const scaleValue = SCALE_MAP[scaleKey];
1210
+ if (scaleValue !== void 0) {
1211
+ return { transform: [{ scaleY: scaleValue }] };
1212
+ }
1213
+ }
1214
+ if (cls.startsWith("rotate-") || cls.startsWith("-rotate-")) {
1215
+ const isNegative = cls.startsWith("-");
1216
+ const rotateKey = isNegative ? cls.substring(8) : cls.substring(7);
1217
+ const arbitraryRotate = parseArbitraryRotation(rotateKey);
1218
+ if (arbitraryRotate !== null) {
1219
+ const degrees = isNegative ? `-${arbitraryRotate}` : arbitraryRotate;
1220
+ return { transform: [{ rotate: degrees }] };
1221
+ }
1222
+ const rotateValue = ROTATE_MAP[rotateKey];
1223
+ if (rotateValue !== void 0) {
1224
+ const degrees = isNegative ? -rotateValue : rotateValue;
1225
+ return { transform: [{ rotate: `${degrees}deg` }] };
1226
+ }
1227
+ }
1228
+ if (cls.startsWith("rotate-x-") || cls.startsWith("-rotate-x-")) {
1229
+ const isNegative = cls.startsWith("-");
1230
+ const rotateKey = isNegative ? cls.substring(10) : cls.substring(9);
1231
+ const arbitraryRotate = parseArbitraryRotation(rotateKey);
1232
+ if (arbitraryRotate !== null) {
1233
+ const degrees = isNegative ? `-${arbitraryRotate}` : arbitraryRotate;
1234
+ return { transform: [{ rotateX: degrees }] };
1235
+ }
1236
+ const rotateValue = ROTATE_MAP[rotateKey];
1237
+ if (rotateValue !== void 0) {
1238
+ const degrees = isNegative ? -rotateValue : rotateValue;
1239
+ return { transform: [{ rotateX: `${degrees}deg` }] };
1240
+ }
1241
+ }
1242
+ if (cls.startsWith("rotate-y-") || cls.startsWith("-rotate-y-")) {
1243
+ const isNegative = cls.startsWith("-");
1244
+ const rotateKey = isNegative ? cls.substring(10) : cls.substring(9);
1245
+ const arbitraryRotate = parseArbitraryRotation(rotateKey);
1246
+ if (arbitraryRotate !== null) {
1247
+ const degrees = isNegative ? `-${arbitraryRotate}` : arbitraryRotate;
1248
+ return { transform: [{ rotateY: degrees }] };
1249
+ }
1250
+ const rotateValue = ROTATE_MAP[rotateKey];
1251
+ if (rotateValue !== void 0) {
1252
+ const degrees = isNegative ? -rotateValue : rotateValue;
1253
+ return { transform: [{ rotateY: `${degrees}deg` }] };
1254
+ }
1255
+ }
1256
+ if (cls.startsWith("rotate-z-") || cls.startsWith("-rotate-z-")) {
1257
+ const isNegative = cls.startsWith("-");
1258
+ const rotateKey = isNegative ? cls.substring(10) : cls.substring(9);
1259
+ const arbitraryRotate = parseArbitraryRotation(rotateKey);
1260
+ if (arbitraryRotate !== null) {
1261
+ const degrees = isNegative ? `-${arbitraryRotate}` : arbitraryRotate;
1262
+ return { transform: [{ rotateZ: degrees }] };
1263
+ }
1264
+ const rotateValue = ROTATE_MAP[rotateKey];
1265
+ if (rotateValue !== void 0) {
1266
+ const degrees = isNegative ? -rotateValue : rotateValue;
1267
+ return { transform: [{ rotateZ: `${degrees}deg` }] };
1268
+ }
1269
+ }
1270
+ if (cls.startsWith("translate-x-") || cls.startsWith("-translate-x-")) {
1271
+ const isNegative = cls.startsWith("-");
1272
+ const translateKey = isNegative ? cls.substring(13) : cls.substring(12);
1273
+ const arbitraryTranslate = parseArbitraryTranslation(translateKey);
1274
+ if (arbitraryTranslate !== null) {
1275
+ const value = typeof arbitraryTranslate === "number" ? isNegative ? -arbitraryTranslate : arbitraryTranslate : isNegative ? `-${arbitraryTranslate}` : arbitraryTranslate;
1276
+ return { transform: [{ translateX: value }] };
1277
+ }
1278
+ const translateValue = SPACING_SCALE[translateKey];
1279
+ if (translateValue !== void 0) {
1280
+ const value = isNegative ? -translateValue : translateValue;
1281
+ return { transform: [{ translateX: value }] };
1282
+ }
1283
+ }
1284
+ if (cls.startsWith("translate-y-") || cls.startsWith("-translate-y-")) {
1285
+ const isNegative = cls.startsWith("-");
1286
+ const translateKey = isNegative ? cls.substring(13) : cls.substring(12);
1287
+ const arbitraryTranslate = parseArbitraryTranslation(translateKey);
1288
+ if (arbitraryTranslate !== null) {
1289
+ const value = typeof arbitraryTranslate === "number" ? isNegative ? -arbitraryTranslate : arbitraryTranslate : isNegative ? `-${arbitraryTranslate}` : arbitraryTranslate;
1290
+ return { transform: [{ translateY: value }] };
1291
+ }
1292
+ const translateValue = SPACING_SCALE[translateKey];
1293
+ if (translateValue !== void 0) {
1294
+ const value = isNegative ? -translateValue : translateValue;
1295
+ return { transform: [{ translateY: value }] };
1296
+ }
1297
+ }
1298
+ if (cls.startsWith("skew-x-") || cls.startsWith("-skew-x-")) {
1299
+ const isNegative = cls.startsWith("-");
1300
+ const skewKey = isNegative ? cls.substring(8) : cls.substring(7);
1301
+ const arbitrarySkew = parseArbitraryRotation(skewKey);
1302
+ if (arbitrarySkew !== null) {
1303
+ const degrees = isNegative ? `-${arbitrarySkew}` : arbitrarySkew;
1304
+ return { transform: [{ skewX: degrees }] };
1305
+ }
1306
+ const skewValue = SKEW_MAP[skewKey];
1307
+ if (skewValue !== void 0) {
1308
+ const degrees = isNegative ? -skewValue : skewValue;
1309
+ return { transform: [{ skewX: `${degrees}deg` }] };
1310
+ }
1311
+ }
1312
+ if (cls.startsWith("skew-y-") || cls.startsWith("-skew-y-")) {
1313
+ const isNegative = cls.startsWith("-");
1314
+ const skewKey = isNegative ? cls.substring(8) : cls.substring(7);
1315
+ const arbitrarySkew = parseArbitraryRotation(skewKey);
1316
+ if (arbitrarySkew !== null) {
1317
+ const degrees = isNegative ? `-${arbitrarySkew}` : arbitrarySkew;
1318
+ return { transform: [{ skewY: degrees }] };
1319
+ }
1320
+ const skewValue = SKEW_MAP[skewKey];
1321
+ if (skewValue !== void 0) {
1322
+ const degrees = isNegative ? -skewValue : skewValue;
1323
+ return { transform: [{ skewY: `${degrees}deg` }] };
1324
+ }
1325
+ }
1326
+ if (cls.startsWith("perspective-")) {
1327
+ const perspectiveKey = cls.substring(12);
1328
+ const arbitraryPerspective = parseArbitraryPerspective(perspectiveKey);
1329
+ if (arbitraryPerspective !== null) {
1330
+ return { transform: [{ perspective: arbitraryPerspective }] };
1331
+ }
1332
+ const perspectiveValue = PERSPECTIVE_SCALE[perspectiveKey];
1333
+ if (perspectiveValue !== void 0) {
1334
+ return { transform: [{ perspective: perspectiveValue }] };
1335
+ }
1336
+ }
1337
+ return null;
1338
+ }
1339
+
987
1340
  // src/parser/typography.ts
988
1341
  var FONT_SIZES = {
989
1342
  xs: 12,
@@ -1157,7 +1510,8 @@ function parseClass(cls, customColors) {
1157
1510
  parseTypography,
1158
1511
  parseSizing,
1159
1512
  parseShadow,
1160
- parseAspectRatio
1513
+ parseAspectRatio,
1514
+ parseTransform
1161
1515
  ];
1162
1516
  for (const parser of parsers) {
1163
1517
  const result = parser(cls);
@@ -0,0 +1,9 @@
1
+ // Bun Snapshot v1, https://bun.sh/docs/test/snapshots
2
+
3
+ exports[`ASPECT_RATIO_PRESETS should export aspect ratio presets 1`] = `
4
+ {
5
+ "aspect-auto": undefined,
6
+ "aspect-square": 1,
7
+ "aspect-video": 1.7777777777777777,
8
+ }
9
+ `;
@@ -0,0 +1,23 @@
1
+ // Bun Snapshot v1, https://bun.sh/docs/test/snapshots
2
+
3
+ exports[`BORDER_WIDTH_SCALE should export complete border width scale 1`] = `
4
+ {
5
+ "0": 0,
6
+ "2": 2,
7
+ "4": 4,
8
+ "8": 8,
9
+ }
10
+ `;
11
+
12
+ exports[`BORDER_RADIUS_SCALE should export complete border radius scale 1`] = `
13
+ {
14
+ "2xl": 16,
15
+ "3xl": 24,
16
+ "full": 9999,
17
+ "lg": 8,
18
+ "md": 6,
19
+ "none": 0,
20
+ "sm": 2,
21
+ "xl": 12,
22
+ }
23
+ `;