@mgcrea/react-native-tailwind 0.9.1 → 0.11.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.
Files changed (55) hide show
  1. package/README.md +386 -43
  2. package/dist/babel/config-loader.d.ts +12 -3
  3. package/dist/babel/config-loader.test.ts +154 -0
  4. package/dist/babel/config-loader.ts +41 -9
  5. package/dist/babel/index.cjs +592 -69
  6. package/dist/babel/plugin.d.ts +23 -1
  7. package/dist/babel/plugin.test.ts +331 -0
  8. package/dist/babel/plugin.ts +268 -37
  9. package/dist/babel/utils/colorSchemeModifierProcessing.d.ts +34 -0
  10. package/dist/babel/utils/colorSchemeModifierProcessing.ts +89 -0
  11. package/dist/babel/utils/dynamicProcessing.d.ts +34 -3
  12. package/dist/babel/utils/dynamicProcessing.ts +358 -39
  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 +13 -0
  18. package/dist/babel/utils/styleInjection.ts +101 -0
  19. package/dist/babel/utils/styleTransforms.test.ts +56 -0
  20. package/dist/babel/utils/twProcessing.d.ts +5 -3
  21. package/dist/babel/utils/twProcessing.ts +27 -6
  22. package/dist/parser/index.d.ts +13 -6
  23. package/dist/parser/index.js +1 -1
  24. package/dist/parser/modifiers.d.ts +48 -2
  25. package/dist/parser/modifiers.js +1 -1
  26. package/dist/parser/modifiers.test.js +1 -1
  27. package/dist/parser/typography.d.ts +3 -1
  28. package/dist/parser/typography.js +1 -1
  29. package/dist/runtime.cjs +1 -1
  30. package/dist/runtime.cjs.map +3 -3
  31. package/dist/runtime.d.ts +8 -1
  32. package/dist/runtime.js +1 -1
  33. package/dist/runtime.js.map +3 -3
  34. package/dist/runtime.test.js +1 -1
  35. package/dist/types/config.d.ts +7 -0
  36. package/dist/types/config.js +0 -0
  37. package/package.json +3 -2
  38. package/src/babel/config-loader.test.ts +154 -0
  39. package/src/babel/config-loader.ts +41 -9
  40. package/src/babel/plugin.test.ts +331 -0
  41. package/src/babel/plugin.ts +268 -37
  42. package/src/babel/utils/colorSchemeModifierProcessing.ts +89 -0
  43. package/src/babel/utils/dynamicProcessing.ts +358 -39
  44. package/src/babel/utils/modifierProcessing.ts +5 -5
  45. package/src/babel/utils/platformModifierProcessing.ts +4 -4
  46. package/src/babel/utils/styleInjection.ts +101 -0
  47. package/src/babel/utils/styleTransforms.test.ts +56 -0
  48. package/src/babel/utils/twProcessing.ts +27 -6
  49. package/src/parser/index.ts +28 -9
  50. package/src/parser/modifiers.test.ts +151 -1
  51. package/src/parser/modifiers.ts +139 -4
  52. package/src/parser/typography.ts +14 -2
  53. package/src/runtime.test.ts +7 -7
  54. package/src/runtime.ts +37 -14
  55. package/src/types/config.ts +7 -0
@@ -1678,7 +1678,13 @@ function parseArbitraryLineHeight(value) {
1678
1678
  }
1679
1679
  return null;
1680
1680
  }
1681
- function parseTypography(cls) {
1681
+ function parseTypography(cls, customFontFamily) {
1682
+ const fontFamilyMap = customFontFamily ? {
1683
+ ...FONT_FAMILY_MAP,
1684
+ ...Object.fromEntries(
1685
+ Object.entries(customFontFamily).map(([key, value]) => [`font-${key}`, { fontFamily: value }])
1686
+ )
1687
+ } : FONT_FAMILY_MAP;
1682
1688
  if (cls.startsWith("text-")) {
1683
1689
  const sizeKey = cls.substring(5);
1684
1690
  const arbitraryValue = parseArbitraryFontSize(sizeKey);
@@ -1701,7 +1707,7 @@ function parseTypography(cls) {
1701
1707
  return { lineHeight };
1702
1708
  }
1703
1709
  }
1704
- return FONT_FAMILY_MAP[cls] ?? FONT_WEIGHT_MAP[cls] ?? FONT_STYLE_MAP[cls] ?? TEXT_ALIGN_MAP[cls] ?? TEXT_DECORATION_MAP[cls] ?? TEXT_TRANSFORM_MAP[cls] ?? LINE_HEIGHT_MAP[cls] ?? TRACKING_MAP[cls] ?? null;
1710
+ return fontFamilyMap[cls] ?? FONT_WEIGHT_MAP[cls] ?? FONT_STYLE_MAP[cls] ?? TEXT_ALIGN_MAP[cls] ?? TEXT_DECORATION_MAP[cls] ?? TEXT_TRANSFORM_MAP[cls] ?? LINE_HEIGHT_MAP[cls] ?? TRACKING_MAP[cls] ?? null;
1705
1711
  }
1706
1712
 
1707
1713
  // src/parser/placeholder.ts
@@ -1741,7 +1747,14 @@ var STATE_MODIFIERS = [
1741
1747
  "placeholder"
1742
1748
  ];
1743
1749
  var PLATFORM_MODIFIERS = ["ios", "android", "web"];
1744
- var SUPPORTED_MODIFIERS = [...STATE_MODIFIERS, ...PLATFORM_MODIFIERS];
1750
+ var COLOR_SCHEME_MODIFIERS = ["dark", "light"];
1751
+ var SCHEME_MODIFIERS = ["scheme"];
1752
+ var SUPPORTED_MODIFIERS = [
1753
+ ...STATE_MODIFIERS,
1754
+ ...PLATFORM_MODIFIERS,
1755
+ ...COLOR_SCHEME_MODIFIERS,
1756
+ ...SCHEME_MODIFIERS
1757
+ ];
1745
1758
  function parseModifier(cls) {
1746
1759
  const colonIndex = cls.indexOf(":");
1747
1760
  if (colonIndex === -1) {
@@ -1769,6 +1782,56 @@ function isStateModifier(modifier) {
1769
1782
  function isPlatformModifier(modifier) {
1770
1783
  return PLATFORM_MODIFIERS.includes(modifier);
1771
1784
  }
1785
+ function isColorSchemeModifier(modifier) {
1786
+ return COLOR_SCHEME_MODIFIERS.includes(modifier);
1787
+ }
1788
+ function isSchemeModifier(modifier) {
1789
+ return SCHEME_MODIFIERS.includes(modifier);
1790
+ }
1791
+ function isColorClass(className) {
1792
+ return className.startsWith("text-") || className.startsWith("bg-") || className.startsWith("border-");
1793
+ }
1794
+ function expandSchemeModifier(schemeModifier, customColors, darkSuffix = "-dark", lightSuffix = "-light") {
1795
+ const { baseClass } = schemeModifier;
1796
+ if (!isColorClass(baseClass)) {
1797
+ if (process.env.NODE_ENV !== "production") {
1798
+ console.warn(
1799
+ `[react-native-tailwind] scheme: modifier only supports color classes (text-*, bg-*, border-*). Found: "${baseClass}". This modifier will be ignored.`
1800
+ );
1801
+ }
1802
+ return [];
1803
+ }
1804
+ const match = baseClass.match(/^(text|bg|border)-(.+)$/);
1805
+ if (!match) {
1806
+ return [];
1807
+ }
1808
+ const [, prefix, colorName] = match;
1809
+ const darkColorName = `${colorName}${darkSuffix}`;
1810
+ const lightColorName = `${colorName}${lightSuffix}`;
1811
+ const darkColorExists = customColors[darkColorName] !== void 0;
1812
+ const lightColorExists = customColors[lightColorName] !== void 0;
1813
+ if (!darkColorExists || !lightColorExists) {
1814
+ if (process.env.NODE_ENV !== "production") {
1815
+ const missing = [];
1816
+ if (!darkColorExists) missing.push(`${colorName}${darkSuffix}`);
1817
+ if (!lightColorExists) missing.push(`${colorName}${lightSuffix}`);
1818
+ console.warn(
1819
+ `[react-native-tailwind] scheme:${baseClass} requires both color variants to exist. Missing: ${missing.join(", ")}. This modifier will be ignored.`
1820
+ );
1821
+ }
1822
+ return [];
1823
+ }
1824
+ return [
1825
+ {
1826
+ modifier: "dark",
1827
+ baseClass: `${prefix}-${darkColorName}`
1828
+ },
1829
+ {
1830
+ modifier: "light",
1831
+ baseClass: `${prefix}-${lightColorName}`
1832
+ }
1833
+ ];
1834
+ }
1772
1835
  function splitModifierClasses(className) {
1773
1836
  const classes = className.trim().split(/\s+/).filter(Boolean);
1774
1837
  const baseClasses = [];
@@ -1785,22 +1848,22 @@ function splitModifierClasses(className) {
1785
1848
  }
1786
1849
 
1787
1850
  // src/parser/index.ts
1788
- function parseClassName(className, customColors) {
1851
+ function parseClassName(className, customTheme) {
1789
1852
  const classes = className.split(/\s+/).filter(Boolean);
1790
1853
  const style = {};
1791
1854
  for (const cls of classes) {
1792
- const parsedStyle = parseClass(cls, customColors);
1855
+ const parsedStyle = parseClass(cls, customTheme);
1793
1856
  Object.assign(style, parsedStyle);
1794
1857
  }
1795
1858
  return style;
1796
1859
  }
1797
- function parseClass(cls, customColors) {
1860
+ function parseClass(cls, customTheme) {
1798
1861
  const parsers = [
1799
1862
  parseSpacing,
1800
1863
  parseBorder,
1801
- (cls2) => parseColor(cls2, customColors),
1864
+ (cls2) => parseColor(cls2, customTheme?.colors),
1802
1865
  parseLayout,
1803
- parseTypography,
1866
+ (cls2) => parseTypography(cls2, customTheme?.fontFamily),
1804
1867
  parseSizing,
1805
1868
  parseShadow,
1806
1869
  parseAspectRatio,
@@ -1868,15 +1931,15 @@ function loadTailwindConfig(configPath) {
1868
1931
  return null;
1869
1932
  }
1870
1933
  }
1871
- function extractCustomColors(filename) {
1934
+ function extractCustomTheme(filename) {
1872
1935
  const projectDir = path.dirname(filename);
1873
1936
  const configPath = findTailwindConfig(projectDir);
1874
1937
  if (!configPath) {
1875
- return {};
1938
+ return { colors: {}, fontFamily: {} };
1876
1939
  }
1877
1940
  const config = loadTailwindConfig(configPath);
1878
1941
  if (!config?.theme) {
1879
- return {};
1942
+ return { colors: {}, fontFamily: {} };
1880
1943
  }
1881
1944
  if (config.theme.colors && !config.theme.extend?.colors && process.env.NODE_ENV !== "production") {
1882
1945
  console.warn(
@@ -1884,7 +1947,24 @@ function extractCustomColors(filename) {
1884
1947
  );
1885
1948
  }
1886
1949
  const colors = config.theme.extend?.colors ?? config.theme.colors ?? {};
1887
- return flattenColors(colors);
1950
+ if (config.theme.fontFamily && !config.theme.extend?.fontFamily && process.env.NODE_ENV !== "production") {
1951
+ console.warn(
1952
+ "[react-native-tailwind] Using theme.fontFamily will override all default font families. Use theme.extend.fontFamily to add custom fonts while keeping defaults."
1953
+ );
1954
+ }
1955
+ const fontFamily = config.theme.extend?.fontFamily ?? config.theme.fontFamily ?? {};
1956
+ const fontFamilyResult = {};
1957
+ for (const [key, value] of Object.entries(fontFamily)) {
1958
+ if (Array.isArray(value)) {
1959
+ fontFamilyResult[key] = value[0];
1960
+ } else {
1961
+ fontFamilyResult[key] = value;
1962
+ }
1963
+ }
1964
+ return {
1965
+ colors: flattenColors(colors),
1966
+ fontFamily: fontFamilyResult
1967
+ };
1888
1968
  }
1889
1969
 
1890
1970
  // src/babel/utils/attributeMatchers.ts
@@ -1923,6 +2003,38 @@ function getTargetStyleProp(attributeName) {
1923
2003
  return attributeName.endsWith("ClassName") ? attributeName.replace("ClassName", "Style") : "style";
1924
2004
  }
1925
2005
 
2006
+ // src/babel/utils/colorSchemeModifierProcessing.ts
2007
+ function processColorSchemeModifiers(colorSchemeModifiers, state, parseClassName2, generateStyleKey2, t) {
2008
+ state.needsColorSchemeImport = true;
2009
+ const modifiersByScheme = /* @__PURE__ */ new Map();
2010
+ for (const mod of colorSchemeModifiers) {
2011
+ const scheme = mod.modifier;
2012
+ if (!modifiersByScheme.has(scheme)) {
2013
+ modifiersByScheme.set(scheme, []);
2014
+ }
2015
+ const schemeGroup = modifiersByScheme.get(scheme);
2016
+ if (schemeGroup) {
2017
+ schemeGroup.push(mod);
2018
+ }
2019
+ }
2020
+ const conditionalExpressions = [];
2021
+ for (const [scheme, modifiers] of modifiersByScheme) {
2022
+ const classNames = modifiers.map((m) => m.baseClass).join(" ");
2023
+ const styleObject = parseClassName2(classNames, state.customTheme);
2024
+ const styleKey = generateStyleKey2(`${scheme}_${classNames}`);
2025
+ state.styleRegistry.set(styleKey, styleObject);
2026
+ const colorSchemeCheck = t.binaryExpression(
2027
+ "===",
2028
+ t.identifier(state.colorSchemeVariableName),
2029
+ t.stringLiteral(scheme)
2030
+ );
2031
+ const styleReference = t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey));
2032
+ const conditionalExpression = t.logicalExpression("&&", colorSchemeCheck, styleReference);
2033
+ conditionalExpressions.push(conditionalExpression);
2034
+ }
2035
+ return conditionalExpressions;
2036
+ }
2037
+
1926
2038
  // src/babel/utils/componentSupport.ts
1927
2039
  function getComponentModifierSupport(jsxElement, t) {
1928
2040
  if (!t.isJSXOpeningElement(jsxElement)) {
@@ -1967,32 +2079,89 @@ function getStatePropertyForModifier(modifier) {
1967
2079
  }
1968
2080
 
1969
2081
  // src/babel/utils/dynamicProcessing.ts
1970
- function processDynamicExpression(expression, state, parseClassName2, generateStyleKey2, t) {
2082
+ function processDynamicExpression(expression, state, parseClassName2, generateStyleKey2, splitModifierClasses2, processPlatformModifiers2, processColorSchemeModifiers2, componentScope, isPlatformModifier2, isColorSchemeModifier2, isSchemeModifier2, expandSchemeModifier2, t) {
1971
2083
  if (t.isTemplateLiteral(expression)) {
1972
- return processTemplateLiteral(expression, state, parseClassName2, generateStyleKey2, t);
2084
+ return processTemplateLiteral(
2085
+ expression,
2086
+ state,
2087
+ parseClassName2,
2088
+ generateStyleKey2,
2089
+ splitModifierClasses2,
2090
+ processPlatformModifiers2,
2091
+ processColorSchemeModifiers2,
2092
+ componentScope,
2093
+ isPlatformModifier2,
2094
+ isColorSchemeModifier2,
2095
+ isSchemeModifier2,
2096
+ expandSchemeModifier2,
2097
+ t
2098
+ );
1973
2099
  }
1974
2100
  if (t.isConditionalExpression(expression)) {
1975
- return processConditionalExpression(expression, state, parseClassName2, generateStyleKey2, t);
2101
+ return processConditionalExpression(
2102
+ expression,
2103
+ state,
2104
+ parseClassName2,
2105
+ generateStyleKey2,
2106
+ splitModifierClasses2,
2107
+ processPlatformModifiers2,
2108
+ processColorSchemeModifiers2,
2109
+ componentScope,
2110
+ isPlatformModifier2,
2111
+ isColorSchemeModifier2,
2112
+ isSchemeModifier2,
2113
+ expandSchemeModifier2,
2114
+ t
2115
+ );
1976
2116
  }
1977
2117
  if (t.isLogicalExpression(expression)) {
1978
- return processLogicalExpression(expression, state, parseClassName2, generateStyleKey2, t);
2118
+ return processLogicalExpression(
2119
+ expression,
2120
+ state,
2121
+ parseClassName2,
2122
+ generateStyleKey2,
2123
+ splitModifierClasses2,
2124
+ processPlatformModifiers2,
2125
+ processColorSchemeModifiers2,
2126
+ componentScope,
2127
+ isPlatformModifier2,
2128
+ isColorSchemeModifier2,
2129
+ isSchemeModifier2,
2130
+ expandSchemeModifier2,
2131
+ t
2132
+ );
1979
2133
  }
1980
2134
  return null;
1981
2135
  }
1982
- function processTemplateLiteral(node, state, parseClassName2, generateStyleKey2, t) {
2136
+ function processTemplateLiteral(node, state, parseClassName2, generateStyleKey2, splitModifierClasses2, processPlatformModifiers2, processColorSchemeModifiers2, componentScope, isPlatformModifier2, isColorSchemeModifier2, isSchemeModifier2, expandSchemeModifier2, t) {
1983
2137
  const parts = [];
1984
2138
  const staticParts = [];
1985
2139
  for (let i = 0; i < node.quasis.length; i++) {
1986
2140
  const quasi = node.quasis[i];
1987
2141
  const staticText = quasi.value.cooked?.trim();
1988
2142
  if (staticText) {
1989
- const classes = staticText.split(/\s+/).filter(Boolean);
1990
- for (const cls of classes) {
1991
- const styleObject = parseClassName2(cls, state.customColors);
1992
- const styleKey = generateStyleKey2(cls);
1993
- state.styleRegistry.set(styleKey, styleObject);
1994
- staticParts.push(cls);
1995
- parts.push(t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey)));
2143
+ const processedExpression = processStringOrExpressionHelper(
2144
+ t.stringLiteral(staticText),
2145
+ state,
2146
+ parseClassName2,
2147
+ generateStyleKey2,
2148
+ splitModifierClasses2,
2149
+ processPlatformModifiers2,
2150
+ processColorSchemeModifiers2,
2151
+ componentScope,
2152
+ isPlatformModifier2,
2153
+ isColorSchemeModifier2,
2154
+ isSchemeModifier2,
2155
+ expandSchemeModifier2,
2156
+ t
2157
+ );
2158
+ if (processedExpression) {
2159
+ staticParts.push(staticText);
2160
+ if (t.isArrayExpression(processedExpression)) {
2161
+ parts.push(...processedExpression.elements);
2162
+ } else {
2163
+ parts.push(processedExpression);
2164
+ }
1996
2165
  }
1997
2166
  }
1998
2167
  if (i < node.expressions.length) {
@@ -2002,6 +2171,14 @@ function processTemplateLiteral(node, state, parseClassName2, generateStyleKey2,
2002
2171
  state,
2003
2172
  parseClassName2,
2004
2173
  generateStyleKey2,
2174
+ splitModifierClasses2,
2175
+ processPlatformModifiers2,
2176
+ processColorSchemeModifiers2,
2177
+ componentScope,
2178
+ isPlatformModifier2,
2179
+ isColorSchemeModifier2,
2180
+ isSchemeModifier2,
2181
+ expandSchemeModifier2,
2005
2182
  t
2006
2183
  );
2007
2184
  if (result) {
@@ -2020,9 +2197,37 @@ function processTemplateLiteral(node, state, parseClassName2, generateStyleKey2,
2020
2197
  staticParts: staticParts.length > 0 ? staticParts : void 0
2021
2198
  };
2022
2199
  }
2023
- function processConditionalExpression(node, state, parseClassName2, generateStyleKey2, t) {
2024
- const consequent = processStringOrExpression(node.consequent, state, parseClassName2, generateStyleKey2, t);
2025
- const alternate = processStringOrExpression(node.alternate, state, parseClassName2, generateStyleKey2, t);
2200
+ function processConditionalExpression(node, state, parseClassName2, generateStyleKey2, splitModifierClasses2, processPlatformModifiers2, processColorSchemeModifiers2, componentScope, isPlatformModifier2, isColorSchemeModifier2, isSchemeModifier2, expandSchemeModifier2, t) {
2201
+ const consequent = processStringOrExpressionHelper(
2202
+ node.consequent,
2203
+ state,
2204
+ parseClassName2,
2205
+ generateStyleKey2,
2206
+ splitModifierClasses2,
2207
+ processPlatformModifiers2,
2208
+ processColorSchemeModifiers2,
2209
+ componentScope,
2210
+ isPlatformModifier2,
2211
+ isColorSchemeModifier2,
2212
+ isSchemeModifier2,
2213
+ expandSchemeModifier2,
2214
+ t
2215
+ );
2216
+ const alternate = processStringOrExpressionHelper(
2217
+ node.alternate,
2218
+ state,
2219
+ parseClassName2,
2220
+ generateStyleKey2,
2221
+ splitModifierClasses2,
2222
+ processPlatformModifiers2,
2223
+ processColorSchemeModifiers2,
2224
+ componentScope,
2225
+ isPlatformModifier2,
2226
+ isColorSchemeModifier2,
2227
+ isSchemeModifier2,
2228
+ expandSchemeModifier2,
2229
+ t
2230
+ );
2026
2231
  if (!consequent && !alternate) {
2027
2232
  return null;
2028
2233
  }
@@ -2033,38 +2238,153 @@ function processConditionalExpression(node, state, parseClassName2, generateStyl
2033
2238
  );
2034
2239
  return { expression };
2035
2240
  }
2036
- function processLogicalExpression(node, state, parseClassName2, generateStyleKey2, t) {
2241
+ function processLogicalExpression(node, state, parseClassName2, generateStyleKey2, splitModifierClasses2, processPlatformModifiers2, processColorSchemeModifiers2, componentScope, isPlatformModifier2, isColorSchemeModifier2, isSchemeModifier2, expandSchemeModifier2, t) {
2037
2242
  if (node.operator !== "&&") {
2038
2243
  return null;
2039
2244
  }
2040
- const right = processStringOrExpression(node.right, state, parseClassName2, generateStyleKey2, t);
2245
+ const right = processStringOrExpressionHelper(
2246
+ node.right,
2247
+ state,
2248
+ parseClassName2,
2249
+ generateStyleKey2,
2250
+ splitModifierClasses2,
2251
+ processPlatformModifiers2,
2252
+ processColorSchemeModifiers2,
2253
+ componentScope,
2254
+ isPlatformModifier2,
2255
+ isColorSchemeModifier2,
2256
+ isSchemeModifier2,
2257
+ expandSchemeModifier2,
2258
+ t
2259
+ );
2041
2260
  if (!right) {
2042
2261
  return null;
2043
2262
  }
2044
2263
  const expression = t.logicalExpression("&&", node.left, right);
2045
2264
  return { expression };
2046
2265
  }
2047
- function processStringOrExpression(node, state, parseClassName2, generateStyleKey2, t) {
2266
+ function processStringOrExpressionHelper(node, state, parseClassName2, generateStyleKey2, splitModifierClasses2, processPlatformModifiers2, processColorSchemeModifiers2, componentScope, isPlatformModifier2, isColorSchemeModifier2, isSchemeModifier2, expandSchemeModifier2, t) {
2048
2267
  if (t.isStringLiteral(node)) {
2049
2268
  const className = node.value.trim();
2050
2269
  if (!className) {
2051
2270
  return null;
2052
2271
  }
2053
- const styleObject = parseClassName2(className, state.customColors);
2054
- const styleKey = generateStyleKey2(className);
2055
- state.styleRegistry.set(styleKey, styleObject);
2056
- return t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey));
2272
+ const { baseClasses, modifierClasses: rawModifierClasses } = splitModifierClasses2(className);
2273
+ const modifierClasses = [];
2274
+ for (const modifier of rawModifierClasses) {
2275
+ if (isSchemeModifier2(modifier.modifier)) {
2276
+ const expanded = expandSchemeModifier2(
2277
+ modifier,
2278
+ state.customTheme.colors ?? {},
2279
+ state.schemeModifierConfig.darkSuffix ?? "-dark",
2280
+ state.schemeModifierConfig.lightSuffix ?? "-light"
2281
+ );
2282
+ modifierClasses.push(...expanded);
2283
+ } else {
2284
+ modifierClasses.push(modifier);
2285
+ }
2286
+ }
2287
+ const platformModifiers = modifierClasses.filter((m) => isPlatformModifier2(m.modifier));
2288
+ const colorSchemeModifiers = modifierClasses.filter((m) => isColorSchemeModifier2(m.modifier));
2289
+ const styleElements = [];
2290
+ if (baseClasses.length > 0) {
2291
+ const baseClassName = baseClasses.join(" ");
2292
+ const styleObject = parseClassName2(baseClassName, state.customTheme);
2293
+ const styleKey = generateStyleKey2(baseClassName);
2294
+ state.styleRegistry.set(styleKey, styleObject);
2295
+ styleElements.push(t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey)));
2296
+ }
2297
+ if (platformModifiers.length > 0) {
2298
+ state.needsPlatformImport = true;
2299
+ const platformExpression = processPlatformModifiers2(
2300
+ platformModifiers,
2301
+ state,
2302
+ parseClassName2,
2303
+ generateStyleKey2,
2304
+ t
2305
+ );
2306
+ styleElements.push(platformExpression);
2307
+ }
2308
+ if (colorSchemeModifiers.length > 0) {
2309
+ if (componentScope) {
2310
+ state.needsColorSchemeImport = true;
2311
+ state.functionComponentsNeedingColorScheme.add(componentScope);
2312
+ const colorSchemeExpressions = processColorSchemeModifiers2(
2313
+ colorSchemeModifiers,
2314
+ state,
2315
+ parseClassName2,
2316
+ generateStyleKey2,
2317
+ t
2318
+ );
2319
+ styleElements.push(...colorSchemeExpressions);
2320
+ } else {
2321
+ if (process.env.NODE_ENV !== "production") {
2322
+ console.warn(
2323
+ "[react-native-tailwind] dark:/light: modifiers in dynamic expressions require a function component scope. These modifiers will be ignored."
2324
+ );
2325
+ }
2326
+ }
2327
+ }
2328
+ if (styleElements.length === 0) {
2329
+ return null;
2330
+ }
2331
+ if (styleElements.length === 1) {
2332
+ return styleElements[0];
2333
+ }
2334
+ return t.arrayExpression(styleElements);
2057
2335
  }
2058
2336
  if (t.isConditionalExpression(node)) {
2059
- const result = processConditionalExpression(node, state, parseClassName2, generateStyleKey2, t);
2337
+ const result = processConditionalExpression(
2338
+ node,
2339
+ state,
2340
+ parseClassName2,
2341
+ generateStyleKey2,
2342
+ splitModifierClasses2,
2343
+ processPlatformModifiers2,
2344
+ processColorSchemeModifiers2,
2345
+ componentScope,
2346
+ isPlatformModifier2,
2347
+ isColorSchemeModifier2,
2348
+ isSchemeModifier2,
2349
+ expandSchemeModifier2,
2350
+ t
2351
+ );
2060
2352
  return result?.expression ?? null;
2061
2353
  }
2062
2354
  if (t.isLogicalExpression(node)) {
2063
- const result = processLogicalExpression(node, state, parseClassName2, generateStyleKey2, t);
2355
+ const result = processLogicalExpression(
2356
+ node,
2357
+ state,
2358
+ parseClassName2,
2359
+ generateStyleKey2,
2360
+ splitModifierClasses2,
2361
+ processPlatformModifiers2,
2362
+ processColorSchemeModifiers2,
2363
+ componentScope,
2364
+ isPlatformModifier2,
2365
+ isColorSchemeModifier2,
2366
+ isSchemeModifier2,
2367
+ expandSchemeModifier2,
2368
+ t
2369
+ );
2064
2370
  return result?.expression ?? null;
2065
2371
  }
2066
2372
  if (t.isTemplateLiteral(node)) {
2067
- const result = processTemplateLiteral(node, state, parseClassName2, generateStyleKey2, t);
2373
+ const result = processTemplateLiteral(
2374
+ node,
2375
+ state,
2376
+ parseClassName2,
2377
+ generateStyleKey2,
2378
+ splitModifierClasses2,
2379
+ processPlatformModifiers2,
2380
+ processColorSchemeModifiers2,
2381
+ componentScope,
2382
+ isPlatformModifier2,
2383
+ isColorSchemeModifier2,
2384
+ isSchemeModifier2,
2385
+ expandSchemeModifier2,
2386
+ t
2387
+ );
2068
2388
  return result?.expression ?? null;
2069
2389
  }
2070
2390
  return null;
@@ -2076,7 +2396,7 @@ function processStaticClassNameWithModifiers(className, state, parseClassName2,
2076
2396
  let baseStyleExpression = null;
2077
2397
  if (baseClasses.length > 0) {
2078
2398
  const baseClassName = baseClasses.join(" ");
2079
- const baseStyleObject = parseClassName2(baseClassName, state.customColors);
2399
+ const baseStyleObject = parseClassName2(baseClassName, state.customTheme);
2080
2400
  const baseStyleKey = generateStyleKey2(baseClassName);
2081
2401
  state.styleRegistry.set(baseStyleKey, baseStyleObject);
2082
2402
  baseStyleExpression = t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey));
@@ -2097,7 +2417,7 @@ function processStaticClassNameWithModifiers(className, state, parseClassName2,
2097
2417
  }
2098
2418
  for (const [modifierType, modifiers] of modifiersByType) {
2099
2419
  const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
2100
- const modifierStyleObject = parseClassName2(modifierClassNames, state.customColors);
2420
+ const modifierStyleObject = parseClassName2(modifierClassNames, state.customTheme);
2101
2421
  const modifierStyleKey = generateStyleKey2(`${modifierType}_${modifierClassNames}`);
2102
2422
  state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
2103
2423
  const stateProperty = getStatePropertyForModifier(modifierType);
@@ -2146,7 +2466,7 @@ function processPlatformModifiers(platformModifiers, state, parseClassName2, gen
2146
2466
  const selectProperties = [];
2147
2467
  for (const [platform, modifiers] of modifiersByPlatform) {
2148
2468
  const classNames = modifiers.map((m) => m.baseClass).join(" ");
2149
- const styleObject = parseClassName2(classNames, state.customColors);
2469
+ const styleObject = parseClassName2(classNames, state.customTheme);
2150
2470
  const styleKey = generateStyleKey2(`${platform}_${classNames}`);
2151
2471
  state.styleRegistry.set(styleKey, styleObject);
2152
2472
  const styleReference = t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey));
@@ -2198,6 +2518,63 @@ function addPlatformImport(path2, t) {
2198
2518
  path2.unshiftContainer("body", importDeclaration);
2199
2519
  }
2200
2520
  }
2521
+ function addColorSchemeImport(path2, t) {
2522
+ const body = path2.node.body;
2523
+ let reactNativeImport = null;
2524
+ for (const statement of body) {
2525
+ if (t.isImportDeclaration(statement) && statement.source.value === "react-native") {
2526
+ reactNativeImport = statement;
2527
+ break;
2528
+ }
2529
+ }
2530
+ if (reactNativeImport) {
2531
+ const hasUseColorScheme = reactNativeImport.specifiers.some(
2532
+ (spec) => t.isImportSpecifier(spec) && spec.imported.type === "Identifier" && spec.imported.name === "useColorScheme"
2533
+ );
2534
+ if (!hasUseColorScheme) {
2535
+ reactNativeImport.specifiers.push(
2536
+ t.importSpecifier(t.identifier("useColorScheme"), t.identifier("useColorScheme"))
2537
+ );
2538
+ }
2539
+ } else {
2540
+ const importDeclaration = t.importDeclaration(
2541
+ [t.importSpecifier(t.identifier("useColorScheme"), t.identifier("useColorScheme"))],
2542
+ t.stringLiteral("react-native")
2543
+ );
2544
+ path2.unshiftContainer("body", importDeclaration);
2545
+ }
2546
+ }
2547
+ function injectColorSchemeHook(functionPath, colorSchemeVariableName, t) {
2548
+ let body = functionPath.node.body;
2549
+ if (!t.isBlockStatement(body)) {
2550
+ if (t.isArrowFunctionExpression(functionPath.node) && t.isExpression(body)) {
2551
+ const returnStatement = t.returnStatement(body);
2552
+ const blockStatement = t.blockStatement([returnStatement]);
2553
+ functionPath.node.body = blockStatement;
2554
+ body = blockStatement;
2555
+ } else {
2556
+ return false;
2557
+ }
2558
+ }
2559
+ const hasHook = body.body.some((statement) => {
2560
+ if (t.isVariableDeclaration(statement) && statement.declarations.length > 0 && t.isVariableDeclarator(statement.declarations[0])) {
2561
+ const declarator = statement.declarations[0];
2562
+ return t.isIdentifier(declarator.id) && declarator.id.name === colorSchemeVariableName;
2563
+ }
2564
+ return false;
2565
+ });
2566
+ if (hasHook) {
2567
+ return false;
2568
+ }
2569
+ const hookCall = t.variableDeclaration("const", [
2570
+ t.variableDeclarator(
2571
+ t.identifier(colorSchemeVariableName),
2572
+ t.callExpression(t.identifier("useColorScheme"), [])
2573
+ )
2574
+ ]);
2575
+ body.body.unshift(hookCall);
2576
+ return true;
2577
+ }
2201
2578
  function injectStylesAtTop(path2, styleRegistry, stylesIdentifier, t) {
2202
2579
  const styleProperties = [];
2203
2580
  for (const [key, styleObject] of styleRegistry) {
@@ -2348,11 +2725,25 @@ function addOrMergePlaceholderTextColorProp(jsxOpeningElement, color, t) {
2348
2725
 
2349
2726
  // src/babel/utils/twProcessing.ts
2350
2727
  function processTwCall(className, path2, state, parseClassName2, generateStyleKey2, splitModifierClasses2, t) {
2351
- const { baseClasses, modifierClasses } = splitModifierClasses2(className);
2728
+ const { baseClasses, modifierClasses: rawModifierClasses } = splitModifierClasses2(className);
2729
+ const modifierClasses = [];
2730
+ for (const modifier of rawModifierClasses) {
2731
+ if (isSchemeModifier(modifier.modifier)) {
2732
+ const expanded = expandSchemeModifier(
2733
+ modifier,
2734
+ state.customTheme.colors ?? {},
2735
+ state.schemeModifierConfig.darkSuffix ?? "-dark",
2736
+ state.schemeModifierConfig.lightSuffix ?? "-light"
2737
+ );
2738
+ modifierClasses.push(...expanded);
2739
+ } else {
2740
+ modifierClasses.push(modifier);
2741
+ }
2742
+ }
2352
2743
  const objectProperties = [];
2353
2744
  if (baseClasses.length > 0) {
2354
2745
  const baseClassName = baseClasses.join(" ");
2355
- const baseStyleObject = parseClassName2(baseClassName, state.customColors);
2746
+ const baseStyleObject = parseClassName2(baseClassName, state.customTheme);
2356
2747
  const baseStyleKey = generateStyleKey2(baseClassName);
2357
2748
  state.styleRegistry.set(baseStyleKey, baseStyleObject);
2358
2749
  objectProperties.push(
@@ -2376,7 +2767,7 @@ function processTwCall(className, path2, state, parseClassName2, generateStyleKe
2376
2767
  }
2377
2768
  for (const [modifierType, modifiers] of modifiersByType) {
2378
2769
  const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
2379
- const modifierStyleObject = parseClassName2(modifierClassNames, state.customColors);
2770
+ const modifierStyleObject = parseClassName2(modifierClassNames, state.customTheme);
2380
2771
  const modifierStyleKey = generateStyleKey2(`${modifierType}_${modifierClassNames}`);
2381
2772
  state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
2382
2773
  const propertyName = `${modifierType}Style`;
@@ -2415,10 +2806,52 @@ function removeTwImports(path2, t) {
2415
2806
 
2416
2807
  // src/babel/plugin.ts
2417
2808
  var DEFAULT_STYLES_IDENTIFIER = "_twStyles";
2809
+ function isComponentScope(functionPath, t) {
2810
+ const node = functionPath.node;
2811
+ const parent = functionPath.parent;
2812
+ const parentPath = functionPath.parentPath;
2813
+ if (t.isClassMethod(parent)) {
2814
+ return false;
2815
+ }
2816
+ if (functionPath.findParent((p) => t.isClassBody(p.node))) {
2817
+ return false;
2818
+ }
2819
+ if (t.isFunctionDeclaration(node)) {
2820
+ if (t.isProgram(parent) || t.isExportNamedDeclaration(parent) || t.isExportDefaultDeclaration(parent)) {
2821
+ return true;
2822
+ }
2823
+ }
2824
+ if (t.isFunctionExpression(node) || t.isArrowFunctionExpression(node)) {
2825
+ if (t.isVariableDeclarator(parent)) {
2826
+ const varDeclarationPath = parentPath?.parentPath;
2827
+ if (varDeclarationPath && t.isVariableDeclaration(varDeclarationPath.node) && (t.isProgram(varDeclarationPath.parent) || t.isExportNamedDeclaration(varDeclarationPath.parent))) {
2828
+ if (t.isIdentifier(parent.id)) {
2829
+ const name = parent.id.name;
2830
+ return /^[A-Z]/.test(name);
2831
+ }
2832
+ }
2833
+ }
2834
+ }
2835
+ return false;
2836
+ }
2837
+ function findComponentScope(path2, t) {
2838
+ let current = path2.getFunctionParent();
2839
+ while (current) {
2840
+ if (t.isFunction(current.node) && isComponentScope(current, t)) {
2841
+ return current;
2842
+ }
2843
+ current = current.getFunctionParent();
2844
+ }
2845
+ return null;
2846
+ }
2418
2847
  function reactNativeTailwindBabelPlugin({ types: t }, options) {
2419
2848
  const attributes = options?.attributes ?? [...DEFAULT_CLASS_ATTRIBUTES];
2420
2849
  const { exactMatches, patterns } = buildAttributeMatchers(attributes);
2421
2850
  const stylesIdentifier = options?.stylesIdentifier ?? DEFAULT_STYLES_IDENTIFIER;
2851
+ const schemeModifierConfig = {
2852
+ darkSuffix: options?.schemeModifier?.darkSuffix ?? "-dark",
2853
+ lightSuffix: options?.schemeModifier?.lightSuffix ?? "-light"
2854
+ };
2422
2855
  return {
2423
2856
  name: "react-native-tailwind",
2424
2857
  visitor: {
@@ -2429,12 +2862,17 @@ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2429
2862
  state.hasStyleSheetImport = false;
2430
2863
  state.hasPlatformImport = false;
2431
2864
  state.needsPlatformImport = false;
2865
+ state.hasColorSchemeImport = false;
2866
+ state.needsColorSchemeImport = false;
2867
+ state.colorSchemeVariableName = "_twColorScheme";
2432
2868
  state.supportedAttributes = exactMatches;
2433
2869
  state.attributePatterns = patterns;
2434
2870
  state.stylesIdentifier = stylesIdentifier;
2435
2871
  state.twImportNames = /* @__PURE__ */ new Set();
2436
2872
  state.hasTwImport = false;
2437
- state.customColors = extractCustomColors(state.file.opts.filename ?? "");
2873
+ state.functionComponentsNeedingColorScheme = /* @__PURE__ */ new Set();
2874
+ state.customTheme = extractCustomTheme(state.file.opts.filename ?? "");
2875
+ state.schemeModifierConfig = schemeModifierConfig;
2438
2876
  },
2439
2877
  exit(path2, state) {
2440
2878
  if (state.hasTwImport) {
@@ -2449,6 +2887,14 @@ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2449
2887
  if (state.needsPlatformImport && !state.hasPlatformImport) {
2450
2888
  addPlatformImport(path2, t);
2451
2889
  }
2890
+ if (state.needsColorSchemeImport && !state.hasColorSchemeImport) {
2891
+ addColorSchemeImport(path2, t);
2892
+ }
2893
+ if (state.needsColorSchemeImport) {
2894
+ for (const functionPath of state.functionComponentsNeedingColorScheme) {
2895
+ injectColorSchemeHook(functionPath, state.colorSchemeVariableName, t);
2896
+ }
2897
+ }
2452
2898
  injectStylesAtTop(path2, state.styleRegistry, state.stylesIdentifier, t);
2453
2899
  }
2454
2900
  },
@@ -2469,12 +2915,21 @@ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2469
2915
  }
2470
2916
  return false;
2471
2917
  });
2918
+ const hasUseColorScheme = specifiers.some((spec) => {
2919
+ if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
2920
+ return spec.imported.name === "useColorScheme";
2921
+ }
2922
+ return false;
2923
+ });
2472
2924
  if (hasStyleSheet) {
2473
2925
  state.hasStyleSheetImport = true;
2474
2926
  }
2475
2927
  if (hasPlatform) {
2476
2928
  state.hasPlatformImport = true;
2477
2929
  }
2930
+ if (hasUseColorScheme) {
2931
+ state.hasColorSchemeImport = true;
2932
+ }
2478
2933
  state.reactNativeImportPath = path2;
2479
2934
  }
2480
2935
  if (node.source.value === "@mgcrea/react-native-tailwind") {
@@ -2576,9 +3031,24 @@ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2576
3031
  return;
2577
3032
  }
2578
3033
  state.hasClassNames = true;
2579
- const { baseClasses, modifierClasses } = splitModifierClasses(className);
3034
+ const { baseClasses, modifierClasses: rawModifierClasses } = splitModifierClasses(className);
3035
+ const modifierClasses = [];
3036
+ for (const modifier of rawModifierClasses) {
3037
+ if (isSchemeModifier(modifier.modifier)) {
3038
+ const expanded = expandSchemeModifier(
3039
+ modifier,
3040
+ state.customTheme.colors ?? {},
3041
+ state.schemeModifierConfig.darkSuffix,
3042
+ state.schemeModifierConfig.lightSuffix
3043
+ );
3044
+ modifierClasses.push(...expanded);
3045
+ } else {
3046
+ modifierClasses.push(modifier);
3047
+ }
3048
+ }
2580
3049
  const placeholderModifiers = modifierClasses.filter((m) => m.modifier === "placeholder");
2581
3050
  const platformModifiers = modifierClasses.filter((m) => isPlatformModifier(m.modifier));
3051
+ const colorSchemeModifiers = modifierClasses.filter((m) => isColorSchemeModifier(m.modifier));
2582
3052
  const stateModifiers = modifierClasses.filter(
2583
3053
  (m) => isStateModifier(m.modifier) && m.modifier !== "placeholder"
2584
3054
  );
@@ -2587,7 +3057,7 @@ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2587
3057
  const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
2588
3058
  if (componentSupport?.supportedModifiers.includes("placeholder")) {
2589
3059
  const placeholderClasses = placeholderModifiers.map((m) => m.baseClass).join(" ");
2590
- const placeholderColor = parsePlaceholderClasses(placeholderClasses, state.customColors);
3060
+ const placeholderColor = parsePlaceholderClasses(placeholderClasses, state.customTheme.colors);
2591
3061
  if (placeholderColor) {
2592
3062
  addOrMergePlaceholderTextColorProp(jsxOpeningElement, placeholderColor, t);
2593
3063
  }
@@ -2600,30 +3070,56 @@ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2600
3070
  }
2601
3071
  }
2602
3072
  const hasPlatformModifiers = platformModifiers.length > 0;
3073
+ const hasColorSchemeModifiers = colorSchemeModifiers.length > 0;
2603
3074
  const hasStateModifiers = stateModifiers.length > 0;
2604
3075
  const hasBaseClasses = baseClasses.length > 0;
2605
- if (hasStateModifiers && hasPlatformModifiers) {
3076
+ let componentScope = null;
3077
+ if (hasColorSchemeModifiers) {
3078
+ componentScope = findComponentScope(path2, t);
3079
+ if (componentScope) {
3080
+ state.functionComponentsNeedingColorScheme.add(componentScope);
3081
+ } else {
3082
+ if (process.env.NODE_ENV !== "production") {
3083
+ console.warn(
3084
+ `[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.`
3085
+ );
3086
+ }
3087
+ }
3088
+ }
3089
+ if (hasStateModifiers && (hasPlatformModifiers || hasColorSchemeModifiers)) {
2606
3090
  const jsxOpeningElement = path2.parent;
2607
3091
  const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
2608
3092
  if (componentSupport) {
2609
3093
  const styleArrayElements = [];
2610
3094
  if (hasBaseClasses) {
2611
3095
  const baseClassName = baseClasses.join(" ");
2612
- const baseStyleObject = parseClassName(baseClassName, state.customColors);
3096
+ const baseStyleObject = parseClassName(baseClassName, state.customTheme);
2613
3097
  const baseStyleKey = generateStyleKey(baseClassName);
2614
3098
  state.styleRegistry.set(baseStyleKey, baseStyleObject);
2615
3099
  styleArrayElements.push(
2616
3100
  t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey))
2617
3101
  );
2618
3102
  }
2619
- const platformSelectExpression = processPlatformModifiers(
2620
- platformModifiers,
2621
- state,
2622
- parseClassName,
2623
- generateStyleKey,
2624
- t
2625
- );
2626
- styleArrayElements.push(platformSelectExpression);
3103
+ if (hasPlatformModifiers) {
3104
+ const platformSelectExpression = processPlatformModifiers(
3105
+ platformModifiers,
3106
+ state,
3107
+ parseClassName,
3108
+ generateStyleKey,
3109
+ t
3110
+ );
3111
+ styleArrayElements.push(platformSelectExpression);
3112
+ }
3113
+ if (hasColorSchemeModifiers && componentScope) {
3114
+ const colorSchemeConditionals = processColorSchemeModifiers(
3115
+ colorSchemeModifiers,
3116
+ state,
3117
+ parseClassName,
3118
+ generateStyleKey,
3119
+ t
3120
+ );
3121
+ styleArrayElements.push(...colorSchemeConditionals);
3122
+ }
2627
3123
  const modifiersByType = /* @__PURE__ */ new Map();
2628
3124
  for (const mod of stateModifiers) {
2629
3125
  const modType = mod.modifier;
@@ -2637,7 +3133,7 @@ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2637
3133
  continue;
2638
3134
  }
2639
3135
  const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
2640
- const modifierStyleObject = parseClassName(modifierClassNames, state.customColors);
3136
+ const modifierStyleObject = parseClassName(modifierClassNames, state.customTheme);
2641
3137
  const modifierStyleKey = generateStyleKey(`${modifierType}_${modifierClassNames}`);
2642
3138
  state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
2643
3139
  const stateProperty = getStatePropertyForModifier(modifierType);
@@ -2663,25 +3159,37 @@ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2663
3159
  } else {
2664
3160
  }
2665
3161
  }
2666
- if (hasPlatformModifiers && !hasStateModifiers) {
3162
+ if ((hasPlatformModifiers || hasColorSchemeModifiers) && !hasStateModifiers) {
2667
3163
  const styleExpressions = [];
2668
3164
  if (hasBaseClasses) {
2669
3165
  const baseClassName = baseClasses.join(" ");
2670
- const baseStyleObject = parseClassName(baseClassName, state.customColors);
3166
+ const baseStyleObject = parseClassName(baseClassName, state.customTheme);
2671
3167
  const baseStyleKey = generateStyleKey(baseClassName);
2672
3168
  state.styleRegistry.set(baseStyleKey, baseStyleObject);
2673
3169
  styleExpressions.push(
2674
3170
  t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey))
2675
3171
  );
2676
3172
  }
2677
- const platformSelectExpression = processPlatformModifiers(
2678
- platformModifiers,
2679
- state,
2680
- parseClassName,
2681
- generateStyleKey,
2682
- t
2683
- );
2684
- styleExpressions.push(platformSelectExpression);
3173
+ if (hasPlatformModifiers) {
3174
+ const platformSelectExpression = processPlatformModifiers(
3175
+ platformModifiers,
3176
+ state,
3177
+ parseClassName,
3178
+ generateStyleKey,
3179
+ t
3180
+ );
3181
+ styleExpressions.push(platformSelectExpression);
3182
+ }
3183
+ if (hasColorSchemeModifiers && componentScope) {
3184
+ const colorSchemeConditionals = processColorSchemeModifiers(
3185
+ colorSchemeModifiers,
3186
+ state,
3187
+ parseClassName,
3188
+ generateStyleKey,
3189
+ t
3190
+ );
3191
+ styleExpressions.push(...colorSchemeConditionals);
3192
+ }
2685
3193
  const styleExpression = styleExpressions.length === 1 ? styleExpressions[0] : t.arrayExpression(styleExpressions);
2686
3194
  const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
2687
3195
  if (styleAttribute2) {
@@ -2771,7 +3279,7 @@ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2771
3279
  path2.remove();
2772
3280
  return;
2773
3281
  }
2774
- const styleObject = parseClassName(classNameForStyle, state.customColors);
3282
+ const styleObject = parseClassName(classNameForStyle, state.customTheme);
2775
3283
  const styleKey = generateStyleKey(classNameForStyle);
2776
3284
  state.styleRegistry.set(styleKey, styleObject);
2777
3285
  const styleAttribute = findStyleAttribute(path2, targetStyleProp, t);
@@ -2788,7 +3296,22 @@ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2788
3296
  return;
2789
3297
  }
2790
3298
  try {
2791
- const result = processDynamicExpression(expression, state, parseClassName, generateStyleKey, t);
3299
+ const componentScope = findComponentScope(path2, t);
3300
+ const result = processDynamicExpression(
3301
+ expression,
3302
+ state,
3303
+ parseClassName,
3304
+ generateStyleKey,
3305
+ splitModifierClasses,
3306
+ processPlatformModifiers,
3307
+ processColorSchemeModifiers,
3308
+ componentScope,
3309
+ isPlatformModifier,
3310
+ isColorSchemeModifier,
3311
+ isSchemeModifier,
3312
+ expandSchemeModifier,
3313
+ t
3314
+ );
2792
3315
  if (result) {
2793
3316
  state.hasClassNames = true;
2794
3317
  const styleAttribute = findStyleAttribute(path2, targetStyleProp, t);