@mgcrea/react-native-tailwind 0.11.0 → 0.12.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 +129 -0
- package/dist/babel/index.cjs +229 -46
- package/dist/babel/plugin.d.ts +37 -0
- package/dist/babel/plugin.test.ts +773 -1
- package/dist/babel/plugin.ts +127 -30
- package/dist/babel/utils/styleInjection.d.ts +5 -3
- package/dist/babel/utils/styleInjection.ts +38 -23
- package/dist/babel/utils/twProcessing.d.ts +8 -1
- package/dist/babel/utils/twProcessing.ts +212 -4
- 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 +2 -2
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +2 -2
- package/dist/runtime.test.js +1 -1
- package/dist/types/runtime.d.ts +8 -1
- package/package.json +1 -1
- package/src/babel/plugin.test.ts +773 -1
- package/src/babel/plugin.ts +127 -30
- package/src/babel/utils/styleInjection.ts +38 -23
- package/src/babel/utils/twProcessing.ts +212 -4
- package/src/parser/spacing.test.ts +62 -0
- package/src/parser/spacing.ts +7 -7
- package/src/runtime.test.ts +4 -1
- package/src/types/runtime.ts +8 -1
package/dist/babel/plugin.ts
CHANGED
|
@@ -89,6 +89,42 @@ export type PluginOptions = {
|
|
|
89
89
|
darkSuffix?: string;
|
|
90
90
|
lightSuffix?: string;
|
|
91
91
|
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Configuration for color scheme hook import (dark:/light: modifiers)
|
|
95
|
+
*
|
|
96
|
+
* Allows using custom color scheme hooks from theme providers instead of
|
|
97
|
+
* React Native's built-in useColorScheme.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* // Use custom hook from theme provider
|
|
101
|
+
* {
|
|
102
|
+
* importFrom: '@/hooks/useColorScheme',
|
|
103
|
+
* importName: 'useColorScheme'
|
|
104
|
+
* }
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* // Use React Navigation theme
|
|
108
|
+
* {
|
|
109
|
+
* importFrom: '@react-navigation/native',
|
|
110
|
+
* importName: 'useTheme' // You'd wrap this to return ColorSchemeName
|
|
111
|
+
* }
|
|
112
|
+
*
|
|
113
|
+
* @default { importFrom: 'react-native', importName: 'useColorScheme' }
|
|
114
|
+
*/
|
|
115
|
+
colorScheme?: {
|
|
116
|
+
/**
|
|
117
|
+
* Module to import the color scheme hook from
|
|
118
|
+
* @default 'react-native'
|
|
119
|
+
*/
|
|
120
|
+
importFrom?: string;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Name of the hook to import
|
|
124
|
+
* @default 'useColorScheme'
|
|
125
|
+
*/
|
|
126
|
+
importName?: string;
|
|
127
|
+
};
|
|
92
128
|
};
|
|
93
129
|
|
|
94
130
|
type PluginState = PluginPass & {
|
|
@@ -100,6 +136,9 @@ type PluginState = PluginPass & {
|
|
|
100
136
|
hasColorSchemeImport: boolean;
|
|
101
137
|
needsColorSchemeImport: boolean;
|
|
102
138
|
colorSchemeVariableName: string;
|
|
139
|
+
colorSchemeImportSource: string; // Where to import the hook from (e.g., 'react-native')
|
|
140
|
+
colorSchemeHookName: string; // Name of the hook to import (e.g., 'useColorScheme')
|
|
141
|
+
colorSchemeLocalIdentifier?: string; // Local identifier if hook is already imported with an alias
|
|
103
142
|
customTheme: CustomTheme;
|
|
104
143
|
schemeModifierConfig: SchemeModifierConfig;
|
|
105
144
|
supportedAttributes: Set<string>;
|
|
@@ -210,6 +249,10 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
210
249
|
lightSuffix: options?.schemeModifier?.lightSuffix ?? "-light",
|
|
211
250
|
};
|
|
212
251
|
|
|
252
|
+
// Color scheme hook configuration from plugin options
|
|
253
|
+
const colorSchemeImportSource = options?.colorScheme?.importFrom ?? "react-native";
|
|
254
|
+
const colorSchemeHookName = options?.colorScheme?.importName ?? "useColorScheme";
|
|
255
|
+
|
|
213
256
|
return {
|
|
214
257
|
name: "react-native-tailwind",
|
|
215
258
|
|
|
@@ -225,12 +268,18 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
225
268
|
state.hasColorSchemeImport = false;
|
|
226
269
|
state.needsColorSchemeImport = false;
|
|
227
270
|
state.colorSchemeVariableName = "_twColorScheme";
|
|
271
|
+
state.colorSchemeImportSource = colorSchemeImportSource;
|
|
272
|
+
state.colorSchemeHookName = colorSchemeHookName;
|
|
228
273
|
state.supportedAttributes = exactMatches;
|
|
229
274
|
state.attributePatterns = patterns;
|
|
230
275
|
state.stylesIdentifier = stylesIdentifier;
|
|
231
276
|
state.twImportNames = new Set();
|
|
232
277
|
state.hasTwImport = false;
|
|
233
278
|
state.functionComponentsNeedingColorScheme = new Set();
|
|
279
|
+
state.hasColorSchemeImport = false;
|
|
280
|
+
state.colorSchemeLocalIdentifier = undefined;
|
|
281
|
+
state.needsPlatformImport = false;
|
|
282
|
+
state.hasPlatformImport = false;
|
|
234
283
|
|
|
235
284
|
// Load custom theme from tailwind.config.*
|
|
236
285
|
state.customTheme = extractCustomTheme(state.file.opts.filename ?? "");
|
|
@@ -260,15 +309,21 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
260
309
|
addPlatformImport(path, t);
|
|
261
310
|
}
|
|
262
311
|
|
|
263
|
-
// Add
|
|
312
|
+
// Add color scheme hook import if color scheme modifiers were used and not already present
|
|
264
313
|
if (state.needsColorSchemeImport && !state.hasColorSchemeImport) {
|
|
265
|
-
addColorSchemeImport(path, t);
|
|
314
|
+
addColorSchemeImport(path, state.colorSchemeImportSource, state.colorSchemeHookName, t);
|
|
266
315
|
}
|
|
267
316
|
|
|
268
|
-
// Inject
|
|
317
|
+
// Inject color scheme hook in function components that need it
|
|
269
318
|
if (state.needsColorSchemeImport) {
|
|
270
319
|
for (const functionPath of state.functionComponentsNeedingColorScheme) {
|
|
271
|
-
injectColorSchemeHook(
|
|
320
|
+
injectColorSchemeHook(
|
|
321
|
+
functionPath,
|
|
322
|
+
state.colorSchemeVariableName,
|
|
323
|
+
state.colorSchemeHookName,
|
|
324
|
+
state.colorSchemeLocalIdentifier,
|
|
325
|
+
t,
|
|
326
|
+
);
|
|
272
327
|
}
|
|
273
328
|
}
|
|
274
329
|
|
|
@@ -300,13 +355,6 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
300
355
|
return false;
|
|
301
356
|
});
|
|
302
357
|
|
|
303
|
-
const hasUseColorScheme = specifiers.some((spec) => {
|
|
304
|
-
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
305
|
-
return spec.imported.name === "useColorScheme";
|
|
306
|
-
}
|
|
307
|
-
return false;
|
|
308
|
-
});
|
|
309
|
-
|
|
310
358
|
// Only track if imports exist - don't mutate yet
|
|
311
359
|
// Actual import injection happens in Program.exit only if needed
|
|
312
360
|
if (hasStyleSheet) {
|
|
@@ -317,14 +365,29 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
317
365
|
state.hasPlatformImport = true;
|
|
318
366
|
}
|
|
319
367
|
|
|
320
|
-
if (hasUseColorScheme) {
|
|
321
|
-
state.hasColorSchemeImport = true;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
368
|
// Store reference to the react-native import for later modification if needed
|
|
325
369
|
state.reactNativeImportPath = path;
|
|
326
370
|
}
|
|
327
371
|
|
|
372
|
+
// Track color scheme hook import from the configured source
|
|
373
|
+
// (default: react-native, but can be custom like @/hooks/useColorScheme)
|
|
374
|
+
// Only track value imports (not type-only imports which get erased)
|
|
375
|
+
if (node.source.value === state.colorSchemeImportSource && node.importKind !== "type") {
|
|
376
|
+
const specifiers = node.specifiers;
|
|
377
|
+
|
|
378
|
+
for (const spec of specifiers) {
|
|
379
|
+
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
380
|
+
if (spec.imported.name === state.colorSchemeHookName) {
|
|
381
|
+
state.hasColorSchemeImport = true;
|
|
382
|
+
// Track the local identifier (handles aliased imports)
|
|
383
|
+
// e.g., import { useTheme as navTheme } → local name is 'navTheme'
|
|
384
|
+
state.colorSchemeLocalIdentifier = spec.local.name;
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
328
391
|
// Track tw/twStyle imports from main package (for compile-time transformation)
|
|
329
392
|
if (node.source.value === "@mgcrea/react-native-tailwind") {
|
|
330
393
|
const specifiers = node.specifiers;
|
|
@@ -386,7 +449,16 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
386
449
|
state.hasClassNames = true;
|
|
387
450
|
|
|
388
451
|
// Process the className with modifiers
|
|
389
|
-
processTwCall(
|
|
452
|
+
processTwCall(
|
|
453
|
+
className,
|
|
454
|
+
path,
|
|
455
|
+
state,
|
|
456
|
+
parseClassName,
|
|
457
|
+
generateStyleKey,
|
|
458
|
+
splitModifierClasses,
|
|
459
|
+
findComponentScope,
|
|
460
|
+
t,
|
|
461
|
+
);
|
|
390
462
|
},
|
|
391
463
|
|
|
392
464
|
// Handle twStyle('...') call expressions
|
|
@@ -436,7 +508,16 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
436
508
|
state.hasClassNames = true;
|
|
437
509
|
|
|
438
510
|
// Process the className with modifiers
|
|
439
|
-
processTwCall(
|
|
511
|
+
processTwCall(
|
|
512
|
+
className,
|
|
513
|
+
path,
|
|
514
|
+
state,
|
|
515
|
+
parseClassName,
|
|
516
|
+
generateStyleKey,
|
|
517
|
+
splitModifierClasses,
|
|
518
|
+
findComponentScope,
|
|
519
|
+
t,
|
|
520
|
+
);
|
|
440
521
|
},
|
|
441
522
|
|
|
442
523
|
JSXAttribute(path, state) {
|
|
@@ -459,20 +540,22 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
459
540
|
// Determine target style prop based on attribute name
|
|
460
541
|
const targetStyleProp = getTargetStyleProp(attributeName);
|
|
461
542
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
543
|
+
/**
|
|
544
|
+
* Process static className string (handles both direct StringLiteral and StringLiteral in JSXExpressionContainer)
|
|
545
|
+
*/
|
|
546
|
+
const processStaticClassName = (className: string): boolean => {
|
|
547
|
+
const trimmedClassName = className.trim();
|
|
465
548
|
|
|
466
549
|
// Skip empty classNames
|
|
467
|
-
if (!
|
|
550
|
+
if (!trimmedClassName) {
|
|
468
551
|
path.remove();
|
|
469
|
-
return;
|
|
552
|
+
return true;
|
|
470
553
|
}
|
|
471
554
|
|
|
472
555
|
state.hasClassNames = true;
|
|
473
556
|
|
|
474
557
|
// Check if className contains modifiers (active:, hover:, focus:, placeholder:, ios:, android:, web:, dark:, light:, scheme:)
|
|
475
|
-
const { baseClasses, modifierClasses: rawModifierClasses } = splitModifierClasses(
|
|
558
|
+
const { baseClasses, modifierClasses: rawModifierClasses } = splitModifierClasses(trimmedClassName);
|
|
476
559
|
|
|
477
560
|
// Expand scheme: modifiers into dark: and light: modifiers
|
|
478
561
|
const modifierClasses: ParsedModifier[] = [];
|
|
@@ -639,7 +722,7 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
639
722
|
} else {
|
|
640
723
|
replaceWithStyleFunctionAttribute(path, styleFunctionExpression, targetStyleProp, t);
|
|
641
724
|
}
|
|
642
|
-
return;
|
|
725
|
+
return true;
|
|
643
726
|
} else {
|
|
644
727
|
// Component doesn't support state modifiers, but we can still use platform modifiers
|
|
645
728
|
// Fall through to platform-only handling
|
|
@@ -713,7 +796,7 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
713
796
|
path.node.name = t.jsxIdentifier(targetStyleProp);
|
|
714
797
|
path.node.value = t.jsxExpressionContainer(styleExpression);
|
|
715
798
|
}
|
|
716
|
-
return;
|
|
799
|
+
return true;
|
|
717
800
|
}
|
|
718
801
|
|
|
719
802
|
// If there are state modifiers (and no platform modifiers), check if this component supports them
|
|
@@ -771,12 +854,12 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
771
854
|
} else {
|
|
772
855
|
replaceWithStyleFunctionAttribute(path, styleFunctionExpression, targetStyleProp, t);
|
|
773
856
|
}
|
|
774
|
-
return;
|
|
857
|
+
return true;
|
|
775
858
|
}
|
|
776
859
|
} else {
|
|
777
860
|
// All modifiers are supported - process normally
|
|
778
861
|
const styleExpression = processStaticClassNameWithModifiers(
|
|
779
|
-
|
|
862
|
+
trimmedClassName,
|
|
780
863
|
state,
|
|
781
864
|
parseClassName,
|
|
782
865
|
generateStyleKey,
|
|
@@ -793,7 +876,7 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
793
876
|
} else {
|
|
794
877
|
replaceWithStyleFunctionAttribute(path, styleFunctionExpression, targetStyleProp, t);
|
|
795
878
|
}
|
|
796
|
-
return;
|
|
879
|
+
return true;
|
|
797
880
|
}
|
|
798
881
|
} else {
|
|
799
882
|
// Component doesn't support any modifiers
|
|
@@ -813,7 +896,7 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
813
896
|
if (!classNameForStyle) {
|
|
814
897
|
// No base classes, only had placeholder modifiers - just remove className
|
|
815
898
|
path.remove();
|
|
816
|
-
return;
|
|
899
|
+
return true;
|
|
817
900
|
}
|
|
818
901
|
|
|
819
902
|
const styleObject = parseClassName(classNameForStyle, state.customTheme);
|
|
@@ -830,7 +913,14 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
830
913
|
// Replace className with style prop
|
|
831
914
|
replaceWithStyleAttribute(path, styleKey, targetStyleProp, state.stylesIdentifier, t);
|
|
832
915
|
}
|
|
833
|
-
return;
|
|
916
|
+
return true;
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
// Handle static string literals
|
|
920
|
+
if (t.isStringLiteral(value)) {
|
|
921
|
+
if (processStaticClassName(value.value)) {
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
834
924
|
}
|
|
835
925
|
|
|
836
926
|
// Handle dynamic expressions (JSXExpressionContainer)
|
|
@@ -842,6 +932,13 @@ export default function reactNativeTailwindBabelPlugin(
|
|
|
842
932
|
return;
|
|
843
933
|
}
|
|
844
934
|
|
|
935
|
+
// Fast path: Support string literals wrapped in JSXExpressionContainer: className={"flex-row"}
|
|
936
|
+
if (t.isStringLiteral(expression)) {
|
|
937
|
+
if (processStaticClassName(expression.value)) {
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
845
942
|
try {
|
|
846
943
|
// Find component scope for color scheme modifiers
|
|
847
944
|
const componentScope = findComponentScope(path, t);
|
|
@@ -15,16 +15,18 @@ export declare function addPlatformImport(path: NodePath<BabelTypes.Program>, t:
|
|
|
15
15
|
/**
|
|
16
16
|
* Add useColorScheme import to the file or merge with existing react-native import
|
|
17
17
|
*/
|
|
18
|
-
export declare function addColorSchemeImport(path: NodePath<BabelTypes.Program>, t: typeof BabelTypes): void;
|
|
18
|
+
export declare function addColorSchemeImport(path: NodePath<BabelTypes.Program>, importSource: string, hookName: string, t: typeof BabelTypes): void;
|
|
19
19
|
/**
|
|
20
|
-
* Inject
|
|
20
|
+
* Inject color scheme hook call at the top of a function component
|
|
21
21
|
*
|
|
22
22
|
* @param functionPath - Path to the function component
|
|
23
23
|
* @param colorSchemeVariableName - Name for the color scheme variable
|
|
24
|
+
* @param hookName - Name of the hook to call (e.g., 'useColorScheme')
|
|
25
|
+
* @param localIdentifier - Local identifier if hook is already imported with an alias
|
|
24
26
|
* @param t - Babel types
|
|
25
27
|
* @returns true if hook was injected, false if already exists
|
|
26
28
|
*/
|
|
27
|
-
export declare function injectColorSchemeHook(functionPath: NodePath<BabelTypes.Function>, colorSchemeVariableName: string, t: typeof BabelTypes): boolean;
|
|
29
|
+
export declare function injectColorSchemeHook(functionPath: NodePath<BabelTypes.Function>, colorSchemeVariableName: string, hookName: string, localIdentifier: string | undefined, t: typeof BabelTypes): boolean;
|
|
28
30
|
/**
|
|
29
31
|
* Inject StyleSheet.create with all collected styles at the top of the file
|
|
30
32
|
* This ensures the styles object is defined before any code that references it
|
|
@@ -67,54 +67,64 @@ export function addPlatformImport(path: NodePath<BabelTypes.Program>, t: typeof
|
|
|
67
67
|
/**
|
|
68
68
|
* Add useColorScheme import to the file or merge with existing react-native import
|
|
69
69
|
*/
|
|
70
|
-
export function addColorSchemeImport(
|
|
71
|
-
|
|
70
|
+
export function addColorSchemeImport(
|
|
71
|
+
path: NodePath<BabelTypes.Program>,
|
|
72
|
+
importSource: string,
|
|
73
|
+
hookName: string,
|
|
74
|
+
t: typeof BabelTypes,
|
|
75
|
+
): void {
|
|
76
|
+
// Check if there's already an import from the specified source
|
|
72
77
|
const body = path.node.body;
|
|
73
|
-
let
|
|
78
|
+
let existingValueImport: BabelTypes.ImportDeclaration | null = null;
|
|
74
79
|
|
|
75
80
|
for (const statement of body) {
|
|
76
|
-
if (t.isImportDeclaration(statement) && statement.source.value ===
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
if (t.isImportDeclaration(statement) && statement.source.value === importSource) {
|
|
82
|
+
// Only consider value imports (not type-only imports which get erased)
|
|
83
|
+
if (statement.importKind !== "type") {
|
|
84
|
+
existingValueImport = statement;
|
|
85
|
+
break; // Found a value import, we can stop
|
|
86
|
+
}
|
|
79
87
|
}
|
|
80
88
|
}
|
|
81
89
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
// If we found a value import (not type-only), merge with it
|
|
91
|
+
if (existingValueImport) {
|
|
92
|
+
// Check if the hook is already imported
|
|
93
|
+
const hasHook = existingValueImport.specifiers.some(
|
|
85
94
|
(spec) =>
|
|
86
|
-
t.isImportSpecifier(spec) &&
|
|
87
|
-
spec.imported.type === "Identifier" &&
|
|
88
|
-
spec.imported.name === "useColorScheme",
|
|
95
|
+
t.isImportSpecifier(spec) && spec.imported.type === "Identifier" && spec.imported.name === hookName,
|
|
89
96
|
);
|
|
90
97
|
|
|
91
|
-
if (!
|
|
92
|
-
// Add
|
|
93
|
-
|
|
94
|
-
t.importSpecifier(t.identifier("useColorScheme"), t.identifier("useColorScheme")),
|
|
95
|
-
);
|
|
98
|
+
if (!hasHook) {
|
|
99
|
+
// Add hook to existing value import
|
|
100
|
+
existingValueImport.specifiers.push(t.importSpecifier(t.identifier(hookName), t.identifier(hookName)));
|
|
96
101
|
}
|
|
97
102
|
} else {
|
|
98
|
-
//
|
|
103
|
+
// No value import exists - create a new one
|
|
104
|
+
// (Don't merge with type-only imports as they get erased by Babel/TypeScript)
|
|
99
105
|
const importDeclaration = t.importDeclaration(
|
|
100
|
-
[t.importSpecifier(t.identifier(
|
|
101
|
-
t.stringLiteral(
|
|
106
|
+
[t.importSpecifier(t.identifier(hookName), t.identifier(hookName))],
|
|
107
|
+
t.stringLiteral(importSource),
|
|
102
108
|
);
|
|
103
109
|
path.unshiftContainer("body", importDeclaration);
|
|
104
110
|
}
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
/**
|
|
108
|
-
* Inject
|
|
114
|
+
* Inject color scheme hook call at the top of a function component
|
|
109
115
|
*
|
|
110
116
|
* @param functionPath - Path to the function component
|
|
111
117
|
* @param colorSchemeVariableName - Name for the color scheme variable
|
|
118
|
+
* @param hookName - Name of the hook to call (e.g., 'useColorScheme')
|
|
119
|
+
* @param localIdentifier - Local identifier if hook is already imported with an alias
|
|
112
120
|
* @param t - Babel types
|
|
113
121
|
* @returns true if hook was injected, false if already exists
|
|
114
122
|
*/
|
|
115
123
|
export function injectColorSchemeHook(
|
|
116
124
|
functionPath: NodePath<BabelTypes.Function>,
|
|
117
125
|
colorSchemeVariableName: string,
|
|
126
|
+
hookName: string,
|
|
127
|
+
localIdentifier: string | undefined,
|
|
118
128
|
t: typeof BabelTypes,
|
|
119
129
|
): boolean {
|
|
120
130
|
let body = functionPath.node.body;
|
|
@@ -151,11 +161,16 @@ export function injectColorSchemeHook(
|
|
|
151
161
|
return false; // Already injected
|
|
152
162
|
}
|
|
153
163
|
|
|
154
|
-
//
|
|
164
|
+
// Use the local identifier if hook was already imported with an alias,
|
|
165
|
+
// otherwise use the configured hook name
|
|
166
|
+
// e.g., import { useTheme as navTheme } → call navTheme()
|
|
167
|
+
const identifierToCall = localIdentifier ?? hookName;
|
|
168
|
+
|
|
169
|
+
// Create: const _twColorScheme = useColorScheme(); (or aliased name if already imported)
|
|
155
170
|
const hookCall = t.variableDeclaration("const", [
|
|
156
171
|
t.variableDeclarator(
|
|
157
172
|
t.identifier(colorSchemeVariableName),
|
|
158
|
-
t.callExpression(t.identifier(
|
|
173
|
+
t.callExpression(t.identifier(identifierToCall), []),
|
|
159
174
|
),
|
|
160
175
|
]);
|
|
161
176
|
|
|
@@ -14,15 +14,22 @@ export interface TwProcessingState {
|
|
|
14
14
|
customTheme: CustomTheme;
|
|
15
15
|
schemeModifierConfig: SchemeModifierConfig;
|
|
16
16
|
stylesIdentifier: string;
|
|
17
|
+
needsColorSchemeImport: boolean;
|
|
18
|
+
colorSchemeVariableName: string;
|
|
19
|
+
functionComponentsNeedingColorScheme: Set<NodePath<BabelTypes.Function>>;
|
|
20
|
+
colorSchemeLocalIdentifier?: string;
|
|
21
|
+
needsPlatformImport: boolean;
|
|
17
22
|
}
|
|
18
23
|
/**
|
|
19
24
|
* Process tw`...` or twStyle('...') call and replace with TwStyle object
|
|
20
25
|
* Generates: { style: styles._base, activeStyle: styles._active, ... }
|
|
26
|
+
* When color-scheme modifiers are present, generates: { style: [base, _twColorScheme === 'dark' && dark, ...] }
|
|
27
|
+
* When platform modifiers are present, generates: { style: [base, Platform.select({ ios: ..., android: ... })] }
|
|
21
28
|
*/
|
|
22
29
|
export declare function processTwCall(className: string, path: NodePath, state: TwProcessingState, parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject, generateStyleKey: (className: string) => string, splitModifierClasses: (className: string) => {
|
|
23
30
|
baseClasses: string[];
|
|
24
31
|
modifierClasses: ParsedModifier[];
|
|
25
|
-
}, t: typeof BabelTypes): void;
|
|
32
|
+
}, findComponentScope: (path: NodePath, t: typeof BabelTypes) => NodePath<BabelTypes.Function> | null, t: typeof BabelTypes): void;
|
|
26
33
|
/**
|
|
27
34
|
* Remove tw/twStyle imports from @mgcrea/react-native-tailwind
|
|
28
35
|
* This is called after all tw calls have been transformed
|