@mgcrea/react-native-tailwind 0.13.0 → 0.14.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 +21 -22
- package/dist/babel/index.cjs +342 -17
- package/dist/babel/plugin/state.d.ts +4 -0
- package/dist/babel/plugin/state.ts +8 -0
- package/dist/babel/plugin/visitors/className.test.ts +313 -0
- package/dist/babel/plugin/visitors/className.ts +36 -8
- package/dist/babel/plugin/visitors/imports.ts +16 -1
- package/dist/babel/plugin/visitors/program.ts +19 -2
- package/dist/babel/plugin/visitors/tw.test.ts +151 -0
- package/dist/babel/utils/directionalModifierProcessing.d.ts +34 -0
- package/dist/babel/utils/directionalModifierProcessing.ts +99 -0
- package/dist/babel/utils/styleInjection.d.ts +16 -0
- package/dist/babel/utils/styleInjection.ts +138 -7
- package/dist/babel/utils/twProcessing.d.ts +2 -0
- package/dist/babel/utils/twProcessing.ts +92 -3
- package/dist/parser/borders.js +1 -1
- package/dist/parser/borders.test.js +1 -1
- package/dist/parser/index.d.ts +2 -2
- package/dist/parser/index.js +1 -1
- package/dist/parser/layout.js +1 -1
- package/dist/parser/layout.test.js +1 -1
- package/dist/parser/modifiers.d.ts +32 -2
- package/dist/parser/modifiers.js +1 -1
- package/dist/parser/modifiers.test.js +1 -1
- package/dist/parser/spacing.d.ts +1 -1
- package/dist/parser/spacing.js +1 -1
- package/dist/parser/spacing.test.js +1 -1
- package/dist/parser/typography.test.js +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +3 -3
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +3 -3
- package/package.json +6 -6
- package/src/babel/plugin/state.ts +8 -0
- package/src/babel/plugin/visitors/className.test.ts +313 -0
- package/src/babel/plugin/visitors/className.ts +36 -8
- package/src/babel/plugin/visitors/imports.ts +16 -1
- package/src/babel/plugin/visitors/program.ts +19 -2
- package/src/babel/plugin/visitors/tw.test.ts +151 -0
- package/src/babel/utils/directionalModifierProcessing.ts +99 -0
- package/src/babel/utils/styleInjection.ts +138 -7
- package/src/babel/utils/twProcessing.ts +92 -3
- package/src/parser/borders.test.ts +104 -0
- package/src/parser/borders.ts +50 -7
- package/src/parser/index.ts +2 -0
- package/src/parser/layout.test.ts +74 -0
- package/src/parser/layout.ts +94 -0
- package/src/parser/modifiers.test.ts +206 -0
- package/src/parser/modifiers.ts +62 -3
- package/src/parser/spacing.test.ts +66 -0
- package/src/parser/spacing.ts +15 -5
- package/src/parser/typography.test.ts +8 -0
- package/src/parser/typography.ts +4 -0
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
<img src="https://img.shields.io/codecov/c/github/mgcrea/react-native-tailwind?style=for-the-badge" alt="coverage" />
|
|
28
28
|
</a>
|
|
29
29
|
<a href="https://depfu.com/github/mgcrea/react-native-tailwind">
|
|
30
|
-
<img src="https://img.shields.io/
|
|
30
|
+
<img src="https://img.shields.io/badge/dependencies-none-brightgreen?style=for-the-badge" alt="dependencies status" />
|
|
31
31
|
</a>
|
|
32
32
|
</p>
|
|
33
33
|
|
|
@@ -37,22 +37,21 @@ Compile-time Tailwind CSS for React Native with zero runtime overhead. Transform
|
|
|
37
37
|
|
|
38
38
|
## Features
|
|
39
39
|
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- 🎛️ **Custom attributes** — Configure which props to transform with exact matching or glob patterns
|
|
40
|
+
- **⚡ Zero Runtime Overhead** - All transformations happen at compile time
|
|
41
|
+
- **🔧 No Dependencies** - Direct-to-React-Native style generation without tailwindcss package
|
|
42
|
+
- **🎯 Babel-only Setup** - No Metro configuration required
|
|
43
|
+
- **📝 TypeScript-first** - Full type safety and autocomplete support
|
|
44
|
+
- **🚀 Optimized Performance** - Compiles down to StyleSheet.create for optimal performance
|
|
45
|
+
- **🔀 Dynamic className** - Conditional styles support with compile-time optimization
|
|
46
|
+
- **📦 Small Bundle Size** - Only includes actual styles used in your app
|
|
47
|
+
- **🎯 State Modifiers** - `active:`, `hover:`, `focus:`, and `disabled:` modifiers for interactive components
|
|
48
|
+
- **📱 Platform Modifiers** - `ios:`, `android:`, and `web:` modifiers for platform-specific styling
|
|
49
|
+
- **🌓 Color Scheme Modifiers** - `dark:` and `light:` and `scheme:` modifiers for automatic theme adaptation
|
|
50
|
+
- **🎨 Custom Colors** - Extend the default palette via tailwind.config.\*
|
|
51
|
+
- **📐 Arbitrary Values** - Use custom sizes and borders: `w-[123px]`, `rounded-[20px]`
|
|
52
|
+
- **📜 Special Style Props** - Support for `contentContainerClassName`, `columnWrapperClassName`, and more
|
|
53
|
+
|
|
54
|
+
📊 **[How It Compares](https://mgcrea.github.io/react-native-tailwind/getting-started/how-it-compares/)** - See how this library stacks up against other React Native styling solutions.
|
|
56
55
|
|
|
57
56
|
## Demo
|
|
58
57
|
|
|
@@ -200,9 +199,7 @@ import { View, Text } from "react-native";
|
|
|
200
199
|
export function PlatformCard() {
|
|
201
200
|
return (
|
|
202
201
|
<View className="p-4 ios:p-6 android:p-8 bg-white rounded-lg">
|
|
203
|
-
<Text className="text-base ios:text-blue-600 android:text-green-600">
|
|
204
|
-
Platform-specific styles
|
|
205
|
-
</Text>
|
|
202
|
+
<Text className="text-base ios:text-blue-600 android:text-green-600">Platform-specific styles</Text>
|
|
206
203
|
</View>
|
|
207
204
|
);
|
|
208
205
|
}
|
|
@@ -212,12 +209,14 @@ export function PlatformCard() {
|
|
|
212
209
|
|
|
213
210
|
Contributions are welcome! Please read our [Contributing Guide](https://mgcrea.github.io/react-native-tailwind/advanced/contributing/) for details.
|
|
214
211
|
|
|
212
|
+
## Credits
|
|
213
|
+
|
|
214
|
+
- [Tailwind CSS](https://tailwindcss.com/) - The utility-first CSS framework that revolutionized the way we style applications. If you enjoy this library, consider supporting them by purchasing [Tailwind Plus](https://tailwindcss.com/plus).
|
|
215
|
+
|
|
215
216
|
## Authors
|
|
216
217
|
|
|
217
218
|
- [Olivier Louvignes](https://github.com/mgcrea) - [@mgcrea](https://twitter.com/mgcrea)
|
|
218
219
|
|
|
219
|
-
## License
|
|
220
|
-
|
|
221
220
|
```text
|
|
222
221
|
MIT License
|
|
223
222
|
|
package/dist/babel/index.cjs
CHANGED
|
@@ -212,6 +212,10 @@ function createInitialState(options, filename, colorSchemeImportSource, colorSch
|
|
|
212
212
|
needsWindowDimensionsImport: false,
|
|
213
213
|
windowDimensionsVariableName: "_twDimensions",
|
|
214
214
|
windowDimensionsLocalIdentifier: void 0,
|
|
215
|
+
hasI18nManagerImport: false,
|
|
216
|
+
needsI18nManagerImport: false,
|
|
217
|
+
i18nManagerVariableName: "_twIsRTL",
|
|
218
|
+
i18nManagerLocalIdentifier: void 0,
|
|
215
219
|
customTheme,
|
|
216
220
|
schemeModifierConfig,
|
|
217
221
|
supportedAttributes: exactMatches,
|
|
@@ -715,7 +719,9 @@ var BORDER_WIDTH_PROP_MAP = {
|
|
|
715
719
|
t: "borderTopWidth",
|
|
716
720
|
r: "borderRightWidth",
|
|
717
721
|
b: "borderBottomWidth",
|
|
718
|
-
l: "borderLeftWidth"
|
|
722
|
+
l: "borderLeftWidth",
|
|
723
|
+
s: "borderStartWidth",
|
|
724
|
+
e: "borderEndWidth"
|
|
719
725
|
};
|
|
720
726
|
var BORDER_RADIUS_CORNER_MAP = {
|
|
721
727
|
tl: "borderTopLeftRadius",
|
|
@@ -723,11 +729,19 @@ var BORDER_RADIUS_CORNER_MAP = {
|
|
|
723
729
|
bl: "borderBottomLeftRadius",
|
|
724
730
|
br: "borderBottomRightRadius"
|
|
725
731
|
};
|
|
732
|
+
var BORDER_RADIUS_LOGICAL_CORNER_MAP = {
|
|
733
|
+
ss: "borderTopStartRadius",
|
|
734
|
+
se: "borderTopEndRadius",
|
|
735
|
+
es: "borderBottomStartRadius",
|
|
736
|
+
ee: "borderBottomEndRadius"
|
|
737
|
+
};
|
|
726
738
|
var BORDER_RADIUS_SIDE_MAP = {
|
|
727
739
|
t: ["borderTopLeftRadius", "borderTopRightRadius"],
|
|
728
740
|
r: ["borderTopRightRadius", "borderBottomRightRadius"],
|
|
729
741
|
b: ["borderBottomLeftRadius", "borderBottomRightRadius"],
|
|
730
|
-
l: ["borderTopLeftRadius", "borderBottomLeftRadius"]
|
|
742
|
+
l: ["borderTopLeftRadius", "borderBottomLeftRadius"],
|
|
743
|
+
s: ["borderTopStartRadius", "borderBottomStartRadius"],
|
|
744
|
+
e: ["borderTopEndRadius", "borderBottomEndRadius"]
|
|
731
745
|
};
|
|
732
746
|
function parseArbitraryBorderWidth(value) {
|
|
733
747
|
const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
|
|
@@ -775,11 +789,11 @@ function parseBorder(cls, customColors) {
|
|
|
775
789
|
return null;
|
|
776
790
|
}
|
|
777
791
|
function parseBorderWidth(cls, customColors) {
|
|
778
|
-
const dirMatch = cls.match(/^border-([
|
|
792
|
+
const dirMatch = cls.match(/^border-([trblse])(?:-(.+))?$/);
|
|
779
793
|
if (dirMatch) {
|
|
780
794
|
const dir = dirMatch[1];
|
|
781
795
|
const valueStr = dirMatch[2] || "";
|
|
782
|
-
if (valueStr) {
|
|
796
|
+
if (valueStr && dir !== "s" && dir !== "e") {
|
|
783
797
|
const colorResult = parseColor(cls, customColors);
|
|
784
798
|
if (colorResult !== null) {
|
|
785
799
|
return null;
|
|
@@ -843,7 +857,24 @@ function parseBorderRadius(cls) {
|
|
|
843
857
|
}
|
|
844
858
|
return null;
|
|
845
859
|
}
|
|
846
|
-
const
|
|
860
|
+
const logicalCornerMatch = rest.match(/^(ss|se|es|ee)(?:-(.+))?$/);
|
|
861
|
+
if (logicalCornerMatch) {
|
|
862
|
+
const corner = logicalCornerMatch[1];
|
|
863
|
+
const valueStr = logicalCornerMatch[2] || "";
|
|
864
|
+
if (valueStr.startsWith("[")) {
|
|
865
|
+
const arbitraryValue = parseArbitraryBorderRadius(valueStr);
|
|
866
|
+
if (arbitraryValue !== null) {
|
|
867
|
+
return { [BORDER_RADIUS_LOGICAL_CORNER_MAP[corner]]: arbitraryValue };
|
|
868
|
+
}
|
|
869
|
+
return null;
|
|
870
|
+
}
|
|
871
|
+
const scaleValue2 = BORDER_RADIUS_SCALE[valueStr];
|
|
872
|
+
if (scaleValue2 !== void 0) {
|
|
873
|
+
return { [BORDER_RADIUS_LOGICAL_CORNER_MAP[corner]]: scaleValue2 };
|
|
874
|
+
}
|
|
875
|
+
return null;
|
|
876
|
+
}
|
|
877
|
+
const sideMatch = rest.match(/^([trblse])(?:-(.+))?$/);
|
|
847
878
|
if (sideMatch) {
|
|
848
879
|
const side = sideMatch[1];
|
|
849
880
|
const valueStr = sideMatch[2] || "";
|
|
@@ -1120,6 +1151,52 @@ function parseLayout(cls) {
|
|
|
1120
1151
|
return { left: leftValue };
|
|
1121
1152
|
}
|
|
1122
1153
|
}
|
|
1154
|
+
const startMatch = cls.match(/^(-?)start-(.+)$/);
|
|
1155
|
+
if (startMatch) {
|
|
1156
|
+
const [, negPrefix, startKey] = startMatch;
|
|
1157
|
+
const isNegative = negPrefix === "-";
|
|
1158
|
+
if (startKey === "auto") {
|
|
1159
|
+
return {};
|
|
1160
|
+
}
|
|
1161
|
+
const arbitraryStart = parseArbitraryInset(startKey);
|
|
1162
|
+
if (arbitraryStart !== null) {
|
|
1163
|
+
if (typeof arbitraryStart === "number") {
|
|
1164
|
+
return { start: isNegative ? -arbitraryStart : arbitraryStart };
|
|
1165
|
+
}
|
|
1166
|
+
if (isNegative && arbitraryStart.endsWith("%")) {
|
|
1167
|
+
const numValue = parseFloat(arbitraryStart);
|
|
1168
|
+
return { start: `${-numValue}%` };
|
|
1169
|
+
}
|
|
1170
|
+
return { start: arbitraryStart };
|
|
1171
|
+
}
|
|
1172
|
+
const startValue = INSET_SCALE[startKey];
|
|
1173
|
+
if (startValue !== void 0) {
|
|
1174
|
+
return { start: isNegative ? -startValue : startValue };
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
const endMatch = cls.match(/^(-?)end-(.+)$/);
|
|
1178
|
+
if (endMatch) {
|
|
1179
|
+
const [, negPrefix, endKey] = endMatch;
|
|
1180
|
+
const isNegative = negPrefix === "-";
|
|
1181
|
+
if (endKey === "auto") {
|
|
1182
|
+
return {};
|
|
1183
|
+
}
|
|
1184
|
+
const arbitraryEnd = parseArbitraryInset(endKey);
|
|
1185
|
+
if (arbitraryEnd !== null) {
|
|
1186
|
+
if (typeof arbitraryEnd === "number") {
|
|
1187
|
+
return { end: isNegative ? -arbitraryEnd : arbitraryEnd };
|
|
1188
|
+
}
|
|
1189
|
+
if (isNegative && arbitraryEnd.endsWith("%")) {
|
|
1190
|
+
const numValue = parseFloat(arbitraryEnd);
|
|
1191
|
+
return { end: `${-numValue}%` };
|
|
1192
|
+
}
|
|
1193
|
+
return { end: arbitraryEnd };
|
|
1194
|
+
}
|
|
1195
|
+
const endValue = INSET_SCALE[endKey];
|
|
1196
|
+
if (endValue !== void 0) {
|
|
1197
|
+
return { end: isNegative ? -endValue : endValue };
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1123
1200
|
if (cls.startsWith("inset-x-")) {
|
|
1124
1201
|
const insetKey = cls.substring(8);
|
|
1125
1202
|
const arbitraryInset = parseArbitraryInset(insetKey);
|
|
@@ -1142,6 +1219,28 @@ function parseLayout(cls) {
|
|
|
1142
1219
|
return { top: insetValue, bottom: insetValue };
|
|
1143
1220
|
}
|
|
1144
1221
|
}
|
|
1222
|
+
if (cls.startsWith("inset-s-")) {
|
|
1223
|
+
const insetKey = cls.substring(8);
|
|
1224
|
+
const arbitraryInset = parseArbitraryInset(insetKey);
|
|
1225
|
+
if (arbitraryInset !== null) {
|
|
1226
|
+
return { start: arbitraryInset };
|
|
1227
|
+
}
|
|
1228
|
+
const insetValue = INSET_SCALE[insetKey];
|
|
1229
|
+
if (insetValue !== void 0) {
|
|
1230
|
+
return { start: insetValue };
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
if (cls.startsWith("inset-e-")) {
|
|
1234
|
+
const insetKey = cls.substring(8);
|
|
1235
|
+
const arbitraryInset = parseArbitraryInset(insetKey);
|
|
1236
|
+
if (arbitraryInset !== null) {
|
|
1237
|
+
return { end: arbitraryInset };
|
|
1238
|
+
}
|
|
1239
|
+
const insetValue = INSET_SCALE[insetKey];
|
|
1240
|
+
if (insetValue !== void 0) {
|
|
1241
|
+
return { end: insetValue };
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1145
1244
|
if (cls.startsWith("inset-")) {
|
|
1146
1245
|
const insetKey = cls.substring(6);
|
|
1147
1246
|
const arbitraryInset = parseArbitraryInset(insetKey);
|
|
@@ -1467,7 +1566,7 @@ function parseArbitrarySpacing(value) {
|
|
|
1467
1566
|
return null;
|
|
1468
1567
|
}
|
|
1469
1568
|
function parseSpacing(cls) {
|
|
1470
|
-
const marginMatch = cls.match(/^(-?)m([
|
|
1569
|
+
const marginMatch = cls.match(/^(-?)m([xytrblse]?)-(.+)$/);
|
|
1471
1570
|
if (marginMatch) {
|
|
1472
1571
|
const [, negativePrefix, dir, valueStr] = marginMatch;
|
|
1473
1572
|
const isNegative = negativePrefix === "-";
|
|
@@ -1482,7 +1581,7 @@ function parseSpacing(cls) {
|
|
|
1482
1581
|
return getMarginStyle(dir, finalValue);
|
|
1483
1582
|
}
|
|
1484
1583
|
}
|
|
1485
|
-
const paddingMatch = cls.match(/^p([
|
|
1584
|
+
const paddingMatch = cls.match(/^p([xytrblse]?)-(.+)$/);
|
|
1486
1585
|
if (paddingMatch) {
|
|
1487
1586
|
const [, dir, valueStr] = paddingMatch;
|
|
1488
1587
|
const arbitraryValue = parseArbitrarySpacing(valueStr);
|
|
@@ -1524,6 +1623,10 @@ function getMarginStyle(dir, value) {
|
|
|
1524
1623
|
return { marginBottom: value };
|
|
1525
1624
|
case "l":
|
|
1526
1625
|
return { marginLeft: value };
|
|
1626
|
+
case "s":
|
|
1627
|
+
return { marginStart: value };
|
|
1628
|
+
case "e":
|
|
1629
|
+
return { marginEnd: value };
|
|
1527
1630
|
default:
|
|
1528
1631
|
return {};
|
|
1529
1632
|
}
|
|
@@ -1544,6 +1647,10 @@ function getPaddingStyle(dir, value) {
|
|
|
1544
1647
|
return { paddingBottom: value };
|
|
1545
1648
|
case "l":
|
|
1546
1649
|
return { paddingLeft: value };
|
|
1650
|
+
case "s":
|
|
1651
|
+
return { paddingStart: value };
|
|
1652
|
+
case "e":
|
|
1653
|
+
return { paddingEnd: value };
|
|
1547
1654
|
default:
|
|
1548
1655
|
return {};
|
|
1549
1656
|
}
|
|
@@ -2032,11 +2139,13 @@ var STATE_MODIFIERS = [
|
|
|
2032
2139
|
var PLATFORM_MODIFIERS = ["ios", "android", "web"];
|
|
2033
2140
|
var COLOR_SCHEME_MODIFIERS = ["dark", "light"];
|
|
2034
2141
|
var SCHEME_MODIFIERS = ["scheme"];
|
|
2142
|
+
var DIRECTIONAL_MODIFIERS = ["rtl", "ltr"];
|
|
2035
2143
|
var SUPPORTED_MODIFIERS = [
|
|
2036
2144
|
...STATE_MODIFIERS,
|
|
2037
2145
|
...PLATFORM_MODIFIERS,
|
|
2038
2146
|
...COLOR_SCHEME_MODIFIERS,
|
|
2039
|
-
...SCHEME_MODIFIERS
|
|
2147
|
+
...SCHEME_MODIFIERS,
|
|
2148
|
+
...DIRECTIONAL_MODIFIERS
|
|
2040
2149
|
];
|
|
2041
2150
|
function parseModifier(cls) {
|
|
2042
2151
|
const colonIndex = cls.indexOf(":");
|
|
@@ -2071,6 +2180,9 @@ function isColorSchemeModifier(modifier) {
|
|
|
2071
2180
|
function isSchemeModifier(modifier) {
|
|
2072
2181
|
return SCHEME_MODIFIERS.includes(modifier);
|
|
2073
2182
|
}
|
|
2183
|
+
function isDirectionalModifier(modifier) {
|
|
2184
|
+
return DIRECTIONAL_MODIFIERS.includes(modifier);
|
|
2185
|
+
}
|
|
2074
2186
|
function isColorClass(className) {
|
|
2075
2187
|
return className.startsWith("text-") || className.startsWith("bg-") || className.startsWith("border-");
|
|
2076
2188
|
}
|
|
@@ -2115,11 +2227,24 @@ function expandSchemeModifier(schemeModifier, customColors, darkSuffix = "-dark"
|
|
|
2115
2227
|
}
|
|
2116
2228
|
];
|
|
2117
2229
|
}
|
|
2230
|
+
var DIRECTIONAL_TEXT_ALIGN_EXPANSIONS = {
|
|
2231
|
+
"text-start": { ltr: "text-left", rtl: "text-right" },
|
|
2232
|
+
"text-end": { ltr: "text-right", rtl: "text-left" }
|
|
2233
|
+
};
|
|
2234
|
+
function getDirectionalExpansion(cls) {
|
|
2235
|
+
return DIRECTIONAL_TEXT_ALIGN_EXPANSIONS[cls];
|
|
2236
|
+
}
|
|
2118
2237
|
function splitModifierClasses(className) {
|
|
2119
2238
|
const classes = className.trim().split(/\s+/).filter(Boolean);
|
|
2120
2239
|
const baseClasses = [];
|
|
2121
2240
|
const modifierClasses = [];
|
|
2122
2241
|
for (const cls of classes) {
|
|
2242
|
+
const directionalExpansion = getDirectionalExpansion(cls);
|
|
2243
|
+
if (directionalExpansion) {
|
|
2244
|
+
modifierClasses.push({ modifier: "ltr", baseClass: directionalExpansion.ltr });
|
|
2245
|
+
modifierClasses.push({ modifier: "rtl", baseClass: directionalExpansion.rtl });
|
|
2246
|
+
continue;
|
|
2247
|
+
}
|
|
2123
2248
|
const parsed = parseModifier(cls);
|
|
2124
2249
|
if (parsed) {
|
|
2125
2250
|
modifierClasses.push(parsed);
|
|
@@ -2298,6 +2423,40 @@ function getStatePropertyForModifier(modifier) {
|
|
|
2298
2423
|
}
|
|
2299
2424
|
}
|
|
2300
2425
|
|
|
2426
|
+
// src/babel/utils/directionalModifierProcessing.ts
|
|
2427
|
+
function processDirectionalModifiers(directionalModifiers, state, parseClassName2, generateStyleKey2, t) {
|
|
2428
|
+
state.needsI18nManagerImport = true;
|
|
2429
|
+
const modifiersByDirection = /* @__PURE__ */ new Map();
|
|
2430
|
+
for (const mod of directionalModifiers) {
|
|
2431
|
+
const direction = mod.modifier;
|
|
2432
|
+
if (!modifiersByDirection.has(direction)) {
|
|
2433
|
+
modifiersByDirection.set(direction, []);
|
|
2434
|
+
}
|
|
2435
|
+
const directionGroup = modifiersByDirection.get(direction);
|
|
2436
|
+
if (directionGroup) {
|
|
2437
|
+
directionGroup.push(mod);
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
const conditionalExpressions = [];
|
|
2441
|
+
for (const [direction, modifiers] of modifiersByDirection) {
|
|
2442
|
+
const classNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
2443
|
+
const styleObject = parseClassName2(classNames, state.customTheme);
|
|
2444
|
+
if (hasRuntimeDimensions(styleObject)) {
|
|
2445
|
+
throw new Error(
|
|
2446
|
+
`w-screen and h-screen cannot be combined with directional modifiers (rtl:, ltr:). Found in: "${direction}:${classNames}". Use w-screen/h-screen without modifiers instead.`
|
|
2447
|
+
);
|
|
2448
|
+
}
|
|
2449
|
+
const styleKey = generateStyleKey2(`${direction}_${classNames}`);
|
|
2450
|
+
state.styleRegistry.set(styleKey, styleObject);
|
|
2451
|
+
const rtlVariable = t.identifier(state.i18nManagerVariableName);
|
|
2452
|
+
const directionCheck = direction === "rtl" ? rtlVariable : t.unaryExpression("!", rtlVariable);
|
|
2453
|
+
const styleReference = t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey));
|
|
2454
|
+
const conditionalExpression = t.logicalExpression("&&", directionCheck, styleReference);
|
|
2455
|
+
conditionalExpressions.push(conditionalExpression);
|
|
2456
|
+
}
|
|
2457
|
+
return conditionalExpressions;
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2301
2460
|
// src/babel/utils/dynamicProcessing.ts
|
|
2302
2461
|
function processDynamicExpression(expression, state, parseClassName2, generateStyleKey2, splitModifierClasses2, processPlatformModifiers2, processColorSchemeModifiers2, componentScope, isPlatformModifier2, isColorSchemeModifier2, isSchemeModifier2, expandSchemeModifier2, t) {
|
|
2303
2462
|
if (t.isTemplateLiteral(expression)) {
|
|
@@ -2901,6 +3060,7 @@ function jsxAttributeVisitor(path2, state, t) {
|
|
|
2901
3060
|
const placeholderModifiers = modifierClasses.filter((m) => m.modifier === "placeholder");
|
|
2902
3061
|
const platformModifiers = modifierClasses.filter((m) => isPlatformModifier(m.modifier));
|
|
2903
3062
|
const colorSchemeModifiers = modifierClasses.filter((m) => isColorSchemeModifier(m.modifier));
|
|
3063
|
+
const directionalModifiers = modifierClasses.filter((m) => isDirectionalModifier(m.modifier));
|
|
2904
3064
|
const stateModifiers = modifierClasses.filter(
|
|
2905
3065
|
(m) => isStateModifier(m.modifier) && m.modifier !== "placeholder"
|
|
2906
3066
|
);
|
|
@@ -2923,6 +3083,7 @@ function jsxAttributeVisitor(path2, state, t) {
|
|
|
2923
3083
|
}
|
|
2924
3084
|
const hasPlatformModifiers = platformModifiers.length > 0;
|
|
2925
3085
|
const hasColorSchemeModifiers = colorSchemeModifiers.length > 0;
|
|
3086
|
+
const hasDirectionalModifiers = directionalModifiers.length > 0;
|
|
2926
3087
|
const hasStateModifiers = stateModifiers.length > 0;
|
|
2927
3088
|
const hasBaseClasses = baseClasses.length > 0;
|
|
2928
3089
|
let componentScope = null;
|
|
@@ -2938,7 +3099,7 @@ function jsxAttributeVisitor(path2, state, t) {
|
|
|
2938
3099
|
}
|
|
2939
3100
|
}
|
|
2940
3101
|
}
|
|
2941
|
-
if (hasStateModifiers && (hasPlatformModifiers || hasColorSchemeModifiers)) {
|
|
3102
|
+
if (hasStateModifiers && (hasPlatformModifiers || hasColorSchemeModifiers || hasDirectionalModifiers)) {
|
|
2942
3103
|
const jsxOpeningElement = path2.parent;
|
|
2943
3104
|
const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
|
|
2944
3105
|
if (componentSupport) {
|
|
@@ -2948,7 +3109,7 @@ function jsxAttributeVisitor(path2, state, t) {
|
|
|
2948
3109
|
const baseStyleObject = parseClassName(baseClassName, state.customTheme);
|
|
2949
3110
|
if (hasRuntimeDimensions(baseStyleObject)) {
|
|
2950
3111
|
throw path2.buildCodeFrameError(
|
|
2951
|
-
`w-screen and h-screen cannot be combined with modifiers. Found: "${baseClassName}" with state, platform,
|
|
3112
|
+
`w-screen and h-screen cannot be combined with modifiers. Found: "${baseClassName}" with state, platform, color scheme, or directional modifiers. Use w-screen/h-screen without modifiers instead.`
|
|
2952
3113
|
);
|
|
2953
3114
|
}
|
|
2954
3115
|
const baseStyleKey = generateStyleKey(baseClassName);
|
|
@@ -2977,6 +3138,16 @@ function jsxAttributeVisitor(path2, state, t) {
|
|
|
2977
3138
|
);
|
|
2978
3139
|
styleArrayElements.push(...colorSchemeConditionals);
|
|
2979
3140
|
}
|
|
3141
|
+
if (hasDirectionalModifiers) {
|
|
3142
|
+
const directionalConditionals = processDirectionalModifiers(
|
|
3143
|
+
directionalModifiers,
|
|
3144
|
+
state,
|
|
3145
|
+
parseClassName,
|
|
3146
|
+
generateStyleKey,
|
|
3147
|
+
t
|
|
3148
|
+
);
|
|
3149
|
+
styleArrayElements.push(...directionalConditionals);
|
|
3150
|
+
}
|
|
2980
3151
|
const modifiersByType = /* @__PURE__ */ new Map();
|
|
2981
3152
|
for (const mod of stateModifiers) {
|
|
2982
3153
|
const modType = mod.modifier;
|
|
@@ -3016,14 +3187,14 @@ function jsxAttributeVisitor(path2, state, t) {
|
|
|
3016
3187
|
} else {
|
|
3017
3188
|
}
|
|
3018
3189
|
}
|
|
3019
|
-
if ((hasPlatformModifiers || hasColorSchemeModifiers) && !hasStateModifiers) {
|
|
3190
|
+
if ((hasPlatformModifiers || hasColorSchemeModifiers || hasDirectionalModifiers) && !hasStateModifiers) {
|
|
3020
3191
|
const styleExpressions = [];
|
|
3021
3192
|
if (hasBaseClasses) {
|
|
3022
3193
|
const baseClassName = baseClasses.join(" ");
|
|
3023
3194
|
const baseStyleObject = parseClassName(baseClassName, state.customTheme);
|
|
3024
3195
|
if (hasRuntimeDimensions(baseStyleObject)) {
|
|
3025
3196
|
throw path2.buildCodeFrameError(
|
|
3026
|
-
`w-screen and h-screen cannot be combined with modifiers. Found: "${baseClassName}" with platform
|
|
3197
|
+
`w-screen and h-screen cannot be combined with modifiers. Found: "${baseClassName}" with platform, color scheme, or directional modifiers. Use w-screen/h-screen without modifiers instead.`
|
|
3027
3198
|
);
|
|
3028
3199
|
}
|
|
3029
3200
|
const baseStyleKey = generateStyleKey(baseClassName);
|
|
@@ -3052,6 +3223,16 @@ function jsxAttributeVisitor(path2, state, t) {
|
|
|
3052
3223
|
);
|
|
3053
3224
|
styleExpressions.push(...colorSchemeConditionals);
|
|
3054
3225
|
}
|
|
3226
|
+
if (hasDirectionalModifiers) {
|
|
3227
|
+
const directionalConditionals = processDirectionalModifiers(
|
|
3228
|
+
directionalModifiers,
|
|
3229
|
+
state,
|
|
3230
|
+
parseClassName,
|
|
3231
|
+
generateStyleKey,
|
|
3232
|
+
t
|
|
3233
|
+
);
|
|
3234
|
+
styleExpressions.push(...directionalConditionals);
|
|
3235
|
+
}
|
|
3055
3236
|
const styleExpression = styleExpressions.length === 1 ? styleExpressions[0] : t.arrayExpression(styleExpressions);
|
|
3056
3237
|
const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
|
|
3057
3238
|
if (styleAttribute2) {
|
|
@@ -3277,6 +3458,17 @@ function importDeclarationVisitor(path2, state, t) {
|
|
|
3277
3458
|
}
|
|
3278
3459
|
return false;
|
|
3279
3460
|
});
|
|
3461
|
+
if (node.importKind !== "type") {
|
|
3462
|
+
for (const spec of specifiers) {
|
|
3463
|
+
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
3464
|
+
if (spec.imported.name === "I18nManager") {
|
|
3465
|
+
state.hasI18nManagerImport = true;
|
|
3466
|
+
state.i18nManagerLocalIdentifier = spec.local.name;
|
|
3467
|
+
break;
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
}
|
|
3280
3472
|
if (node.importKind !== "type") {
|
|
3281
3473
|
for (const spec of specifiers) {
|
|
3282
3474
|
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
@@ -3447,6 +3639,71 @@ function injectColorSchemeHook(functionPath, colorSchemeVariableName, hookName,
|
|
|
3447
3639
|
body.body.unshift(hookCall);
|
|
3448
3640
|
return true;
|
|
3449
3641
|
}
|
|
3642
|
+
function addI18nManagerImport(path2, t) {
|
|
3643
|
+
const body = path2.node.body;
|
|
3644
|
+
let existingValueImport = null;
|
|
3645
|
+
for (const statement of body) {
|
|
3646
|
+
if (t.isImportDeclaration(statement) && statement.source.value === "react-native") {
|
|
3647
|
+
if (statement.importKind === "type") {
|
|
3648
|
+
continue;
|
|
3649
|
+
}
|
|
3650
|
+
const hasNamespaceImport = statement.specifiers.some((spec) => t.isImportNamespaceSpecifier(spec));
|
|
3651
|
+
if (hasNamespaceImport) {
|
|
3652
|
+
continue;
|
|
3653
|
+
}
|
|
3654
|
+
existingValueImport = statement;
|
|
3655
|
+
break;
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3658
|
+
if (existingValueImport) {
|
|
3659
|
+
const hasI18nManager = existingValueImport.specifiers.some(
|
|
3660
|
+
(spec) => t.isImportSpecifier(spec) && spec.imported.type === "Identifier" && spec.imported.name === "I18nManager"
|
|
3661
|
+
);
|
|
3662
|
+
if (!hasI18nManager) {
|
|
3663
|
+
existingValueImport.specifiers.push(
|
|
3664
|
+
t.importSpecifier(t.identifier("I18nManager"), t.identifier("I18nManager"))
|
|
3665
|
+
);
|
|
3666
|
+
}
|
|
3667
|
+
} else {
|
|
3668
|
+
const importDeclaration = t.importDeclaration(
|
|
3669
|
+
[t.importSpecifier(t.identifier("I18nManager"), t.identifier("I18nManager"))],
|
|
3670
|
+
t.stringLiteral("react-native")
|
|
3671
|
+
);
|
|
3672
|
+
path2.unshiftContainer("body", importDeclaration);
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
function injectI18nManagerVariable(path2, variableName, localIdentifier, t) {
|
|
3676
|
+
const body = path2.node.body;
|
|
3677
|
+
for (const statement of body) {
|
|
3678
|
+
if (t.isVariableDeclaration(statement) && statement.declarations.length > 0 && t.isVariableDeclarator(statement.declarations[0])) {
|
|
3679
|
+
const declarator = statement.declarations[0];
|
|
3680
|
+
if (t.isIdentifier(declarator.id) && declarator.id.name === variableName) {
|
|
3681
|
+
return;
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
const identifierToUse = localIdentifier ?? "I18nManager";
|
|
3686
|
+
const i18nVariable = t.variableDeclaration("const", [
|
|
3687
|
+
t.variableDeclarator(
|
|
3688
|
+
t.identifier(variableName),
|
|
3689
|
+
t.memberExpression(t.identifier(identifierToUse), t.identifier("isRTL"))
|
|
3690
|
+
)
|
|
3691
|
+
]);
|
|
3692
|
+
let insertIndex = 0;
|
|
3693
|
+
for (let i = 0; i < body.length; i++) {
|
|
3694
|
+
const statement = body[i];
|
|
3695
|
+
if (t.isExpressionStatement(statement) && t.isStringLiteral(statement.expression)) {
|
|
3696
|
+
insertIndex = i + 1;
|
|
3697
|
+
continue;
|
|
3698
|
+
}
|
|
3699
|
+
if (t.isImportDeclaration(statement)) {
|
|
3700
|
+
insertIndex = i + 1;
|
|
3701
|
+
continue;
|
|
3702
|
+
}
|
|
3703
|
+
break;
|
|
3704
|
+
}
|
|
3705
|
+
body.splice(insertIndex, 0, i18nVariable);
|
|
3706
|
+
}
|
|
3450
3707
|
function addWindowDimensionsImport(path2, t) {
|
|
3451
3708
|
const body = path2.node.body;
|
|
3452
3709
|
let existingValueImport = null;
|
|
@@ -3534,11 +3791,16 @@ function injectStylesAtTop(path2, styleRegistry, stylesIdentifier, t) {
|
|
|
3534
3791
|
const body = path2.node.body;
|
|
3535
3792
|
let insertIndex = 0;
|
|
3536
3793
|
for (let i = 0; i < body.length; i++) {
|
|
3537
|
-
|
|
3794
|
+
const statement = body[i];
|
|
3795
|
+
if (t.isExpressionStatement(statement) && t.isStringLiteral(statement.expression)) {
|
|
3538
3796
|
insertIndex = i + 1;
|
|
3539
|
-
|
|
3540
|
-
|
|
3797
|
+
continue;
|
|
3798
|
+
}
|
|
3799
|
+
if (t.isImportDeclaration(statement)) {
|
|
3800
|
+
insertIndex = i + 1;
|
|
3801
|
+
continue;
|
|
3541
3802
|
}
|
|
3803
|
+
break;
|
|
3542
3804
|
}
|
|
3543
3805
|
body.splice(insertIndex, 0, styleSheet);
|
|
3544
3806
|
}
|
|
@@ -3582,8 +3844,9 @@ function processTwCall(className, path2, state, parseClassName2, generateStyleKe
|
|
|
3582
3844
|
}
|
|
3583
3845
|
const colorSchemeModifiers = modifierClasses.filter((m) => isColorSchemeModifier(m.modifier));
|
|
3584
3846
|
const platformModifiers = modifierClasses.filter((m) => isPlatformModifier(m.modifier));
|
|
3847
|
+
const directionalModifiers = modifierClasses.filter((m) => isDirectionalModifier(m.modifier));
|
|
3585
3848
|
const otherModifiers = modifierClasses.filter(
|
|
3586
|
-
(m) => !isColorSchemeModifier(m.modifier) && !isPlatformModifier(m.modifier)
|
|
3849
|
+
(m) => !isColorSchemeModifier(m.modifier) && !isPlatformModifier(m.modifier) && !isDirectionalModifier(m.modifier)
|
|
3587
3850
|
);
|
|
3588
3851
|
const hasColorSchemeModifiers = colorSchemeModifiers.length > 0;
|
|
3589
3852
|
let componentScope = null;
|
|
@@ -3717,6 +3980,62 @@ function processTwCall(className, path2, state, parseClassName2, generateStyleKe
|
|
|
3717
3980
|
);
|
|
3718
3981
|
}
|
|
3719
3982
|
}
|
|
3983
|
+
const hasDirectionalModifiers = directionalModifiers.length > 0;
|
|
3984
|
+
if (hasDirectionalModifiers) {
|
|
3985
|
+
state.needsI18nManagerImport = true;
|
|
3986
|
+
const directionalConditionals = processDirectionalModifiers(
|
|
3987
|
+
directionalModifiers,
|
|
3988
|
+
state,
|
|
3989
|
+
parseClassName2,
|
|
3990
|
+
generateStyleKey2,
|
|
3991
|
+
t
|
|
3992
|
+
);
|
|
3993
|
+
const styleProperty = objectProperties.find(
|
|
3994
|
+
(prop) => t.isIdentifier(prop.key) && prop.key.name === "style"
|
|
3995
|
+
);
|
|
3996
|
+
if (styleProperty && t.isArrayExpression(styleProperty.value)) {
|
|
3997
|
+
styleProperty.value.elements.push(...directionalConditionals);
|
|
3998
|
+
} else {
|
|
3999
|
+
const styleArrayElements = [];
|
|
4000
|
+
if (baseClasses.length > 0) {
|
|
4001
|
+
const baseClassName = baseClasses.join(" ");
|
|
4002
|
+
const baseStyleObject = parseClassName2(baseClassName, state.customTheme);
|
|
4003
|
+
const baseStyleKey = generateStyleKey2(baseClassName);
|
|
4004
|
+
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
4005
|
+
styleArrayElements.push(
|
|
4006
|
+
t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey))
|
|
4007
|
+
);
|
|
4008
|
+
}
|
|
4009
|
+
styleArrayElements.push(...directionalConditionals);
|
|
4010
|
+
objectProperties[0] = t.objectProperty(t.identifier("style"), t.arrayExpression(styleArrayElements));
|
|
4011
|
+
}
|
|
4012
|
+
const rtlModifiers = directionalModifiers.filter((m) => m.modifier === "rtl");
|
|
4013
|
+
const ltrModifiers = directionalModifiers.filter((m) => m.modifier === "ltr");
|
|
4014
|
+
if (rtlModifiers.length > 0) {
|
|
4015
|
+
const rtlClassNames = rtlModifiers.map((m) => m.baseClass).join(" ");
|
|
4016
|
+
const rtlStyleObject = parseClassName2(rtlClassNames, state.customTheme);
|
|
4017
|
+
const rtlStyleKey = generateStyleKey2(`rtl_${rtlClassNames}`);
|
|
4018
|
+
state.styleRegistry.set(rtlStyleKey, rtlStyleObject);
|
|
4019
|
+
objectProperties.push(
|
|
4020
|
+
t.objectProperty(
|
|
4021
|
+
t.identifier("rtlStyle"),
|
|
4022
|
+
t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(rtlStyleKey))
|
|
4023
|
+
)
|
|
4024
|
+
);
|
|
4025
|
+
}
|
|
4026
|
+
if (ltrModifiers.length > 0) {
|
|
4027
|
+
const ltrClassNames = ltrModifiers.map((m) => m.baseClass).join(" ");
|
|
4028
|
+
const ltrStyleObject = parseClassName2(ltrClassNames, state.customTheme);
|
|
4029
|
+
const ltrStyleKey = generateStyleKey2(`ltr_${ltrClassNames}`);
|
|
4030
|
+
state.styleRegistry.set(ltrStyleKey, ltrStyleObject);
|
|
4031
|
+
objectProperties.push(
|
|
4032
|
+
t.objectProperty(
|
|
4033
|
+
t.identifier("ltrStyle"),
|
|
4034
|
+
t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(ltrStyleKey))
|
|
4035
|
+
)
|
|
4036
|
+
);
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
3720
4039
|
const modifiersByType = /* @__PURE__ */ new Map();
|
|
3721
4040
|
for (const mod of otherModifiers) {
|
|
3722
4041
|
if (!modifiersByType.has(mod.modifier)) {
|
|
@@ -3773,7 +4092,7 @@ function programExit(path2, state, t) {
|
|
|
3773
4092
|
if (state.hasTwImport) {
|
|
3774
4093
|
removeTwImports(path2, t);
|
|
3775
4094
|
}
|
|
3776
|
-
if (!state.hasClassNames && !state.needsWindowDimensionsImport && !state.needsColorSchemeImport) {
|
|
4095
|
+
if (!state.hasClassNames && !state.needsWindowDimensionsImport && !state.needsColorSchemeImport && !state.needsI18nManagerImport) {
|
|
3777
4096
|
return;
|
|
3778
4097
|
}
|
|
3779
4098
|
if (!state.hasStyleSheetImport && state.styleRegistry.size > 0) {
|
|
@@ -3782,6 +4101,12 @@ function programExit(path2, state, t) {
|
|
|
3782
4101
|
if (state.needsPlatformImport && !state.hasPlatformImport) {
|
|
3783
4102
|
addPlatformImport(path2, t);
|
|
3784
4103
|
}
|
|
4104
|
+
if (state.needsI18nManagerImport && !state.hasI18nManagerImport) {
|
|
4105
|
+
addI18nManagerImport(path2, t);
|
|
4106
|
+
}
|
|
4107
|
+
if (state.needsI18nManagerImport) {
|
|
4108
|
+
injectI18nManagerVariable(path2, state.i18nManagerVariableName, state.i18nManagerLocalIdentifier, t);
|
|
4109
|
+
}
|
|
3785
4110
|
if (state.needsColorSchemeImport && !state.hasColorSchemeImport) {
|
|
3786
4111
|
addColorSchemeImport(path2, state.colorSchemeImportSource, state.colorSchemeHookName, t);
|
|
3787
4112
|
}
|
|
@@ -94,6 +94,10 @@ export type PluginState = PluginPass & {
|
|
|
94
94
|
needsWindowDimensionsImport: boolean;
|
|
95
95
|
windowDimensionsVariableName: string;
|
|
96
96
|
windowDimensionsLocalIdentifier?: string;
|
|
97
|
+
hasI18nManagerImport: boolean;
|
|
98
|
+
needsI18nManagerImport: boolean;
|
|
99
|
+
i18nManagerVariableName: string;
|
|
100
|
+
i18nManagerLocalIdentifier?: string;
|
|
97
101
|
customTheme: CustomTheme;
|
|
98
102
|
schemeModifierConfig: SchemeModifierConfig;
|
|
99
103
|
supportedAttributes: Set<string>;
|