@mgcrea/react-native-tailwind 0.10.0 → 0.11.1

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.
Files changed (45) hide show
  1. package/README.md +159 -13
  2. package/dist/babel/config-loader.d.ts +12 -3
  3. package/dist/babel/config-loader.test.ts +14 -12
  4. package/dist/babel/config-loader.ts +41 -9
  5. package/dist/babel/index.cjs +91 -54
  6. package/dist/babel/plugin.d.ts +39 -1
  7. package/dist/babel/plugin.test.ts +275 -1
  8. package/dist/babel/plugin.ts +84 -25
  9. package/dist/babel/utils/colorSchemeModifierProcessing.d.ts +3 -3
  10. package/dist/babel/utils/colorSchemeModifierProcessing.ts +4 -4
  11. package/dist/babel/utils/dynamicProcessing.d.ts +5 -5
  12. package/dist/babel/utils/dynamicProcessing.ts +11 -11
  13. package/dist/babel/utils/modifierProcessing.d.ts +3 -3
  14. package/dist/babel/utils/modifierProcessing.ts +5 -5
  15. package/dist/babel/utils/platformModifierProcessing.d.ts +3 -3
  16. package/dist/babel/utils/platformModifierProcessing.ts +4 -4
  17. package/dist/babel/utils/styleInjection.d.ts +5 -3
  18. package/dist/babel/utils/styleInjection.ts +38 -23
  19. package/dist/babel/utils/twProcessing.d.ts +3 -3
  20. package/dist/babel/utils/twProcessing.ts +6 -6
  21. package/dist/parser/index.d.ts +11 -4
  22. package/dist/parser/index.js +1 -1
  23. package/dist/parser/typography.d.ts +3 -1
  24. package/dist/parser/typography.js +1 -1
  25. package/dist/runtime.cjs +1 -1
  26. package/dist/runtime.cjs.map +3 -3
  27. package/dist/runtime.d.ts +8 -1
  28. package/dist/runtime.js +1 -1
  29. package/dist/runtime.js.map +3 -3
  30. package/dist/runtime.test.js +1 -1
  31. package/package.json +1 -1
  32. package/src/babel/config-loader.test.ts +14 -12
  33. package/src/babel/config-loader.ts +41 -9
  34. package/src/babel/plugin.test.ts +275 -1
  35. package/src/babel/plugin.ts +84 -25
  36. package/src/babel/utils/colorSchemeModifierProcessing.ts +4 -4
  37. package/src/babel/utils/dynamicProcessing.ts +11 -11
  38. package/src/babel/utils/modifierProcessing.ts +5 -5
  39. package/src/babel/utils/platformModifierProcessing.ts +4 -4
  40. package/src/babel/utils/styleInjection.ts +38 -23
  41. package/src/babel/utils/twProcessing.ts +6 -6
  42. package/src/parser/index.ts +16 -8
  43. package/src/parser/typography.ts +14 -2
  44. package/src/runtime.test.ts +7 -7
  45. package/src/runtime.ts +37 -14
@@ -7,7 +7,9 @@ import babelPlugin, { type PluginOptions } from "./plugin.js";
7
7
  * Helper to transform code with the Babel plugin
8
8
  */
9
9
  function transform(code: string, options?: PluginOptions, includeJsx = false) {
10
- const presets = includeJsx ? ["@babel/preset-react"] : [];
10
+ const presets = includeJsx
11
+ ? ["@babel/preset-react", ["@babel/preset-typescript", { isTSX: true, allExtensions: true }]]
12
+ : [];
11
13
 
12
14
  const result = transformSync(code, {
13
15
  presets,
@@ -1022,6 +1024,278 @@ describe("Babel plugin - color scheme modifier transformation", () => {
1022
1024
  });
1023
1025
  });
1024
1026
 
1027
+ describe("Babel plugin - custom color scheme hook import", () => {
1028
+ it("should use custom import source for color scheme hook", () => {
1029
+ const input = `
1030
+ import React from 'react';
1031
+ import { View } from 'react-native';
1032
+
1033
+ export function Component() {
1034
+ return <View className="dark:bg-gray-900" />;
1035
+ }
1036
+ `;
1037
+
1038
+ const output = transform(
1039
+ input,
1040
+ {
1041
+ colorScheme: {
1042
+ importFrom: "@/hooks/useColorScheme",
1043
+ importName: "useColorScheme",
1044
+ },
1045
+ },
1046
+ true,
1047
+ );
1048
+
1049
+ // Should import from custom source
1050
+ expect(output).toContain('from "@/hooks/useColorScheme"');
1051
+ expect(output).not.toContain('useColorScheme } from "react-native"');
1052
+
1053
+ // Should inject hook call
1054
+ expect(output).toContain("_twColorScheme = useColorScheme()");
1055
+
1056
+ // Should have conditional styling
1057
+ expect(output).toMatch(/_twColorScheme\s*===\s*['"]dark['"]/);
1058
+ });
1059
+
1060
+ it("should use custom hook name", () => {
1061
+ const input = `
1062
+ import React from 'react';
1063
+ import { View } from 'react-native';
1064
+
1065
+ export function Component() {
1066
+ return <View className="dark:bg-gray-900" />;
1067
+ }
1068
+ `;
1069
+
1070
+ const output = transform(
1071
+ input,
1072
+ {
1073
+ colorScheme: {
1074
+ importFrom: "@react-navigation/native",
1075
+ importName: "useTheme",
1076
+ },
1077
+ },
1078
+ true,
1079
+ );
1080
+
1081
+ // Should import useTheme from React Navigation
1082
+ expect(output).toContain('from "@react-navigation/native"');
1083
+ expect(output).toContain("useTheme");
1084
+
1085
+ // Should call useTheme hook
1086
+ expect(output).toContain("_twColorScheme = useTheme()");
1087
+
1088
+ // Should have conditional styling
1089
+ expect(output).toMatch(/_twColorScheme\s*===\s*['"]dark['"]/);
1090
+ });
1091
+
1092
+ it("should merge custom hook with existing import from same source", () => {
1093
+ const input = `
1094
+ import React from 'react';
1095
+ import { View, Text } from 'react-native';
1096
+ import { useNavigation } from '@react-navigation/native';
1097
+
1098
+ export function Component() {
1099
+ const navigation = useNavigation();
1100
+ return (
1101
+ <View className="dark:bg-gray-900">
1102
+ <Text onPress={() => navigation.navigate('Home')}>Go Home</Text>
1103
+ </View>
1104
+ );
1105
+ }
1106
+ `;
1107
+
1108
+ const output = transform(
1109
+ input,
1110
+ {
1111
+ colorScheme: {
1112
+ importFrom: "@react-navigation/native",
1113
+ importName: "useTheme",
1114
+ },
1115
+ },
1116
+ true,
1117
+ );
1118
+
1119
+ // Should merge with existing import (both useNavigation and useTheme in same import)
1120
+ expect(output).toMatch(
1121
+ /import\s+\{\s*useNavigation[^}]*useTheme[^}]*\}\s+from\s+['"]@react-navigation\/native['"]/,
1122
+ );
1123
+ expect(output).toContain("useNavigation()");
1124
+ expect(output).toContain("useTheme()");
1125
+
1126
+ // Should only have one import from that source
1127
+ const importCount = (output.match(/@react-navigation\/native/g) ?? []).length;
1128
+ expect(importCount).toBe(1);
1129
+ });
1130
+
1131
+ it("should not duplicate custom hook if already imported", () => {
1132
+ const input = `
1133
+ import React from 'react';
1134
+ import { View } from 'react-native';
1135
+ import { useColorScheme } from '@/hooks/useColorScheme';
1136
+
1137
+ export function Component() {
1138
+ return <View className="dark:bg-gray-900" />;
1139
+ }
1140
+ `;
1141
+
1142
+ const output = transform(
1143
+ input,
1144
+ {
1145
+ colorScheme: {
1146
+ importFrom: "@/hooks/useColorScheme",
1147
+ importName: "useColorScheme",
1148
+ },
1149
+ },
1150
+ true,
1151
+ );
1152
+
1153
+ // Should not add duplicate import
1154
+ const importMatches = output.match(/import.*useColorScheme.*from ['"]@\/hooks\/useColorScheme['"]/g);
1155
+ expect(importMatches).toHaveLength(1);
1156
+
1157
+ // Should still inject hook call
1158
+ expect(output).toContain("_twColorScheme = useColorScheme()");
1159
+ });
1160
+
1161
+ it("should use react-native by default when no custom config provided", () => {
1162
+ const input = `
1163
+ import React from 'react';
1164
+ import { View } from 'react-native';
1165
+
1166
+ export function Component() {
1167
+ return <View className="dark:bg-gray-900" />;
1168
+ }
1169
+ `;
1170
+
1171
+ const output = transform(input, undefined, true);
1172
+
1173
+ // Should use default react-native import (can be single or double quotes)
1174
+ expect(output).toMatch(/useColorScheme\s*}\s*from\s+['"]react-native['"]/);
1175
+ expect(output).not.toContain("@/hooks");
1176
+ expect(output).not.toContain("@react-navigation");
1177
+
1178
+ // Should inject hook call with default name
1179
+ expect(output).toContain("_twColorScheme = useColorScheme()");
1180
+ });
1181
+
1182
+ it("should create separate import when only type-only import exists", () => {
1183
+ const input = `
1184
+ import React from 'react';
1185
+ import { View } from 'react-native';
1186
+ import type { NavigationProp } from '@react-navigation/native';
1187
+
1188
+ export function Component() {
1189
+ return <View className="dark:bg-gray-900" />;
1190
+ }
1191
+ `;
1192
+
1193
+ const output = transform(
1194
+ input,
1195
+ {
1196
+ colorScheme: {
1197
+ importFrom: "@react-navigation/native",
1198
+ importName: "useTheme",
1199
+ },
1200
+ },
1201
+ true,
1202
+ );
1203
+
1204
+ // TypeScript preset strips type-only imports, but the important thing is:
1205
+ // 1. useTheme hook is imported (not skipped thinking it was already imported)
1206
+ // 2. Hook is correctly called in the component
1207
+ expect(output).toMatch(/import\s+\{\s*useTheme\s*\}\s+from\s+['"]@react-navigation\/native['"]/);
1208
+ expect(output).toContain("_twColorScheme = useTheme()");
1209
+ });
1210
+
1211
+ it("should use aliased identifier when hook is already imported with alias", () => {
1212
+ const input = `
1213
+ import React from 'react';
1214
+ import { View, Text } from 'react-native';
1215
+ import { useTheme as navTheme } from '@react-navigation/native';
1216
+
1217
+ export function Component() {
1218
+ const theme = navTheme();
1219
+ return (
1220
+ <View className="dark:bg-gray-900">
1221
+ <Text>{theme.dark ? 'Dark' : 'Light'}</Text>
1222
+ </View>
1223
+ );
1224
+ }
1225
+ `;
1226
+
1227
+ const output = transform(
1228
+ input,
1229
+ {
1230
+ colorScheme: {
1231
+ importFrom: "@react-navigation/native",
1232
+ importName: "useTheme",
1233
+ },
1234
+ },
1235
+ true,
1236
+ );
1237
+
1238
+ // Should not add duplicate import
1239
+ const importMatches = output.match(
1240
+ /import\s+\{[^}]*useTheme[^}]*\}\s+from\s+['"]@react-navigation\/native['"]/g,
1241
+ );
1242
+ expect(importMatches).toHaveLength(1);
1243
+
1244
+ // Should still have the aliased import
1245
+ expect(output).toMatch(/useTheme\s+as\s+navTheme/);
1246
+
1247
+ // Should call the aliased name (navTheme), not the export name (useTheme)
1248
+ // Both the user's code and our injected hook should use navTheme
1249
+ expect(output).toContain("_twColorScheme = navTheme()");
1250
+ expect(output).not.toContain("_twColorScheme = useTheme()");
1251
+ });
1252
+
1253
+ it("should handle both type-only and aliased imports together", () => {
1254
+ const input = `
1255
+ import React from 'react';
1256
+ import { View, Text } from 'react-native';
1257
+ import type { Theme } from '@react-navigation/native';
1258
+ import { useTheme as getNavTheme } from '@react-navigation/native';
1259
+
1260
+ export function Component() {
1261
+ const theme = getNavTheme();
1262
+ return (
1263
+ <View className="dark:bg-gray-900">
1264
+ <Text>{theme.dark ? 'Dark Mode' : 'Light Mode'}</Text>
1265
+ </View>
1266
+ );
1267
+ }
1268
+ `;
1269
+
1270
+ const output = transform(
1271
+ input,
1272
+ {
1273
+ colorScheme: {
1274
+ importFrom: "@react-navigation/native",
1275
+ importName: "useTheme",
1276
+ },
1277
+ },
1278
+ true,
1279
+ );
1280
+
1281
+ // TypeScript preset strips type-only imports
1282
+ // The important thing is: should not add duplicate import, and should use aliased name
1283
+ expect(output).toMatch(
1284
+ /import\s+\{[^}]*useTheme\s+as\s+getNavTheme[^}]*\}\s+from\s+['"]@react-navigation\/native['"]/,
1285
+ );
1286
+
1287
+ // Should not add duplicate import - useTheme should only appear in the aliased import
1288
+ const useThemeImports = output.match(
1289
+ /import\s+\{[^}]*useTheme[^}]*\}\s+from\s+['"]@react-navigation\/native['"]/g,
1290
+ );
1291
+ expect(useThemeImports).toHaveLength(1);
1292
+
1293
+ // Should call the aliased name for both user code and our injected hook
1294
+ expect(output).toContain("_twColorScheme = getNavTheme()");
1295
+ expect(output).not.toContain("_twColorScheme = useTheme()");
1296
+ });
1297
+ });
1298
+
1025
1299
  describe("Babel plugin - import injection", () => {
1026
1300
  it("should not add StyleSheet import to files without className usage", () => {
1027
1301
  const input = `
@@ -18,7 +18,8 @@ import {
18
18
  } from "../parser/index.js";
19
19
  import type { StyleObject } from "../types/core.js";
20
20
  import { generateStyleKey } from "../utils/styleKey.js";
21
- import { extractCustomColors } from "./config-loader.js";
21
+ import type { CustomTheme } from "./config-loader.js";
22
+ import { extractCustomTheme } from "./config-loader.js";
22
23
 
23
24
  // Import utility functions
24
25
  import type { SchemeModifierConfig } from "../types/config.js";
@@ -88,6 +89,42 @@ export type PluginOptions = {
88
89
  darkSuffix?: string;
89
90
  lightSuffix?: string;
90
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
+ };
91
128
  };
92
129
 
93
130
  type PluginState = PluginPass & {
@@ -99,7 +136,10 @@ type PluginState = PluginPass & {
99
136
  hasColorSchemeImport: boolean;
100
137
  needsColorSchemeImport: boolean;
101
138
  colorSchemeVariableName: string;
102
- customColors: Record<string, 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
142
+ customTheme: CustomTheme;
103
143
  schemeModifierConfig: SchemeModifierConfig;
104
144
  supportedAttributes: Set<string>;
105
145
  attributePatterns: RegExp[];
@@ -209,6 +249,10 @@ export default function reactNativeTailwindBabelPlugin(
209
249
  lightSuffix: options?.schemeModifier?.lightSuffix ?? "-light",
210
250
  };
211
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
+
212
256
  return {
213
257
  name: "react-native-tailwind",
214
258
 
@@ -224,6 +268,8 @@ export default function reactNativeTailwindBabelPlugin(
224
268
  state.hasColorSchemeImport = false;
225
269
  state.needsColorSchemeImport = false;
226
270
  state.colorSchemeVariableName = "_twColorScheme";
271
+ state.colorSchemeImportSource = colorSchemeImportSource;
272
+ state.colorSchemeHookName = colorSchemeHookName;
227
273
  state.supportedAttributes = exactMatches;
228
274
  state.attributePatterns = patterns;
229
275
  state.stylesIdentifier = stylesIdentifier;
@@ -231,8 +277,8 @@ export default function reactNativeTailwindBabelPlugin(
231
277
  state.hasTwImport = false;
232
278
  state.functionComponentsNeedingColorScheme = new Set();
233
279
 
234
- // Load custom colors from tailwind.config.*
235
- state.customColors = extractCustomColors(state.file.opts.filename ?? "");
280
+ // Load custom theme from tailwind.config.*
281
+ state.customTheme = extractCustomTheme(state.file.opts.filename ?? "");
236
282
 
237
283
  // Use scheme modifier config from plugin options
238
284
  state.schemeModifierConfig = schemeModifierConfig;
@@ -259,15 +305,21 @@ export default function reactNativeTailwindBabelPlugin(
259
305
  addPlatformImport(path, t);
260
306
  }
261
307
 
262
- // Add useColorScheme import if color scheme modifiers were used and not already present
308
+ // Add color scheme hook import if color scheme modifiers were used and not already present
263
309
  if (state.needsColorSchemeImport && !state.hasColorSchemeImport) {
264
- addColorSchemeImport(path, t);
310
+ addColorSchemeImport(path, state.colorSchemeImportSource, state.colorSchemeHookName, t);
265
311
  }
266
312
 
267
- // Inject useColorScheme hook in function components that need it
313
+ // Inject color scheme hook in function components that need it
268
314
  if (state.needsColorSchemeImport) {
269
315
  for (const functionPath of state.functionComponentsNeedingColorScheme) {
270
- injectColorSchemeHook(functionPath, state.colorSchemeVariableName, t);
316
+ injectColorSchemeHook(
317
+ functionPath,
318
+ state.colorSchemeVariableName,
319
+ state.colorSchemeHookName,
320
+ state.colorSchemeLocalIdentifier,
321
+ t,
322
+ );
271
323
  }
272
324
  }
273
325
 
@@ -299,13 +351,6 @@ export default function reactNativeTailwindBabelPlugin(
299
351
  return false;
300
352
  });
301
353
 
302
- const hasUseColorScheme = specifiers.some((spec) => {
303
- if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
304
- return spec.imported.name === "useColorScheme";
305
- }
306
- return false;
307
- });
308
-
309
354
  // Only track if imports exist - don't mutate yet
310
355
  // Actual import injection happens in Program.exit only if needed
311
356
  if (hasStyleSheet) {
@@ -316,14 +361,28 @@ export default function reactNativeTailwindBabelPlugin(
316
361
  state.hasPlatformImport = true;
317
362
  }
318
363
 
319
- if (hasUseColorScheme) {
320
- state.hasColorSchemeImport = true;
321
- }
322
-
323
364
  // Store reference to the react-native import for later modification if needed
324
365
  state.reactNativeImportPath = path;
325
366
  }
326
367
 
368
+ // Track color scheme hook import from the configured source
369
+ // (default: react-native, but can be custom like @/hooks/useColorScheme)
370
+ if (node.source.value === state.colorSchemeImportSource) {
371
+ const specifiers = node.specifiers;
372
+
373
+ for (const spec of specifiers) {
374
+ if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
375
+ if (spec.imported.name === state.colorSchemeHookName) {
376
+ state.hasColorSchemeImport = true;
377
+ // Track the local identifier (handles aliased imports)
378
+ // e.g., import { useTheme as navTheme } → local name is 'navTheme'
379
+ state.colorSchemeLocalIdentifier = spec.local.name;
380
+ break;
381
+ }
382
+ }
383
+ }
384
+ }
385
+
327
386
  // Track tw/twStyle imports from main package (for compile-time transformation)
328
387
  if (node.source.value === "@mgcrea/react-native-tailwind") {
329
388
  const specifiers = node.specifiers;
@@ -480,7 +539,7 @@ export default function reactNativeTailwindBabelPlugin(
480
539
  // Expand scheme: into dark: and light:
481
540
  const expanded = expandSchemeModifier(
482
541
  modifier,
483
- state.customColors,
542
+ state.customTheme.colors ?? {},
484
543
  state.schemeModifierConfig.darkSuffix,
485
544
  state.schemeModifierConfig.lightSuffix,
486
545
  );
@@ -507,7 +566,7 @@ export default function reactNativeTailwindBabelPlugin(
507
566
 
508
567
  if (componentSupport?.supportedModifiers.includes("placeholder")) {
509
568
  const placeholderClasses = placeholderModifiers.map((m) => m.baseClass).join(" ");
510
- const placeholderColor = parsePlaceholderClasses(placeholderClasses, state.customColors);
569
+ const placeholderColor = parsePlaceholderClasses(placeholderClasses, state.customTheme.colors);
511
570
 
512
571
  if (placeholderColor) {
513
572
  // Add or merge placeholderTextColor prop
@@ -561,7 +620,7 @@ export default function reactNativeTailwindBabelPlugin(
561
620
  // Add base classes
562
621
  if (hasBaseClasses) {
563
622
  const baseClassName = baseClasses.join(" ");
564
- const baseStyleObject = parseClassName(baseClassName, state.customColors);
623
+ const baseStyleObject = parseClassName(baseClassName, state.customTheme);
565
624
  const baseStyleKey = generateStyleKey(baseClassName);
566
625
  state.styleRegistry.set(baseStyleKey, baseStyleObject);
567
626
  styleArrayElements.push(
@@ -611,7 +670,7 @@ export default function reactNativeTailwindBabelPlugin(
611
670
  }
612
671
 
613
672
  const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
614
- const modifierStyleObject = parseClassName(modifierClassNames, state.customColors);
673
+ const modifierStyleObject = parseClassName(modifierClassNames, state.customTheme);
615
674
  const modifierStyleKey = generateStyleKey(`${modifierType}_${modifierClassNames}`);
616
675
  state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
617
676
 
@@ -653,7 +712,7 @@ export default function reactNativeTailwindBabelPlugin(
653
712
  // Add base classes
654
713
  if (hasBaseClasses) {
655
714
  const baseClassName = baseClasses.join(" ");
656
- const baseStyleObject = parseClassName(baseClassName, state.customColors);
715
+ const baseStyleObject = parseClassName(baseClassName, state.customTheme);
657
716
  const baseStyleKey = generateStyleKey(baseClassName);
658
717
  state.styleRegistry.set(baseStyleKey, baseStyleObject);
659
718
  styleExpressions.push(
@@ -815,7 +874,7 @@ export default function reactNativeTailwindBabelPlugin(
815
874
  return;
816
875
  }
817
876
 
818
- const styleObject = parseClassName(classNameForStyle, state.customColors);
877
+ const styleObject = parseClassName(classNameForStyle, state.customTheme);
819
878
  const styleKey = generateStyleKey(classNameForStyle);
820
879
  state.styleRegistry.set(styleKey, styleObject);
821
880
 
@@ -2,14 +2,14 @@
2
2
  * Utility functions for processing color scheme modifiers (dark:, light:)
3
3
  */
4
4
  import type * as BabelTypes from "@babel/types";
5
- import type { ParsedModifier } from "../../parser/index.js";
5
+ import type { CustomTheme, ParsedModifier } from "../../parser/index.js";
6
6
  import type { StyleObject } from "../../types/core.js";
7
7
  /**
8
8
  * Plugin state interface (subset needed for color scheme modifier processing)
9
9
  */
10
10
  export interface ColorSchemeModifierProcessingState {
11
11
  styleRegistry: Map<string, StyleObject>;
12
- customColors: Record<string, string>;
12
+ customTheme: CustomTheme;
13
13
  stylesIdentifier: string;
14
14
  needsColorSchemeImport: boolean;
15
15
  colorSchemeVariableName: string;
@@ -31,4 +31,4 @@ export interface ColorSchemeModifierProcessingState {
31
31
  * _twColorScheme === 'light' && styles._light_bg_white
32
32
  * ]
33
33
  */
34
- export declare function processColorSchemeModifiers(colorSchemeModifiers: ParsedModifier[], state: ColorSchemeModifierProcessingState, parseClassName: (className: string, customColors: Record<string, string>) => StyleObject, generateStyleKey: (className: string) => string, t: typeof BabelTypes): BabelTypes.Expression[];
34
+ export declare function processColorSchemeModifiers(colorSchemeModifiers: ParsedModifier[], state: ColorSchemeModifierProcessingState, parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject, generateStyleKey: (className: string) => string, t: typeof BabelTypes): BabelTypes.Expression[];
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import type * as BabelTypes from "@babel/types";
6
- import type { ColorSchemeModifierType, ParsedModifier } from "../../parser/index.js";
6
+ import type { ColorSchemeModifierType, CustomTheme, ParsedModifier } from "../../parser/index.js";
7
7
  import type { StyleObject } from "../../types/core.js";
8
8
 
9
9
  /**
@@ -12,7 +12,7 @@ import type { StyleObject } from "../../types/core.js";
12
12
  // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
13
13
  export interface ColorSchemeModifierProcessingState {
14
14
  styleRegistry: Map<string, StyleObject>;
15
- customColors: Record<string, string>;
15
+ customTheme: CustomTheme;
16
16
  stylesIdentifier: string;
17
17
  needsColorSchemeImport: boolean;
18
18
  colorSchemeVariableName: string;
@@ -38,7 +38,7 @@ export interface ColorSchemeModifierProcessingState {
38
38
  export function processColorSchemeModifiers(
39
39
  colorSchemeModifiers: ParsedModifier[],
40
40
  state: ColorSchemeModifierProcessingState,
41
- parseClassName: (className: string, customColors: Record<string, string>) => StyleObject,
41
+ parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject,
42
42
  generateStyleKey: (className: string) => string,
43
43
  t: typeof BabelTypes,
44
44
  ): BabelTypes.Expression[] {
@@ -65,7 +65,7 @@ export function processColorSchemeModifiers(
65
65
  for (const [scheme, modifiers] of modifiersByScheme) {
66
66
  // Parse all classes for this color scheme together
67
67
  const classNames = modifiers.map((m) => m.baseClass).join(" ");
68
- const styleObject = parseClassName(classNames, state.customColors);
68
+ const styleObject = parseClassName(classNames, state.customTheme);
69
69
  const styleKey = generateStyleKey(`${scheme}_${classNames}`);
70
70
 
71
71
  // Register style in the registry
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import type { NodePath } from "@babel/core";
5
5
  import type * as BabelTypes from "@babel/types";
6
- import type { ParsedModifier } from "../../parser/index.js";
6
+ import type { CustomTheme, ParsedModifier } from "../../parser/index.js";
7
7
  import type { SchemeModifierConfig } from "../../types/config.js";
8
8
  import type { StyleObject } from "../../types/core.js";
9
9
  /**
@@ -11,7 +11,7 @@ import type { StyleObject } from "../../types/core.js";
11
11
  */
12
12
  export interface DynamicProcessingState {
13
13
  styleRegistry: Map<string, StyleObject>;
14
- customColors: Record<string, string>;
14
+ customTheme: CustomTheme;
15
15
  schemeModifierConfig: SchemeModifierConfig;
16
16
  stylesIdentifier: string;
17
17
  needsPlatformImport: boolean;
@@ -29,11 +29,11 @@ export type SplitModifierClassesFn = (className: string) => {
29
29
  /**
30
30
  * Type for the processPlatformModifiers function
31
31
  */
32
- export type ProcessPlatformModifiersFn = (modifiers: ParsedModifier[], state: DynamicProcessingState, parseClassName: (className: string, customColors: Record<string, string>) => StyleObject, generateStyleKey: (className: string) => string, t: typeof BabelTypes) => BabelTypes.Expression;
32
+ export type ProcessPlatformModifiersFn = (modifiers: ParsedModifier[], state: DynamicProcessingState, parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject, generateStyleKey: (className: string) => string, t: typeof BabelTypes) => BabelTypes.Expression;
33
33
  /**
34
34
  * Type for the processColorSchemeModifiers function
35
35
  */
36
- export type ProcessColorSchemeModifiersFn = (modifiers: ParsedModifier[], state: DynamicProcessingState, parseClassName: (className: string, customColors: Record<string, string>) => StyleObject, generateStyleKey: (className: string) => string, t: typeof BabelTypes) => BabelTypes.Expression[];
36
+ export type ProcessColorSchemeModifiersFn = (modifiers: ParsedModifier[], state: DynamicProcessingState, parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject, generateStyleKey: (className: string) => string, t: typeof BabelTypes) => BabelTypes.Expression[];
37
37
  /**
38
38
  * Type for modifier type guard functions
39
39
  */
@@ -53,7 +53,7 @@ export type DynamicExpressionResult = {
53
53
  * Process a dynamic className expression
54
54
  * Extracts static strings and transforms the expression to use pre-compiled styles
55
55
  */
56
- export declare function processDynamicExpression(expression: BabelTypes.Expression, state: DynamicProcessingState, parseClassName: (className: string, customColors: Record<string, string>) => StyleObject, generateStyleKey: (className: string) => string, splitModifierClasses: SplitModifierClassesFn, processPlatformModifiers: ProcessPlatformModifiersFn, processColorSchemeModifiers: ProcessColorSchemeModifiersFn, componentScope: NodePath<BabelTypes.Function> | null, isPlatformModifier: ModifierTypeGuardFn, isColorSchemeModifier: ModifierTypeGuardFn, isSchemeModifier: ModifierTypeGuardFn, expandSchemeModifier: ExpandSchemeModifierFn, t: typeof BabelTypes): {
56
+ export declare function processDynamicExpression(expression: BabelTypes.Expression, state: DynamicProcessingState, parseClassName: (className: string, customTheme?: CustomTheme) => StyleObject, generateStyleKey: (className: string) => string, splitModifierClasses: SplitModifierClassesFn, processPlatformModifiers: ProcessPlatformModifiersFn, processColorSchemeModifiers: ProcessColorSchemeModifiersFn, componentScope: NodePath<BabelTypes.Function> | null, isPlatformModifier: ModifierTypeGuardFn, isColorSchemeModifier: ModifierTypeGuardFn, isSchemeModifier: ModifierTypeGuardFn, expandSchemeModifier: ExpandSchemeModifierFn, t: typeof BabelTypes): {
57
57
  expression: BabelTypes.Expression;
58
58
  staticParts: string[] | undefined;
59
59
  } | {