@mgcrea/react-native-tailwind 0.9.0 → 0.10.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 +356 -30
- package/dist/babel/config-loader.test.ts +152 -0
- package/dist/babel/index.cjs +575 -60
- package/dist/babel/plugin.d.ts +23 -1
- package/dist/babel/plugin.test.ts +417 -0
- package/dist/babel/plugin.ts +265 -32
- package/dist/babel/utils/colorSchemeModifierProcessing.d.ts +34 -0
- package/dist/babel/utils/colorSchemeModifierProcessing.ts +89 -0
- package/dist/babel/utils/dynamicProcessing.d.ts +33 -2
- package/dist/babel/utils/dynamicProcessing.ts +352 -33
- package/dist/babel/utils/styleInjection.d.ts +14 -1
- package/dist/babel/utils/styleInjection.ts +125 -7
- package/dist/babel/utils/styleTransforms.test.ts +56 -0
- package/dist/babel/utils/twProcessing.d.ts +2 -0
- package/dist/babel/utils/twProcessing.ts +22 -1
- package/dist/parser/aspectRatio.js +1 -1
- package/dist/parser/aspectRatio.test.js +1 -1
- package/dist/parser/index.d.ts +2 -2
- package/dist/parser/index.js +1 -1
- package/dist/parser/modifiers.d.ts +48 -2
- package/dist/parser/modifiers.js +1 -1
- package/dist/parser/modifiers.test.js +1 -1
- package/dist/parser/spacing.d.ts +1 -1
- package/dist/parser/spacing.js +1 -1
- package/dist/parser/spacing.test.js +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +3 -3
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +3 -3
- package/dist/runtime.test.js +1 -1
- package/dist/types/config.d.ts +7 -0
- package/dist/types/config.js +0 -0
- package/package.json +4 -4
- package/src/babel/config-loader.test.ts +152 -0
- package/src/babel/plugin.test.ts +417 -0
- package/src/babel/plugin.ts +265 -32
- package/src/babel/utils/colorSchemeModifierProcessing.ts +89 -0
- package/src/babel/utils/dynamicProcessing.ts +352 -33
- package/src/babel/utils/styleInjection.ts +125 -7
- package/src/babel/utils/styleTransforms.test.ts +56 -0
- package/src/babel/utils/twProcessing.ts +22 -1
- package/src/parser/aspectRatio.test.ts +25 -2
- package/src/parser/aspectRatio.ts +3 -3
- package/src/parser/index.ts +12 -1
- package/src/parser/modifiers.test.ts +151 -1
- package/src/parser/modifiers.ts +139 -4
- package/src/parser/spacing.test.ts +63 -0
- package/src/parser/spacing.ts +10 -6
- package/src/runtime.test.ts +27 -0
- package/src/runtime.ts +2 -1
- package/src/types/config.ts +7 -0
- package/dist/babel/index.test.ts +0 -481
- package/dist/config/palettes.d.ts +0 -302
- package/dist/config/palettes.js +0 -1
- package/dist/parser/__snapshots__/aspectRatio.test.js.snap +0 -9
- package/dist/parser/__snapshots__/borders.test.js.snap +0 -23
- package/dist/parser/__snapshots__/colors.test.js.snap +0 -251
- package/dist/parser/__snapshots__/shadows.test.js.snap +0 -76
- package/dist/parser/__snapshots__/sizing.test.js.snap +0 -61
- package/dist/parser/__snapshots__/spacing.test.js.snap +0 -40
- package/dist/parser/__snapshots__/transforms.test.js.snap +0 -58
- package/dist/parser/__snapshots__/typography.test.js.snap +0 -30
- package/dist/parser/aspectRatio.test.d.ts +0 -1
- package/dist/parser/borders.test.d.ts +0 -1
- package/dist/parser/colors.test.d.ts +0 -1
- package/dist/parser/layout.test.d.ts +0 -1
- package/dist/parser/modifiers.test.d.ts +0 -1
- package/dist/parser/shadows.test.d.ts +0 -1
- package/dist/parser/sizing.test.d.ts +0 -1
- package/dist/parser/spacing.test.d.ts +0 -1
- package/dist/parser/typography.test.d.ts +0 -1
- package/dist/types.d.ts +0 -42
- package/dist/types.js +0 -1
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* Utility functions for processing dynamic className expressions
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import type { NodePath } from "@babel/core";
|
|
5
6
|
import type * as BabelTypes from "@babel/types";
|
|
7
|
+
import type { ParsedModifier } from "../../parser/index.js";
|
|
8
|
+
import type { SchemeModifierConfig } from "../../types/config.js";
|
|
6
9
|
import type { StyleObject } from "../../types/core.js";
|
|
7
10
|
|
|
8
11
|
/**
|
|
@@ -12,9 +15,59 @@ import type { StyleObject } from "../../types/core.js";
|
|
|
12
15
|
export interface DynamicProcessingState {
|
|
13
16
|
styleRegistry: Map<string, StyleObject>;
|
|
14
17
|
customColors: Record<string, string>;
|
|
18
|
+
schemeModifierConfig: SchemeModifierConfig;
|
|
15
19
|
stylesIdentifier: string;
|
|
20
|
+
needsPlatformImport: boolean;
|
|
21
|
+
needsColorSchemeImport: boolean;
|
|
22
|
+
colorSchemeVariableName: string;
|
|
23
|
+
functionComponentsNeedingColorScheme: Set<NodePath<BabelTypes.Function>>;
|
|
16
24
|
}
|
|
17
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Type for the splitModifierClasses function
|
|
28
|
+
*/
|
|
29
|
+
export type SplitModifierClassesFn = (className: string) => {
|
|
30
|
+
baseClasses: string[];
|
|
31
|
+
modifierClasses: ParsedModifier[];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Type for the processPlatformModifiers function
|
|
36
|
+
*/
|
|
37
|
+
export type ProcessPlatformModifiersFn = (
|
|
38
|
+
modifiers: ParsedModifier[],
|
|
39
|
+
state: DynamicProcessingState,
|
|
40
|
+
parseClassName: (className: string, customColors: Record<string, string>) => StyleObject,
|
|
41
|
+
generateStyleKey: (className: string) => string,
|
|
42
|
+
t: typeof BabelTypes,
|
|
43
|
+
) => BabelTypes.Expression;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Type for the processColorSchemeModifiers function
|
|
47
|
+
*/
|
|
48
|
+
export type ProcessColorSchemeModifiersFn = (
|
|
49
|
+
modifiers: ParsedModifier[],
|
|
50
|
+
state: DynamicProcessingState,
|
|
51
|
+
parseClassName: (className: string, customColors: Record<string, string>) => StyleObject,
|
|
52
|
+
generateStyleKey: (className: string) => string,
|
|
53
|
+
t: typeof BabelTypes,
|
|
54
|
+
) => BabelTypes.Expression[];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Type for modifier type guard functions
|
|
58
|
+
*/
|
|
59
|
+
export type ModifierTypeGuardFn = (modifier: unknown) => boolean;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Type for the expandSchemeModifier function
|
|
63
|
+
*/
|
|
64
|
+
export type ExpandSchemeModifierFn = (
|
|
65
|
+
modifier: ParsedModifier,
|
|
66
|
+
customColors: Record<string, string>,
|
|
67
|
+
darkSuffix: string,
|
|
68
|
+
lightSuffix: string,
|
|
69
|
+
) => ParsedModifier[];
|
|
70
|
+
|
|
18
71
|
/**
|
|
19
72
|
* Result of processing a dynamic expression
|
|
20
73
|
*/
|
|
@@ -34,21 +87,71 @@ export function processDynamicExpression(
|
|
|
34
87
|
state: DynamicProcessingState,
|
|
35
88
|
parseClassName: (className: string, customColors: Record<string, string>) => StyleObject,
|
|
36
89
|
generateStyleKey: (className: string) => string,
|
|
90
|
+
splitModifierClasses: SplitModifierClassesFn,
|
|
91
|
+
processPlatformModifiers: ProcessPlatformModifiersFn,
|
|
92
|
+
processColorSchemeModifiers: ProcessColorSchemeModifiersFn,
|
|
93
|
+
componentScope: NodePath<BabelTypes.Function> | null,
|
|
94
|
+
isPlatformModifier: ModifierTypeGuardFn,
|
|
95
|
+
isColorSchemeModifier: ModifierTypeGuardFn,
|
|
96
|
+
isSchemeModifier: ModifierTypeGuardFn,
|
|
97
|
+
expandSchemeModifier: ExpandSchemeModifierFn,
|
|
37
98
|
t: typeof BabelTypes,
|
|
38
99
|
) {
|
|
39
100
|
// Handle template literals: `m-4 ${condition ? "p-4" : "p-2"}`
|
|
40
101
|
if (t.isTemplateLiteral(expression)) {
|
|
41
|
-
return processTemplateLiteral(
|
|
102
|
+
return processTemplateLiteral(
|
|
103
|
+
expression,
|
|
104
|
+
state,
|
|
105
|
+
parseClassName,
|
|
106
|
+
generateStyleKey,
|
|
107
|
+
splitModifierClasses,
|
|
108
|
+
processPlatformModifiers,
|
|
109
|
+
processColorSchemeModifiers,
|
|
110
|
+
componentScope,
|
|
111
|
+
isPlatformModifier,
|
|
112
|
+
isColorSchemeModifier,
|
|
113
|
+
isSchemeModifier,
|
|
114
|
+
expandSchemeModifier,
|
|
115
|
+
t,
|
|
116
|
+
);
|
|
42
117
|
}
|
|
43
118
|
|
|
44
119
|
// Handle conditional expressions: condition ? "m-4" : "p-2"
|
|
45
120
|
if (t.isConditionalExpression(expression)) {
|
|
46
|
-
return processConditionalExpression(
|
|
121
|
+
return processConditionalExpression(
|
|
122
|
+
expression,
|
|
123
|
+
state,
|
|
124
|
+
parseClassName,
|
|
125
|
+
generateStyleKey,
|
|
126
|
+
splitModifierClasses,
|
|
127
|
+
processPlatformModifiers,
|
|
128
|
+
processColorSchemeModifiers,
|
|
129
|
+
componentScope,
|
|
130
|
+
isPlatformModifier,
|
|
131
|
+
isColorSchemeModifier,
|
|
132
|
+
isSchemeModifier,
|
|
133
|
+
expandSchemeModifier,
|
|
134
|
+
t,
|
|
135
|
+
);
|
|
47
136
|
}
|
|
48
137
|
|
|
49
138
|
// Handle logical expressions: condition && "m-4"
|
|
50
139
|
if (t.isLogicalExpression(expression)) {
|
|
51
|
-
return processLogicalExpression(
|
|
140
|
+
return processLogicalExpression(
|
|
141
|
+
expression,
|
|
142
|
+
state,
|
|
143
|
+
parseClassName,
|
|
144
|
+
generateStyleKey,
|
|
145
|
+
splitModifierClasses,
|
|
146
|
+
processPlatformModifiers,
|
|
147
|
+
processColorSchemeModifiers,
|
|
148
|
+
componentScope,
|
|
149
|
+
isPlatformModifier,
|
|
150
|
+
isColorSchemeModifier,
|
|
151
|
+
isSchemeModifier,
|
|
152
|
+
expandSchemeModifier,
|
|
153
|
+
t,
|
|
154
|
+
);
|
|
52
155
|
}
|
|
53
156
|
|
|
54
157
|
// Unsupported expression type
|
|
@@ -63,9 +166,17 @@ function processTemplateLiteral(
|
|
|
63
166
|
state: DynamicProcessingState,
|
|
64
167
|
parseClassName: (className: string, customColors: Record<string, string>) => StyleObject,
|
|
65
168
|
generateStyleKey: (className: string) => string,
|
|
169
|
+
splitModifierClasses: SplitModifierClassesFn,
|
|
170
|
+
processPlatformModifiers: ProcessPlatformModifiersFn,
|
|
171
|
+
processColorSchemeModifiers: ProcessColorSchemeModifiersFn,
|
|
172
|
+
componentScope: NodePath<BabelTypes.Function> | null,
|
|
173
|
+
isPlatformModifier: ModifierTypeGuardFn,
|
|
174
|
+
isColorSchemeModifier: ModifierTypeGuardFn,
|
|
175
|
+
isSchemeModifier: ModifierTypeGuardFn,
|
|
176
|
+
expandSchemeModifier: ExpandSchemeModifierFn,
|
|
66
177
|
t: typeof BabelTypes,
|
|
67
178
|
) {
|
|
68
|
-
const parts: BabelTypes.
|
|
179
|
+
const parts: BabelTypes.Expression[] = [];
|
|
69
180
|
const staticParts: string[] = [];
|
|
70
181
|
|
|
71
182
|
// Process quasis (static parts) and expressions (dynamic parts)
|
|
@@ -75,16 +186,31 @@ function processTemplateLiteral(
|
|
|
75
186
|
|
|
76
187
|
// Add static part if not empty
|
|
77
188
|
if (staticText) {
|
|
78
|
-
// Parse static classes
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
189
|
+
// Parse static classes with modifier support
|
|
190
|
+
const processedExpression = processStringOrExpressionHelper(
|
|
191
|
+
t.stringLiteral(staticText),
|
|
192
|
+
state,
|
|
193
|
+
parseClassName,
|
|
194
|
+
generateStyleKey,
|
|
195
|
+
splitModifierClasses,
|
|
196
|
+
processPlatformModifiers,
|
|
197
|
+
processColorSchemeModifiers,
|
|
198
|
+
componentScope,
|
|
199
|
+
isPlatformModifier,
|
|
200
|
+
isColorSchemeModifier,
|
|
201
|
+
isSchemeModifier,
|
|
202
|
+
expandSchemeModifier,
|
|
203
|
+
t,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
if (processedExpression) {
|
|
207
|
+
staticParts.push(staticText);
|
|
208
|
+
// Handle array or single expression
|
|
209
|
+
if (t.isArrayExpression(processedExpression)) {
|
|
210
|
+
parts.push(...(processedExpression.elements as BabelTypes.Expression[]));
|
|
211
|
+
} else {
|
|
212
|
+
parts.push(processedExpression);
|
|
213
|
+
}
|
|
88
214
|
}
|
|
89
215
|
}
|
|
90
216
|
|
|
@@ -98,14 +224,21 @@ function processTemplateLiteral(
|
|
|
98
224
|
state,
|
|
99
225
|
parseClassName,
|
|
100
226
|
generateStyleKey,
|
|
227
|
+
splitModifierClasses,
|
|
228
|
+
processPlatformModifiers,
|
|
229
|
+
processColorSchemeModifiers,
|
|
230
|
+
componentScope,
|
|
231
|
+
isPlatformModifier,
|
|
232
|
+
isColorSchemeModifier,
|
|
233
|
+
isSchemeModifier,
|
|
234
|
+
expandSchemeModifier,
|
|
101
235
|
t,
|
|
102
236
|
);
|
|
103
237
|
if (result) {
|
|
104
|
-
parts.push(result.expression
|
|
238
|
+
parts.push(result.expression);
|
|
105
239
|
} else {
|
|
106
240
|
// For unsupported expressions, keep them as-is
|
|
107
|
-
|
|
108
|
-
parts.push(expr as BabelTypes.MemberExpression);
|
|
241
|
+
parts.push(expr as BabelTypes.Expression);
|
|
109
242
|
}
|
|
110
243
|
}
|
|
111
244
|
}
|
|
@@ -131,10 +264,46 @@ function processConditionalExpression(
|
|
|
131
264
|
state: DynamicProcessingState,
|
|
132
265
|
parseClassName: (className: string, customColors: Record<string, string>) => StyleObject,
|
|
133
266
|
generateStyleKey: (className: string) => string,
|
|
267
|
+
splitModifierClasses: SplitModifierClassesFn,
|
|
268
|
+
processPlatformModifiers: ProcessPlatformModifiersFn,
|
|
269
|
+
processColorSchemeModifiers: ProcessColorSchemeModifiersFn,
|
|
270
|
+
componentScope: NodePath<BabelTypes.Function> | null,
|
|
271
|
+
isPlatformModifier: ModifierTypeGuardFn,
|
|
272
|
+
isColorSchemeModifier: ModifierTypeGuardFn,
|
|
273
|
+
isSchemeModifier: ModifierTypeGuardFn,
|
|
274
|
+
expandSchemeModifier: ExpandSchemeModifierFn,
|
|
134
275
|
t: typeof BabelTypes,
|
|
135
276
|
) {
|
|
136
|
-
const consequent =
|
|
137
|
-
|
|
277
|
+
const consequent = processStringOrExpressionHelper(
|
|
278
|
+
node.consequent,
|
|
279
|
+
state,
|
|
280
|
+
parseClassName,
|
|
281
|
+
generateStyleKey,
|
|
282
|
+
splitModifierClasses,
|
|
283
|
+
processPlatformModifiers,
|
|
284
|
+
processColorSchemeModifiers,
|
|
285
|
+
componentScope,
|
|
286
|
+
isPlatformModifier,
|
|
287
|
+
isColorSchemeModifier,
|
|
288
|
+
isSchemeModifier,
|
|
289
|
+
expandSchemeModifier,
|
|
290
|
+
t,
|
|
291
|
+
);
|
|
292
|
+
const alternate = processStringOrExpressionHelper(
|
|
293
|
+
node.alternate,
|
|
294
|
+
state,
|
|
295
|
+
parseClassName,
|
|
296
|
+
generateStyleKey,
|
|
297
|
+
splitModifierClasses,
|
|
298
|
+
processPlatformModifiers,
|
|
299
|
+
processColorSchemeModifiers,
|
|
300
|
+
componentScope,
|
|
301
|
+
isPlatformModifier,
|
|
302
|
+
isColorSchemeModifier,
|
|
303
|
+
isSchemeModifier,
|
|
304
|
+
expandSchemeModifier,
|
|
305
|
+
t,
|
|
306
|
+
);
|
|
138
307
|
|
|
139
308
|
if (!consequent && !alternate) {
|
|
140
309
|
return null;
|
|
@@ -143,8 +312,8 @@ function processConditionalExpression(
|
|
|
143
312
|
// Build conditional: condition ? consequentStyle : alternateStyle
|
|
144
313
|
const expression = t.conditionalExpression(
|
|
145
314
|
node.test,
|
|
146
|
-
|
|
147
|
-
|
|
315
|
+
consequent ?? t.nullLiteral(),
|
|
316
|
+
alternate ?? t.nullLiteral(),
|
|
148
317
|
);
|
|
149
318
|
|
|
150
319
|
return { expression };
|
|
@@ -158,6 +327,14 @@ function processLogicalExpression(
|
|
|
158
327
|
state: DynamicProcessingState,
|
|
159
328
|
parseClassName: (className: string, customColors: Record<string, string>) => StyleObject,
|
|
160
329
|
generateStyleKey: (className: string) => string,
|
|
330
|
+
splitModifierClasses: SplitModifierClassesFn,
|
|
331
|
+
processPlatformModifiers: ProcessPlatformModifiersFn,
|
|
332
|
+
processColorSchemeModifiers: ProcessColorSchemeModifiersFn,
|
|
333
|
+
componentScope: NodePath<BabelTypes.Function> | null,
|
|
334
|
+
isPlatformModifier: ModifierTypeGuardFn,
|
|
335
|
+
isColorSchemeModifier: ModifierTypeGuardFn,
|
|
336
|
+
isSchemeModifier: ModifierTypeGuardFn,
|
|
337
|
+
expandSchemeModifier: ExpandSchemeModifierFn,
|
|
161
338
|
t: typeof BabelTypes,
|
|
162
339
|
) {
|
|
163
340
|
// Only handle AND (&&) expressions
|
|
@@ -165,28 +342,52 @@ function processLogicalExpression(
|
|
|
165
342
|
return null;
|
|
166
343
|
}
|
|
167
344
|
|
|
168
|
-
const right =
|
|
345
|
+
const right = processStringOrExpressionHelper(
|
|
346
|
+
node.right,
|
|
347
|
+
state,
|
|
348
|
+
parseClassName,
|
|
349
|
+
generateStyleKey,
|
|
350
|
+
splitModifierClasses,
|
|
351
|
+
processPlatformModifiers,
|
|
352
|
+
processColorSchemeModifiers,
|
|
353
|
+
componentScope,
|
|
354
|
+
isPlatformModifier,
|
|
355
|
+
isColorSchemeModifier,
|
|
356
|
+
isSchemeModifier,
|
|
357
|
+
expandSchemeModifier,
|
|
358
|
+
t,
|
|
359
|
+
);
|
|
169
360
|
|
|
170
361
|
if (!right) {
|
|
171
362
|
return null;
|
|
172
363
|
}
|
|
173
364
|
|
|
174
365
|
// Build logical: condition && style
|
|
175
|
-
const expression = t.logicalExpression("&&", node.left, right
|
|
366
|
+
const expression = t.logicalExpression("&&", node.left, right);
|
|
176
367
|
|
|
177
368
|
return { expression };
|
|
178
369
|
}
|
|
179
370
|
|
|
180
371
|
/**
|
|
181
372
|
* Process a node that might be a string literal or another expression
|
|
373
|
+
*
|
|
374
|
+
* This helper is called by processStringOrExpression below
|
|
182
375
|
*/
|
|
183
|
-
function
|
|
376
|
+
function processStringOrExpressionHelper(
|
|
184
377
|
node: BabelTypes.StringLiteral | BabelTypes.Expression,
|
|
185
378
|
state: DynamicProcessingState,
|
|
186
379
|
parseClassName: (className: string, customColors: Record<string, string>) => StyleObject,
|
|
187
380
|
generateStyleKey: (className: string) => string,
|
|
381
|
+
splitModifierClasses: SplitModifierClassesFn,
|
|
382
|
+
processPlatformModifiers: ProcessPlatformModifiersFn,
|
|
383
|
+
processColorSchemeModifiers: ProcessColorSchemeModifiersFn,
|
|
384
|
+
componentScope: NodePath<BabelTypes.Function> | null,
|
|
385
|
+
isPlatformModifier: ModifierTypeGuardFn,
|
|
386
|
+
isColorSchemeModifier: ModifierTypeGuardFn,
|
|
387
|
+
isSchemeModifier: ModifierTypeGuardFn,
|
|
388
|
+
expandSchemeModifier: ExpandSchemeModifierFn,
|
|
188
389
|
t: typeof BabelTypes,
|
|
189
|
-
) {
|
|
390
|
+
): BabelTypes.Expression | BabelTypes.ArrayExpression | null {
|
|
190
391
|
// Handle string literals
|
|
191
392
|
if (t.isStringLiteral(node)) {
|
|
192
393
|
const className = node.value.trim();
|
|
@@ -194,27 +395,145 @@ function processStringOrExpression(
|
|
|
194
395
|
return null;
|
|
195
396
|
}
|
|
196
397
|
|
|
197
|
-
//
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
398
|
+
// Split into base and modifier classes
|
|
399
|
+
const { baseClasses, modifierClasses: rawModifierClasses } = splitModifierClasses(className);
|
|
400
|
+
|
|
401
|
+
// Expand scheme: modifiers into dark: and light: modifiers
|
|
402
|
+
const modifierClasses: Array<import("../../parser/index.js").ParsedModifier> = [];
|
|
403
|
+
for (const modifier of rawModifierClasses) {
|
|
404
|
+
if (isSchemeModifier(modifier.modifier)) {
|
|
405
|
+
// Expand scheme: into dark: and light:
|
|
406
|
+
const expanded = expandSchemeModifier(
|
|
407
|
+
modifier,
|
|
408
|
+
state.customColors,
|
|
409
|
+
state.schemeModifierConfig.darkSuffix ?? "-dark",
|
|
410
|
+
state.schemeModifierConfig.lightSuffix ?? "-light",
|
|
411
|
+
);
|
|
412
|
+
modifierClasses.push(...expanded);
|
|
413
|
+
} else {
|
|
414
|
+
// Keep other modifiers as-is
|
|
415
|
+
modifierClasses.push(modifier);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Separate modifiers by type
|
|
420
|
+
const platformModifiers = modifierClasses.filter((m) => isPlatformModifier(m.modifier));
|
|
421
|
+
const colorSchemeModifiers = modifierClasses.filter((m) => isColorSchemeModifier(m.modifier));
|
|
422
|
+
|
|
423
|
+
const styleElements: BabelTypes.Expression[] = [];
|
|
201
424
|
|
|
202
|
-
|
|
425
|
+
// Process base classes
|
|
426
|
+
if (baseClasses.length > 0) {
|
|
427
|
+
const baseClassName = baseClasses.join(" ");
|
|
428
|
+
const styleObject = parseClassName(baseClassName, state.customColors);
|
|
429
|
+
const styleKey = generateStyleKey(baseClassName);
|
|
430
|
+
state.styleRegistry.set(styleKey, styleObject);
|
|
431
|
+
styleElements.push(t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey)));
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Process platform modifiers
|
|
435
|
+
if (platformModifiers.length > 0) {
|
|
436
|
+
state.needsPlatformImport = true;
|
|
437
|
+
const platformExpression = processPlatformModifiers(
|
|
438
|
+
platformModifiers,
|
|
439
|
+
state,
|
|
440
|
+
parseClassName,
|
|
441
|
+
generateStyleKey,
|
|
442
|
+
t,
|
|
443
|
+
);
|
|
444
|
+
styleElements.push(platformExpression);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Process color scheme modifiers (only if component scope exists)
|
|
448
|
+
if (colorSchemeModifiers.length > 0) {
|
|
449
|
+
if (componentScope) {
|
|
450
|
+
state.needsColorSchemeImport = true;
|
|
451
|
+
state.functionComponentsNeedingColorScheme.add(componentScope);
|
|
452
|
+
const colorSchemeExpressions = processColorSchemeModifiers(
|
|
453
|
+
colorSchemeModifiers,
|
|
454
|
+
state,
|
|
455
|
+
parseClassName,
|
|
456
|
+
generateStyleKey,
|
|
457
|
+
t,
|
|
458
|
+
);
|
|
459
|
+
styleElements.push(...colorSchemeExpressions);
|
|
460
|
+
} else {
|
|
461
|
+
// Warn in development: color scheme modifiers without valid component scope
|
|
462
|
+
// Skip transformation - these modifiers will be ignored
|
|
463
|
+
if (process.env.NODE_ENV !== "production") {
|
|
464
|
+
console.warn(
|
|
465
|
+
"[react-native-tailwind] dark:/light: modifiers in dynamic expressions require a function component scope. " +
|
|
466
|
+
"These modifiers will be ignored.",
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Return single element or array
|
|
473
|
+
if (styleElements.length === 0) {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
if (styleElements.length === 1) {
|
|
477
|
+
return styleElements[0];
|
|
478
|
+
}
|
|
479
|
+
return t.arrayExpression(styleElements);
|
|
203
480
|
}
|
|
204
481
|
|
|
205
482
|
// Handle nested expressions recursively
|
|
206
483
|
if (t.isConditionalExpression(node)) {
|
|
207
|
-
const result = processConditionalExpression(
|
|
484
|
+
const result = processConditionalExpression(
|
|
485
|
+
node,
|
|
486
|
+
state,
|
|
487
|
+
parseClassName,
|
|
488
|
+
generateStyleKey,
|
|
489
|
+
splitModifierClasses,
|
|
490
|
+
processPlatformModifiers,
|
|
491
|
+
processColorSchemeModifiers,
|
|
492
|
+
componentScope,
|
|
493
|
+
isPlatformModifier,
|
|
494
|
+
isColorSchemeModifier,
|
|
495
|
+
isSchemeModifier,
|
|
496
|
+
expandSchemeModifier,
|
|
497
|
+
t,
|
|
498
|
+
);
|
|
208
499
|
return result?.expression ?? null;
|
|
209
500
|
}
|
|
210
501
|
|
|
211
502
|
if (t.isLogicalExpression(node)) {
|
|
212
|
-
const result = processLogicalExpression(
|
|
503
|
+
const result = processLogicalExpression(
|
|
504
|
+
node,
|
|
505
|
+
state,
|
|
506
|
+
parseClassName,
|
|
507
|
+
generateStyleKey,
|
|
508
|
+
splitModifierClasses,
|
|
509
|
+
processPlatformModifiers,
|
|
510
|
+
processColorSchemeModifiers,
|
|
511
|
+
componentScope,
|
|
512
|
+
isPlatformModifier,
|
|
513
|
+
isColorSchemeModifier,
|
|
514
|
+
isSchemeModifier,
|
|
515
|
+
expandSchemeModifier,
|
|
516
|
+
t,
|
|
517
|
+
);
|
|
213
518
|
return result?.expression ?? null;
|
|
214
519
|
}
|
|
215
520
|
|
|
216
521
|
if (t.isTemplateLiteral(node)) {
|
|
217
|
-
const result = processTemplateLiteral(
|
|
522
|
+
const result = processTemplateLiteral(
|
|
523
|
+
node,
|
|
524
|
+
state,
|
|
525
|
+
parseClassName,
|
|
526
|
+
generateStyleKey,
|
|
527
|
+
splitModifierClasses,
|
|
528
|
+
processPlatformModifiers,
|
|
529
|
+
processColorSchemeModifiers,
|
|
530
|
+
componentScope,
|
|
531
|
+
isPlatformModifier,
|
|
532
|
+
isColorSchemeModifier,
|
|
533
|
+
isSchemeModifier,
|
|
534
|
+
expandSchemeModifier,
|
|
535
|
+
t,
|
|
536
|
+
);
|
|
218
537
|
return result?.expression ?? null;
|
|
219
538
|
}
|
|
220
539
|
|
|
@@ -7,16 +7,33 @@ import type * as BabelTypes from "@babel/types";
|
|
|
7
7
|
import type { StyleObject } from "../../types/core.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Add StyleSheet import to the file
|
|
10
|
+
* Add StyleSheet import to the file or merge with existing react-native import
|
|
11
11
|
*/
|
|
12
12
|
export function addStyleSheetImport(path: NodePath<BabelTypes.Program>, t: typeof BabelTypes): void {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
// Check if there's already a react-native import
|
|
14
|
+
const body = path.node.body;
|
|
15
|
+
let reactNativeImport: BabelTypes.ImportDeclaration | null = null;
|
|
16
|
+
|
|
17
|
+
for (const statement of body) {
|
|
18
|
+
if (t.isImportDeclaration(statement) && statement.source.value === "react-native") {
|
|
19
|
+
reactNativeImport = statement;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
if (reactNativeImport) {
|
|
25
|
+
// Add StyleSheet to existing react-native import
|
|
26
|
+
reactNativeImport.specifiers.push(
|
|
27
|
+
t.importSpecifier(t.identifier("StyleSheet"), t.identifier("StyleSheet")),
|
|
28
|
+
);
|
|
29
|
+
} else {
|
|
30
|
+
// Create new react-native import with StyleSheet
|
|
31
|
+
const importDeclaration = t.importDeclaration(
|
|
32
|
+
[t.importSpecifier(t.identifier("StyleSheet"), t.identifier("StyleSheet"))],
|
|
33
|
+
t.stringLiteral("react-native"),
|
|
34
|
+
);
|
|
35
|
+
path.unshiftContainer("body", importDeclaration);
|
|
36
|
+
}
|
|
20
37
|
}
|
|
21
38
|
|
|
22
39
|
/**
|
|
@@ -47,6 +64,107 @@ export function addPlatformImport(path: NodePath<BabelTypes.Program>, t: typeof
|
|
|
47
64
|
}
|
|
48
65
|
}
|
|
49
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Add useColorScheme import to the file or merge with existing react-native import
|
|
69
|
+
*/
|
|
70
|
+
export function addColorSchemeImport(path: NodePath<BabelTypes.Program>, t: typeof BabelTypes): void {
|
|
71
|
+
// Check if there's already a react-native import
|
|
72
|
+
const body = path.node.body;
|
|
73
|
+
let reactNativeImport: BabelTypes.ImportDeclaration | null = null;
|
|
74
|
+
|
|
75
|
+
for (const statement of body) {
|
|
76
|
+
if (t.isImportDeclaration(statement) && statement.source.value === "react-native") {
|
|
77
|
+
reactNativeImport = statement;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (reactNativeImport) {
|
|
83
|
+
// Check if useColorScheme is already imported
|
|
84
|
+
const hasUseColorScheme = reactNativeImport.specifiers.some(
|
|
85
|
+
(spec) =>
|
|
86
|
+
t.isImportSpecifier(spec) &&
|
|
87
|
+
spec.imported.type === "Identifier" &&
|
|
88
|
+
spec.imported.name === "useColorScheme",
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (!hasUseColorScheme) {
|
|
92
|
+
// Add useColorScheme to existing react-native import
|
|
93
|
+
reactNativeImport.specifiers.push(
|
|
94
|
+
t.importSpecifier(t.identifier("useColorScheme"), t.identifier("useColorScheme")),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
// Create new react-native import with useColorScheme
|
|
99
|
+
const importDeclaration = t.importDeclaration(
|
|
100
|
+
[t.importSpecifier(t.identifier("useColorScheme"), t.identifier("useColorScheme"))],
|
|
101
|
+
t.stringLiteral("react-native"),
|
|
102
|
+
);
|
|
103
|
+
path.unshiftContainer("body", importDeclaration);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Inject useColorScheme hook call at the top of a function component
|
|
109
|
+
*
|
|
110
|
+
* @param functionPath - Path to the function component
|
|
111
|
+
* @param colorSchemeVariableName - Name for the color scheme variable
|
|
112
|
+
* @param t - Babel types
|
|
113
|
+
* @returns true if hook was injected, false if already exists
|
|
114
|
+
*/
|
|
115
|
+
export function injectColorSchemeHook(
|
|
116
|
+
functionPath: NodePath<BabelTypes.Function>,
|
|
117
|
+
colorSchemeVariableName: string,
|
|
118
|
+
t: typeof BabelTypes,
|
|
119
|
+
): boolean {
|
|
120
|
+
let body = functionPath.node.body;
|
|
121
|
+
|
|
122
|
+
// Handle concise arrow functions: () => <JSX />
|
|
123
|
+
// Convert to block statement: () => { const _twColorScheme = useColorScheme(); return <JSX />; }
|
|
124
|
+
if (!t.isBlockStatement(body)) {
|
|
125
|
+
if (t.isArrowFunctionExpression(functionPath.node) && t.isExpression(body)) {
|
|
126
|
+
// Convert concise body to block statement with return
|
|
127
|
+
const returnStatement = t.returnStatement(body);
|
|
128
|
+
const blockStatement = t.blockStatement([returnStatement]);
|
|
129
|
+
functionPath.node.body = blockStatement;
|
|
130
|
+
body = blockStatement;
|
|
131
|
+
} else {
|
|
132
|
+
// Other non-block functions (shouldn't happen for components, but be safe)
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Check if hook is already injected
|
|
138
|
+
const hasHook = body.body.some((statement) => {
|
|
139
|
+
if (
|
|
140
|
+
t.isVariableDeclaration(statement) &&
|
|
141
|
+
statement.declarations.length > 0 &&
|
|
142
|
+
t.isVariableDeclarator(statement.declarations[0])
|
|
143
|
+
) {
|
|
144
|
+
const declarator = statement.declarations[0];
|
|
145
|
+
return t.isIdentifier(declarator.id) && declarator.id.name === colorSchemeVariableName;
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
if (hasHook) {
|
|
151
|
+
return false; // Already injected
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Create: const _twColorScheme = useColorScheme();
|
|
155
|
+
const hookCall = t.variableDeclaration("const", [
|
|
156
|
+
t.variableDeclarator(
|
|
157
|
+
t.identifier(colorSchemeVariableName),
|
|
158
|
+
t.callExpression(t.identifier("useColorScheme"), []),
|
|
159
|
+
),
|
|
160
|
+
]);
|
|
161
|
+
|
|
162
|
+
// Insert at the beginning of function body
|
|
163
|
+
body.body.unshift(hookCall);
|
|
164
|
+
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
50
168
|
/**
|
|
51
169
|
* Inject StyleSheet.create with all collected styles at the top of the file
|
|
52
170
|
* This ensures the styles object is defined before any code that references it
|