@mgcrea/react-native-tailwind 0.12.1 → 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 +45 -2031
- package/dist/babel/index.cjs +1726 -1094
- package/dist/babel/plugin/componentScope.d.ts +26 -0
- package/dist/babel/plugin/componentScope.ts +87 -0
- package/dist/babel/plugin/state.d.ts +123 -0
- package/dist/babel/plugin/state.ts +185 -0
- package/dist/babel/plugin/visitors/className.d.ts +11 -0
- package/{src/babel/plugin.test.ts → dist/babel/plugin/visitors/className.test.ts} +285 -572
- package/dist/babel/plugin/visitors/className.ts +652 -0
- package/dist/babel/plugin/visitors/className.windowDimensions.test.ts +406 -0
- package/dist/babel/plugin/visitors/imports.d.ts +11 -0
- package/dist/babel/plugin/visitors/imports.test.ts +88 -0
- package/dist/babel/plugin/visitors/imports.ts +116 -0
- package/dist/babel/plugin/visitors/program.d.ts +15 -0
- package/dist/babel/plugin/visitors/program.test.ts +325 -0
- package/dist/babel/plugin/visitors/program.ts +116 -0
- package/dist/babel/plugin/visitors/tw.d.ts +16 -0
- package/dist/babel/plugin/visitors/tw.test.ts +771 -0
- package/dist/babel/plugin/visitors/tw.ts +148 -0
- package/dist/babel/plugin.d.ts +3 -96
- package/dist/babel/plugin.test.ts +470 -0
- package/dist/babel/plugin.ts +28 -963
- package/dist/babel/utils/colorSchemeModifierProcessing.ts +11 -0
- package/dist/babel/utils/componentSupport.test.ts +20 -7
- package/dist/babel/utils/componentSupport.ts +2 -0
- package/dist/babel/utils/directionalModifierProcessing.d.ts +34 -0
- package/dist/babel/utils/directionalModifierProcessing.ts +99 -0
- package/dist/babel/utils/modifierProcessing.ts +21 -0
- package/dist/babel/utils/platformModifierProcessing.ts +11 -0
- package/dist/babel/utils/styleInjection.d.ts +31 -0
- package/dist/babel/utils/styleInjection.ts +253 -7
- package/dist/babel/utils/twProcessing.d.ts +2 -0
- package/dist/babel/utils/twProcessing.ts +103 -3
- package/dist/babel/utils/windowDimensionsProcessing.d.ts +56 -0
- package/dist/babel/utils/windowDimensionsProcessing.ts +121 -0
- package/dist/components/TouchableOpacity.d.ts +35 -0
- package/dist/components/TouchableOpacity.js +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +1 -0
- package/dist/config/markers.d.ts +5 -0
- package/dist/config/markers.js +1 -0
- package/dist/index.d.ts +2 -5
- package/dist/index.js +1 -1
- package/dist/parser/borders.d.ts +3 -1
- package/dist/parser/borders.js +1 -1
- package/dist/parser/borders.test.js +1 -1
- package/dist/parser/colors.js +1 -1
- package/dist/parser/colors.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/sizing.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 +4 -4
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +4 -4
- package/package.json +6 -6
- package/src/babel/plugin/componentScope.ts +87 -0
- package/src/babel/plugin/state.ts +185 -0
- package/src/babel/plugin/visitors/className.test.ts +1625 -0
- package/src/babel/plugin/visitors/className.ts +652 -0
- package/src/babel/plugin/visitors/className.windowDimensions.test.ts +406 -0
- package/src/babel/plugin/visitors/imports.test.ts +88 -0
- package/src/babel/plugin/visitors/imports.ts +116 -0
- package/src/babel/plugin/visitors/program.test.ts +325 -0
- package/src/babel/plugin/visitors/program.ts +116 -0
- package/src/babel/plugin/visitors/tw.test.ts +771 -0
- package/src/babel/plugin/visitors/tw.ts +148 -0
- package/src/babel/plugin.ts +28 -963
- package/src/babel/utils/colorSchemeModifierProcessing.ts +11 -0
- package/src/babel/utils/componentSupport.test.ts +20 -7
- package/src/babel/utils/componentSupport.ts +2 -0
- package/src/babel/utils/directionalModifierProcessing.ts +99 -0
- package/src/babel/utils/modifierProcessing.ts +21 -0
- package/src/babel/utils/platformModifierProcessing.ts +11 -0
- package/src/babel/utils/styleInjection.ts +253 -7
- package/src/babel/utils/twProcessing.ts +103 -3
- package/src/babel/utils/windowDimensionsProcessing.ts +121 -0
- package/src/components/TouchableOpacity.tsx +71 -0
- package/src/components/index.ts +3 -0
- package/src/config/markers.ts +5 -0
- package/src/index.ts +4 -5
- package/src/parser/borders.test.ts +162 -0
- package/src/parser/borders.ts +67 -9
- package/src/parser/colors.test.ts +249 -0
- package/src/parser/colors.ts +38 -0
- package/src/parser/index.ts +4 -2
- 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/sizing.ts +11 -0
- 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/dist/babel/index.cjs
CHANGED
|
@@ -34,6 +34,201 @@ __export(index_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
|
+
// src/babel/config-loader.ts
|
|
38
|
+
var fs = __toESM(require("fs"), 1);
|
|
39
|
+
var path = __toESM(require("path"), 1);
|
|
40
|
+
|
|
41
|
+
// src/utils/flattenColors.ts
|
|
42
|
+
function flattenColors(colors, prefix = "") {
|
|
43
|
+
const result = {};
|
|
44
|
+
for (const [key, value] of Object.entries(colors)) {
|
|
45
|
+
const newKey = key === "DEFAULT" && prefix ? prefix : prefix ? `${prefix}-${key}` : key;
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
result[newKey] = value;
|
|
48
|
+
} else if (typeof value === "object" && value !== null) {
|
|
49
|
+
Object.assign(result, flattenColors(value, newKey));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/babel/config-loader.ts
|
|
56
|
+
var configCache = /* @__PURE__ */ new Map();
|
|
57
|
+
function findTailwindConfig(startDir) {
|
|
58
|
+
let currentDir = startDir;
|
|
59
|
+
const root = path.parse(currentDir).root;
|
|
60
|
+
const configNames = [
|
|
61
|
+
"tailwind.config.mjs",
|
|
62
|
+
"tailwind.config.js",
|
|
63
|
+
"tailwind.config.cjs",
|
|
64
|
+
"tailwind.config.ts"
|
|
65
|
+
];
|
|
66
|
+
while (currentDir !== root) {
|
|
67
|
+
for (const configName of configNames) {
|
|
68
|
+
const configPath = path.join(currentDir, configName);
|
|
69
|
+
if (fs.existsSync(configPath)) {
|
|
70
|
+
return configPath;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
currentDir = path.dirname(currentDir);
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
function loadTailwindConfig(configPath) {
|
|
78
|
+
if (configCache.has(configPath)) {
|
|
79
|
+
return configCache.get(configPath);
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const resolvedPath = require.resolve(configPath);
|
|
83
|
+
delete require.cache[resolvedPath];
|
|
84
|
+
const config = require(configPath);
|
|
85
|
+
const resolved = "default" in config ? config.default : config;
|
|
86
|
+
configCache.set(configPath, resolved);
|
|
87
|
+
return resolved;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (process.env.NODE_ENV !== "production") {
|
|
90
|
+
console.warn(`[react-native-tailwind] Failed to load config from ${configPath}:`, error);
|
|
91
|
+
}
|
|
92
|
+
configCache.set(configPath, null);
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function extractCustomTheme(filename) {
|
|
97
|
+
const projectDir = path.dirname(filename);
|
|
98
|
+
const configPath = findTailwindConfig(projectDir);
|
|
99
|
+
if (!configPath) {
|
|
100
|
+
return { colors: {}, fontFamily: {}, fontSize: {} };
|
|
101
|
+
}
|
|
102
|
+
const config = loadTailwindConfig(configPath);
|
|
103
|
+
if (!config?.theme) {
|
|
104
|
+
return { colors: {}, fontFamily: {}, fontSize: {} };
|
|
105
|
+
}
|
|
106
|
+
if (config.theme.colors && !config.theme.extend?.colors && process.env.NODE_ENV !== "production") {
|
|
107
|
+
console.warn(
|
|
108
|
+
"[react-native-tailwind] Using theme.colors will override all default colors. Use theme.extend.colors to add custom colors while keeping defaults."
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const colors = config.theme.extend?.colors ?? config.theme.colors ?? {};
|
|
112
|
+
if (config.theme.fontFamily && !config.theme.extend?.fontFamily && process.env.NODE_ENV !== "production") {
|
|
113
|
+
console.warn(
|
|
114
|
+
"[react-native-tailwind] Using theme.fontFamily will override all default font families. Use theme.extend.fontFamily to add custom fonts while keeping defaults."
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
const fontFamily = config.theme.extend?.fontFamily ?? config.theme.fontFamily ?? {};
|
|
118
|
+
const fontFamilyResult = {};
|
|
119
|
+
for (const [key, value] of Object.entries(fontFamily)) {
|
|
120
|
+
if (Array.isArray(value)) {
|
|
121
|
+
fontFamilyResult[key] = value[0];
|
|
122
|
+
} else {
|
|
123
|
+
fontFamilyResult[key] = value;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (config.theme.fontSize && !config.theme.extend?.fontSize && process.env.NODE_ENV !== "production") {
|
|
127
|
+
console.warn(
|
|
128
|
+
"[react-native-tailwind] Using theme.fontSize will override all default font sizes. Use theme.extend.fontSize to add custom font sizes while keeping defaults."
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
const fontSize = config.theme.extend?.fontSize ?? config.theme.fontSize ?? {};
|
|
132
|
+
const fontSizeResult = {};
|
|
133
|
+
for (const [key, value] of Object.entries(fontSize)) {
|
|
134
|
+
if (typeof value === "number") {
|
|
135
|
+
fontSizeResult[key] = value;
|
|
136
|
+
} else if (typeof value === "string") {
|
|
137
|
+
const parsed = parseFloat(value.replace(/px$/, ""));
|
|
138
|
+
if (!isNaN(parsed)) {
|
|
139
|
+
fontSizeResult[key] = parsed;
|
|
140
|
+
} else {
|
|
141
|
+
if (process.env.NODE_ENV !== "production") {
|
|
142
|
+
console.warn(
|
|
143
|
+
`[react-native-tailwind] Invalid fontSize value for "${key}": ${value}. Expected number or string like "18px".`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
colors: flattenColors(colors),
|
|
151
|
+
fontFamily: fontFamilyResult,
|
|
152
|
+
fontSize: fontSizeResult
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// src/babel/utils/attributeMatchers.ts
|
|
157
|
+
var DEFAULT_CLASS_ATTRIBUTES = [
|
|
158
|
+
"className",
|
|
159
|
+
"contentContainerClassName",
|
|
160
|
+
"columnWrapperClassName",
|
|
161
|
+
"ListHeaderComponentClassName",
|
|
162
|
+
"ListFooterComponentClassName"
|
|
163
|
+
];
|
|
164
|
+
function buildAttributeMatchers(attributes) {
|
|
165
|
+
const exactMatches = /* @__PURE__ */ new Set();
|
|
166
|
+
const patterns = [];
|
|
167
|
+
for (const attr of attributes) {
|
|
168
|
+
if (attr.includes("*")) {
|
|
169
|
+
const regexPattern = "^" + attr.replace(/\*/g, ".*") + "$";
|
|
170
|
+
patterns.push(new RegExp(regexPattern));
|
|
171
|
+
} else {
|
|
172
|
+
exactMatches.add(attr);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return { exactMatches, patterns };
|
|
176
|
+
}
|
|
177
|
+
function isAttributeSupported(attributeName, exactMatches, patterns) {
|
|
178
|
+
if (exactMatches.has(attributeName)) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
for (const pattern of patterns) {
|
|
182
|
+
if (pattern.test(attributeName)) {
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
function getTargetStyleProp(attributeName) {
|
|
189
|
+
return attributeName.endsWith("ClassName") ? attributeName.replace("ClassName", "Style") : "style";
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// src/babel/plugin/state.ts
|
|
193
|
+
var DEFAULT_STYLES_IDENTIFIER = "_twStyles";
|
|
194
|
+
function createInitialState(options, filename, colorSchemeImportSource, colorSchemeHookName, schemeModifierConfig) {
|
|
195
|
+
const attributes = options?.attributes ?? [...DEFAULT_CLASS_ATTRIBUTES];
|
|
196
|
+
const { exactMatches, patterns } = buildAttributeMatchers(attributes);
|
|
197
|
+
const stylesIdentifier = options?.stylesIdentifier ?? DEFAULT_STYLES_IDENTIFIER;
|
|
198
|
+
const customTheme = extractCustomTheme(filename);
|
|
199
|
+
return {
|
|
200
|
+
styleRegistry: /* @__PURE__ */ new Map(),
|
|
201
|
+
hasClassNames: false,
|
|
202
|
+
hasStyleSheetImport: false,
|
|
203
|
+
hasPlatformImport: false,
|
|
204
|
+
needsPlatformImport: false,
|
|
205
|
+
hasColorSchemeImport: false,
|
|
206
|
+
needsColorSchemeImport: false,
|
|
207
|
+
colorSchemeVariableName: "_twColorScheme",
|
|
208
|
+
colorSchemeImportSource,
|
|
209
|
+
colorSchemeHookName,
|
|
210
|
+
colorSchemeLocalIdentifier: void 0,
|
|
211
|
+
hasWindowDimensionsImport: false,
|
|
212
|
+
needsWindowDimensionsImport: false,
|
|
213
|
+
windowDimensionsVariableName: "_twDimensions",
|
|
214
|
+
windowDimensionsLocalIdentifier: void 0,
|
|
215
|
+
hasI18nManagerImport: false,
|
|
216
|
+
needsI18nManagerImport: false,
|
|
217
|
+
i18nManagerVariableName: "_twIsRTL",
|
|
218
|
+
i18nManagerLocalIdentifier: void 0,
|
|
219
|
+
customTheme,
|
|
220
|
+
schemeModifierConfig,
|
|
221
|
+
supportedAttributes: exactMatches,
|
|
222
|
+
attributePatterns: patterns,
|
|
223
|
+
stylesIdentifier,
|
|
224
|
+
twImportNames: /* @__PURE__ */ new Set(),
|
|
225
|
+
hasTwImport: false,
|
|
226
|
+
reactNativeImportPath: void 0,
|
|
227
|
+
functionComponentsNeedingColorScheme: /* @__PURE__ */ new Set(),
|
|
228
|
+
functionComponentsNeedingWindowDimensions: /* @__PURE__ */ new Set()
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
37
232
|
// src/parser/aspectRatio.ts
|
|
38
233
|
var ASPECT_RATIO_PRESETS = {
|
|
39
234
|
"aspect-auto": void 0,
|
|
@@ -77,187 +272,6 @@ function parseAspectRatio(cls) {
|
|
|
77
272
|
return null;
|
|
78
273
|
}
|
|
79
274
|
|
|
80
|
-
// src/parser/borders.ts
|
|
81
|
-
var BORDER_WIDTH_SCALE = {
|
|
82
|
-
"": 1,
|
|
83
|
-
"0": 0,
|
|
84
|
-
"2": 2,
|
|
85
|
-
"4": 4,
|
|
86
|
-
"8": 8
|
|
87
|
-
};
|
|
88
|
-
var BORDER_RADIUS_SCALE = {
|
|
89
|
-
none: 0,
|
|
90
|
-
sm: 2,
|
|
91
|
-
"": 4,
|
|
92
|
-
md: 6,
|
|
93
|
-
lg: 8,
|
|
94
|
-
xl: 12,
|
|
95
|
-
"2xl": 16,
|
|
96
|
-
"3xl": 24,
|
|
97
|
-
full: 9999
|
|
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
|
-
}
|
|
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" };
|
|
151
|
-
if (cls.startsWith("border-")) {
|
|
152
|
-
return parseBorderWidth(cls);
|
|
153
|
-
}
|
|
154
|
-
if (cls === "border") {
|
|
155
|
-
return { borderWidth: 1 };
|
|
156
|
-
}
|
|
157
|
-
if (cls.startsWith("rounded")) {
|
|
158
|
-
return parseBorderRadius(cls);
|
|
159
|
-
}
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
162
|
-
function parseBorderWidth(cls) {
|
|
163
|
-
const dirMatch = cls.match(/^border-([trbl])(?:-(.+))?$/);
|
|
164
|
-
if (dirMatch) {
|
|
165
|
-
const dir = dirMatch[1];
|
|
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 };
|
|
177
|
-
}
|
|
178
|
-
return null;
|
|
179
|
-
}
|
|
180
|
-
const allMatch = cls.match(/^border-(\d+)$/);
|
|
181
|
-
if (allMatch) {
|
|
182
|
-
const value = BORDER_WIDTH_SCALE[allMatch[1]];
|
|
183
|
-
if (value !== void 0) {
|
|
184
|
-
return { borderWidth: value };
|
|
185
|
-
}
|
|
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
|
-
}
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
function parseBorderRadius(cls) {
|
|
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 };
|
|
222
|
-
}
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
const sideMatch = rest.match(/^([trbl])(?:-(.+))?$/);
|
|
226
|
-
if (sideMatch) {
|
|
227
|
-
const side = sideMatch[1];
|
|
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
|
-
}
|
|
240
|
-
if (value !== void 0) {
|
|
241
|
-
const result = {};
|
|
242
|
-
BORDER_RADIUS_SIDE_MAP[side].forEach((prop) => result[prop] = value);
|
|
243
|
-
return result;
|
|
244
|
-
}
|
|
245
|
-
return null;
|
|
246
|
-
}
|
|
247
|
-
if (rest.startsWith("[")) {
|
|
248
|
-
const arbitraryValue = parseArbitraryBorderRadius(rest);
|
|
249
|
-
if (arbitraryValue !== null) {
|
|
250
|
-
return { borderRadius: arbitraryValue };
|
|
251
|
-
}
|
|
252
|
-
return null;
|
|
253
|
-
}
|
|
254
|
-
const scaleValue = BORDER_RADIUS_SCALE[rest];
|
|
255
|
-
if (scaleValue !== void 0) {
|
|
256
|
-
return { borderRadius: scaleValue };
|
|
257
|
-
}
|
|
258
|
-
return null;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
275
|
// src/config/tailwind.ts
|
|
262
276
|
var TAILWIND_COLORS = {
|
|
263
277
|
red: {
|
|
@@ -548,20 +562,6 @@ var TAILWIND_COLORS = {
|
|
|
548
562
|
}
|
|
549
563
|
};
|
|
550
564
|
|
|
551
|
-
// src/utils/flattenColors.ts
|
|
552
|
-
function flattenColors(colors, prefix = "") {
|
|
553
|
-
const result = {};
|
|
554
|
-
for (const [key, value] of Object.entries(colors)) {
|
|
555
|
-
const newKey = key === "DEFAULT" && prefix ? prefix : prefix ? `${prefix}-${key}` : key;
|
|
556
|
-
if (typeof value === "string") {
|
|
557
|
-
result[newKey] = value;
|
|
558
|
-
} else if (typeof value === "object" && value !== null) {
|
|
559
|
-
Object.assign(result, flattenColors(value, newKey));
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
return result;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
565
|
// src/parser/colors.ts
|
|
566
566
|
var COLORS = {
|
|
567
567
|
...flattenColors(TAILWIND_COLORS),
|
|
@@ -663,101 +663,345 @@ function parseColor(cls, customColors) {
|
|
|
663
663
|
return { borderColor: color };
|
|
664
664
|
}
|
|
665
665
|
}
|
|
666
|
+
const dirBorderMatch = cls.match(/^border-([trblxy])-(.+)$/);
|
|
667
|
+
if (dirBorderMatch) {
|
|
668
|
+
const dir = dirBorderMatch[1];
|
|
669
|
+
const colorKey = dirBorderMatch[2];
|
|
670
|
+
if (colorKey.startsWith("[") && !colorKey.startsWith("[#")) {
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
const color = parseColorWithOpacity(colorKey);
|
|
674
|
+
if (color) {
|
|
675
|
+
if (dir === "x") {
|
|
676
|
+
return {
|
|
677
|
+
borderLeftColor: color,
|
|
678
|
+
borderRightColor: color
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
if (dir === "y") {
|
|
682
|
+
return {
|
|
683
|
+
borderTopColor: color,
|
|
684
|
+
borderBottomColor: color
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
const propMap = {
|
|
688
|
+
t: "borderTopColor",
|
|
689
|
+
r: "borderRightColor",
|
|
690
|
+
b: "borderBottomColor",
|
|
691
|
+
l: "borderLeftColor"
|
|
692
|
+
};
|
|
693
|
+
return { [propMap[dir]]: color };
|
|
694
|
+
}
|
|
695
|
+
}
|
|
666
696
|
return null;
|
|
667
697
|
}
|
|
668
698
|
|
|
669
|
-
// src/parser/
|
|
670
|
-
|
|
671
|
-
|
|
699
|
+
// src/parser/borders.ts
|
|
700
|
+
var BORDER_WIDTH_SCALE = {
|
|
701
|
+
"": 1,
|
|
702
|
+
"0": 0,
|
|
703
|
+
"2": 2,
|
|
704
|
+
"4": 4,
|
|
705
|
+
"8": 8
|
|
706
|
+
};
|
|
707
|
+
var BORDER_RADIUS_SCALE = {
|
|
708
|
+
none: 0,
|
|
709
|
+
sm: 2,
|
|
710
|
+
"": 4,
|
|
711
|
+
md: 6,
|
|
712
|
+
lg: 8,
|
|
713
|
+
xl: 12,
|
|
714
|
+
"2xl": 16,
|
|
715
|
+
"3xl": 24,
|
|
716
|
+
full: 9999
|
|
717
|
+
};
|
|
718
|
+
var BORDER_WIDTH_PROP_MAP = {
|
|
719
|
+
t: "borderTopWidth",
|
|
720
|
+
r: "borderRightWidth",
|
|
721
|
+
b: "borderBottomWidth",
|
|
722
|
+
l: "borderLeftWidth",
|
|
723
|
+
s: "borderStartWidth",
|
|
724
|
+
e: "borderEndWidth"
|
|
725
|
+
};
|
|
726
|
+
var BORDER_RADIUS_CORNER_MAP = {
|
|
727
|
+
tl: "borderTopLeftRadius",
|
|
728
|
+
tr: "borderTopRightRadius",
|
|
729
|
+
bl: "borderBottomLeftRadius",
|
|
730
|
+
br: "borderBottomRightRadius"
|
|
731
|
+
};
|
|
732
|
+
var BORDER_RADIUS_LOGICAL_CORNER_MAP = {
|
|
733
|
+
ss: "borderTopStartRadius",
|
|
734
|
+
se: "borderTopEndRadius",
|
|
735
|
+
es: "borderBottomStartRadius",
|
|
736
|
+
ee: "borderBottomEndRadius"
|
|
737
|
+
};
|
|
738
|
+
var BORDER_RADIUS_SIDE_MAP = {
|
|
739
|
+
t: ["borderTopLeftRadius", "borderTopRightRadius"],
|
|
740
|
+
r: ["borderTopRightRadius", "borderBottomRightRadius"],
|
|
741
|
+
b: ["borderBottomLeftRadius", "borderBottomRightRadius"],
|
|
742
|
+
l: ["borderTopLeftRadius", "borderBottomLeftRadius"],
|
|
743
|
+
s: ["borderTopStartRadius", "borderBottomStartRadius"],
|
|
744
|
+
e: ["borderTopEndRadius", "borderBottomEndRadius"]
|
|
745
|
+
};
|
|
746
|
+
function parseArbitraryBorderWidth(value) {
|
|
747
|
+
const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
|
|
672
748
|
if (pxMatch) {
|
|
673
749
|
return parseInt(pxMatch[1], 10);
|
|
674
750
|
}
|
|
675
|
-
const percentMatch = value.match(/^\[(-?\d+(?:\.\d+)?)%\]$/);
|
|
676
|
-
if (percentMatch) {
|
|
677
|
-
return `${percentMatch[1]}%`;
|
|
678
|
-
}
|
|
679
751
|
if (value.startsWith("[") && value.endsWith("]")) {
|
|
680
752
|
if (process.env.NODE_ENV !== "production") {
|
|
681
753
|
console.warn(
|
|
682
|
-
`[react-native-tailwind] Unsupported arbitrary
|
|
754
|
+
`[react-native-tailwind] Unsupported arbitrary border width value: ${value}. Only px values are supported (e.g., [8px] or [8]).`
|
|
683
755
|
);
|
|
684
756
|
}
|
|
685
757
|
return null;
|
|
686
758
|
}
|
|
687
759
|
return null;
|
|
688
760
|
}
|
|
689
|
-
function
|
|
690
|
-
const
|
|
691
|
-
if (
|
|
692
|
-
return parseInt(
|
|
761
|
+
function parseArbitraryBorderRadius(value) {
|
|
762
|
+
const pxMatch = value.match(/^\[(\d+)(?:px)?\]$/);
|
|
763
|
+
if (pxMatch) {
|
|
764
|
+
return parseInt(pxMatch[1], 10);
|
|
693
765
|
}
|
|
694
766
|
if (value.startsWith("[") && value.endsWith("]")) {
|
|
695
767
|
if (process.env.NODE_ENV !== "production") {
|
|
696
768
|
console.warn(
|
|
697
|
-
`[react-native-tailwind]
|
|
769
|
+
`[react-native-tailwind] Unsupported arbitrary border radius value: ${value}. Only px values are supported (e.g., [12px] or [12]).`
|
|
698
770
|
);
|
|
699
771
|
}
|
|
700
772
|
return null;
|
|
701
773
|
}
|
|
702
774
|
return null;
|
|
703
775
|
}
|
|
704
|
-
function
|
|
705
|
-
|
|
706
|
-
if (
|
|
707
|
-
|
|
776
|
+
function parseBorder(cls, customColors) {
|
|
777
|
+
if (cls === "border-solid") return { borderStyle: "solid" };
|
|
778
|
+
if (cls === "border-dotted") return { borderStyle: "dotted" };
|
|
779
|
+
if (cls === "border-dashed") return { borderStyle: "dashed" };
|
|
780
|
+
if (cls.startsWith("border-")) {
|
|
781
|
+
return parseBorderWidth(cls, customColors);
|
|
708
782
|
}
|
|
709
|
-
if (
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
783
|
+
if (cls === "border") {
|
|
784
|
+
return { borderWidth: 1 };
|
|
785
|
+
}
|
|
786
|
+
if (cls.startsWith("rounded")) {
|
|
787
|
+
return parseBorderRadius(cls);
|
|
788
|
+
}
|
|
789
|
+
return null;
|
|
790
|
+
}
|
|
791
|
+
function parseBorderWidth(cls, customColors) {
|
|
792
|
+
const dirMatch = cls.match(/^border-([trblse])(?:-(.+))?$/);
|
|
793
|
+
if (dirMatch) {
|
|
794
|
+
const dir = dirMatch[1];
|
|
795
|
+
const valueStr = dirMatch[2] || "";
|
|
796
|
+
if (valueStr && dir !== "s" && dir !== "e") {
|
|
797
|
+
const colorResult = parseColor(cls, customColors);
|
|
798
|
+
if (colorResult !== null) {
|
|
799
|
+
return null;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
if (valueStr.startsWith("[")) {
|
|
803
|
+
const arbitraryValue = parseArbitraryBorderWidth(valueStr);
|
|
804
|
+
if (arbitraryValue !== null) {
|
|
805
|
+
return { [BORDER_WIDTH_PROP_MAP[dir]]: arbitraryValue };
|
|
806
|
+
}
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
const scaleValue = BORDER_WIDTH_SCALE[valueStr];
|
|
810
|
+
if (scaleValue !== void 0) {
|
|
811
|
+
return { [BORDER_WIDTH_PROP_MAP[dir]]: scaleValue };
|
|
714
812
|
}
|
|
715
813
|
return null;
|
|
716
814
|
}
|
|
815
|
+
const allMatch = cls.match(/^border-(\d+)$/);
|
|
816
|
+
if (allMatch) {
|
|
817
|
+
const value = BORDER_WIDTH_SCALE[allMatch[1]];
|
|
818
|
+
if (value !== void 0) {
|
|
819
|
+
return { borderWidth: value };
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
const allArbMatch = cls.match(/^border-(\[.+\])$/);
|
|
823
|
+
if (allArbMatch) {
|
|
824
|
+
const arbitraryValue = parseArbitraryBorderWidth(allArbMatch[1]);
|
|
825
|
+
if (arbitraryValue !== null) {
|
|
826
|
+
return { borderWidth: arbitraryValue };
|
|
827
|
+
}
|
|
828
|
+
}
|
|
717
829
|
return null;
|
|
718
830
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
};
|
|
723
|
-
|
|
724
|
-
"
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
};
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
831
|
+
function parseBorderRadius(cls) {
|
|
832
|
+
const withoutPrefix = cls.substring(7);
|
|
833
|
+
if (withoutPrefix === "") {
|
|
834
|
+
return { borderRadius: BORDER_RADIUS_SCALE[""] };
|
|
835
|
+
}
|
|
836
|
+
if (!withoutPrefix.startsWith("-")) {
|
|
837
|
+
return null;
|
|
838
|
+
}
|
|
839
|
+
const rest = withoutPrefix.substring(1);
|
|
840
|
+
if (rest === "") {
|
|
841
|
+
return null;
|
|
842
|
+
}
|
|
843
|
+
const cornerMatch = rest.match(/^(tl|tr|bl|br)(?:-(.+))?$/);
|
|
844
|
+
if (cornerMatch) {
|
|
845
|
+
const corner = cornerMatch[1];
|
|
846
|
+
const valueStr = cornerMatch[2] || "";
|
|
847
|
+
if (valueStr.startsWith("[")) {
|
|
848
|
+
const arbitraryValue = parseArbitraryBorderRadius(valueStr);
|
|
849
|
+
if (arbitraryValue !== null) {
|
|
850
|
+
return { [BORDER_RADIUS_CORNER_MAP[corner]]: arbitraryValue };
|
|
851
|
+
}
|
|
852
|
+
return null;
|
|
853
|
+
}
|
|
854
|
+
const scaleValue2 = BORDER_RADIUS_SCALE[valueStr];
|
|
855
|
+
if (scaleValue2 !== void 0) {
|
|
856
|
+
return { [BORDER_RADIUS_CORNER_MAP[corner]]: scaleValue2 };
|
|
857
|
+
}
|
|
858
|
+
return null;
|
|
859
|
+
}
|
|
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])(?:-(.+))?$/);
|
|
878
|
+
if (sideMatch) {
|
|
879
|
+
const side = sideMatch[1];
|
|
880
|
+
const valueStr = sideMatch[2] || "";
|
|
881
|
+
let value;
|
|
882
|
+
if (valueStr.startsWith("[")) {
|
|
883
|
+
const arbitraryValue = parseArbitraryBorderRadius(valueStr);
|
|
884
|
+
if (arbitraryValue !== null) {
|
|
885
|
+
value = arbitraryValue;
|
|
886
|
+
} else {
|
|
887
|
+
return null;
|
|
888
|
+
}
|
|
889
|
+
} else {
|
|
890
|
+
value = BORDER_RADIUS_SCALE[valueStr];
|
|
891
|
+
}
|
|
892
|
+
if (value !== void 0) {
|
|
893
|
+
const result = {};
|
|
894
|
+
BORDER_RADIUS_SIDE_MAP[side].forEach((prop) => result[prop] = value);
|
|
895
|
+
return result;
|
|
896
|
+
}
|
|
897
|
+
return null;
|
|
898
|
+
}
|
|
899
|
+
if (rest.startsWith("[")) {
|
|
900
|
+
const arbitraryValue = parseArbitraryBorderRadius(rest);
|
|
901
|
+
if (arbitraryValue !== null) {
|
|
902
|
+
return { borderRadius: arbitraryValue };
|
|
903
|
+
}
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
const scaleValue = BORDER_RADIUS_SCALE[rest];
|
|
907
|
+
if (scaleValue !== void 0) {
|
|
908
|
+
return { borderRadius: scaleValue };
|
|
909
|
+
}
|
|
910
|
+
return null;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// src/parser/layout.ts
|
|
914
|
+
function parseArbitraryInset(value) {
|
|
915
|
+
const pxMatch = value.match(/^\[(-?\d+)(?:px)?\]$/);
|
|
916
|
+
if (pxMatch) {
|
|
917
|
+
return parseInt(pxMatch[1], 10);
|
|
918
|
+
}
|
|
919
|
+
const percentMatch = value.match(/^\[(-?\d+(?:\.\d+)?)%\]$/);
|
|
920
|
+
if (percentMatch) {
|
|
921
|
+
return `${percentMatch[1]}%`;
|
|
922
|
+
}
|
|
923
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
924
|
+
if (process.env.NODE_ENV !== "production") {
|
|
925
|
+
console.warn(
|
|
926
|
+
`[react-native-tailwind] Unsupported arbitrary inset unit: ${value}. Only px and % are supported.`
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
return null;
|
|
930
|
+
}
|
|
931
|
+
return null;
|
|
932
|
+
}
|
|
933
|
+
function parseArbitraryZIndex(value) {
|
|
934
|
+
const zMatch = value.match(/^\[(-?\d+)\]$/);
|
|
935
|
+
if (zMatch) {
|
|
936
|
+
return parseInt(zMatch[1], 10);
|
|
937
|
+
}
|
|
938
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
939
|
+
if (process.env.NODE_ENV !== "production") {
|
|
940
|
+
console.warn(
|
|
941
|
+
`[react-native-tailwind] Invalid arbitrary z-index: ${value}. Only integers are supported.`
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
return null;
|
|
945
|
+
}
|
|
946
|
+
return null;
|
|
947
|
+
}
|
|
948
|
+
function parseArbitraryGrowShrink(value) {
|
|
949
|
+
const match = value.match(/^\[(\d+(?:\.\d+)?|\.\d+)\]$/);
|
|
950
|
+
if (match) {
|
|
951
|
+
return parseFloat(match[1]);
|
|
952
|
+
}
|
|
953
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
954
|
+
if (process.env.NODE_ENV !== "production") {
|
|
955
|
+
console.warn(
|
|
956
|
+
`[react-native-tailwind] Invalid arbitrary grow/shrink value: ${value}. Only non-negative numbers are supported (e.g., [1.5], [2], [0.5], [.5]).`
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
return null;
|
|
960
|
+
}
|
|
961
|
+
return null;
|
|
962
|
+
}
|
|
963
|
+
var DISPLAY_MAP = {
|
|
964
|
+
flex: { display: "flex" },
|
|
965
|
+
hidden: { display: "none" }
|
|
966
|
+
};
|
|
967
|
+
var FLEX_DIRECTION_MAP = {
|
|
968
|
+
"flex-row": { flexDirection: "row" },
|
|
969
|
+
"flex-row-reverse": { flexDirection: "row-reverse" },
|
|
970
|
+
"flex-col": { flexDirection: "column" },
|
|
971
|
+
"flex-col-reverse": { flexDirection: "column-reverse" }
|
|
972
|
+
};
|
|
973
|
+
var FLEX_WRAP_MAP = {
|
|
974
|
+
"flex-wrap": { flexWrap: "wrap" },
|
|
975
|
+
"flex-wrap-reverse": { flexWrap: "wrap-reverse" },
|
|
976
|
+
"flex-nowrap": { flexWrap: "nowrap" }
|
|
977
|
+
};
|
|
978
|
+
var FLEX_MAP = {
|
|
979
|
+
"flex-1": { flex: 1 },
|
|
980
|
+
"flex-auto": { flex: 1 },
|
|
981
|
+
"flex-none": { flex: 0 }
|
|
982
|
+
};
|
|
983
|
+
var GROW_SHRINK_MAP = {
|
|
984
|
+
grow: { flexGrow: 1 },
|
|
985
|
+
"grow-0": { flexGrow: 0 },
|
|
986
|
+
shrink: { flexShrink: 1 },
|
|
987
|
+
"shrink-0": { flexShrink: 0 },
|
|
988
|
+
// CSS-style aliases
|
|
989
|
+
"flex-grow": { flexGrow: 1 },
|
|
990
|
+
"flex-grow-0": { flexGrow: 0 },
|
|
991
|
+
"flex-shrink": { flexShrink: 1 },
|
|
992
|
+
"flex-shrink-0": { flexShrink: 0 }
|
|
993
|
+
};
|
|
994
|
+
var JUSTIFY_CONTENT_MAP = {
|
|
995
|
+
"justify-start": { justifyContent: "flex-start" },
|
|
996
|
+
"justify-end": { justifyContent: "flex-end" },
|
|
997
|
+
"justify-center": { justifyContent: "center" },
|
|
998
|
+
"justify-between": { justifyContent: "space-between" },
|
|
999
|
+
"justify-around": { justifyContent: "space-around" },
|
|
1000
|
+
"justify-evenly": { justifyContent: "space-evenly" }
|
|
1001
|
+
};
|
|
1002
|
+
var ALIGN_ITEMS_MAP = {
|
|
1003
|
+
"items-start": { alignItems: "flex-start" },
|
|
1004
|
+
"items-end": { alignItems: "flex-end" },
|
|
761
1005
|
"items-center": { alignItems: "center" },
|
|
762
1006
|
"items-baseline": { alignItems: "baseline" },
|
|
763
1007
|
"items-stretch": { alignItems: "stretch" }
|
|
@@ -907,6 +1151,52 @@ function parseLayout(cls) {
|
|
|
907
1151
|
return { left: leftValue };
|
|
908
1152
|
}
|
|
909
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
|
+
}
|
|
910
1200
|
if (cls.startsWith("inset-x-")) {
|
|
911
1201
|
const insetKey = cls.substring(8);
|
|
912
1202
|
const arbitraryInset = parseArbitraryInset(insetKey);
|
|
@@ -929,6 +1219,28 @@ function parseLayout(cls) {
|
|
|
929
1219
|
return { top: insetValue, bottom: insetValue };
|
|
930
1220
|
}
|
|
931
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
|
+
}
|
|
932
1244
|
if (cls.startsWith("inset-")) {
|
|
933
1245
|
const insetKey = cls.substring(6);
|
|
934
1246
|
const arbitraryInset = parseArbitraryInset(insetKey);
|
|
@@ -1018,6 +1330,9 @@ function parseShadow(cls) {
|
|
|
1018
1330
|
return null;
|
|
1019
1331
|
}
|
|
1020
1332
|
|
|
1333
|
+
// src/config/markers.ts
|
|
1334
|
+
var RUNTIME_DIMENSIONS_MARKER = "{{RUNTIME:dimensions.";
|
|
1335
|
+
|
|
1021
1336
|
// src/parser/sizing.ts
|
|
1022
1337
|
var SIZE_SCALE = {
|
|
1023
1338
|
0: 0,
|
|
@@ -1095,6 +1410,9 @@ function parseArbitrarySize(value) {
|
|
|
1095
1410
|
function parseSizing(cls) {
|
|
1096
1411
|
if (cls.startsWith("w-")) {
|
|
1097
1412
|
const sizeKey = cls.substring(2);
|
|
1413
|
+
if (sizeKey === "screen") {
|
|
1414
|
+
return { width: `${RUNTIME_DIMENSIONS_MARKER}width}}` };
|
|
1415
|
+
}
|
|
1098
1416
|
const arbitrarySize = parseArbitrarySize(sizeKey);
|
|
1099
1417
|
if (arbitrarySize !== null) {
|
|
1100
1418
|
return { width: arbitrarySize };
|
|
@@ -1113,6 +1431,9 @@ function parseSizing(cls) {
|
|
|
1113
1431
|
}
|
|
1114
1432
|
if (cls.startsWith("h-")) {
|
|
1115
1433
|
const sizeKey = cls.substring(2);
|
|
1434
|
+
if (sizeKey === "screen") {
|
|
1435
|
+
return { height: `${RUNTIME_DIMENSIONS_MARKER}height}}` };
|
|
1436
|
+
}
|
|
1116
1437
|
const arbitrarySize = parseArbitrarySize(sizeKey);
|
|
1117
1438
|
if (arbitrarySize !== null) {
|
|
1118
1439
|
return { height: arbitrarySize };
|
|
@@ -1245,7 +1566,7 @@ function parseArbitrarySpacing(value) {
|
|
|
1245
1566
|
return null;
|
|
1246
1567
|
}
|
|
1247
1568
|
function parseSpacing(cls) {
|
|
1248
|
-
const marginMatch = cls.match(/^(-?)m([
|
|
1569
|
+
const marginMatch = cls.match(/^(-?)m([xytrblse]?)-(.+)$/);
|
|
1249
1570
|
if (marginMatch) {
|
|
1250
1571
|
const [, negativePrefix, dir, valueStr] = marginMatch;
|
|
1251
1572
|
const isNegative = negativePrefix === "-";
|
|
@@ -1260,7 +1581,7 @@ function parseSpacing(cls) {
|
|
|
1260
1581
|
return getMarginStyle(dir, finalValue);
|
|
1261
1582
|
}
|
|
1262
1583
|
}
|
|
1263
|
-
const paddingMatch = cls.match(/^p([
|
|
1584
|
+
const paddingMatch = cls.match(/^p([xytrblse]?)-(.+)$/);
|
|
1264
1585
|
if (paddingMatch) {
|
|
1265
1586
|
const [, dir, valueStr] = paddingMatch;
|
|
1266
1587
|
const arbitraryValue = parseArbitrarySpacing(valueStr);
|
|
@@ -1302,6 +1623,10 @@ function getMarginStyle(dir, value) {
|
|
|
1302
1623
|
return { marginBottom: value };
|
|
1303
1624
|
case "l":
|
|
1304
1625
|
return { marginLeft: value };
|
|
1626
|
+
case "s":
|
|
1627
|
+
return { marginStart: value };
|
|
1628
|
+
case "e":
|
|
1629
|
+
return { marginEnd: value };
|
|
1305
1630
|
default:
|
|
1306
1631
|
return {};
|
|
1307
1632
|
}
|
|
@@ -1322,6 +1647,10 @@ function getPaddingStyle(dir, value) {
|
|
|
1322
1647
|
return { paddingBottom: value };
|
|
1323
1648
|
case "l":
|
|
1324
1649
|
return { paddingLeft: value };
|
|
1650
|
+
case "s":
|
|
1651
|
+
return { paddingStart: value };
|
|
1652
|
+
case "e":
|
|
1653
|
+
return { paddingEnd: value };
|
|
1325
1654
|
default:
|
|
1326
1655
|
return {};
|
|
1327
1656
|
}
|
|
@@ -1810,11 +2139,13 @@ var STATE_MODIFIERS = [
|
|
|
1810
2139
|
var PLATFORM_MODIFIERS = ["ios", "android", "web"];
|
|
1811
2140
|
var COLOR_SCHEME_MODIFIERS = ["dark", "light"];
|
|
1812
2141
|
var SCHEME_MODIFIERS = ["scheme"];
|
|
2142
|
+
var DIRECTIONAL_MODIFIERS = ["rtl", "ltr"];
|
|
1813
2143
|
var SUPPORTED_MODIFIERS = [
|
|
1814
2144
|
...STATE_MODIFIERS,
|
|
1815
2145
|
...PLATFORM_MODIFIERS,
|
|
1816
2146
|
...COLOR_SCHEME_MODIFIERS,
|
|
1817
|
-
...SCHEME_MODIFIERS
|
|
2147
|
+
...SCHEME_MODIFIERS,
|
|
2148
|
+
...DIRECTIONAL_MODIFIERS
|
|
1818
2149
|
];
|
|
1819
2150
|
function parseModifier(cls) {
|
|
1820
2151
|
const colonIndex = cls.indexOf(":");
|
|
@@ -1849,6 +2180,9 @@ function isColorSchemeModifier(modifier) {
|
|
|
1849
2180
|
function isSchemeModifier(modifier) {
|
|
1850
2181
|
return SCHEME_MODIFIERS.includes(modifier);
|
|
1851
2182
|
}
|
|
2183
|
+
function isDirectionalModifier(modifier) {
|
|
2184
|
+
return DIRECTIONAL_MODIFIERS.includes(modifier);
|
|
2185
|
+
}
|
|
1852
2186
|
function isColorClass(className) {
|
|
1853
2187
|
return className.startsWith("text-") || className.startsWith("bg-") || className.startsWith("border-");
|
|
1854
2188
|
}
|
|
@@ -1893,11 +2227,24 @@ function expandSchemeModifier(schemeModifier, customColors, darkSuffix = "-dark"
|
|
|
1893
2227
|
}
|
|
1894
2228
|
];
|
|
1895
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
|
+
}
|
|
1896
2237
|
function splitModifierClasses(className) {
|
|
1897
2238
|
const classes = className.trim().split(/\s+/).filter(Boolean);
|
|
1898
2239
|
const baseClasses = [];
|
|
1899
2240
|
const modifierClasses = [];
|
|
1900
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
|
+
}
|
|
1901
2248
|
const parsed = parseModifier(cls);
|
|
1902
2249
|
if (parsed) {
|
|
1903
2250
|
modifierClasses.push(parsed);
|
|
@@ -1921,7 +2268,7 @@ function parseClassName(className, customTheme) {
|
|
|
1921
2268
|
function parseClass(cls, customTheme) {
|
|
1922
2269
|
const parsers = [
|
|
1923
2270
|
parseSpacing,
|
|
1924
|
-
parseBorder,
|
|
2271
|
+
(cls2) => parseBorder(cls2, customTheme?.colors),
|
|
1925
2272
|
(cls2) => parseColor(cls2, customTheme?.colors),
|
|
1926
2273
|
parseLayout,
|
|
1927
2274
|
(cls2) => parseTypography(cls2, customTheme?.fontFamily, customTheme?.fontSize),
|
|
@@ -1949,143 +2296,49 @@ function generateStyleKey(className) {
|
|
|
1949
2296
|
return key;
|
|
1950
2297
|
}
|
|
1951
2298
|
|
|
1952
|
-
// src/babel/
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
"
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2299
|
+
// src/babel/utils/windowDimensionsProcessing.ts
|
|
2300
|
+
function hasRuntimeDimensions(styleObject) {
|
|
2301
|
+
return Object.values(styleObject).some(
|
|
2302
|
+
(value) => typeof value === "string" && value.startsWith(RUNTIME_DIMENSIONS_MARKER)
|
|
2303
|
+
);
|
|
2304
|
+
}
|
|
2305
|
+
function createRuntimeDimensionObject(styleObject, state, t) {
|
|
2306
|
+
state.needsWindowDimensionsImport = true;
|
|
2307
|
+
const properties = [];
|
|
2308
|
+
for (const [key, value] of Object.entries(styleObject)) {
|
|
2309
|
+
let valueNode;
|
|
2310
|
+
if (typeof value === "string" && value.startsWith(RUNTIME_DIMENSIONS_MARKER)) {
|
|
2311
|
+
const match = value.match(/dimensions\.(\w+)/);
|
|
2312
|
+
const prop = match?.[1];
|
|
2313
|
+
if (prop) {
|
|
2314
|
+
valueNode = t.memberExpression(t.identifier(state.windowDimensionsVariableName), t.identifier(prop));
|
|
2315
|
+
} else {
|
|
2316
|
+
valueNode = t.stringLiteral(value);
|
|
1970
2317
|
}
|
|
2318
|
+
} else if (typeof value === "number") {
|
|
2319
|
+
valueNode = t.numericLiteral(value);
|
|
2320
|
+
} else if (typeof value === "string") {
|
|
2321
|
+
valueNode = t.stringLiteral(value);
|
|
2322
|
+
} else if (typeof value === "object" && value !== null) {
|
|
2323
|
+
valueNode = t.valueToNode(value);
|
|
2324
|
+
} else {
|
|
2325
|
+
valueNode = t.valueToNode(value);
|
|
1971
2326
|
}
|
|
1972
|
-
|
|
2327
|
+
properties.push(t.objectProperty(t.identifier(key), valueNode));
|
|
1973
2328
|
}
|
|
1974
|
-
return
|
|
2329
|
+
return t.objectExpression(properties);
|
|
1975
2330
|
}
|
|
1976
|
-
function
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
const resolved = "default" in config ? config.default : config;
|
|
1985
|
-
configCache.set(configPath, resolved);
|
|
1986
|
-
return resolved;
|
|
1987
|
-
} catch (error) {
|
|
1988
|
-
if (process.env.NODE_ENV !== "production") {
|
|
1989
|
-
console.warn(`[react-native-tailwind] Failed to load config from ${configPath}:`, error);
|
|
2331
|
+
function splitStaticAndRuntimeStyles(styleObject) {
|
|
2332
|
+
const staticStyles = {};
|
|
2333
|
+
const runtimeStyles = {};
|
|
2334
|
+
for (const [key, value] of Object.entries(styleObject)) {
|
|
2335
|
+
if (typeof value === "string" && value.startsWith(RUNTIME_DIMENSIONS_MARKER)) {
|
|
2336
|
+
runtimeStyles[key] = value;
|
|
2337
|
+
} else {
|
|
2338
|
+
staticStyles[key] = value;
|
|
1990
2339
|
}
|
|
1991
|
-
configCache.set(configPath, null);
|
|
1992
|
-
return null;
|
|
1993
2340
|
}
|
|
1994
|
-
}
|
|
1995
|
-
function extractCustomTheme(filename) {
|
|
1996
|
-
const projectDir = path.dirname(filename);
|
|
1997
|
-
const configPath = findTailwindConfig(projectDir);
|
|
1998
|
-
if (!configPath) {
|
|
1999
|
-
return { colors: {}, fontFamily: {}, fontSize: {} };
|
|
2000
|
-
}
|
|
2001
|
-
const config = loadTailwindConfig(configPath);
|
|
2002
|
-
if (!config?.theme) {
|
|
2003
|
-
return { colors: {}, fontFamily: {}, fontSize: {} };
|
|
2004
|
-
}
|
|
2005
|
-
if (config.theme.colors && !config.theme.extend?.colors && process.env.NODE_ENV !== "production") {
|
|
2006
|
-
console.warn(
|
|
2007
|
-
"[react-native-tailwind] Using theme.colors will override all default colors. Use theme.extend.colors to add custom colors while keeping defaults."
|
|
2008
|
-
);
|
|
2009
|
-
}
|
|
2010
|
-
const colors = config.theme.extend?.colors ?? config.theme.colors ?? {};
|
|
2011
|
-
if (config.theme.fontFamily && !config.theme.extend?.fontFamily && process.env.NODE_ENV !== "production") {
|
|
2012
|
-
console.warn(
|
|
2013
|
-
"[react-native-tailwind] Using theme.fontFamily will override all default font families. Use theme.extend.fontFamily to add custom fonts while keeping defaults."
|
|
2014
|
-
);
|
|
2015
|
-
}
|
|
2016
|
-
const fontFamily = config.theme.extend?.fontFamily ?? config.theme.fontFamily ?? {};
|
|
2017
|
-
const fontFamilyResult = {};
|
|
2018
|
-
for (const [key, value] of Object.entries(fontFamily)) {
|
|
2019
|
-
if (Array.isArray(value)) {
|
|
2020
|
-
fontFamilyResult[key] = value[0];
|
|
2021
|
-
} else {
|
|
2022
|
-
fontFamilyResult[key] = value;
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
if (config.theme.fontSize && !config.theme.extend?.fontSize && process.env.NODE_ENV !== "production") {
|
|
2026
|
-
console.warn(
|
|
2027
|
-
"[react-native-tailwind] Using theme.fontSize will override all default font sizes. Use theme.extend.fontSize to add custom font sizes while keeping defaults."
|
|
2028
|
-
);
|
|
2029
|
-
}
|
|
2030
|
-
const fontSize = config.theme.extend?.fontSize ?? config.theme.fontSize ?? {};
|
|
2031
|
-
const fontSizeResult = {};
|
|
2032
|
-
for (const [key, value] of Object.entries(fontSize)) {
|
|
2033
|
-
if (typeof value === "number") {
|
|
2034
|
-
fontSizeResult[key] = value;
|
|
2035
|
-
} else if (typeof value === "string") {
|
|
2036
|
-
const parsed = parseFloat(value.replace(/px$/, ""));
|
|
2037
|
-
if (!isNaN(parsed)) {
|
|
2038
|
-
fontSizeResult[key] = parsed;
|
|
2039
|
-
} else {
|
|
2040
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2041
|
-
console.warn(
|
|
2042
|
-
`[react-native-tailwind] Invalid fontSize value for "${key}": ${value}. Expected number or string like "18px".`
|
|
2043
|
-
);
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
}
|
|
2047
|
-
}
|
|
2048
|
-
return {
|
|
2049
|
-
colors: flattenColors(colors),
|
|
2050
|
-
fontFamily: fontFamilyResult,
|
|
2051
|
-
fontSize: fontSizeResult
|
|
2052
|
-
};
|
|
2053
|
-
}
|
|
2054
|
-
|
|
2055
|
-
// src/babel/utils/attributeMatchers.ts
|
|
2056
|
-
var DEFAULT_CLASS_ATTRIBUTES = [
|
|
2057
|
-
"className",
|
|
2058
|
-
"contentContainerClassName",
|
|
2059
|
-
"columnWrapperClassName",
|
|
2060
|
-
"ListHeaderComponentClassName",
|
|
2061
|
-
"ListFooterComponentClassName"
|
|
2062
|
-
];
|
|
2063
|
-
function buildAttributeMatchers(attributes) {
|
|
2064
|
-
const exactMatches = /* @__PURE__ */ new Set();
|
|
2065
|
-
const patterns = [];
|
|
2066
|
-
for (const attr of attributes) {
|
|
2067
|
-
if (attr.includes("*")) {
|
|
2068
|
-
const regexPattern = "^" + attr.replace(/\*/g, ".*") + "$";
|
|
2069
|
-
patterns.push(new RegExp(regexPattern));
|
|
2070
|
-
} else {
|
|
2071
|
-
exactMatches.add(attr);
|
|
2072
|
-
}
|
|
2073
|
-
}
|
|
2074
|
-
return { exactMatches, patterns };
|
|
2075
|
-
}
|
|
2076
|
-
function isAttributeSupported(attributeName, exactMatches, patterns) {
|
|
2077
|
-
if (exactMatches.has(attributeName)) {
|
|
2078
|
-
return true;
|
|
2079
|
-
}
|
|
2080
|
-
for (const pattern of patterns) {
|
|
2081
|
-
if (pattern.test(attributeName)) {
|
|
2082
|
-
return true;
|
|
2083
|
-
}
|
|
2084
|
-
}
|
|
2085
|
-
return false;
|
|
2086
|
-
}
|
|
2087
|
-
function getTargetStyleProp(attributeName) {
|
|
2088
|
-
return attributeName.endsWith("ClassName") ? attributeName.replace("ClassName", "Style") : "style";
|
|
2341
|
+
return { static: staticStyles, runtime: runtimeStyles };
|
|
2089
2342
|
}
|
|
2090
2343
|
|
|
2091
2344
|
// src/babel/utils/colorSchemeModifierProcessing.ts
|
|
@@ -2106,6 +2359,11 @@ function processColorSchemeModifiers(colorSchemeModifiers, state, parseClassName
|
|
|
2106
2359
|
for (const [scheme, modifiers] of modifiersByScheme) {
|
|
2107
2360
|
const classNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
2108
2361
|
const styleObject = parseClassName2(classNames, state.customTheme);
|
|
2362
|
+
if (hasRuntimeDimensions(styleObject)) {
|
|
2363
|
+
throw new Error(
|
|
2364
|
+
`w-screen and h-screen cannot be combined with color scheme modifiers (dark:, light:, scheme:). Found in: "${scheme}:${classNames}". Use w-screen/h-screen without modifiers instead.`
|
|
2365
|
+
);
|
|
2366
|
+
}
|
|
2109
2367
|
const styleKey = generateStyleKey2(`${scheme}_${classNames}`);
|
|
2110
2368
|
state.styleRegistry.set(styleKey, styleObject);
|
|
2111
2369
|
const colorSchemeCheck = t.binaryExpression(
|
|
@@ -2142,6 +2400,8 @@ function getComponentModifierSupport(jsxElement, t) {
|
|
|
2142
2400
|
switch (componentName) {
|
|
2143
2401
|
case "Pressable":
|
|
2144
2402
|
return { component: "Pressable", supportedModifiers: ["active", "hover", "focus", "disabled"] };
|
|
2403
|
+
case "TouchableOpacity":
|
|
2404
|
+
return { component: "TouchableOpacity", supportedModifiers: ["active", "disabled"] };
|
|
2145
2405
|
case "TextInput":
|
|
2146
2406
|
return { component: "TextInput", supportedModifiers: ["focus", "disabled", "placeholder"] };
|
|
2147
2407
|
default:
|
|
@@ -2163,6 +2423,40 @@ function getStatePropertyForModifier(modifier) {
|
|
|
2163
2423
|
}
|
|
2164
2424
|
}
|
|
2165
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
|
+
|
|
2166
2460
|
// src/babel/utils/dynamicProcessing.ts
|
|
2167
2461
|
function processDynamicExpression(expression, state, parseClassName2, generateStyleKey2, splitModifierClasses2, processPlatformModifiers2, processColorSchemeModifiers2, componentScope, isPlatformModifier2, isColorSchemeModifier2, isSchemeModifier2, expandSchemeModifier2, t) {
|
|
2168
2462
|
if (t.isTemplateLiteral(expression)) {
|
|
@@ -2482,6 +2776,11 @@ function processStaticClassNameWithModifiers(className, state, parseClassName2,
|
|
|
2482
2776
|
if (baseClasses.length > 0) {
|
|
2483
2777
|
const baseClassName = baseClasses.join(" ");
|
|
2484
2778
|
const baseStyleObject = parseClassName2(baseClassName, state.customTheme);
|
|
2779
|
+
if (hasRuntimeDimensions(baseStyleObject)) {
|
|
2780
|
+
throw new Error(
|
|
2781
|
+
`w-screen and h-screen cannot be combined with state modifiers (active:, hover:, focus:, etc.) or platform modifiers (ios:, android:, web:). Found in: "${baseClassName}". Use w-screen/h-screen without modifiers instead.`
|
|
2782
|
+
);
|
|
2783
|
+
}
|
|
2485
2784
|
const baseStyleKey = generateStyleKey2(baseClassName);
|
|
2486
2785
|
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
2487
2786
|
baseStyleExpression = t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey));
|
|
@@ -2503,6 +2802,11 @@ function processStaticClassNameWithModifiers(className, state, parseClassName2,
|
|
|
2503
2802
|
for (const [modifierType, modifiers] of modifiersByType) {
|
|
2504
2803
|
const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
2505
2804
|
const modifierStyleObject = parseClassName2(modifierClassNames, state.customTheme);
|
|
2805
|
+
if (hasRuntimeDimensions(modifierStyleObject)) {
|
|
2806
|
+
throw new Error(
|
|
2807
|
+
`w-screen and h-screen cannot be combined with state modifiers (active:, hover:, focus:, etc.) or platform modifiers (ios:, android:, web:). Found in: "${modifierType}:${modifierClassNames}". Use w-screen/h-screen without modifiers instead.`
|
|
2808
|
+
);
|
|
2809
|
+
}
|
|
2506
2810
|
const modifierStyleKey = generateStyleKey2(`${modifierType}_${modifierClassNames}`);
|
|
2507
2811
|
state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
|
|
2508
2812
|
const stateProperty = getStatePropertyForModifier(modifierType);
|
|
@@ -2530,36 +2834,684 @@ function createStyleFunction(styleExpression, modifierTypes, t) {
|
|
|
2530
2834
|
);
|
|
2531
2835
|
}
|
|
2532
2836
|
}
|
|
2533
|
-
const param = t.objectPattern(paramProperties);
|
|
2534
|
-
return t.arrowFunctionExpression([param], styleExpression);
|
|
2837
|
+
const param = t.objectPattern(paramProperties);
|
|
2838
|
+
return t.arrowFunctionExpression([param], styleExpression);
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
// src/babel/utils/platformModifierProcessing.ts
|
|
2842
|
+
function processPlatformModifiers(platformModifiers, state, parseClassName2, generateStyleKey2, t) {
|
|
2843
|
+
state.needsPlatformImport = true;
|
|
2844
|
+
const modifiersByPlatform = /* @__PURE__ */ new Map();
|
|
2845
|
+
for (const mod of platformModifiers) {
|
|
2846
|
+
const platform = mod.modifier;
|
|
2847
|
+
if (!modifiersByPlatform.has(platform)) {
|
|
2848
|
+
modifiersByPlatform.set(platform, []);
|
|
2849
|
+
}
|
|
2850
|
+
const platformGroup = modifiersByPlatform.get(platform);
|
|
2851
|
+
if (platformGroup) {
|
|
2852
|
+
platformGroup.push(mod);
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
const selectProperties = [];
|
|
2856
|
+
for (const [platform, modifiers] of modifiersByPlatform) {
|
|
2857
|
+
const classNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
2858
|
+
const styleObject = parseClassName2(classNames, state.customTheme);
|
|
2859
|
+
if (hasRuntimeDimensions(styleObject)) {
|
|
2860
|
+
throw new Error(
|
|
2861
|
+
`w-screen and h-screen cannot be combined with platform modifiers (ios:, android:, web:). Found in: "${platform}:${classNames}". Use w-screen/h-screen without modifiers instead.`
|
|
2862
|
+
);
|
|
2863
|
+
}
|
|
2864
|
+
const styleKey = generateStyleKey2(`${platform}_${classNames}`);
|
|
2865
|
+
state.styleRegistry.set(styleKey, styleObject);
|
|
2866
|
+
const styleReference = t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey));
|
|
2867
|
+
selectProperties.push(t.objectProperty(t.identifier(platform), styleReference));
|
|
2868
|
+
}
|
|
2869
|
+
return t.callExpression(t.memberExpression(t.identifier("Platform"), t.identifier("select")), [
|
|
2870
|
+
t.objectExpression(selectProperties)
|
|
2871
|
+
]);
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
// src/babel/utils/styleTransforms.ts
|
|
2875
|
+
function getStyleExpression(styleAttribute, t) {
|
|
2876
|
+
const value = styleAttribute.value;
|
|
2877
|
+
if (!t.isJSXExpressionContainer(value)) return null;
|
|
2878
|
+
const expression = value.expression;
|
|
2879
|
+
if (t.isJSXEmptyExpression(expression)) return null;
|
|
2880
|
+
return expression;
|
|
2881
|
+
}
|
|
2882
|
+
function findStyleAttribute(path2, targetStyleProp, t) {
|
|
2883
|
+
const parent = path2.parent;
|
|
2884
|
+
return parent.attributes.find(
|
|
2885
|
+
(attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === targetStyleProp
|
|
2886
|
+
);
|
|
2887
|
+
}
|
|
2888
|
+
function replaceWithStyleAttribute(classNamePath, styleKey, targetStyleProp, stylesIdentifier, t) {
|
|
2889
|
+
const styleAttribute = t.jsxAttribute(
|
|
2890
|
+
t.jsxIdentifier(targetStyleProp),
|
|
2891
|
+
t.jsxExpressionContainer(t.memberExpression(t.identifier(stylesIdentifier), t.identifier(styleKey)))
|
|
2892
|
+
);
|
|
2893
|
+
classNamePath.replaceWith(styleAttribute);
|
|
2894
|
+
}
|
|
2895
|
+
function mergeStyleAttribute(classNamePath, styleAttribute, styleKey, stylesIdentifier, t) {
|
|
2896
|
+
const existingStyle = getStyleExpression(styleAttribute, t);
|
|
2897
|
+
if (!existingStyle) return;
|
|
2898
|
+
if (t.isArrowFunctionExpression(existingStyle) || t.isFunctionExpression(existingStyle)) {
|
|
2899
|
+
const paramIdentifier = t.identifier("_state");
|
|
2900
|
+
const functionCall = t.callExpression(existingStyle, [paramIdentifier]);
|
|
2901
|
+
const mergedArray = t.arrayExpression([
|
|
2902
|
+
t.memberExpression(t.identifier(stylesIdentifier), t.identifier(styleKey)),
|
|
2903
|
+
functionCall
|
|
2904
|
+
]);
|
|
2905
|
+
const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
|
|
2906
|
+
styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
|
|
2907
|
+
} else {
|
|
2908
|
+
const styleArray = t.arrayExpression([
|
|
2909
|
+
t.memberExpression(t.identifier(stylesIdentifier), t.identifier(styleKey)),
|
|
2910
|
+
existingStyle
|
|
2911
|
+
]);
|
|
2912
|
+
styleAttribute.value = t.jsxExpressionContainer(styleArray);
|
|
2913
|
+
}
|
|
2914
|
+
classNamePath.remove();
|
|
2915
|
+
}
|
|
2916
|
+
function replaceDynamicWithStyleAttribute(classNamePath, result, targetStyleProp, t) {
|
|
2917
|
+
const styleAttribute = t.jsxAttribute(
|
|
2918
|
+
t.jsxIdentifier(targetStyleProp),
|
|
2919
|
+
t.jsxExpressionContainer(result.expression)
|
|
2920
|
+
);
|
|
2921
|
+
classNamePath.replaceWith(styleAttribute);
|
|
2922
|
+
}
|
|
2923
|
+
function mergeDynamicStyleAttribute(classNamePath, styleAttribute, result, t) {
|
|
2924
|
+
const existingStyle = getStyleExpression(styleAttribute, t);
|
|
2925
|
+
if (!existingStyle) return;
|
|
2926
|
+
if (t.isArrowFunctionExpression(existingStyle) || t.isFunctionExpression(existingStyle)) {
|
|
2927
|
+
const paramIdentifier = t.identifier("_state");
|
|
2928
|
+
const functionCall = t.callExpression(existingStyle, [paramIdentifier]);
|
|
2929
|
+
const mergedArray = t.arrayExpression([result.expression, functionCall]);
|
|
2930
|
+
const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
|
|
2931
|
+
styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
|
|
2932
|
+
} else {
|
|
2933
|
+
let styleArray;
|
|
2934
|
+
if (t.isArrayExpression(existingStyle)) {
|
|
2935
|
+
styleArray = t.arrayExpression([result.expression, ...existingStyle.elements]);
|
|
2936
|
+
} else {
|
|
2937
|
+
styleArray = t.arrayExpression([result.expression, existingStyle]);
|
|
2938
|
+
}
|
|
2939
|
+
styleAttribute.value = t.jsxExpressionContainer(styleArray);
|
|
2940
|
+
}
|
|
2941
|
+
classNamePath.remove();
|
|
2942
|
+
}
|
|
2943
|
+
function replaceWithStyleFunctionAttribute(classNamePath, styleFunctionExpression, targetStyleProp, t) {
|
|
2944
|
+
const styleAttribute = t.jsxAttribute(
|
|
2945
|
+
t.jsxIdentifier(targetStyleProp),
|
|
2946
|
+
t.jsxExpressionContainer(styleFunctionExpression)
|
|
2947
|
+
);
|
|
2948
|
+
classNamePath.replaceWith(styleAttribute);
|
|
2949
|
+
}
|
|
2950
|
+
function mergeStyleFunctionAttribute(classNamePath, styleAttribute, styleFunctionExpression, t) {
|
|
2951
|
+
const existingStyle = getStyleExpression(styleAttribute, t);
|
|
2952
|
+
if (!existingStyle) return;
|
|
2953
|
+
if (t.isArrowFunctionExpression(existingStyle) || t.isFunctionExpression(existingStyle)) {
|
|
2954
|
+
const paramIdentifier = t.identifier("_state");
|
|
2955
|
+
const newFunctionCall = t.callExpression(styleFunctionExpression, [paramIdentifier]);
|
|
2956
|
+
const existingFunctionCall = t.callExpression(existingStyle, [paramIdentifier]);
|
|
2957
|
+
const mergedArray = t.arrayExpression([newFunctionCall, existingFunctionCall]);
|
|
2958
|
+
const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
|
|
2959
|
+
styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
|
|
2960
|
+
} else {
|
|
2961
|
+
const paramIdentifier = t.identifier("_state");
|
|
2962
|
+
const functionCall = t.callExpression(styleFunctionExpression, [paramIdentifier]);
|
|
2963
|
+
const mergedArray = t.arrayExpression([functionCall, existingStyle]);
|
|
2964
|
+
const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
|
|
2965
|
+
styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
|
|
2966
|
+
}
|
|
2967
|
+
classNamePath.remove();
|
|
2968
|
+
}
|
|
2969
|
+
function addOrMergePlaceholderTextColorProp(jsxOpeningElement, color, t) {
|
|
2970
|
+
const existingProp = jsxOpeningElement.attributes.find(
|
|
2971
|
+
(attr) => t.isJSXAttribute(attr) && attr.name.name === "placeholderTextColor"
|
|
2972
|
+
);
|
|
2973
|
+
if (existingProp) {
|
|
2974
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2975
|
+
console.warn(
|
|
2976
|
+
`[react-native-tailwind] placeholderTextColor prop will be overridden by className placeholder: modifier. Remove the explicit prop or the placeholder: modifier to avoid confusion.`
|
|
2977
|
+
);
|
|
2978
|
+
}
|
|
2979
|
+
existingProp.value = t.stringLiteral(color);
|
|
2980
|
+
} else {
|
|
2981
|
+
const newProp = t.jsxAttribute(t.jsxIdentifier("placeholderTextColor"), t.stringLiteral(color));
|
|
2982
|
+
jsxOpeningElement.attributes.push(newProp);
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
|
|
2986
|
+
// src/babel/plugin/componentScope.ts
|
|
2987
|
+
function isComponentScope(functionPath, t) {
|
|
2988
|
+
const node = functionPath.node;
|
|
2989
|
+
const parent = functionPath.parent;
|
|
2990
|
+
const parentPath = functionPath.parentPath;
|
|
2991
|
+
if (t.isClassMethod(parent)) {
|
|
2992
|
+
return false;
|
|
2993
|
+
}
|
|
2994
|
+
if (functionPath.findParent((p) => t.isClassBody(p.node))) {
|
|
2995
|
+
return false;
|
|
2996
|
+
}
|
|
2997
|
+
if (t.isFunctionDeclaration(node)) {
|
|
2998
|
+
if (t.isProgram(parent) || t.isExportNamedDeclaration(parent) || t.isExportDefaultDeclaration(parent)) {
|
|
2999
|
+
return true;
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
if (t.isFunctionExpression(node) || t.isArrowFunctionExpression(node)) {
|
|
3003
|
+
if (t.isVariableDeclarator(parent)) {
|
|
3004
|
+
const varDeclarationPath = parentPath?.parentPath;
|
|
3005
|
+
if (varDeclarationPath && t.isVariableDeclaration(varDeclarationPath.node) && (t.isProgram(varDeclarationPath.parent) || t.isExportNamedDeclaration(varDeclarationPath.parent))) {
|
|
3006
|
+
if (t.isIdentifier(parent.id)) {
|
|
3007
|
+
const name = parent.id.name;
|
|
3008
|
+
return /^[A-Z]/.test(name);
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
return false;
|
|
3014
|
+
}
|
|
3015
|
+
function findComponentScope(path2, t) {
|
|
3016
|
+
let current = path2.getFunctionParent();
|
|
3017
|
+
while (current) {
|
|
3018
|
+
if (t.isFunction(current.node) && isComponentScope(current, t)) {
|
|
3019
|
+
return current;
|
|
3020
|
+
}
|
|
3021
|
+
current = current.getFunctionParent();
|
|
3022
|
+
}
|
|
3023
|
+
return null;
|
|
3024
|
+
}
|
|
3025
|
+
|
|
3026
|
+
// src/babel/plugin/visitors/className.ts
|
|
3027
|
+
function jsxAttributeVisitor(path2, state, t) {
|
|
3028
|
+
const node = path2.node;
|
|
3029
|
+
if (!t.isJSXIdentifier(node.name)) {
|
|
3030
|
+
return;
|
|
3031
|
+
}
|
|
3032
|
+
const attributeName = node.name.name;
|
|
3033
|
+
if (!isAttributeSupported(attributeName, state.supportedAttributes, state.attributePatterns)) {
|
|
3034
|
+
return;
|
|
3035
|
+
}
|
|
3036
|
+
const value = node.value;
|
|
3037
|
+
const targetStyleProp = getTargetStyleProp(attributeName);
|
|
3038
|
+
const processStaticClassName = (className) => {
|
|
3039
|
+
const trimmedClassName = className.trim();
|
|
3040
|
+
if (!trimmedClassName) {
|
|
3041
|
+
path2.remove();
|
|
3042
|
+
return true;
|
|
3043
|
+
}
|
|
3044
|
+
state.hasClassNames = true;
|
|
3045
|
+
const { baseClasses, modifierClasses: rawModifierClasses } = splitModifierClasses(trimmedClassName);
|
|
3046
|
+
const modifierClasses = [];
|
|
3047
|
+
for (const modifier of rawModifierClasses) {
|
|
3048
|
+
if (isSchemeModifier(modifier.modifier)) {
|
|
3049
|
+
const expanded = expandSchemeModifier(
|
|
3050
|
+
modifier,
|
|
3051
|
+
state.customTheme.colors ?? {},
|
|
3052
|
+
state.schemeModifierConfig.darkSuffix,
|
|
3053
|
+
state.schemeModifierConfig.lightSuffix
|
|
3054
|
+
);
|
|
3055
|
+
modifierClasses.push(...expanded);
|
|
3056
|
+
} else {
|
|
3057
|
+
modifierClasses.push(modifier);
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
const placeholderModifiers = modifierClasses.filter((m) => m.modifier === "placeholder");
|
|
3061
|
+
const platformModifiers = modifierClasses.filter((m) => isPlatformModifier(m.modifier));
|
|
3062
|
+
const colorSchemeModifiers = modifierClasses.filter((m) => isColorSchemeModifier(m.modifier));
|
|
3063
|
+
const directionalModifiers = modifierClasses.filter((m) => isDirectionalModifier(m.modifier));
|
|
3064
|
+
const stateModifiers = modifierClasses.filter(
|
|
3065
|
+
(m) => isStateModifier(m.modifier) && m.modifier !== "placeholder"
|
|
3066
|
+
);
|
|
3067
|
+
if (placeholderModifiers.length > 0) {
|
|
3068
|
+
const jsxOpeningElement = path2.parent;
|
|
3069
|
+
const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
|
|
3070
|
+
if (componentSupport?.supportedModifiers.includes("placeholder")) {
|
|
3071
|
+
const placeholderClasses = placeholderModifiers.map((m) => m.baseClass).join(" ");
|
|
3072
|
+
const placeholderColor = parsePlaceholderClasses(placeholderClasses, state.customTheme.colors);
|
|
3073
|
+
if (placeholderColor) {
|
|
3074
|
+
addOrMergePlaceholderTextColorProp(jsxOpeningElement, placeholderColor, t);
|
|
3075
|
+
}
|
|
3076
|
+
} else {
|
|
3077
|
+
if (process.env.NODE_ENV !== "production") {
|
|
3078
|
+
console.warn(
|
|
3079
|
+
`[react-native-tailwind] placeholder: modifier can only be used on TextInput component at ${state.file.opts.filename ?? "unknown"}`
|
|
3080
|
+
);
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
const hasPlatformModifiers = platformModifiers.length > 0;
|
|
3085
|
+
const hasColorSchemeModifiers = colorSchemeModifiers.length > 0;
|
|
3086
|
+
const hasDirectionalModifiers = directionalModifiers.length > 0;
|
|
3087
|
+
const hasStateModifiers = stateModifiers.length > 0;
|
|
3088
|
+
const hasBaseClasses = baseClasses.length > 0;
|
|
3089
|
+
let componentScope = null;
|
|
3090
|
+
if (hasColorSchemeModifiers) {
|
|
3091
|
+
componentScope = findComponentScope(path2, t);
|
|
3092
|
+
if (componentScope) {
|
|
3093
|
+
state.functionComponentsNeedingColorScheme.add(componentScope);
|
|
3094
|
+
} else {
|
|
3095
|
+
if (process.env.NODE_ENV !== "production") {
|
|
3096
|
+
console.warn(
|
|
3097
|
+
`[react-native-tailwind] dark:/light: modifiers require a function component scope. Found in non-component context at ${state.file.opts.filename ?? "unknown"}. These modifiers are not supported in class components or nested callbacks.`
|
|
3098
|
+
);
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
if (hasStateModifiers && (hasPlatformModifiers || hasColorSchemeModifiers || hasDirectionalModifiers)) {
|
|
3103
|
+
const jsxOpeningElement = path2.parent;
|
|
3104
|
+
const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
|
|
3105
|
+
if (componentSupport) {
|
|
3106
|
+
const styleArrayElements = [];
|
|
3107
|
+
if (hasBaseClasses) {
|
|
3108
|
+
const baseClassName = baseClasses.join(" ");
|
|
3109
|
+
const baseStyleObject = parseClassName(baseClassName, state.customTheme);
|
|
3110
|
+
if (hasRuntimeDimensions(baseStyleObject)) {
|
|
3111
|
+
throw path2.buildCodeFrameError(
|
|
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.`
|
|
3113
|
+
);
|
|
3114
|
+
}
|
|
3115
|
+
const baseStyleKey = generateStyleKey(baseClassName);
|
|
3116
|
+
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
3117
|
+
styleArrayElements.push(
|
|
3118
|
+
t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey))
|
|
3119
|
+
);
|
|
3120
|
+
}
|
|
3121
|
+
if (hasPlatformModifiers) {
|
|
3122
|
+
const platformSelectExpression = processPlatformModifiers(
|
|
3123
|
+
platformModifiers,
|
|
3124
|
+
state,
|
|
3125
|
+
parseClassName,
|
|
3126
|
+
generateStyleKey,
|
|
3127
|
+
t
|
|
3128
|
+
);
|
|
3129
|
+
styleArrayElements.push(platformSelectExpression);
|
|
3130
|
+
}
|
|
3131
|
+
if (hasColorSchemeModifiers && componentScope) {
|
|
3132
|
+
const colorSchemeConditionals = processColorSchemeModifiers(
|
|
3133
|
+
colorSchemeModifiers,
|
|
3134
|
+
state,
|
|
3135
|
+
parseClassName,
|
|
3136
|
+
generateStyleKey,
|
|
3137
|
+
t
|
|
3138
|
+
);
|
|
3139
|
+
styleArrayElements.push(...colorSchemeConditionals);
|
|
3140
|
+
}
|
|
3141
|
+
if (hasDirectionalModifiers) {
|
|
3142
|
+
const directionalConditionals = processDirectionalModifiers(
|
|
3143
|
+
directionalModifiers,
|
|
3144
|
+
state,
|
|
3145
|
+
parseClassName,
|
|
3146
|
+
generateStyleKey,
|
|
3147
|
+
t
|
|
3148
|
+
);
|
|
3149
|
+
styleArrayElements.push(...directionalConditionals);
|
|
3150
|
+
}
|
|
3151
|
+
const modifiersByType = /* @__PURE__ */ new Map();
|
|
3152
|
+
for (const mod of stateModifiers) {
|
|
3153
|
+
const modType = mod.modifier;
|
|
3154
|
+
if (!modifiersByType.has(modType)) {
|
|
3155
|
+
modifiersByType.set(modType, []);
|
|
3156
|
+
}
|
|
3157
|
+
modifiersByType.get(modType)?.push(mod);
|
|
3158
|
+
}
|
|
3159
|
+
for (const [modifierType, modifiers] of modifiersByType) {
|
|
3160
|
+
if (!componentSupport.supportedModifiers.includes(modifierType)) {
|
|
3161
|
+
continue;
|
|
3162
|
+
}
|
|
3163
|
+
const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
3164
|
+
const modifierStyleObject = parseClassName(modifierClassNames, state.customTheme);
|
|
3165
|
+
const modifierStyleKey = generateStyleKey(`${modifierType}_${modifierClassNames}`);
|
|
3166
|
+
state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
|
|
3167
|
+
const stateProperty = getStatePropertyForModifier(modifierType);
|
|
3168
|
+
const conditionalExpression = t.logicalExpression(
|
|
3169
|
+
"&&",
|
|
3170
|
+
t.identifier(stateProperty),
|
|
3171
|
+
t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(modifierStyleKey))
|
|
3172
|
+
);
|
|
3173
|
+
styleArrayElements.push(conditionalExpression);
|
|
3174
|
+
}
|
|
3175
|
+
const usedModifiers = Array.from(new Set(stateModifiers.map((m) => m.modifier))).filter(
|
|
3176
|
+
(mod) => componentSupport.supportedModifiers.includes(mod)
|
|
3177
|
+
);
|
|
3178
|
+
const styleArrayExpression = t.arrayExpression(styleArrayElements);
|
|
3179
|
+
const styleFunctionExpression = createStyleFunction(styleArrayExpression, usedModifiers, t);
|
|
3180
|
+
const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
|
|
3181
|
+
if (styleAttribute2) {
|
|
3182
|
+
mergeStyleFunctionAttribute(path2, styleAttribute2, styleFunctionExpression, t);
|
|
3183
|
+
} else {
|
|
3184
|
+
replaceWithStyleFunctionAttribute(path2, styleFunctionExpression, targetStyleProp, t);
|
|
3185
|
+
}
|
|
3186
|
+
return true;
|
|
3187
|
+
} else {
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
if ((hasPlatformModifiers || hasColorSchemeModifiers || hasDirectionalModifiers) && !hasStateModifiers) {
|
|
3191
|
+
const styleExpressions = [];
|
|
3192
|
+
if (hasBaseClasses) {
|
|
3193
|
+
const baseClassName = baseClasses.join(" ");
|
|
3194
|
+
const baseStyleObject = parseClassName(baseClassName, state.customTheme);
|
|
3195
|
+
if (hasRuntimeDimensions(baseStyleObject)) {
|
|
3196
|
+
throw path2.buildCodeFrameError(
|
|
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.`
|
|
3198
|
+
);
|
|
3199
|
+
}
|
|
3200
|
+
const baseStyleKey = generateStyleKey(baseClassName);
|
|
3201
|
+
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
3202
|
+
styleExpressions.push(
|
|
3203
|
+
t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey))
|
|
3204
|
+
);
|
|
3205
|
+
}
|
|
3206
|
+
if (hasPlatformModifiers) {
|
|
3207
|
+
const platformSelectExpression = processPlatformModifiers(
|
|
3208
|
+
platformModifiers,
|
|
3209
|
+
state,
|
|
3210
|
+
parseClassName,
|
|
3211
|
+
generateStyleKey,
|
|
3212
|
+
t
|
|
3213
|
+
);
|
|
3214
|
+
styleExpressions.push(platformSelectExpression);
|
|
3215
|
+
}
|
|
3216
|
+
if (hasColorSchemeModifiers && componentScope) {
|
|
3217
|
+
const colorSchemeConditionals = processColorSchemeModifiers(
|
|
3218
|
+
colorSchemeModifiers,
|
|
3219
|
+
state,
|
|
3220
|
+
parseClassName,
|
|
3221
|
+
generateStyleKey,
|
|
3222
|
+
t
|
|
3223
|
+
);
|
|
3224
|
+
styleExpressions.push(...colorSchemeConditionals);
|
|
3225
|
+
}
|
|
3226
|
+
if (hasDirectionalModifiers) {
|
|
3227
|
+
const directionalConditionals = processDirectionalModifiers(
|
|
3228
|
+
directionalModifiers,
|
|
3229
|
+
state,
|
|
3230
|
+
parseClassName,
|
|
3231
|
+
generateStyleKey,
|
|
3232
|
+
t
|
|
3233
|
+
);
|
|
3234
|
+
styleExpressions.push(...directionalConditionals);
|
|
3235
|
+
}
|
|
3236
|
+
const styleExpression = styleExpressions.length === 1 ? styleExpressions[0] : t.arrayExpression(styleExpressions);
|
|
3237
|
+
const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
|
|
3238
|
+
if (styleAttribute2) {
|
|
3239
|
+
const existingStyle = styleAttribute2.value;
|
|
3240
|
+
if (t.isJSXExpressionContainer(existingStyle) && !t.isJSXEmptyExpression(existingStyle.expression)) {
|
|
3241
|
+
const existing = existingStyle.expression;
|
|
3242
|
+
const mergedArray = t.isArrayExpression(existing) ? t.arrayExpression([styleExpression, ...existing.elements]) : t.arrayExpression([styleExpression, existing]);
|
|
3243
|
+
styleAttribute2.value = t.jsxExpressionContainer(mergedArray);
|
|
3244
|
+
} else {
|
|
3245
|
+
styleAttribute2.value = t.jsxExpressionContainer(styleExpression);
|
|
3246
|
+
}
|
|
3247
|
+
path2.remove();
|
|
3248
|
+
} else {
|
|
3249
|
+
path2.node.name = t.jsxIdentifier(targetStyleProp);
|
|
3250
|
+
path2.node.value = t.jsxExpressionContainer(styleExpression);
|
|
3251
|
+
}
|
|
3252
|
+
return true;
|
|
3253
|
+
}
|
|
3254
|
+
if (hasStateModifiers) {
|
|
3255
|
+
const jsxOpeningElement = path2.parent;
|
|
3256
|
+
const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
|
|
3257
|
+
if (componentSupport) {
|
|
3258
|
+
const usedModifiers = Array.from(new Set(stateModifiers.map((m) => m.modifier)));
|
|
3259
|
+
const unsupportedModifiers = usedModifiers.filter(
|
|
3260
|
+
(mod) => !componentSupport.supportedModifiers.includes(mod)
|
|
3261
|
+
);
|
|
3262
|
+
if (unsupportedModifiers.length > 0) {
|
|
3263
|
+
if (process.env.NODE_ENV !== "production") {
|
|
3264
|
+
console.warn(
|
|
3265
|
+
`[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(", ")}`
|
|
3266
|
+
);
|
|
3267
|
+
}
|
|
3268
|
+
const supportedModifierClasses = stateModifiers.filter(
|
|
3269
|
+
(m) => componentSupport.supportedModifiers.includes(m.modifier)
|
|
3270
|
+
);
|
|
3271
|
+
if (supportedModifierClasses.length === 0) {
|
|
3272
|
+
} else {
|
|
3273
|
+
const filteredClassName = baseClasses.join(" ") + " " + supportedModifierClasses.map((m) => `${m.modifier}:${m.baseClass}`).join(" ");
|
|
3274
|
+
const styleExpression = processStaticClassNameWithModifiers(
|
|
3275
|
+
filteredClassName.trim(),
|
|
3276
|
+
state,
|
|
3277
|
+
parseClassName,
|
|
3278
|
+
generateStyleKey,
|
|
3279
|
+
splitModifierClasses,
|
|
3280
|
+
t
|
|
3281
|
+
);
|
|
3282
|
+
const modifierTypes = Array.from(new Set(supportedModifierClasses.map((m) => m.modifier)));
|
|
3283
|
+
const styleFunctionExpression = createStyleFunction(styleExpression, modifierTypes, t);
|
|
3284
|
+
const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
|
|
3285
|
+
if (styleAttribute2) {
|
|
3286
|
+
mergeStyleFunctionAttribute(path2, styleAttribute2, styleFunctionExpression, t);
|
|
3287
|
+
} else {
|
|
3288
|
+
replaceWithStyleFunctionAttribute(path2, styleFunctionExpression, targetStyleProp, t);
|
|
3289
|
+
}
|
|
3290
|
+
return true;
|
|
3291
|
+
}
|
|
3292
|
+
} else {
|
|
3293
|
+
const styleExpression = processStaticClassNameWithModifiers(
|
|
3294
|
+
trimmedClassName,
|
|
3295
|
+
state,
|
|
3296
|
+
parseClassName,
|
|
3297
|
+
generateStyleKey,
|
|
3298
|
+
splitModifierClasses,
|
|
3299
|
+
t
|
|
3300
|
+
);
|
|
3301
|
+
const modifierTypes = usedModifiers;
|
|
3302
|
+
const styleFunctionExpression = createStyleFunction(styleExpression, modifierTypes, t);
|
|
3303
|
+
const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
|
|
3304
|
+
if (styleAttribute2) {
|
|
3305
|
+
mergeStyleFunctionAttribute(path2, styleAttribute2, styleFunctionExpression, t);
|
|
3306
|
+
} else {
|
|
3307
|
+
replaceWithStyleFunctionAttribute(path2, styleFunctionExpression, targetStyleProp, t);
|
|
3308
|
+
}
|
|
3309
|
+
return true;
|
|
3310
|
+
}
|
|
3311
|
+
} else {
|
|
3312
|
+
if (process.env.NODE_ENV !== "production") {
|
|
3313
|
+
const usedModifiers = Array.from(new Set(stateModifiers.map((m) => m.modifier)));
|
|
3314
|
+
console.warn(
|
|
3315
|
+
`[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"}`
|
|
3316
|
+
);
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
const classNameForStyle = baseClasses.join(" ");
|
|
3321
|
+
if (!classNameForStyle) {
|
|
3322
|
+
path2.remove();
|
|
3323
|
+
return true;
|
|
3324
|
+
}
|
|
3325
|
+
const styleObject = parseClassName(classNameForStyle, state.customTheme);
|
|
3326
|
+
if (hasRuntimeDimensions(styleObject)) {
|
|
3327
|
+
const { static: staticStyles, runtime: runtimeStyles } = splitStaticAndRuntimeStyles(styleObject);
|
|
3328
|
+
const componentScope2 = findComponentScope(path2, t);
|
|
3329
|
+
if (componentScope2) {
|
|
3330
|
+
state.hasClassNames = true;
|
|
3331
|
+
state.functionComponentsNeedingWindowDimensions.add(componentScope2);
|
|
3332
|
+
state.needsWindowDimensionsImport = true;
|
|
3333
|
+
const styleExpressions = [];
|
|
3334
|
+
if (Object.keys(staticStyles).length > 0) {
|
|
3335
|
+
const styleKey2 = generateStyleKey(classNameForStyle);
|
|
3336
|
+
state.styleRegistry.set(styleKey2, staticStyles);
|
|
3337
|
+
styleExpressions.push(
|
|
3338
|
+
t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey2))
|
|
3339
|
+
);
|
|
3340
|
+
}
|
|
3341
|
+
const runtimeDimensionObject = createRuntimeDimensionObject(runtimeStyles, state, t);
|
|
3342
|
+
styleExpressions.push(runtimeDimensionObject);
|
|
3343
|
+
const styleExpression = styleExpressions.length === 1 ? styleExpressions[0] : t.arrayExpression(styleExpressions);
|
|
3344
|
+
const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
|
|
3345
|
+
if (styleAttribute2) {
|
|
3346
|
+
const existingStyle = styleAttribute2.value;
|
|
3347
|
+
if (t.isJSXExpressionContainer(existingStyle) && !t.isJSXEmptyExpression(existingStyle.expression)) {
|
|
3348
|
+
const existing = existingStyle.expression;
|
|
3349
|
+
if (t.isArrowFunctionExpression(existing) || t.isFunctionExpression(existing)) {
|
|
3350
|
+
const paramIdentifier = t.identifier("_state");
|
|
3351
|
+
const functionCall = t.callExpression(existing, [paramIdentifier]);
|
|
3352
|
+
const mergedArray = t.arrayExpression([styleExpression, functionCall]);
|
|
3353
|
+
const wrappedFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
|
|
3354
|
+
styleAttribute2.value = t.jsxExpressionContainer(wrappedFunction);
|
|
3355
|
+
} else {
|
|
3356
|
+
const mergedArray = t.isArrayExpression(existing) ? t.arrayExpression([styleExpression, ...existing.elements]) : t.arrayExpression([styleExpression, existing]);
|
|
3357
|
+
styleAttribute2.value = t.jsxExpressionContainer(mergedArray);
|
|
3358
|
+
}
|
|
3359
|
+
} else {
|
|
3360
|
+
styleAttribute2.value = t.jsxExpressionContainer(styleExpression);
|
|
3361
|
+
}
|
|
3362
|
+
path2.remove();
|
|
3363
|
+
} else {
|
|
3364
|
+
path2.node.name = t.jsxIdentifier(targetStyleProp);
|
|
3365
|
+
path2.node.value = t.jsxExpressionContainer(styleExpression);
|
|
3366
|
+
}
|
|
3367
|
+
return true;
|
|
3368
|
+
} else {
|
|
3369
|
+
if (process.env.NODE_ENV !== "production") {
|
|
3370
|
+
console.warn(
|
|
3371
|
+
`[react-native-tailwind] w-screen/h-screen classes require a function component scope. Found in non-component context at ${state.file.opts.filename ?? "unknown"}. These classes are not supported in class components or nested callbacks.`
|
|
3372
|
+
);
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
const styleKey = generateStyleKey(classNameForStyle);
|
|
3377
|
+
state.styleRegistry.set(styleKey, styleObject);
|
|
3378
|
+
const styleAttribute = findStyleAttribute(path2, targetStyleProp, t);
|
|
3379
|
+
if (styleAttribute) {
|
|
3380
|
+
mergeStyleAttribute(path2, styleAttribute, styleKey, state.stylesIdentifier, t);
|
|
3381
|
+
} else {
|
|
3382
|
+
replaceWithStyleAttribute(path2, styleKey, targetStyleProp, state.stylesIdentifier, t);
|
|
3383
|
+
}
|
|
3384
|
+
return true;
|
|
3385
|
+
};
|
|
3386
|
+
if (t.isStringLiteral(value)) {
|
|
3387
|
+
if (processStaticClassName(value.value)) {
|
|
3388
|
+
return;
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
if (t.isJSXExpressionContainer(value)) {
|
|
3392
|
+
const expression = value.expression;
|
|
3393
|
+
if (t.isJSXEmptyExpression(expression)) {
|
|
3394
|
+
return;
|
|
3395
|
+
}
|
|
3396
|
+
if (t.isStringLiteral(expression)) {
|
|
3397
|
+
if (processStaticClassName(expression.value)) {
|
|
3398
|
+
return;
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
try {
|
|
3402
|
+
const componentScope = findComponentScope(path2, t);
|
|
3403
|
+
const result = processDynamicExpression(
|
|
3404
|
+
expression,
|
|
3405
|
+
state,
|
|
3406
|
+
parseClassName,
|
|
3407
|
+
generateStyleKey,
|
|
3408
|
+
splitModifierClasses,
|
|
3409
|
+
processPlatformModifiers,
|
|
3410
|
+
processColorSchemeModifiers,
|
|
3411
|
+
componentScope,
|
|
3412
|
+
isPlatformModifier,
|
|
3413
|
+
isColorSchemeModifier,
|
|
3414
|
+
isSchemeModifier,
|
|
3415
|
+
expandSchemeModifier,
|
|
3416
|
+
t
|
|
3417
|
+
);
|
|
3418
|
+
if (result) {
|
|
3419
|
+
state.hasClassNames = true;
|
|
3420
|
+
const styleAttribute = findStyleAttribute(path2, targetStyleProp, t);
|
|
3421
|
+
if (styleAttribute) {
|
|
3422
|
+
mergeDynamicStyleAttribute(path2, styleAttribute, result, t);
|
|
3423
|
+
} else {
|
|
3424
|
+
replaceDynamicWithStyleAttribute(path2, result, targetStyleProp, t);
|
|
3425
|
+
}
|
|
3426
|
+
return;
|
|
3427
|
+
}
|
|
3428
|
+
} catch (error) {
|
|
3429
|
+
if (process.env.NODE_ENV !== "production") {
|
|
3430
|
+
console.warn(
|
|
3431
|
+
`[react-native-tailwind] Failed to process dynamic ${attributeName} at ${state.file.opts.filename ?? "unknown"}: ${error instanceof Error ? error.message : String(error)}`
|
|
3432
|
+
);
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
if (process.env.NODE_ENV !== "production") {
|
|
3437
|
+
const filename = state.file.opts.filename ?? "unknown";
|
|
3438
|
+
console.warn(
|
|
3439
|
+
`[react-native-tailwind] Dynamic ${attributeName} values are not fully supported at ${filename}. Use the ${targetStyleProp} prop for dynamic values.`
|
|
3440
|
+
);
|
|
3441
|
+
}
|
|
2535
3442
|
}
|
|
2536
3443
|
|
|
2537
|
-
// src/babel/
|
|
2538
|
-
function
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
const
|
|
2543
|
-
|
|
2544
|
-
|
|
3444
|
+
// src/babel/plugin/visitors/imports.ts
|
|
3445
|
+
function importDeclarationVisitor(path2, state, t) {
|
|
3446
|
+
const node = path2.node;
|
|
3447
|
+
if (node.source.value === "react-native") {
|
|
3448
|
+
const specifiers = node.specifiers;
|
|
3449
|
+
const hasStyleSheet = specifiers.some((spec) => {
|
|
3450
|
+
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
3451
|
+
return spec.imported.name === "StyleSheet";
|
|
3452
|
+
}
|
|
3453
|
+
return false;
|
|
3454
|
+
});
|
|
3455
|
+
const hasPlatform = specifiers.some((spec) => {
|
|
3456
|
+
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
3457
|
+
return spec.imported.name === "Platform";
|
|
3458
|
+
}
|
|
3459
|
+
return false;
|
|
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
|
+
}
|
|
2545
3471
|
}
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
3472
|
+
if (node.importKind !== "type") {
|
|
3473
|
+
for (const spec of specifiers) {
|
|
3474
|
+
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
3475
|
+
if (spec.imported.name === "useWindowDimensions") {
|
|
3476
|
+
state.hasWindowDimensionsImport = true;
|
|
3477
|
+
state.windowDimensionsLocalIdentifier = spec.local.name;
|
|
3478
|
+
break;
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
if (hasStyleSheet) {
|
|
3484
|
+
state.hasStyleSheetImport = true;
|
|
2549
3485
|
}
|
|
3486
|
+
if (hasPlatform) {
|
|
3487
|
+
state.hasPlatformImport = true;
|
|
3488
|
+
}
|
|
3489
|
+
state.reactNativeImportPath = path2;
|
|
2550
3490
|
}
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
const
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
3491
|
+
if (node.source.value === state.colorSchemeImportSource && node.importKind !== "type") {
|
|
3492
|
+
const specifiers = node.specifiers;
|
|
3493
|
+
for (const spec of specifiers) {
|
|
3494
|
+
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
3495
|
+
if (spec.imported.name === state.colorSchemeHookName) {
|
|
3496
|
+
state.hasColorSchemeImport = true;
|
|
3497
|
+
state.colorSchemeLocalIdentifier = spec.local.name;
|
|
3498
|
+
break;
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
}
|
|
3503
|
+
if (node.source.value === "@mgcrea/react-native-tailwind") {
|
|
3504
|
+
const specifiers = node.specifiers;
|
|
3505
|
+
specifiers.forEach((spec) => {
|
|
3506
|
+
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
3507
|
+
const importedName = spec.imported.name;
|
|
3508
|
+
if (importedName === "tw" || importedName === "twStyle") {
|
|
3509
|
+
const localName = spec.local.name;
|
|
3510
|
+
state.twImportNames.add(localName);
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
});
|
|
2559
3514
|
}
|
|
2560
|
-
return t.callExpression(t.memberExpression(t.identifier("Platform"), t.identifier("select")), [
|
|
2561
|
-
t.objectExpression(selectProperties)
|
|
2562
|
-
]);
|
|
2563
3515
|
}
|
|
2564
3516
|
|
|
2565
3517
|
// src/babel/utils/styleInjection.ts
|
|
@@ -2687,152 +3639,170 @@ function injectColorSchemeHook(functionPath, colorSchemeVariableName, hookName,
|
|
|
2687
3639
|
body.body.unshift(hookCall);
|
|
2688
3640
|
return true;
|
|
2689
3641
|
}
|
|
2690
|
-
function
|
|
2691
|
-
const
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
if (
|
|
2696
|
-
|
|
2697
|
-
} else if (typeof styleValue === "string") {
|
|
2698
|
-
valueNode = t.stringLiteral(styleValue);
|
|
2699
|
-
} else {
|
|
2700
|
-
valueNode = t.valueToNode(styleValue);
|
|
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;
|
|
2701
3649
|
}
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
3650
|
+
const hasNamespaceImport = statement.specifiers.some((spec) => t.isImportNamespaceSpecifier(spec));
|
|
3651
|
+
if (hasNamespaceImport) {
|
|
3652
|
+
continue;
|
|
3653
|
+
}
|
|
3654
|
+
existingValueImport = statement;
|
|
3655
|
+
break;
|
|
3656
|
+
}
|
|
2705
3657
|
}
|
|
2706
|
-
|
|
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", [
|
|
2707
3687
|
t.variableDeclarator(
|
|
2708
|
-
t.identifier(
|
|
2709
|
-
t.
|
|
2710
|
-
t.objectExpression(styleProperties)
|
|
2711
|
-
])
|
|
3688
|
+
t.identifier(variableName),
|
|
3689
|
+
t.memberExpression(t.identifier(identifierToUse), t.identifier("isRTL"))
|
|
2712
3690
|
)
|
|
2713
3691
|
]);
|
|
2714
|
-
const body = path2.node.body;
|
|
2715
3692
|
let insertIndex = 0;
|
|
2716
3693
|
for (let i = 0; i < body.length; i++) {
|
|
2717
|
-
|
|
3694
|
+
const statement = body[i];
|
|
3695
|
+
if (t.isExpressionStatement(statement) && t.isStringLiteral(statement.expression)) {
|
|
2718
3696
|
insertIndex = i + 1;
|
|
2719
|
-
|
|
2720
|
-
|
|
3697
|
+
continue;
|
|
3698
|
+
}
|
|
3699
|
+
if (t.isImportDeclaration(statement)) {
|
|
3700
|
+
insertIndex = i + 1;
|
|
3701
|
+
continue;
|
|
2721
3702
|
}
|
|
3703
|
+
break;
|
|
2722
3704
|
}
|
|
2723
|
-
body.splice(insertIndex, 0,
|
|
2724
|
-
}
|
|
2725
|
-
|
|
2726
|
-
// src/babel/utils/styleTransforms.ts
|
|
2727
|
-
function getStyleExpression(styleAttribute, t) {
|
|
2728
|
-
const value = styleAttribute.value;
|
|
2729
|
-
if (!t.isJSXExpressionContainer(value)) return null;
|
|
2730
|
-
const expression = value.expression;
|
|
2731
|
-
if (t.isJSXEmptyExpression(expression)) return null;
|
|
2732
|
-
return expression;
|
|
2733
|
-
}
|
|
2734
|
-
function findStyleAttribute(path2, targetStyleProp, t) {
|
|
2735
|
-
const parent = path2.parent;
|
|
2736
|
-
return parent.attributes.find(
|
|
2737
|
-
(attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === targetStyleProp
|
|
2738
|
-
);
|
|
2739
|
-
}
|
|
2740
|
-
function replaceWithStyleAttribute(classNamePath, styleKey, targetStyleProp, stylesIdentifier, t) {
|
|
2741
|
-
const styleAttribute = t.jsxAttribute(
|
|
2742
|
-
t.jsxIdentifier(targetStyleProp),
|
|
2743
|
-
t.jsxExpressionContainer(t.memberExpression(t.identifier(stylesIdentifier), t.identifier(styleKey)))
|
|
2744
|
-
);
|
|
2745
|
-
classNamePath.replaceWith(styleAttribute);
|
|
3705
|
+
body.splice(insertIndex, 0, i18nVariable);
|
|
2746
3706
|
}
|
|
2747
|
-
function
|
|
2748
|
-
const
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
3707
|
+
function addWindowDimensionsImport(path2, t) {
|
|
3708
|
+
const body = path2.node.body;
|
|
3709
|
+
let existingValueImport = null;
|
|
3710
|
+
for (const statement of body) {
|
|
3711
|
+
if (t.isImportDeclaration(statement) && statement.source.value === "react-native") {
|
|
3712
|
+
if (statement.importKind !== "type") {
|
|
3713
|
+
existingValueImport = statement;
|
|
3714
|
+
break;
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
if (existingValueImport) {
|
|
3719
|
+
const hasHook = existingValueImport.specifiers.some(
|
|
3720
|
+
(spec) => t.isImportSpecifier(spec) && spec.imported.type === "Identifier" && spec.imported.name === "useWindowDimensions"
|
|
3721
|
+
);
|
|
3722
|
+
if (!hasHook) {
|
|
3723
|
+
existingValueImport.specifiers.push(
|
|
3724
|
+
t.importSpecifier(t.identifier("useWindowDimensions"), t.identifier("useWindowDimensions"))
|
|
3725
|
+
);
|
|
3726
|
+
}
|
|
2759
3727
|
} else {
|
|
2760
|
-
const
|
|
2761
|
-
t.
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
3728
|
+
const importDeclaration = t.importDeclaration(
|
|
3729
|
+
[t.importSpecifier(t.identifier("useWindowDimensions"), t.identifier("useWindowDimensions"))],
|
|
3730
|
+
t.stringLiteral("react-native")
|
|
3731
|
+
);
|
|
3732
|
+
path2.unshiftContainer("body", importDeclaration);
|
|
2765
3733
|
}
|
|
2766
|
-
classNamePath.remove();
|
|
2767
|
-
}
|
|
2768
|
-
function replaceDynamicWithStyleAttribute(classNamePath, result, targetStyleProp, t) {
|
|
2769
|
-
const styleAttribute = t.jsxAttribute(
|
|
2770
|
-
t.jsxIdentifier(targetStyleProp),
|
|
2771
|
-
t.jsxExpressionContainer(result.expression)
|
|
2772
|
-
);
|
|
2773
|
-
classNamePath.replaceWith(styleAttribute);
|
|
2774
3734
|
}
|
|
2775
|
-
function
|
|
2776
|
-
|
|
2777
|
-
if (!
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
|
|
2784
|
-
} else {
|
|
2785
|
-
let styleArray;
|
|
2786
|
-
if (t.isArrayExpression(existingStyle)) {
|
|
2787
|
-
styleArray = t.arrayExpression([result.expression, ...existingStyle.elements]);
|
|
3735
|
+
function injectWindowDimensionsHook(functionPath, dimensionsVariableName, hookName, localIdentifier, t) {
|
|
3736
|
+
let body = functionPath.node.body;
|
|
3737
|
+
if (!t.isBlockStatement(body)) {
|
|
3738
|
+
if (t.isArrowFunctionExpression(functionPath.node) && t.isExpression(body)) {
|
|
3739
|
+
const returnStatement = t.returnStatement(body);
|
|
3740
|
+
const blockStatement = t.blockStatement([returnStatement]);
|
|
3741
|
+
functionPath.node.body = blockStatement;
|
|
3742
|
+
body = blockStatement;
|
|
2788
3743
|
} else {
|
|
2789
|
-
|
|
3744
|
+
return false;
|
|
2790
3745
|
}
|
|
2791
|
-
styleAttribute.value = t.jsxExpressionContainer(styleArray);
|
|
2792
3746
|
}
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
);
|
|
2800
|
-
|
|
3747
|
+
const hasHook = body.body.some((statement) => {
|
|
3748
|
+
if (t.isVariableDeclaration(statement) && statement.declarations.length > 0 && t.isVariableDeclarator(statement.declarations[0])) {
|
|
3749
|
+
const declarator = statement.declarations[0];
|
|
3750
|
+
return t.isIdentifier(declarator.id) && declarator.id.name === dimensionsVariableName;
|
|
3751
|
+
}
|
|
3752
|
+
return false;
|
|
3753
|
+
});
|
|
3754
|
+
if (hasHook) {
|
|
3755
|
+
return false;
|
|
3756
|
+
}
|
|
3757
|
+
const identifierToCall = localIdentifier ?? hookName;
|
|
3758
|
+
const hookCall = t.variableDeclaration("const", [
|
|
3759
|
+
t.variableDeclarator(
|
|
3760
|
+
t.identifier(dimensionsVariableName),
|
|
3761
|
+
t.callExpression(t.identifier(identifierToCall), [])
|
|
3762
|
+
)
|
|
3763
|
+
]);
|
|
3764
|
+
body.body.unshift(hookCall);
|
|
3765
|
+
return true;
|
|
2801
3766
|
}
|
|
2802
|
-
function
|
|
2803
|
-
const
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
|
|
3767
|
+
function injectStylesAtTop(path2, styleRegistry, stylesIdentifier, t) {
|
|
3768
|
+
const styleProperties = [];
|
|
3769
|
+
for (const [key, styleObject] of styleRegistry) {
|
|
3770
|
+
const properties = Object.entries(styleObject).map(([styleProp, styleValue]) => {
|
|
3771
|
+
let valueNode;
|
|
3772
|
+
if (typeof styleValue === "number") {
|
|
3773
|
+
valueNode = t.numericLiteral(styleValue);
|
|
3774
|
+
} else if (typeof styleValue === "string") {
|
|
3775
|
+
valueNode = t.stringLiteral(styleValue);
|
|
3776
|
+
} else {
|
|
3777
|
+
valueNode = t.valueToNode(styleValue);
|
|
3778
|
+
}
|
|
3779
|
+
return t.objectProperty(t.identifier(styleProp), valueNode);
|
|
3780
|
+
});
|
|
3781
|
+
styleProperties.push(t.objectProperty(t.identifier(key), t.objectExpression(properties)));
|
|
2818
3782
|
}
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
3783
|
+
const styleSheet = t.variableDeclaration("const", [
|
|
3784
|
+
t.variableDeclarator(
|
|
3785
|
+
t.identifier(stylesIdentifier),
|
|
3786
|
+
t.callExpression(t.memberExpression(t.identifier("StyleSheet"), t.identifier("create")), [
|
|
3787
|
+
t.objectExpression(styleProperties)
|
|
3788
|
+
])
|
|
3789
|
+
)
|
|
3790
|
+
]);
|
|
3791
|
+
const body = path2.node.body;
|
|
3792
|
+
let insertIndex = 0;
|
|
3793
|
+
for (let i = 0; i < body.length; i++) {
|
|
3794
|
+
const statement = body[i];
|
|
3795
|
+
if (t.isExpressionStatement(statement) && t.isStringLiteral(statement.expression)) {
|
|
3796
|
+
insertIndex = i + 1;
|
|
3797
|
+
continue;
|
|
2830
3798
|
}
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
3799
|
+
if (t.isImportDeclaration(statement)) {
|
|
3800
|
+
insertIndex = i + 1;
|
|
3801
|
+
continue;
|
|
3802
|
+
}
|
|
3803
|
+
break;
|
|
2835
3804
|
}
|
|
3805
|
+
body.splice(insertIndex, 0, styleSheet);
|
|
2836
3806
|
}
|
|
2837
3807
|
|
|
2838
3808
|
// src/babel/utils/twProcessing.ts
|
|
@@ -2856,6 +3826,11 @@ function processTwCall(className, path2, state, parseClassName2, generateStyleKe
|
|
|
2856
3826
|
if (baseClasses.length > 0) {
|
|
2857
3827
|
const baseClassName = baseClasses.join(" ");
|
|
2858
3828
|
const baseStyleObject = parseClassName2(baseClassName, state.customTheme);
|
|
3829
|
+
if (hasRuntimeDimensions(baseStyleObject)) {
|
|
3830
|
+
throw path2.buildCodeFrameError(
|
|
3831
|
+
`w-screen and h-screen are not supported in tw\`\` or twStyle() calls. Found: "${baseClassName}". Use them in className attributes instead.`
|
|
3832
|
+
);
|
|
3833
|
+
}
|
|
2859
3834
|
const baseStyleKey = generateStyleKey2(baseClassName);
|
|
2860
3835
|
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
2861
3836
|
objectProperties.push(
|
|
@@ -2869,8 +3844,9 @@ function processTwCall(className, path2, state, parseClassName2, generateStyleKe
|
|
|
2869
3844
|
}
|
|
2870
3845
|
const colorSchemeModifiers = modifierClasses.filter((m) => isColorSchemeModifier(m.modifier));
|
|
2871
3846
|
const platformModifiers = modifierClasses.filter((m) => isPlatformModifier(m.modifier));
|
|
3847
|
+
const directionalModifiers = modifierClasses.filter((m) => isDirectionalModifier(m.modifier));
|
|
2872
3848
|
const otherModifiers = modifierClasses.filter(
|
|
2873
|
-
(m) => !isColorSchemeModifier(m.modifier) && !isPlatformModifier(m.modifier)
|
|
3849
|
+
(m) => !isColorSchemeModifier(m.modifier) && !isPlatformModifier(m.modifier) && !isDirectionalModifier(m.modifier)
|
|
2874
3850
|
);
|
|
2875
3851
|
const hasColorSchemeModifiers = colorSchemeModifiers.length > 0;
|
|
2876
3852
|
let componentScope = null;
|
|
@@ -3004,6 +3980,62 @@ function processTwCall(className, path2, state, parseClassName2, generateStyleKe
|
|
|
3004
3980
|
);
|
|
3005
3981
|
}
|
|
3006
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
|
+
}
|
|
3007
4039
|
const modifiersByType = /* @__PURE__ */ new Map();
|
|
3008
4040
|
for (const mod of otherModifiers) {
|
|
3009
4041
|
if (!modifiersByType.has(mod.modifier)) {
|
|
@@ -3053,586 +4085,186 @@ function removeTwImports(path2, t) {
|
|
|
3053
4085
|
});
|
|
3054
4086
|
}
|
|
3055
4087
|
|
|
3056
|
-
// src/babel/plugin.ts
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
if (t.isClassMethod(parent)) {
|
|
3063
|
-
return false;
|
|
4088
|
+
// src/babel/plugin/visitors/program.ts
|
|
4089
|
+
function programEnter(_path, _state) {
|
|
4090
|
+
}
|
|
4091
|
+
function programExit(path2, state, t) {
|
|
4092
|
+
if (state.hasTwImport) {
|
|
4093
|
+
removeTwImports(path2, t);
|
|
3064
4094
|
}
|
|
3065
|
-
if (
|
|
3066
|
-
return
|
|
4095
|
+
if (!state.hasClassNames && !state.needsWindowDimensionsImport && !state.needsColorSchemeImport && !state.needsI18nManagerImport) {
|
|
4096
|
+
return;
|
|
3067
4097
|
}
|
|
3068
|
-
if (
|
|
3069
|
-
|
|
3070
|
-
|
|
4098
|
+
if (!state.hasStyleSheetImport && state.styleRegistry.size > 0) {
|
|
4099
|
+
addStyleSheetImport(path2, t);
|
|
4100
|
+
}
|
|
4101
|
+
if (state.needsPlatformImport && !state.hasPlatformImport) {
|
|
4102
|
+
addPlatformImport(path2, t);
|
|
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
|
+
}
|
|
4110
|
+
if (state.needsColorSchemeImport && !state.hasColorSchemeImport) {
|
|
4111
|
+
addColorSchemeImport(path2, state.colorSchemeImportSource, state.colorSchemeHookName, t);
|
|
4112
|
+
}
|
|
4113
|
+
if (state.needsColorSchemeImport) {
|
|
4114
|
+
for (const functionPath of state.functionComponentsNeedingColorScheme) {
|
|
4115
|
+
injectColorSchemeHook(
|
|
4116
|
+
functionPath,
|
|
4117
|
+
state.colorSchemeVariableName,
|
|
4118
|
+
state.colorSchemeHookName,
|
|
4119
|
+
state.colorSchemeLocalIdentifier,
|
|
4120
|
+
t
|
|
4121
|
+
);
|
|
3071
4122
|
}
|
|
3072
4123
|
}
|
|
3073
|
-
if (
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
4124
|
+
if (state.needsWindowDimensionsImport && !state.hasWindowDimensionsImport) {
|
|
4125
|
+
addWindowDimensionsImport(path2, t);
|
|
4126
|
+
}
|
|
4127
|
+
if (state.needsWindowDimensionsImport) {
|
|
4128
|
+
for (const functionPath of state.functionComponentsNeedingWindowDimensions) {
|
|
4129
|
+
injectWindowDimensionsHook(
|
|
4130
|
+
functionPath,
|
|
4131
|
+
state.windowDimensionsVariableName,
|
|
4132
|
+
"useWindowDimensions",
|
|
4133
|
+
state.windowDimensionsLocalIdentifier,
|
|
4134
|
+
t
|
|
4135
|
+
);
|
|
3082
4136
|
}
|
|
3083
4137
|
}
|
|
3084
|
-
|
|
4138
|
+
if (state.styleRegistry.size > 0) {
|
|
4139
|
+
injectStylesAtTop(path2, state.styleRegistry, state.stylesIdentifier, t);
|
|
4140
|
+
}
|
|
3085
4141
|
}
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
4142
|
+
|
|
4143
|
+
// src/babel/plugin/visitors/tw.ts
|
|
4144
|
+
function taggedTemplateVisitor(path2, state, t) {
|
|
4145
|
+
const node = path2.node;
|
|
4146
|
+
if (!t.isIdentifier(node.tag)) {
|
|
4147
|
+
return;
|
|
4148
|
+
}
|
|
4149
|
+
const tagName = node.tag.name;
|
|
4150
|
+
if (!state.twImportNames.has(tagName)) {
|
|
4151
|
+
return;
|
|
4152
|
+
}
|
|
4153
|
+
const quasi = node.quasi;
|
|
4154
|
+
if (!t.isTemplateLiteral(quasi)) {
|
|
4155
|
+
return;
|
|
4156
|
+
}
|
|
4157
|
+
if (quasi.expressions.length > 0) {
|
|
4158
|
+
if (process.env.NODE_ENV !== "production") {
|
|
4159
|
+
console.warn(
|
|
4160
|
+
`[react-native-tailwind] Dynamic tw\`...\` with interpolations is not supported at ${state.file.opts.filename ?? "unknown"}. Use style prop for dynamic values.`
|
|
4161
|
+
);
|
|
3091
4162
|
}
|
|
3092
|
-
|
|
4163
|
+
return;
|
|
3093
4164
|
}
|
|
3094
|
-
|
|
4165
|
+
const className = quasi.quasis[0]?.value.cooked?.trim() ?? "";
|
|
4166
|
+
if (!className) {
|
|
4167
|
+
path2.replaceWith(t.objectExpression([t.objectProperty(t.identifier("style"), t.objectExpression([]))]));
|
|
4168
|
+
state.hasTwImport = true;
|
|
4169
|
+
return;
|
|
4170
|
+
}
|
|
4171
|
+
state.hasClassNames = true;
|
|
4172
|
+
processTwCall(
|
|
4173
|
+
className,
|
|
4174
|
+
path2,
|
|
4175
|
+
state,
|
|
4176
|
+
parseClassName,
|
|
4177
|
+
generateStyleKey,
|
|
4178
|
+
splitModifierClasses,
|
|
4179
|
+
findComponentScope,
|
|
4180
|
+
t
|
|
4181
|
+
);
|
|
4182
|
+
state.hasTwImport = true;
|
|
4183
|
+
}
|
|
4184
|
+
function callExpressionVisitor(path2, state, t) {
|
|
4185
|
+
const node = path2.node;
|
|
4186
|
+
if (!t.isIdentifier(node.callee)) {
|
|
4187
|
+
return;
|
|
4188
|
+
}
|
|
4189
|
+
const calleeName = node.callee.name;
|
|
4190
|
+
if (!state.twImportNames.has(calleeName)) {
|
|
4191
|
+
return;
|
|
4192
|
+
}
|
|
4193
|
+
if (node.arguments.length !== 1) {
|
|
4194
|
+
if (process.env.NODE_ENV !== "production") {
|
|
4195
|
+
console.warn(
|
|
4196
|
+
`[react-native-tailwind] twStyle() expects exactly one argument at ${state.file.opts.filename ?? "unknown"}`
|
|
4197
|
+
);
|
|
4198
|
+
}
|
|
4199
|
+
return;
|
|
4200
|
+
}
|
|
4201
|
+
const arg = node.arguments[0];
|
|
4202
|
+
if (!t.isStringLiteral(arg)) {
|
|
4203
|
+
if (process.env.NODE_ENV !== "production") {
|
|
4204
|
+
console.warn(
|
|
4205
|
+
`[react-native-tailwind] twStyle() only supports static string literals at ${state.file.opts.filename ?? "unknown"}. Use style prop for dynamic values.`
|
|
4206
|
+
);
|
|
4207
|
+
}
|
|
4208
|
+
return;
|
|
4209
|
+
}
|
|
4210
|
+
const className = arg.value.trim();
|
|
4211
|
+
if (!className) {
|
|
4212
|
+
path2.replaceWith(t.identifier("undefined"));
|
|
4213
|
+
state.hasTwImport = true;
|
|
4214
|
+
return;
|
|
4215
|
+
}
|
|
4216
|
+
state.hasClassNames = true;
|
|
4217
|
+
processTwCall(
|
|
4218
|
+
className,
|
|
4219
|
+
path2,
|
|
4220
|
+
state,
|
|
4221
|
+
parseClassName,
|
|
4222
|
+
generateStyleKey,
|
|
4223
|
+
splitModifierClasses,
|
|
4224
|
+
findComponentScope,
|
|
4225
|
+
t
|
|
4226
|
+
);
|
|
4227
|
+
state.hasTwImport = true;
|
|
3095
4228
|
}
|
|
4229
|
+
|
|
4230
|
+
// src/babel/plugin.ts
|
|
3096
4231
|
function reactNativeTailwindBabelPlugin({ types: t }, options) {
|
|
3097
|
-
const
|
|
3098
|
-
const
|
|
3099
|
-
const stylesIdentifier = options?.stylesIdentifier ?? DEFAULT_STYLES_IDENTIFIER;
|
|
4232
|
+
const colorSchemeImportSource = options?.colorScheme?.importFrom ?? "react-native";
|
|
4233
|
+
const colorSchemeHookName = options?.colorScheme?.importName ?? "useColorScheme";
|
|
3100
4234
|
const schemeModifierConfig = {
|
|
3101
4235
|
darkSuffix: options?.schemeModifier?.darkSuffix ?? "-dark",
|
|
3102
4236
|
lightSuffix: options?.schemeModifier?.lightSuffix ?? "-light"
|
|
3103
4237
|
};
|
|
3104
|
-
const colorSchemeImportSource = options?.colorScheme?.importFrom ?? "react-native";
|
|
3105
|
-
const colorSchemeHookName = options?.colorScheme?.importName ?? "useColorScheme";
|
|
3106
4238
|
return {
|
|
3107
4239
|
name: "react-native-tailwind",
|
|
3108
4240
|
visitor: {
|
|
3109
4241
|
Program: {
|
|
3110
|
-
enter(
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
state
|
|
3119
|
-
state
|
|
3120
|
-
state.colorSchemeHookName = colorSchemeHookName;
|
|
3121
|
-
state.supportedAttributes = exactMatches;
|
|
3122
|
-
state.attributePatterns = patterns;
|
|
3123
|
-
state.stylesIdentifier = stylesIdentifier;
|
|
3124
|
-
state.twImportNames = /* @__PURE__ */ new Set();
|
|
3125
|
-
state.hasTwImport = false;
|
|
3126
|
-
state.functionComponentsNeedingColorScheme = /* @__PURE__ */ new Set();
|
|
3127
|
-
state.hasColorSchemeImport = false;
|
|
3128
|
-
state.colorSchemeLocalIdentifier = void 0;
|
|
3129
|
-
state.needsPlatformImport = false;
|
|
3130
|
-
state.hasPlatformImport = false;
|
|
3131
|
-
state.customTheme = extractCustomTheme(state.file.opts.filename ?? "");
|
|
3132
|
-
state.schemeModifierConfig = schemeModifierConfig;
|
|
4242
|
+
enter(path2, state) {
|
|
4243
|
+
const initialState = createInitialState(
|
|
4244
|
+
options,
|
|
4245
|
+
state.file.opts.filename ?? "",
|
|
4246
|
+
colorSchemeImportSource,
|
|
4247
|
+
colorSchemeHookName,
|
|
4248
|
+
schemeModifierConfig
|
|
4249
|
+
);
|
|
4250
|
+
Object.assign(state, initialState);
|
|
4251
|
+
programEnter(path2, state);
|
|
3133
4252
|
},
|
|
3134
4253
|
exit(path2, state) {
|
|
3135
|
-
|
|
3136
|
-
removeTwImports(path2, t);
|
|
3137
|
-
}
|
|
3138
|
-
if (!state.hasClassNames || state.styleRegistry.size === 0) {
|
|
3139
|
-
return;
|
|
3140
|
-
}
|
|
3141
|
-
if (!state.hasStyleSheetImport) {
|
|
3142
|
-
addStyleSheetImport(path2, t);
|
|
3143
|
-
}
|
|
3144
|
-
if (state.needsPlatformImport && !state.hasPlatformImport) {
|
|
3145
|
-
addPlatformImport(path2, t);
|
|
3146
|
-
}
|
|
3147
|
-
if (state.needsColorSchemeImport && !state.hasColorSchemeImport) {
|
|
3148
|
-
addColorSchemeImport(path2, state.colorSchemeImportSource, state.colorSchemeHookName, t);
|
|
3149
|
-
}
|
|
3150
|
-
if (state.needsColorSchemeImport) {
|
|
3151
|
-
for (const functionPath of state.functionComponentsNeedingColorScheme) {
|
|
3152
|
-
injectColorSchemeHook(
|
|
3153
|
-
functionPath,
|
|
3154
|
-
state.colorSchemeVariableName,
|
|
3155
|
-
state.colorSchemeHookName,
|
|
3156
|
-
state.colorSchemeLocalIdentifier,
|
|
3157
|
-
t
|
|
3158
|
-
);
|
|
3159
|
-
}
|
|
3160
|
-
}
|
|
3161
|
-
injectStylesAtTop(path2, state.styleRegistry, state.stylesIdentifier, t);
|
|
4254
|
+
programExit(path2, state, t);
|
|
3162
4255
|
}
|
|
3163
4256
|
},
|
|
3164
|
-
// Check if StyleSheet/Platform are already imported and track tw/twStyle imports
|
|
3165
4257
|
ImportDeclaration(path2, state) {
|
|
3166
|
-
|
|
3167
|
-
if (node.source.value === "react-native") {
|
|
3168
|
-
const specifiers = node.specifiers;
|
|
3169
|
-
const hasStyleSheet = specifiers.some((spec) => {
|
|
3170
|
-
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
3171
|
-
return spec.imported.name === "StyleSheet";
|
|
3172
|
-
}
|
|
3173
|
-
return false;
|
|
3174
|
-
});
|
|
3175
|
-
const hasPlatform = specifiers.some((spec) => {
|
|
3176
|
-
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
3177
|
-
return spec.imported.name === "Platform";
|
|
3178
|
-
}
|
|
3179
|
-
return false;
|
|
3180
|
-
});
|
|
3181
|
-
if (hasStyleSheet) {
|
|
3182
|
-
state.hasStyleSheetImport = true;
|
|
3183
|
-
}
|
|
3184
|
-
if (hasPlatform) {
|
|
3185
|
-
state.hasPlatformImport = true;
|
|
3186
|
-
}
|
|
3187
|
-
state.reactNativeImportPath = path2;
|
|
3188
|
-
}
|
|
3189
|
-
if (node.source.value === state.colorSchemeImportSource && node.importKind !== "type") {
|
|
3190
|
-
const specifiers = node.specifiers;
|
|
3191
|
-
for (const spec of specifiers) {
|
|
3192
|
-
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
3193
|
-
if (spec.imported.name === state.colorSchemeHookName) {
|
|
3194
|
-
state.hasColorSchemeImport = true;
|
|
3195
|
-
state.colorSchemeLocalIdentifier = spec.local.name;
|
|
3196
|
-
break;
|
|
3197
|
-
}
|
|
3198
|
-
}
|
|
3199
|
-
}
|
|
3200
|
-
}
|
|
3201
|
-
if (node.source.value === "@mgcrea/react-native-tailwind") {
|
|
3202
|
-
const specifiers = node.specifiers;
|
|
3203
|
-
specifiers.forEach((spec) => {
|
|
3204
|
-
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
3205
|
-
const importedName = spec.imported.name;
|
|
3206
|
-
if (importedName === "tw" || importedName === "twStyle") {
|
|
3207
|
-
const localName = spec.local.name;
|
|
3208
|
-
state.twImportNames.add(localName);
|
|
3209
|
-
}
|
|
3210
|
-
}
|
|
3211
|
-
});
|
|
3212
|
-
}
|
|
4258
|
+
importDeclarationVisitor(path2, state, t);
|
|
3213
4259
|
},
|
|
3214
|
-
// Handle tw`...` tagged template expressions
|
|
3215
4260
|
TaggedTemplateExpression(path2, state) {
|
|
3216
|
-
|
|
3217
|
-
if (!t.isIdentifier(node.tag)) {
|
|
3218
|
-
return;
|
|
3219
|
-
}
|
|
3220
|
-
const tagName = node.tag.name;
|
|
3221
|
-
if (!state.twImportNames.has(tagName)) {
|
|
3222
|
-
return;
|
|
3223
|
-
}
|
|
3224
|
-
const quasi = node.quasi;
|
|
3225
|
-
if (!t.isTemplateLiteral(quasi)) {
|
|
3226
|
-
return;
|
|
3227
|
-
}
|
|
3228
|
-
if (quasi.expressions.length > 0) {
|
|
3229
|
-
if (process.env.NODE_ENV !== "production") {
|
|
3230
|
-
console.warn(
|
|
3231
|
-
`[react-native-tailwind] Dynamic tw\`...\` with interpolations is not supported at ${state.file.opts.filename ?? "unknown"}. Use style prop for dynamic values.`
|
|
3232
|
-
);
|
|
3233
|
-
}
|
|
3234
|
-
return;
|
|
3235
|
-
}
|
|
3236
|
-
const className = quasi.quasis[0]?.value.cooked?.trim() ?? "";
|
|
3237
|
-
if (!className) {
|
|
3238
|
-
path2.replaceWith(
|
|
3239
|
-
t.objectExpression([t.objectProperty(t.identifier("style"), t.objectExpression([]))])
|
|
3240
|
-
);
|
|
3241
|
-
state.hasTwImport = true;
|
|
3242
|
-
return;
|
|
3243
|
-
}
|
|
3244
|
-
state.hasClassNames = true;
|
|
3245
|
-
processTwCall(
|
|
3246
|
-
className,
|
|
3247
|
-
path2,
|
|
3248
|
-
state,
|
|
3249
|
-
parseClassName,
|
|
3250
|
-
generateStyleKey,
|
|
3251
|
-
splitModifierClasses,
|
|
3252
|
-
findComponentScope,
|
|
3253
|
-
t
|
|
3254
|
-
);
|
|
3255
|
-
state.hasTwImport = true;
|
|
4261
|
+
taggedTemplateVisitor(path2, state, t);
|
|
3256
4262
|
},
|
|
3257
|
-
// Handle twStyle('...') call expressions
|
|
3258
4263
|
CallExpression(path2, state) {
|
|
3259
|
-
|
|
3260
|
-
if (!t.isIdentifier(node.callee)) {
|
|
3261
|
-
return;
|
|
3262
|
-
}
|
|
3263
|
-
const calleeName = node.callee.name;
|
|
3264
|
-
if (!state.twImportNames.has(calleeName)) {
|
|
3265
|
-
return;
|
|
3266
|
-
}
|
|
3267
|
-
if (node.arguments.length !== 1) {
|
|
3268
|
-
if (process.env.NODE_ENV !== "production") {
|
|
3269
|
-
console.warn(
|
|
3270
|
-
`[react-native-tailwind] twStyle() expects exactly one argument at ${state.file.opts.filename ?? "unknown"}`
|
|
3271
|
-
);
|
|
3272
|
-
}
|
|
3273
|
-
return;
|
|
3274
|
-
}
|
|
3275
|
-
const arg = node.arguments[0];
|
|
3276
|
-
if (!t.isStringLiteral(arg)) {
|
|
3277
|
-
if (process.env.NODE_ENV !== "production") {
|
|
3278
|
-
console.warn(
|
|
3279
|
-
`[react-native-tailwind] twStyle() only supports static string literals at ${state.file.opts.filename ?? "unknown"}. Use style prop for dynamic values.`
|
|
3280
|
-
);
|
|
3281
|
-
}
|
|
3282
|
-
return;
|
|
3283
|
-
}
|
|
3284
|
-
const className = arg.value.trim();
|
|
3285
|
-
if (!className) {
|
|
3286
|
-
path2.replaceWith(t.identifier("undefined"));
|
|
3287
|
-
state.hasTwImport = true;
|
|
3288
|
-
return;
|
|
3289
|
-
}
|
|
3290
|
-
state.hasClassNames = true;
|
|
3291
|
-
processTwCall(
|
|
3292
|
-
className,
|
|
3293
|
-
path2,
|
|
3294
|
-
state,
|
|
3295
|
-
parseClassName,
|
|
3296
|
-
generateStyleKey,
|
|
3297
|
-
splitModifierClasses,
|
|
3298
|
-
findComponentScope,
|
|
3299
|
-
t
|
|
3300
|
-
);
|
|
3301
|
-
state.hasTwImport = true;
|
|
4264
|
+
callExpressionVisitor(path2, state, t);
|
|
3302
4265
|
},
|
|
3303
4266
|
JSXAttribute(path2, state) {
|
|
3304
|
-
|
|
3305
|
-
if (!t.isJSXIdentifier(node.name)) {
|
|
3306
|
-
return;
|
|
3307
|
-
}
|
|
3308
|
-
const attributeName = node.name.name;
|
|
3309
|
-
if (!isAttributeSupported(attributeName, state.supportedAttributes, state.attributePatterns)) {
|
|
3310
|
-
return;
|
|
3311
|
-
}
|
|
3312
|
-
const value = node.value;
|
|
3313
|
-
const targetStyleProp = getTargetStyleProp(attributeName);
|
|
3314
|
-
const processStaticClassName = (className) => {
|
|
3315
|
-
const trimmedClassName = className.trim();
|
|
3316
|
-
if (!trimmedClassName) {
|
|
3317
|
-
path2.remove();
|
|
3318
|
-
return true;
|
|
3319
|
-
}
|
|
3320
|
-
state.hasClassNames = true;
|
|
3321
|
-
const { baseClasses, modifierClasses: rawModifierClasses } = splitModifierClasses(trimmedClassName);
|
|
3322
|
-
const modifierClasses = [];
|
|
3323
|
-
for (const modifier of rawModifierClasses) {
|
|
3324
|
-
if (isSchemeModifier(modifier.modifier)) {
|
|
3325
|
-
const expanded = expandSchemeModifier(
|
|
3326
|
-
modifier,
|
|
3327
|
-
state.customTheme.colors ?? {},
|
|
3328
|
-
state.schemeModifierConfig.darkSuffix,
|
|
3329
|
-
state.schemeModifierConfig.lightSuffix
|
|
3330
|
-
);
|
|
3331
|
-
modifierClasses.push(...expanded);
|
|
3332
|
-
} else {
|
|
3333
|
-
modifierClasses.push(modifier);
|
|
3334
|
-
}
|
|
3335
|
-
}
|
|
3336
|
-
const placeholderModifiers = modifierClasses.filter((m) => m.modifier === "placeholder");
|
|
3337
|
-
const platformModifiers = modifierClasses.filter((m) => isPlatformModifier(m.modifier));
|
|
3338
|
-
const colorSchemeModifiers = modifierClasses.filter((m) => isColorSchemeModifier(m.modifier));
|
|
3339
|
-
const stateModifiers = modifierClasses.filter(
|
|
3340
|
-
(m) => isStateModifier(m.modifier) && m.modifier !== "placeholder"
|
|
3341
|
-
);
|
|
3342
|
-
if (placeholderModifiers.length > 0) {
|
|
3343
|
-
const jsxOpeningElement = path2.parent;
|
|
3344
|
-
const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
|
|
3345
|
-
if (componentSupport?.supportedModifiers.includes("placeholder")) {
|
|
3346
|
-
const placeholderClasses = placeholderModifiers.map((m) => m.baseClass).join(" ");
|
|
3347
|
-
const placeholderColor = parsePlaceholderClasses(placeholderClasses, state.customTheme.colors);
|
|
3348
|
-
if (placeholderColor) {
|
|
3349
|
-
addOrMergePlaceholderTextColorProp(jsxOpeningElement, placeholderColor, t);
|
|
3350
|
-
}
|
|
3351
|
-
} else {
|
|
3352
|
-
if (process.env.NODE_ENV !== "production") {
|
|
3353
|
-
console.warn(
|
|
3354
|
-
`[react-native-tailwind] placeholder: modifier can only be used on TextInput component at ${state.file.opts.filename ?? "unknown"}`
|
|
3355
|
-
);
|
|
3356
|
-
}
|
|
3357
|
-
}
|
|
3358
|
-
}
|
|
3359
|
-
const hasPlatformModifiers = platformModifiers.length > 0;
|
|
3360
|
-
const hasColorSchemeModifiers = colorSchemeModifiers.length > 0;
|
|
3361
|
-
const hasStateModifiers = stateModifiers.length > 0;
|
|
3362
|
-
const hasBaseClasses = baseClasses.length > 0;
|
|
3363
|
-
let componentScope = null;
|
|
3364
|
-
if (hasColorSchemeModifiers) {
|
|
3365
|
-
componentScope = findComponentScope(path2, t);
|
|
3366
|
-
if (componentScope) {
|
|
3367
|
-
state.functionComponentsNeedingColorScheme.add(componentScope);
|
|
3368
|
-
} else {
|
|
3369
|
-
if (process.env.NODE_ENV !== "production") {
|
|
3370
|
-
console.warn(
|
|
3371
|
-
`[react-native-tailwind] dark:/light: modifiers require a function component scope. Found in non-component context at ${state.file.opts.filename ?? "unknown"}. These modifiers are not supported in class components or nested callbacks.`
|
|
3372
|
-
);
|
|
3373
|
-
}
|
|
3374
|
-
}
|
|
3375
|
-
}
|
|
3376
|
-
if (hasStateModifiers && (hasPlatformModifiers || hasColorSchemeModifiers)) {
|
|
3377
|
-
const jsxOpeningElement = path2.parent;
|
|
3378
|
-
const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
|
|
3379
|
-
if (componentSupport) {
|
|
3380
|
-
const styleArrayElements = [];
|
|
3381
|
-
if (hasBaseClasses) {
|
|
3382
|
-
const baseClassName = baseClasses.join(" ");
|
|
3383
|
-
const baseStyleObject = parseClassName(baseClassName, state.customTheme);
|
|
3384
|
-
const baseStyleKey = generateStyleKey(baseClassName);
|
|
3385
|
-
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
3386
|
-
styleArrayElements.push(
|
|
3387
|
-
t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey))
|
|
3388
|
-
);
|
|
3389
|
-
}
|
|
3390
|
-
if (hasPlatformModifiers) {
|
|
3391
|
-
const platformSelectExpression = processPlatformModifiers(
|
|
3392
|
-
platformModifiers,
|
|
3393
|
-
state,
|
|
3394
|
-
parseClassName,
|
|
3395
|
-
generateStyleKey,
|
|
3396
|
-
t
|
|
3397
|
-
);
|
|
3398
|
-
styleArrayElements.push(platformSelectExpression);
|
|
3399
|
-
}
|
|
3400
|
-
if (hasColorSchemeModifiers && componentScope) {
|
|
3401
|
-
const colorSchemeConditionals = processColorSchemeModifiers(
|
|
3402
|
-
colorSchemeModifiers,
|
|
3403
|
-
state,
|
|
3404
|
-
parseClassName,
|
|
3405
|
-
generateStyleKey,
|
|
3406
|
-
t
|
|
3407
|
-
);
|
|
3408
|
-
styleArrayElements.push(...colorSchemeConditionals);
|
|
3409
|
-
}
|
|
3410
|
-
const modifiersByType = /* @__PURE__ */ new Map();
|
|
3411
|
-
for (const mod of stateModifiers) {
|
|
3412
|
-
const modType = mod.modifier;
|
|
3413
|
-
if (!modifiersByType.has(modType)) {
|
|
3414
|
-
modifiersByType.set(modType, []);
|
|
3415
|
-
}
|
|
3416
|
-
modifiersByType.get(modType)?.push(mod);
|
|
3417
|
-
}
|
|
3418
|
-
for (const [modifierType, modifiers] of modifiersByType) {
|
|
3419
|
-
if (!componentSupport.supportedModifiers.includes(modifierType)) {
|
|
3420
|
-
continue;
|
|
3421
|
-
}
|
|
3422
|
-
const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
|
|
3423
|
-
const modifierStyleObject = parseClassName(modifierClassNames, state.customTheme);
|
|
3424
|
-
const modifierStyleKey = generateStyleKey(`${modifierType}_${modifierClassNames}`);
|
|
3425
|
-
state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
|
|
3426
|
-
const stateProperty = getStatePropertyForModifier(modifierType);
|
|
3427
|
-
const conditionalExpression = t.logicalExpression(
|
|
3428
|
-
"&&",
|
|
3429
|
-
t.identifier(stateProperty),
|
|
3430
|
-
t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(modifierStyleKey))
|
|
3431
|
-
);
|
|
3432
|
-
styleArrayElements.push(conditionalExpression);
|
|
3433
|
-
}
|
|
3434
|
-
const usedModifiers = Array.from(new Set(stateModifiers.map((m) => m.modifier))).filter(
|
|
3435
|
-
(mod) => componentSupport.supportedModifiers.includes(mod)
|
|
3436
|
-
);
|
|
3437
|
-
const styleArrayExpression = t.arrayExpression(styleArrayElements);
|
|
3438
|
-
const styleFunctionExpression = createStyleFunction(styleArrayExpression, usedModifiers, t);
|
|
3439
|
-
const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
|
|
3440
|
-
if (styleAttribute2) {
|
|
3441
|
-
mergeStyleFunctionAttribute(path2, styleAttribute2, styleFunctionExpression, t);
|
|
3442
|
-
} else {
|
|
3443
|
-
replaceWithStyleFunctionAttribute(path2, styleFunctionExpression, targetStyleProp, t);
|
|
3444
|
-
}
|
|
3445
|
-
return true;
|
|
3446
|
-
} else {
|
|
3447
|
-
}
|
|
3448
|
-
}
|
|
3449
|
-
if ((hasPlatformModifiers || hasColorSchemeModifiers) && !hasStateModifiers) {
|
|
3450
|
-
const styleExpressions = [];
|
|
3451
|
-
if (hasBaseClasses) {
|
|
3452
|
-
const baseClassName = baseClasses.join(" ");
|
|
3453
|
-
const baseStyleObject = parseClassName(baseClassName, state.customTheme);
|
|
3454
|
-
const baseStyleKey = generateStyleKey(baseClassName);
|
|
3455
|
-
state.styleRegistry.set(baseStyleKey, baseStyleObject);
|
|
3456
|
-
styleExpressions.push(
|
|
3457
|
-
t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey))
|
|
3458
|
-
);
|
|
3459
|
-
}
|
|
3460
|
-
if (hasPlatformModifiers) {
|
|
3461
|
-
const platformSelectExpression = processPlatformModifiers(
|
|
3462
|
-
platformModifiers,
|
|
3463
|
-
state,
|
|
3464
|
-
parseClassName,
|
|
3465
|
-
generateStyleKey,
|
|
3466
|
-
t
|
|
3467
|
-
);
|
|
3468
|
-
styleExpressions.push(platformSelectExpression);
|
|
3469
|
-
}
|
|
3470
|
-
if (hasColorSchemeModifiers && componentScope) {
|
|
3471
|
-
const colorSchemeConditionals = processColorSchemeModifiers(
|
|
3472
|
-
colorSchemeModifiers,
|
|
3473
|
-
state,
|
|
3474
|
-
parseClassName,
|
|
3475
|
-
generateStyleKey,
|
|
3476
|
-
t
|
|
3477
|
-
);
|
|
3478
|
-
styleExpressions.push(...colorSchemeConditionals);
|
|
3479
|
-
}
|
|
3480
|
-
const styleExpression = styleExpressions.length === 1 ? styleExpressions[0] : t.arrayExpression(styleExpressions);
|
|
3481
|
-
const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
|
|
3482
|
-
if (styleAttribute2) {
|
|
3483
|
-
const existingStyle = styleAttribute2.value;
|
|
3484
|
-
if (t.isJSXExpressionContainer(existingStyle) && !t.isJSXEmptyExpression(existingStyle.expression)) {
|
|
3485
|
-
const existing = existingStyle.expression;
|
|
3486
|
-
const mergedArray = t.isArrayExpression(existing) ? t.arrayExpression([styleExpression, ...existing.elements]) : t.arrayExpression([styleExpression, existing]);
|
|
3487
|
-
styleAttribute2.value = t.jsxExpressionContainer(mergedArray);
|
|
3488
|
-
} else {
|
|
3489
|
-
styleAttribute2.value = t.jsxExpressionContainer(styleExpression);
|
|
3490
|
-
}
|
|
3491
|
-
path2.remove();
|
|
3492
|
-
} else {
|
|
3493
|
-
path2.node.name = t.jsxIdentifier(targetStyleProp);
|
|
3494
|
-
path2.node.value = t.jsxExpressionContainer(styleExpression);
|
|
3495
|
-
}
|
|
3496
|
-
return true;
|
|
3497
|
-
}
|
|
3498
|
-
if (hasStateModifiers) {
|
|
3499
|
-
const jsxOpeningElement = path2.parent;
|
|
3500
|
-
const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
|
|
3501
|
-
if (componentSupport) {
|
|
3502
|
-
const usedModifiers = Array.from(new Set(stateModifiers.map((m) => m.modifier)));
|
|
3503
|
-
const unsupportedModifiers = usedModifiers.filter(
|
|
3504
|
-
(mod) => !componentSupport.supportedModifiers.includes(mod)
|
|
3505
|
-
);
|
|
3506
|
-
if (unsupportedModifiers.length > 0) {
|
|
3507
|
-
if (process.env.NODE_ENV !== "production") {
|
|
3508
|
-
console.warn(
|
|
3509
|
-
`[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(", ")}`
|
|
3510
|
-
);
|
|
3511
|
-
}
|
|
3512
|
-
const supportedModifierClasses = stateModifiers.filter(
|
|
3513
|
-
(m) => componentSupport.supportedModifiers.includes(m.modifier)
|
|
3514
|
-
);
|
|
3515
|
-
if (supportedModifierClasses.length === 0) {
|
|
3516
|
-
} else {
|
|
3517
|
-
const filteredClassName = baseClasses.join(" ") + " " + supportedModifierClasses.map((m) => `${m.modifier}:${m.baseClass}`).join(" ");
|
|
3518
|
-
const styleExpression = processStaticClassNameWithModifiers(
|
|
3519
|
-
filteredClassName.trim(),
|
|
3520
|
-
state,
|
|
3521
|
-
parseClassName,
|
|
3522
|
-
generateStyleKey,
|
|
3523
|
-
splitModifierClasses,
|
|
3524
|
-
t
|
|
3525
|
-
);
|
|
3526
|
-
const modifierTypes = Array.from(new Set(supportedModifierClasses.map((m) => m.modifier)));
|
|
3527
|
-
const styleFunctionExpression = createStyleFunction(styleExpression, modifierTypes, t);
|
|
3528
|
-
const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
|
|
3529
|
-
if (styleAttribute2) {
|
|
3530
|
-
mergeStyleFunctionAttribute(path2, styleAttribute2, styleFunctionExpression, t);
|
|
3531
|
-
} else {
|
|
3532
|
-
replaceWithStyleFunctionAttribute(path2, styleFunctionExpression, targetStyleProp, t);
|
|
3533
|
-
}
|
|
3534
|
-
return true;
|
|
3535
|
-
}
|
|
3536
|
-
} else {
|
|
3537
|
-
const styleExpression = processStaticClassNameWithModifiers(
|
|
3538
|
-
trimmedClassName,
|
|
3539
|
-
state,
|
|
3540
|
-
parseClassName,
|
|
3541
|
-
generateStyleKey,
|
|
3542
|
-
splitModifierClasses,
|
|
3543
|
-
t
|
|
3544
|
-
);
|
|
3545
|
-
const modifierTypes = usedModifiers;
|
|
3546
|
-
const styleFunctionExpression = createStyleFunction(styleExpression, modifierTypes, t);
|
|
3547
|
-
const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
|
|
3548
|
-
if (styleAttribute2) {
|
|
3549
|
-
mergeStyleFunctionAttribute(path2, styleAttribute2, styleFunctionExpression, t);
|
|
3550
|
-
} else {
|
|
3551
|
-
replaceWithStyleFunctionAttribute(path2, styleFunctionExpression, targetStyleProp, t);
|
|
3552
|
-
}
|
|
3553
|
-
return true;
|
|
3554
|
-
}
|
|
3555
|
-
} else {
|
|
3556
|
-
if (process.env.NODE_ENV !== "production") {
|
|
3557
|
-
const usedModifiers = Array.from(new Set(stateModifiers.map((m) => m.modifier)));
|
|
3558
|
-
console.warn(
|
|
3559
|
-
`[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"}`
|
|
3560
|
-
);
|
|
3561
|
-
}
|
|
3562
|
-
}
|
|
3563
|
-
}
|
|
3564
|
-
const classNameForStyle = baseClasses.join(" ");
|
|
3565
|
-
if (!classNameForStyle) {
|
|
3566
|
-
path2.remove();
|
|
3567
|
-
return true;
|
|
3568
|
-
}
|
|
3569
|
-
const styleObject = parseClassName(classNameForStyle, state.customTheme);
|
|
3570
|
-
const styleKey = generateStyleKey(classNameForStyle);
|
|
3571
|
-
state.styleRegistry.set(styleKey, styleObject);
|
|
3572
|
-
const styleAttribute = findStyleAttribute(path2, targetStyleProp, t);
|
|
3573
|
-
if (styleAttribute) {
|
|
3574
|
-
mergeStyleAttribute(path2, styleAttribute, styleKey, state.stylesIdentifier, t);
|
|
3575
|
-
} else {
|
|
3576
|
-
replaceWithStyleAttribute(path2, styleKey, targetStyleProp, state.stylesIdentifier, t);
|
|
3577
|
-
}
|
|
3578
|
-
return true;
|
|
3579
|
-
};
|
|
3580
|
-
if (t.isStringLiteral(value)) {
|
|
3581
|
-
if (processStaticClassName(value.value)) {
|
|
3582
|
-
return;
|
|
3583
|
-
}
|
|
3584
|
-
}
|
|
3585
|
-
if (t.isJSXExpressionContainer(value)) {
|
|
3586
|
-
const expression = value.expression;
|
|
3587
|
-
if (t.isJSXEmptyExpression(expression)) {
|
|
3588
|
-
return;
|
|
3589
|
-
}
|
|
3590
|
-
if (t.isStringLiteral(expression)) {
|
|
3591
|
-
if (processStaticClassName(expression.value)) {
|
|
3592
|
-
return;
|
|
3593
|
-
}
|
|
3594
|
-
}
|
|
3595
|
-
try {
|
|
3596
|
-
const componentScope = findComponentScope(path2, t);
|
|
3597
|
-
const result = processDynamicExpression(
|
|
3598
|
-
expression,
|
|
3599
|
-
state,
|
|
3600
|
-
parseClassName,
|
|
3601
|
-
generateStyleKey,
|
|
3602
|
-
splitModifierClasses,
|
|
3603
|
-
processPlatformModifiers,
|
|
3604
|
-
processColorSchemeModifiers,
|
|
3605
|
-
componentScope,
|
|
3606
|
-
isPlatformModifier,
|
|
3607
|
-
isColorSchemeModifier,
|
|
3608
|
-
isSchemeModifier,
|
|
3609
|
-
expandSchemeModifier,
|
|
3610
|
-
t
|
|
3611
|
-
);
|
|
3612
|
-
if (result) {
|
|
3613
|
-
state.hasClassNames = true;
|
|
3614
|
-
const styleAttribute = findStyleAttribute(path2, targetStyleProp, t);
|
|
3615
|
-
if (styleAttribute) {
|
|
3616
|
-
mergeDynamicStyleAttribute(path2, styleAttribute, result, t);
|
|
3617
|
-
} else {
|
|
3618
|
-
replaceDynamicWithStyleAttribute(path2, result, targetStyleProp, t);
|
|
3619
|
-
}
|
|
3620
|
-
return;
|
|
3621
|
-
}
|
|
3622
|
-
} catch (error) {
|
|
3623
|
-
if (process.env.NODE_ENV !== "production") {
|
|
3624
|
-
console.warn(
|
|
3625
|
-
`[react-native-tailwind] Failed to process dynamic ${attributeName} at ${state.file.opts.filename ?? "unknown"}: ${error instanceof Error ? error.message : String(error)}`
|
|
3626
|
-
);
|
|
3627
|
-
}
|
|
3628
|
-
}
|
|
3629
|
-
}
|
|
3630
|
-
if (process.env.NODE_ENV !== "production") {
|
|
3631
|
-
const filename = state.file.opts.filename ?? "unknown";
|
|
3632
|
-
console.warn(
|
|
3633
|
-
`[react-native-tailwind] Dynamic ${attributeName} values are not fully supported at ${filename}. Use the ${targetStyleProp} prop for dynamic values.`
|
|
3634
|
-
);
|
|
3635
|
-
}
|
|
4267
|
+
jsxAttributeVisitor(path2, state, t);
|
|
3636
4268
|
}
|
|
3637
4269
|
}
|
|
3638
4270
|
};
|