@mgcrea/react-native-tailwind 0.6.1 → 0.8.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 (100) hide show
  1. package/README.md +406 -1
  2. package/dist/babel/config-loader.ts +1 -23
  3. package/dist/babel/index.cjs +516 -211
  4. package/dist/babel/index.d.ts +4 -15
  5. package/dist/babel/index.test.ts +481 -0
  6. package/dist/babel/index.ts +4 -861
  7. package/dist/babel/plugin.d.ts +42 -0
  8. package/dist/babel/plugin.test.ts +482 -0
  9. package/dist/babel/plugin.ts +491 -0
  10. package/dist/babel/utils/attributeMatchers.d.ts +23 -0
  11. package/dist/babel/utils/attributeMatchers.ts +71 -0
  12. package/dist/babel/utils/componentSupport.d.ts +18 -0
  13. package/dist/babel/utils/componentSupport.ts +68 -0
  14. package/dist/babel/utils/dynamicProcessing.d.ts +32 -0
  15. package/dist/babel/utils/dynamicProcessing.ts +223 -0
  16. package/dist/babel/utils/modifierProcessing.d.ts +26 -0
  17. package/dist/babel/utils/modifierProcessing.ts +118 -0
  18. package/dist/babel/utils/styleInjection.d.ts +15 -0
  19. package/dist/babel/utils/styleInjection.ts +80 -0
  20. package/dist/babel/utils/styleTransforms.d.ts +39 -0
  21. package/dist/babel/utils/styleTransforms.test.ts +349 -0
  22. package/dist/babel/utils/styleTransforms.ts +258 -0
  23. package/dist/babel/utils/twProcessing.d.ts +28 -0
  24. package/dist/babel/utils/twProcessing.ts +124 -0
  25. package/dist/components/TextInput.d.ts +171 -14
  26. package/dist/config/tailwind.d.ts +302 -0
  27. package/dist/config/tailwind.js +1 -0
  28. package/dist/index.d.ts +6 -2
  29. package/dist/index.js +1 -1
  30. package/dist/parser/__snapshots__/colors.test.js.snap +242 -90
  31. package/dist/parser/__snapshots__/transforms.test.js.snap +58 -0
  32. package/dist/parser/colors.js +1 -1
  33. package/dist/parser/index.d.ts +1 -0
  34. package/dist/parser/index.js +1 -1
  35. package/dist/parser/modifiers.d.ts +2 -2
  36. package/dist/parser/modifiers.js +1 -1
  37. package/dist/parser/placeholder.d.ts +36 -0
  38. package/dist/parser/placeholder.js +1 -0
  39. package/dist/parser/placeholder.test.js +1 -0
  40. package/dist/parser/typography.d.ts +1 -0
  41. package/dist/parser/typography.js +1 -1
  42. package/dist/parser/typography.test.js +1 -1
  43. package/dist/runtime.cjs +2 -0
  44. package/dist/runtime.cjs.map +7 -0
  45. package/dist/runtime.d.ts +126 -0
  46. package/dist/runtime.js +2 -0
  47. package/dist/runtime.js.map +7 -0
  48. package/dist/runtime.test.js +1 -0
  49. package/dist/stubs/tw.d.ts +47 -0
  50. package/dist/stubs/tw.js +1 -0
  51. package/dist/types/core.d.ts +40 -0
  52. package/dist/types/core.js +0 -0
  53. package/dist/types/index.d.ts +2 -0
  54. package/dist/types/index.js +1 -0
  55. package/dist/types/runtime.d.ts +15 -0
  56. package/dist/types/runtime.js +1 -0
  57. package/dist/types/util.d.ts +3 -0
  58. package/dist/types/util.js +0 -0
  59. package/dist/utils/flattenColors.d.ts +16 -0
  60. package/dist/utils/flattenColors.js +1 -0
  61. package/dist/utils/flattenColors.test.js +1 -0
  62. package/dist/utils/modifiers.d.ts +29 -0
  63. package/dist/utils/modifiers.js +1 -0
  64. package/dist/utils/modifiers.test.js +1 -0
  65. package/dist/utils/styleKey.test.js +1 -0
  66. package/package.json +15 -3
  67. package/src/babel/config-loader.ts +1 -23
  68. package/src/babel/index.ts +4 -861
  69. package/src/babel/plugin.test.ts +482 -0
  70. package/src/babel/plugin.ts +491 -0
  71. package/src/babel/utils/attributeMatchers.ts +71 -0
  72. package/src/babel/utils/componentSupport.ts +68 -0
  73. package/src/babel/utils/dynamicProcessing.ts +223 -0
  74. package/src/babel/utils/modifierProcessing.ts +118 -0
  75. package/src/babel/utils/styleInjection.ts +80 -0
  76. package/src/babel/utils/styleTransforms.test.ts +349 -0
  77. package/src/babel/utils/styleTransforms.ts +258 -0
  78. package/src/babel/utils/twProcessing.ts +124 -0
  79. package/src/components/TextInput.tsx +17 -14
  80. package/src/config/{palettes.ts → tailwind.ts} +2 -2
  81. package/src/index.ts +9 -1
  82. package/src/parser/colors.ts +9 -23
  83. package/src/parser/index.ts +1 -0
  84. package/src/parser/modifiers.ts +10 -4
  85. package/src/parser/placeholder.test.ts +105 -0
  86. package/src/parser/placeholder.ts +78 -0
  87. package/src/parser/typography.test.ts +11 -0
  88. package/src/parser/typography.ts +20 -2
  89. package/src/runtime.test.ts +325 -0
  90. package/src/runtime.ts +265 -0
  91. package/src/stubs/tw.ts +65 -0
  92. package/src/{types.ts → types/core.ts} +0 -4
  93. package/src/types/index.ts +2 -0
  94. package/src/types/runtime.ts +17 -0
  95. package/src/types/util.ts +1 -0
  96. package/src/utils/flattenColors.test.ts +361 -0
  97. package/src/utils/flattenColors.ts +32 -0
  98. package/src/utils/modifiers.test.ts +286 -0
  99. package/src/utils/modifiers.ts +63 -0
  100. package/src/utils/styleKey.test.ts +168 -0
@@ -258,8 +258,8 @@ function parseBorderRadius(cls) {
258
258
  return null;
259
259
  }
260
260
 
261
- // src/config/palettes.ts
262
- var TAILWIND_PALETTES = {
261
+ // src/config/tailwind.ts
262
+ var TAILWIND_COLORS = {
263
263
  red: {
264
264
  "50": "#fef2f2",
265
265
  "100": "#ffe2e2",
@@ -548,20 +548,28 @@ var TAILWIND_PALETTES = {
548
548
  }
549
549
  };
550
550
 
551
- // src/parser/colors.ts
552
- function flattenColors() {
553
- const flat = {};
554
- for (const [colorName, shades] of Object.entries(TAILWIND_PALETTES)) {
555
- for (const [shade, hex] of Object.entries(shades)) {
556
- flat[`${colorName}-${shade}`] = hex;
551
+ // src/utils/flattenColors.ts
552
+ function flattenColors(colors, prefix = "") {
553
+ const result = {};
554
+ for (const [key, value] of Object.entries(colors)) {
555
+ const newKey = prefix ? `${prefix}-${key}` : key;
556
+ if (typeof value === "string") {
557
+ result[newKey] = value;
558
+ } else if (typeof value === "object" && value !== null) {
559
+ Object.assign(result, flattenColors(value, newKey));
557
560
  }
558
561
  }
559
- flat.white = "#FFFFFF";
560
- flat.black = "#000000";
561
- flat.transparent = "transparent";
562
- return flat;
562
+ return result;
563
563
  }
564
- var COLORS = flattenColors();
564
+
565
+ // src/parser/colors.ts
566
+ var COLORS = {
567
+ ...flattenColors(TAILWIND_COLORS),
568
+ // Add basic colors
569
+ white: "#FFFFFF",
570
+ black: "#000000",
571
+ transparent: "transparent"
572
+ };
565
573
  function applyOpacity(hex, opacity) {
566
574
  if (hex === "transparent") {
567
575
  return "transparent";
@@ -1611,6 +1619,16 @@ var TEXT_TRANSFORM_MAP = {
1611
1619
  capitalize: { textTransform: "capitalize" },
1612
1620
  "normal-case": { textTransform: "none" }
1613
1621
  };
1622
+ var LINE_HEIGHT_SCALE = {
1623
+ 3: 12,
1624
+ 4: 16,
1625
+ 5: 20,
1626
+ 6: 24,
1627
+ 7: 28,
1628
+ 8: 32,
1629
+ 9: 36,
1630
+ 10: 40
1631
+ };
1614
1632
  var LINE_HEIGHT_MAP = {
1615
1633
  "leading-none": { lineHeight: 16 },
1616
1634
  "leading-tight": { lineHeight: 20 },
@@ -1675,12 +1693,50 @@ function parseTypography(cls) {
1675
1693
  if (arbitraryValue !== null) {
1676
1694
  return { lineHeight: arbitraryValue };
1677
1695
  }
1696
+ const lineHeight = LINE_HEIGHT_SCALE[heightKey];
1697
+ if (lineHeight !== void 0) {
1698
+ return { lineHeight };
1699
+ }
1678
1700
  }
1679
1701
  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;
1680
1702
  }
1681
1703
 
1704
+ // src/parser/placeholder.ts
1705
+ function parsePlaceholderClass(cls, customColors) {
1706
+ if (!cls.startsWith("text-")) {
1707
+ if (process.env.NODE_ENV !== "production") {
1708
+ console.warn(
1709
+ `[react-native-tailwind] Only text color utilities are supported in placeholder: modifier. Class "${cls}" will be ignored. React Native only supports placeholderTextColor prop.`
1710
+ );
1711
+ }
1712
+ return null;
1713
+ }
1714
+ const styleObject = parseColor(cls, customColors);
1715
+ if (!styleObject?.color) {
1716
+ return null;
1717
+ }
1718
+ return styleObject.color;
1719
+ }
1720
+ function parsePlaceholderClasses(classes, customColors) {
1721
+ const classList = classes.trim().split(/\s+/).filter(Boolean);
1722
+ let finalColor = null;
1723
+ for (const cls of classList) {
1724
+ const color = parsePlaceholderClass(cls, customColors);
1725
+ if (color) {
1726
+ finalColor = color;
1727
+ }
1728
+ }
1729
+ return finalColor;
1730
+ }
1731
+
1682
1732
  // src/parser/modifiers.ts
1683
- var SUPPORTED_MODIFIERS = ["active", "hover", "focus", "disabled"];
1733
+ var SUPPORTED_MODIFIERS = [
1734
+ "active",
1735
+ "hover",
1736
+ "focus",
1737
+ "disabled",
1738
+ "placeholder"
1739
+ ];
1684
1740
  function parseModifier(cls) {
1685
1741
  const colonIndex = cls.indexOf(":");
1686
1742
  if (colonIndex === -1) {
@@ -1801,18 +1857,6 @@ function loadTailwindConfig(configPath) {
1801
1857
  return null;
1802
1858
  }
1803
1859
  }
1804
- function flattenColors2(colors, prefix = "") {
1805
- const result = {};
1806
- for (const [key, value] of Object.entries(colors)) {
1807
- const newKey = prefix ? `${prefix}-${key}` : key;
1808
- if (typeof value === "string") {
1809
- result[newKey] = value;
1810
- } else if (typeof value === "object" && value !== null) {
1811
- Object.assign(result, flattenColors2(value, newKey));
1812
- }
1813
- }
1814
- return result;
1815
- }
1816
1860
  function extractCustomColors(filename) {
1817
1861
  const projectDir = path.dirname(filename);
1818
1862
  const configPath = findTailwindConfig(projectDir);
@@ -1829,37 +1873,46 @@ function extractCustomColors(filename) {
1829
1873
  );
1830
1874
  }
1831
1875
  const colors = config.theme.extend?.colors ?? config.theme.colors ?? {};
1832
- return flattenColors2(colors);
1876
+ return flattenColors(colors);
1833
1877
  }
1834
1878
 
1835
- // src/babel/index.ts
1836
- var STYLES_IDENTIFIER = "_twStyles";
1837
- var SUPPORTED_CLASS_ATTRIBUTES = [
1879
+ // src/babel/utils/attributeMatchers.ts
1880
+ var DEFAULT_CLASS_ATTRIBUTES = [
1838
1881
  "className",
1839
- "containerClassName",
1840
1882
  "contentContainerClassName",
1841
1883
  "columnWrapperClassName",
1842
1884
  "ListHeaderComponentClassName",
1843
1885
  "ListFooterComponentClassName"
1844
1886
  ];
1845
- function getTargetStyleProp(attributeName) {
1846
- if (attributeName === "containerClassName") {
1847
- return "containerStyle";
1848
- }
1849
- if (attributeName === "contentContainerClassName") {
1850
- return "contentContainerStyle";
1851
- }
1852
- if (attributeName === "columnWrapperClassName") {
1853
- return "columnWrapperStyle";
1887
+ function buildAttributeMatchers(attributes) {
1888
+ const exactMatches = /* @__PURE__ */ new Set();
1889
+ const patterns = [];
1890
+ for (const attr of attributes) {
1891
+ if (attr.includes("*")) {
1892
+ const regexPattern = "^" + attr.replace(/\*/g, ".*") + "$";
1893
+ patterns.push(new RegExp(regexPattern));
1894
+ } else {
1895
+ exactMatches.add(attr);
1896
+ }
1854
1897
  }
1855
- if (attributeName === "ListHeaderComponentClassName") {
1856
- return "ListHeaderComponentStyle";
1898
+ return { exactMatches, patterns };
1899
+ }
1900
+ function isAttributeSupported(attributeName, exactMatches, patterns) {
1901
+ if (exactMatches.has(attributeName)) {
1902
+ return true;
1857
1903
  }
1858
- if (attributeName === "ListFooterComponentClassName") {
1859
- return "ListFooterComponentStyle";
1904
+ for (const pattern of patterns) {
1905
+ if (pattern.test(attributeName)) {
1906
+ return true;
1907
+ }
1860
1908
  }
1861
- return "style";
1909
+ return false;
1910
+ }
1911
+ function getTargetStyleProp(attributeName) {
1912
+ return attributeName.endsWith("ClassName") ? attributeName.replace("ClassName", "Style") : "style";
1862
1913
  }
1914
+
1915
+ // src/babel/utils/componentSupport.ts
1863
1916
  function getComponentModifierSupport(jsxElement, t) {
1864
1917
  if (!t.isJSXOpeningElement(jsxElement)) {
1865
1918
  return null;
@@ -1882,24 +1935,40 @@ function getComponentModifierSupport(jsxElement, t) {
1882
1935
  case "Pressable":
1883
1936
  return { component: "Pressable", supportedModifiers: ["active", "hover", "focus", "disabled"] };
1884
1937
  case "TextInput":
1885
- return { component: "TextInput", supportedModifiers: ["focus", "disabled"] };
1938
+ return { component: "TextInput", supportedModifiers: ["focus", "disabled", "placeholder"] };
1886
1939
  default:
1887
1940
  return null;
1888
1941
  }
1889
1942
  }
1890
- function processDynamicExpression(expression, state, t) {
1943
+ function getStatePropertyForModifier(modifier) {
1944
+ switch (modifier) {
1945
+ case "active":
1946
+ return "pressed";
1947
+ case "hover":
1948
+ return "hovered";
1949
+ case "focus":
1950
+ return "focused";
1951
+ case "disabled":
1952
+ return "disabled";
1953
+ default:
1954
+ return "pressed";
1955
+ }
1956
+ }
1957
+
1958
+ // src/babel/utils/dynamicProcessing.ts
1959
+ function processDynamicExpression(expression, state, parseClassName2, generateStyleKey2, t) {
1891
1960
  if (t.isTemplateLiteral(expression)) {
1892
- return processTemplateLiteral(expression, state, t);
1961
+ return processTemplateLiteral(expression, state, parseClassName2, generateStyleKey2, t);
1893
1962
  }
1894
1963
  if (t.isConditionalExpression(expression)) {
1895
- return processConditionalExpression(expression, state, t);
1964
+ return processConditionalExpression(expression, state, parseClassName2, generateStyleKey2, t);
1896
1965
  }
1897
1966
  if (t.isLogicalExpression(expression)) {
1898
- return processLogicalExpression(expression, state, t);
1967
+ return processLogicalExpression(expression, state, parseClassName2, generateStyleKey2, t);
1899
1968
  }
1900
1969
  return null;
1901
1970
  }
1902
- function processTemplateLiteral(node, state, t) {
1971
+ function processTemplateLiteral(node, state, parseClassName2, generateStyleKey2, t) {
1903
1972
  const parts = [];
1904
1973
  const staticParts = [];
1905
1974
  for (let i = 0; i < node.quasis.length; i++) {
@@ -1912,12 +1981,18 @@ function processTemplateLiteral(node, state, t) {
1912
1981
  const styleKey = generateStyleKey2(cls);
1913
1982
  state.styleRegistry.set(styleKey, styleObject);
1914
1983
  staticParts.push(cls);
1915
- parts.push(t.memberExpression(t.identifier(STYLES_IDENTIFIER), t.identifier(styleKey)));
1984
+ parts.push(t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey)));
1916
1985
  }
1917
1986
  }
1918
1987
  if (i < node.expressions.length) {
1919
1988
  const expr = node.expressions[i];
1920
- const result = processDynamicExpression(expr, state, t);
1989
+ const result = processDynamicExpression(
1990
+ expr,
1991
+ state,
1992
+ parseClassName2,
1993
+ generateStyleKey2,
1994
+ t
1995
+ );
1921
1996
  if (result) {
1922
1997
  parts.push(result.expression);
1923
1998
  } else {
@@ -1934,9 +2009,9 @@ function processTemplateLiteral(node, state, t) {
1934
2009
  staticParts: staticParts.length > 0 ? staticParts : void 0
1935
2010
  };
1936
2011
  }
1937
- function processConditionalExpression(node, state, t) {
1938
- const consequent = processStringOrExpression(node.consequent, state, t);
1939
- const alternate = processStringOrExpression(node.alternate, state, t);
2012
+ function processConditionalExpression(node, state, parseClassName2, generateStyleKey2, t) {
2013
+ const consequent = processStringOrExpression(node.consequent, state, parseClassName2, generateStyleKey2, t);
2014
+ const alternate = processStringOrExpression(node.alternate, state, parseClassName2, generateStyleKey2, t);
1940
2015
  if (!consequent && !alternate) {
1941
2016
  return null;
1942
2017
  }
@@ -1947,18 +2022,18 @@ function processConditionalExpression(node, state, t) {
1947
2022
  );
1948
2023
  return { expression };
1949
2024
  }
1950
- function processLogicalExpression(node, state, t) {
2025
+ function processLogicalExpression(node, state, parseClassName2, generateStyleKey2, t) {
1951
2026
  if (node.operator !== "&&") {
1952
2027
  return null;
1953
2028
  }
1954
- const right = processStringOrExpression(node.right, state, t);
2029
+ const right = processStringOrExpression(node.right, state, parseClassName2, generateStyleKey2, t);
1955
2030
  if (!right) {
1956
2031
  return null;
1957
2032
  }
1958
2033
  const expression = t.logicalExpression("&&", node.left, right);
1959
2034
  return { expression };
1960
2035
  }
1961
- function processStringOrExpression(node, state, t) {
2036
+ function processStringOrExpression(node, state, parseClassName2, generateStyleKey2, t) {
1962
2037
  if (t.isStringLiteral(node)) {
1963
2038
  const className = node.value.trim();
1964
2039
  if (!className) {
@@ -1967,31 +2042,33 @@ function processStringOrExpression(node, state, t) {
1967
2042
  const styleObject = parseClassName2(className, state.customColors);
1968
2043
  const styleKey = generateStyleKey2(className);
1969
2044
  state.styleRegistry.set(styleKey, styleObject);
1970
- return t.memberExpression(t.identifier(STYLES_IDENTIFIER), t.identifier(styleKey));
2045
+ return t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(styleKey));
1971
2046
  }
1972
2047
  if (t.isConditionalExpression(node)) {
1973
- const result = processConditionalExpression(node, state, t);
2048
+ const result = processConditionalExpression(node, state, parseClassName2, generateStyleKey2, t);
1974
2049
  return result?.expression ?? null;
1975
2050
  }
1976
2051
  if (t.isLogicalExpression(node)) {
1977
- const result = processLogicalExpression(node, state, t);
2052
+ const result = processLogicalExpression(node, state, parseClassName2, generateStyleKey2, t);
1978
2053
  return result?.expression ?? null;
1979
2054
  }
1980
2055
  if (t.isTemplateLiteral(node)) {
1981
- const result = processTemplateLiteral(node, state, t);
2056
+ const result = processTemplateLiteral(node, state, parseClassName2, generateStyleKey2, t);
1982
2057
  return result?.expression ?? null;
1983
2058
  }
1984
2059
  return null;
1985
2060
  }
1986
- function processStaticClassNameWithModifiers(className, state, t) {
1987
- const { baseClasses, modifierClasses } = splitModifierClasses(className);
2061
+
2062
+ // src/babel/utils/modifierProcessing.ts
2063
+ function processStaticClassNameWithModifiers(className, state, parseClassName2, generateStyleKey2, splitModifierClasses2, t) {
2064
+ const { baseClasses, modifierClasses } = splitModifierClasses2(className);
1988
2065
  let baseStyleExpression = null;
1989
2066
  if (baseClasses.length > 0) {
1990
2067
  const baseClassName = baseClasses.join(" ");
1991
2068
  const baseStyleObject = parseClassName2(baseClassName, state.customColors);
1992
2069
  const baseStyleKey = generateStyleKey2(baseClassName);
1993
2070
  state.styleRegistry.set(baseStyleKey, baseStyleObject);
1994
- baseStyleExpression = t.memberExpression(t.identifier(STYLES_IDENTIFIER), t.identifier(baseStyleKey));
2071
+ baseStyleExpression = t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey));
1995
2072
  }
1996
2073
  const modifiersByType = /* @__PURE__ */ new Map();
1997
2074
  for (const mod of modifierClasses) {
@@ -2016,7 +2093,7 @@ function processStaticClassNameWithModifiers(className, state, t) {
2016
2093
  const conditionalExpression = t.logicalExpression(
2017
2094
  "&&",
2018
2095
  t.identifier(stateProperty),
2019
- t.memberExpression(t.identifier(STYLES_IDENTIFIER), t.identifier(modifierStyleKey))
2096
+ t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(modifierStyleKey))
2020
2097
  );
2021
2098
  styleArrayElements.push(conditionalExpression);
2022
2099
  }
@@ -2025,20 +2102,6 @@ function processStaticClassNameWithModifiers(className, state, t) {
2025
2102
  }
2026
2103
  return t.arrayExpression(styleArrayElements);
2027
2104
  }
2028
- function getStatePropertyForModifier(modifier) {
2029
- switch (modifier) {
2030
- case "active":
2031
- return "pressed";
2032
- case "hover":
2033
- return "hovered";
2034
- case "focus":
2035
- return "focused";
2036
- case "disabled":
2037
- return "disabled";
2038
- default:
2039
- return "pressed";
2040
- }
2041
- }
2042
2105
  function createStyleFunction(styleExpression, modifierTypes, t) {
2043
2106
  const paramProperties = [];
2044
2107
  const usedStateProps = /* @__PURE__ */ new Set();
@@ -2054,9 +2117,236 @@ function createStyleFunction(styleExpression, modifierTypes, t) {
2054
2117
  const param = t.objectPattern(paramProperties);
2055
2118
  return t.arrowFunctionExpression([param], styleExpression);
2056
2119
  }
2057
- function reactNativeTailwindBabelPlugin({
2058
- types: t
2059
- }) {
2120
+
2121
+ // src/babel/utils/styleInjection.ts
2122
+ function addStyleSheetImport(path2, t) {
2123
+ const importDeclaration = t.importDeclaration(
2124
+ [t.importSpecifier(t.identifier("StyleSheet"), t.identifier("StyleSheet"))],
2125
+ t.stringLiteral("react-native")
2126
+ );
2127
+ path2.unshiftContainer("body", importDeclaration);
2128
+ }
2129
+ function injectStylesAtTop(path2, styleRegistry, stylesIdentifier, t) {
2130
+ const styleProperties = [];
2131
+ for (const [key, styleObject] of styleRegistry) {
2132
+ const properties = Object.entries(styleObject).map(([styleProp, styleValue]) => {
2133
+ let valueNode;
2134
+ if (typeof styleValue === "number") {
2135
+ valueNode = t.numericLiteral(styleValue);
2136
+ } else if (typeof styleValue === "string") {
2137
+ valueNode = t.stringLiteral(styleValue);
2138
+ } else {
2139
+ valueNode = t.valueToNode(styleValue);
2140
+ }
2141
+ return t.objectProperty(t.identifier(styleProp), valueNode);
2142
+ });
2143
+ styleProperties.push(t.objectProperty(t.identifier(key), t.objectExpression(properties)));
2144
+ }
2145
+ const styleSheet = t.variableDeclaration("const", [
2146
+ t.variableDeclarator(
2147
+ t.identifier(stylesIdentifier),
2148
+ t.callExpression(t.memberExpression(t.identifier("StyleSheet"), t.identifier("create")), [
2149
+ t.objectExpression(styleProperties)
2150
+ ])
2151
+ )
2152
+ ]);
2153
+ const body = path2.node.body;
2154
+ let insertIndex = 0;
2155
+ for (let i = 0; i < body.length; i++) {
2156
+ if (t.isImportDeclaration(body[i])) {
2157
+ insertIndex = i + 1;
2158
+ } else {
2159
+ break;
2160
+ }
2161
+ }
2162
+ body.splice(insertIndex, 0, styleSheet);
2163
+ }
2164
+
2165
+ // src/babel/utils/styleTransforms.ts
2166
+ function getStyleExpression(styleAttribute, t) {
2167
+ const value = styleAttribute.value;
2168
+ if (!t.isJSXExpressionContainer(value)) return null;
2169
+ const expression = value.expression;
2170
+ if (t.isJSXEmptyExpression(expression)) return null;
2171
+ return expression;
2172
+ }
2173
+ function findStyleAttribute(path2, targetStyleProp, t) {
2174
+ const parent = path2.parent;
2175
+ return parent.attributes.find(
2176
+ (attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === targetStyleProp
2177
+ );
2178
+ }
2179
+ function replaceWithStyleAttribute(classNamePath, styleKey, targetStyleProp, stylesIdentifier, t) {
2180
+ const styleAttribute = t.jsxAttribute(
2181
+ t.jsxIdentifier(targetStyleProp),
2182
+ t.jsxExpressionContainer(t.memberExpression(t.identifier(stylesIdentifier), t.identifier(styleKey)))
2183
+ );
2184
+ classNamePath.replaceWith(styleAttribute);
2185
+ }
2186
+ function mergeStyleAttribute(classNamePath, styleAttribute, styleKey, stylesIdentifier, t) {
2187
+ const existingStyle = getStyleExpression(styleAttribute, t);
2188
+ if (!existingStyle) return;
2189
+ if (t.isArrowFunctionExpression(existingStyle) || t.isFunctionExpression(existingStyle)) {
2190
+ const paramIdentifier = t.identifier("_state");
2191
+ const functionCall = t.callExpression(existingStyle, [paramIdentifier]);
2192
+ const mergedArray = t.arrayExpression([
2193
+ t.memberExpression(t.identifier(stylesIdentifier), t.identifier(styleKey)),
2194
+ functionCall
2195
+ ]);
2196
+ const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
2197
+ styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
2198
+ } else {
2199
+ const styleArray = t.arrayExpression([
2200
+ t.memberExpression(t.identifier(stylesIdentifier), t.identifier(styleKey)),
2201
+ existingStyle
2202
+ ]);
2203
+ styleAttribute.value = t.jsxExpressionContainer(styleArray);
2204
+ }
2205
+ classNamePath.remove();
2206
+ }
2207
+ function replaceDynamicWithStyleAttribute(classNamePath, result, targetStyleProp, t) {
2208
+ const styleAttribute = t.jsxAttribute(
2209
+ t.jsxIdentifier(targetStyleProp),
2210
+ t.jsxExpressionContainer(result.expression)
2211
+ );
2212
+ classNamePath.replaceWith(styleAttribute);
2213
+ }
2214
+ function mergeDynamicStyleAttribute(classNamePath, styleAttribute, result, t) {
2215
+ const existingStyle = getStyleExpression(styleAttribute, t);
2216
+ if (!existingStyle) return;
2217
+ if (t.isArrowFunctionExpression(existingStyle) || t.isFunctionExpression(existingStyle)) {
2218
+ const paramIdentifier = t.identifier("_state");
2219
+ const functionCall = t.callExpression(existingStyle, [paramIdentifier]);
2220
+ const mergedArray = t.arrayExpression([result.expression, functionCall]);
2221
+ const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
2222
+ styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
2223
+ } else {
2224
+ let styleArray;
2225
+ if (t.isArrayExpression(existingStyle)) {
2226
+ styleArray = t.arrayExpression([result.expression, ...existingStyle.elements]);
2227
+ } else {
2228
+ styleArray = t.arrayExpression([result.expression, existingStyle]);
2229
+ }
2230
+ styleAttribute.value = t.jsxExpressionContainer(styleArray);
2231
+ }
2232
+ classNamePath.remove();
2233
+ }
2234
+ function replaceWithStyleFunctionAttribute(classNamePath, styleFunctionExpression, targetStyleProp, t) {
2235
+ const styleAttribute = t.jsxAttribute(
2236
+ t.jsxIdentifier(targetStyleProp),
2237
+ t.jsxExpressionContainer(styleFunctionExpression)
2238
+ );
2239
+ classNamePath.replaceWith(styleAttribute);
2240
+ }
2241
+ function mergeStyleFunctionAttribute(classNamePath, styleAttribute, styleFunctionExpression, t) {
2242
+ const existingStyle = getStyleExpression(styleAttribute, t);
2243
+ if (!existingStyle) return;
2244
+ if (t.isArrowFunctionExpression(existingStyle) || t.isFunctionExpression(existingStyle)) {
2245
+ const paramIdentifier = t.identifier("_state");
2246
+ const newFunctionCall = t.callExpression(styleFunctionExpression, [paramIdentifier]);
2247
+ const existingFunctionCall = t.callExpression(existingStyle, [paramIdentifier]);
2248
+ const mergedArray = t.arrayExpression([newFunctionCall, existingFunctionCall]);
2249
+ const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
2250
+ styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
2251
+ } else {
2252
+ const paramIdentifier = t.identifier("_state");
2253
+ const functionCall = t.callExpression(styleFunctionExpression, [paramIdentifier]);
2254
+ const mergedArray = t.arrayExpression([functionCall, existingStyle]);
2255
+ const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
2256
+ styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
2257
+ }
2258
+ classNamePath.remove();
2259
+ }
2260
+ function addOrMergePlaceholderTextColorProp(jsxOpeningElement, color, t) {
2261
+ const existingProp = jsxOpeningElement.attributes.find(
2262
+ (attr) => t.isJSXAttribute(attr) && attr.name.name === "placeholderTextColor"
2263
+ );
2264
+ if (existingProp) {
2265
+ if (process.env.NODE_ENV !== "production") {
2266
+ console.warn(
2267
+ `[react-native-tailwind] placeholderTextColor prop will be overridden by className placeholder: modifier. Remove the explicit prop or the placeholder: modifier to avoid confusion.`
2268
+ );
2269
+ }
2270
+ existingProp.value = t.stringLiteral(color);
2271
+ } else {
2272
+ const newProp = t.jsxAttribute(t.jsxIdentifier("placeholderTextColor"), t.stringLiteral(color));
2273
+ jsxOpeningElement.attributes.push(newProp);
2274
+ }
2275
+ }
2276
+
2277
+ // src/babel/utils/twProcessing.ts
2278
+ function processTwCall(className, path2, state, parseClassName2, generateStyleKey2, splitModifierClasses2, t) {
2279
+ const { baseClasses, modifierClasses } = splitModifierClasses2(className);
2280
+ const objectProperties = [];
2281
+ if (baseClasses.length > 0) {
2282
+ const baseClassName = baseClasses.join(" ");
2283
+ const baseStyleObject = parseClassName2(baseClassName, state.customColors);
2284
+ const baseStyleKey = generateStyleKey2(baseClassName);
2285
+ state.styleRegistry.set(baseStyleKey, baseStyleObject);
2286
+ objectProperties.push(
2287
+ t.objectProperty(
2288
+ t.identifier("style"),
2289
+ t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(baseStyleKey))
2290
+ )
2291
+ );
2292
+ } else {
2293
+ objectProperties.push(t.objectProperty(t.identifier("style"), t.objectExpression([])));
2294
+ }
2295
+ const modifiersByType = /* @__PURE__ */ new Map();
2296
+ for (const mod of modifierClasses) {
2297
+ if (!modifiersByType.has(mod.modifier)) {
2298
+ modifiersByType.set(mod.modifier, []);
2299
+ }
2300
+ const modGroup = modifiersByType.get(mod.modifier);
2301
+ if (modGroup) {
2302
+ modGroup.push(mod);
2303
+ }
2304
+ }
2305
+ for (const [modifierType, modifiers] of modifiersByType) {
2306
+ const modifierClassNames = modifiers.map((m) => m.baseClass).join(" ");
2307
+ const modifierStyleObject = parseClassName2(modifierClassNames, state.customColors);
2308
+ const modifierStyleKey = generateStyleKey2(`${modifierType}_${modifierClassNames}`);
2309
+ state.styleRegistry.set(modifierStyleKey, modifierStyleObject);
2310
+ const propertyName = `${modifierType}Style`;
2311
+ objectProperties.push(
2312
+ t.objectProperty(
2313
+ t.identifier(propertyName),
2314
+ t.memberExpression(t.identifier(state.stylesIdentifier), t.identifier(modifierStyleKey))
2315
+ )
2316
+ );
2317
+ }
2318
+ const twStyleObject = t.objectExpression(objectProperties);
2319
+ path2.replaceWith(twStyleObject);
2320
+ }
2321
+ function removeTwImports(path2, t) {
2322
+ path2.traverse({
2323
+ ImportDeclaration(importPath) {
2324
+ const node = importPath.node;
2325
+ if (node.source.value !== "@mgcrea/react-native-tailwind") {
2326
+ return;
2327
+ }
2328
+ const remainingSpecifiers = node.specifiers.filter((spec) => {
2329
+ if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
2330
+ const importedName = spec.imported.name;
2331
+ return importedName !== "tw" && importedName !== "twStyle";
2332
+ }
2333
+ return true;
2334
+ });
2335
+ if (remainingSpecifiers.length === 0) {
2336
+ importPath.remove();
2337
+ } else if (remainingSpecifiers.length < node.specifiers.length) {
2338
+ node.specifiers = remainingSpecifiers;
2339
+ }
2340
+ }
2341
+ });
2342
+ }
2343
+
2344
+ // src/babel/plugin.ts
2345
+ var DEFAULT_STYLES_IDENTIFIER = "_twStyles";
2346
+ function reactNativeTailwindBabelPlugin({ types: t }, options) {
2347
+ const attributes = options?.attributes ?? [...DEFAULT_CLASS_ATTRIBUTES];
2348
+ const { exactMatches, patterns } = buildAttributeMatchers(attributes);
2349
+ const stylesIdentifier = options?.stylesIdentifier ?? DEFAULT_STYLES_IDENTIFIER;
2060
2350
  return {
2061
2351
  name: "react-native-tailwind",
2062
2352
  visitor: {
@@ -2065,19 +2355,27 @@ function reactNativeTailwindBabelPlugin({
2065
2355
  state.styleRegistry = /* @__PURE__ */ new Map();
2066
2356
  state.hasClassNames = false;
2067
2357
  state.hasStyleSheetImport = false;
2358
+ state.supportedAttributes = exactMatches;
2359
+ state.attributePatterns = patterns;
2360
+ state.stylesIdentifier = stylesIdentifier;
2361
+ state.twImportNames = /* @__PURE__ */ new Set();
2362
+ state.hasTwImport = false;
2068
2363
  state.customColors = extractCustomColors(state.file.opts.filename ?? "");
2069
2364
  },
2070
2365
  exit(path2, state) {
2366
+ if (state.hasTwImport) {
2367
+ removeTwImports(path2, t);
2368
+ }
2071
2369
  if (!state.hasClassNames || state.styleRegistry.size === 0) {
2072
2370
  return;
2073
2371
  }
2074
2372
  if (!state.hasStyleSheetImport) {
2075
2373
  addStyleSheetImport(path2, t);
2076
2374
  }
2077
- injectStyles(path2, state.styleRegistry, t);
2375
+ injectStylesAtTop(path2, state.styleRegistry, state.stylesIdentifier, t);
2078
2376
  }
2079
2377
  },
2080
- // Check if StyleSheet is already imported
2378
+ // Check if StyleSheet is already imported and track tw/twStyle imports
2081
2379
  ImportDeclaration(path2, state) {
2082
2380
  const node = path2.node;
2083
2381
  if (node.source.value === "react-native") {
@@ -2095,11 +2393,94 @@ function reactNativeTailwindBabelPlugin({
2095
2393
  state.hasStyleSheetImport = true;
2096
2394
  }
2097
2395
  }
2396
+ if (node.source.value === "@mgcrea/react-native-tailwind") {
2397
+ const specifiers = node.specifiers;
2398
+ specifiers.forEach((spec) => {
2399
+ if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
2400
+ const importedName = spec.imported.name;
2401
+ if (importedName === "tw" || importedName === "twStyle") {
2402
+ const localName = spec.local.name;
2403
+ state.twImportNames.add(localName);
2404
+ state.hasTwImport = true;
2405
+ }
2406
+ }
2407
+ });
2408
+ }
2409
+ },
2410
+ // Handle tw`...` tagged template expressions
2411
+ TaggedTemplateExpression(path2, state) {
2412
+ const node = path2.node;
2413
+ if (!t.isIdentifier(node.tag)) {
2414
+ return;
2415
+ }
2416
+ const tagName = node.tag.name;
2417
+ if (!state.twImportNames.has(tagName)) {
2418
+ return;
2419
+ }
2420
+ const quasi = node.quasi;
2421
+ if (!t.isTemplateLiteral(quasi)) {
2422
+ return;
2423
+ }
2424
+ if (quasi.expressions.length > 0) {
2425
+ if (process.env.NODE_ENV !== "production") {
2426
+ console.warn(
2427
+ `[react-native-tailwind] Dynamic tw\`...\` with interpolations is not supported at ${state.file.opts.filename ?? "unknown"}. Use style prop for dynamic values.`
2428
+ );
2429
+ }
2430
+ return;
2431
+ }
2432
+ const className = quasi.quasis[0]?.value.cooked?.trim() ?? "";
2433
+ if (!className) {
2434
+ path2.replaceWith(
2435
+ t.objectExpression([t.objectProperty(t.identifier("style"), t.objectExpression([]))])
2436
+ );
2437
+ return;
2438
+ }
2439
+ state.hasClassNames = true;
2440
+ processTwCall(className, path2, state, parseClassName, generateStyleKey, splitModifierClasses, t);
2441
+ },
2442
+ // Handle twStyle('...') call expressions
2443
+ CallExpression(path2, state) {
2444
+ const node = path2.node;
2445
+ if (!t.isIdentifier(node.callee)) {
2446
+ return;
2447
+ }
2448
+ const calleeName = node.callee.name;
2449
+ if (!state.twImportNames.has(calleeName)) {
2450
+ return;
2451
+ }
2452
+ if (node.arguments.length !== 1) {
2453
+ if (process.env.NODE_ENV !== "production") {
2454
+ console.warn(
2455
+ `[react-native-tailwind] twStyle() expects exactly one argument at ${state.file.opts.filename ?? "unknown"}`
2456
+ );
2457
+ }
2458
+ return;
2459
+ }
2460
+ const arg = node.arguments[0];
2461
+ if (!t.isStringLiteral(arg)) {
2462
+ if (process.env.NODE_ENV !== "production") {
2463
+ console.warn(
2464
+ `[react-native-tailwind] twStyle() only supports static string literals at ${state.file.opts.filename ?? "unknown"}. Use style prop for dynamic values.`
2465
+ );
2466
+ }
2467
+ return;
2468
+ }
2469
+ const className = arg.value.trim();
2470
+ if (!className) {
2471
+ path2.replaceWith(t.identifier("undefined"));
2472
+ return;
2473
+ }
2474
+ state.hasClassNames = true;
2475
+ processTwCall(className, path2, state, parseClassName, generateStyleKey, splitModifierClasses, t);
2098
2476
  },
2099
2477
  JSXAttribute(path2, state) {
2100
2478
  const node = path2.node;
2479
+ if (!t.isJSXIdentifier(node.name)) {
2480
+ return;
2481
+ }
2101
2482
  const attributeName = node.name.name;
2102
- if (!SUPPORTED_CLASS_ATTRIBUTES.includes(attributeName)) {
2483
+ if (!isAttributeSupported(attributeName, state.supportedAttributes, state.attributePatterns)) {
2103
2484
  return;
2104
2485
  }
2105
2486
  const value = node.value;
@@ -2112,11 +2493,30 @@ function reactNativeTailwindBabelPlugin({
2112
2493
  }
2113
2494
  state.hasClassNames = true;
2114
2495
  const { baseClasses, modifierClasses } = splitModifierClasses(className);
2115
- if (modifierClasses.length > 0) {
2496
+ const placeholderModifiers = modifierClasses.filter((m) => m.modifier === "placeholder");
2497
+ const stateModifiers = modifierClasses.filter((m) => m.modifier !== "placeholder");
2498
+ if (placeholderModifiers.length > 0) {
2499
+ const jsxOpeningElement = path2.parent;
2500
+ const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
2501
+ if (componentSupport?.supportedModifiers.includes("placeholder")) {
2502
+ const placeholderClasses = placeholderModifiers.map((m) => m.baseClass).join(" ");
2503
+ const placeholderColor = parsePlaceholderClasses(placeholderClasses, state.customColors);
2504
+ if (placeholderColor) {
2505
+ addOrMergePlaceholderTextColorProp(jsxOpeningElement, placeholderColor, t);
2506
+ }
2507
+ } else {
2508
+ if (process.env.NODE_ENV !== "production") {
2509
+ console.warn(
2510
+ `[react-native-tailwind] placeholder: modifier can only be used on TextInput component at ${state.file.opts.filename ?? "unknown"}`
2511
+ );
2512
+ }
2513
+ }
2514
+ }
2515
+ if (stateModifiers.length > 0) {
2116
2516
  const jsxOpeningElement = path2.parent;
2117
2517
  const componentSupport = getComponentModifierSupport(jsxOpeningElement, t);
2118
2518
  if (componentSupport) {
2119
- const usedModifiers = Array.from(new Set(modifierClasses.map((m) => m.modifier)));
2519
+ const usedModifiers = Array.from(new Set(stateModifiers.map((m) => m.modifier)));
2120
2520
  const unsupportedModifiers = usedModifiers.filter(
2121
2521
  (mod) => !componentSupport.supportedModifiers.includes(mod)
2122
2522
  );
@@ -2126,7 +2526,7 @@ function reactNativeTailwindBabelPlugin({
2126
2526
  `[react-native-tailwind] Modifiers (${unsupportedModifiers.map((m) => `${m}:`).join(", ")}) are not supported on ${componentSupport.component} component at ${state.file.opts.filename ?? "unknown"}. Supported modifiers: ${componentSupport.supportedModifiers.join(", ")}`
2127
2527
  );
2128
2528
  }
2129
- const supportedModifierClasses = modifierClasses.filter(
2529
+ const supportedModifierClasses = stateModifiers.filter(
2130
2530
  (m) => componentSupport.supportedModifiers.includes(m.modifier)
2131
2531
  );
2132
2532
  if (supportedModifierClasses.length === 0) {
@@ -2135,14 +2535,14 @@ function reactNativeTailwindBabelPlugin({
2135
2535
  const styleExpression = processStaticClassNameWithModifiers(
2136
2536
  filteredClassName.trim(),
2137
2537
  state,
2538
+ parseClassName,
2539
+ generateStyleKey,
2540
+ splitModifierClasses,
2138
2541
  t
2139
2542
  );
2140
2543
  const modifierTypes = Array.from(new Set(supportedModifierClasses.map((m) => m.modifier)));
2141
2544
  const styleFunctionExpression = createStyleFunction(styleExpression, modifierTypes, t);
2142
- const parent2 = path2.parent;
2143
- const styleAttribute2 = parent2.attributes.find(
2144
- (attr) => t.isJSXAttribute(attr) && attr.name.name === targetStyleProp
2145
- );
2545
+ const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
2146
2546
  if (styleAttribute2) {
2147
2547
  mergeStyleFunctionAttribute(path2, styleAttribute2, styleFunctionExpression, t);
2148
2548
  } else {
@@ -2151,13 +2551,17 @@ function reactNativeTailwindBabelPlugin({
2151
2551
  return;
2152
2552
  }
2153
2553
  } else {
2154
- const styleExpression = processStaticClassNameWithModifiers(className, state, t);
2554
+ const styleExpression = processStaticClassNameWithModifiers(
2555
+ className,
2556
+ state,
2557
+ parseClassName,
2558
+ generateStyleKey,
2559
+ splitModifierClasses,
2560
+ t
2561
+ );
2155
2562
  const modifierTypes = usedModifiers;
2156
2563
  const styleFunctionExpression = createStyleFunction(styleExpression, modifierTypes, t);
2157
- const parent2 = path2.parent;
2158
- const styleAttribute2 = parent2.attributes.find(
2159
- (attr) => t.isJSXAttribute(attr) && attr.name.name === targetStyleProp
2160
- );
2564
+ const styleAttribute2 = findStyleAttribute(path2, targetStyleProp, t);
2161
2565
  if (styleAttribute2) {
2162
2566
  mergeStyleFunctionAttribute(path2, styleAttribute2, styleFunctionExpression, t);
2163
2567
  } else {
@@ -2167,24 +2571,26 @@ function reactNativeTailwindBabelPlugin({
2167
2571
  }
2168
2572
  } else {
2169
2573
  if (process.env.NODE_ENV !== "production") {
2170
- const usedModifiers = Array.from(new Set(modifierClasses.map((m) => m.modifier)));
2574
+ const usedModifiers = Array.from(new Set(stateModifiers.map((m) => m.modifier)));
2171
2575
  console.warn(
2172
2576
  `[react-native-tailwind] Modifiers (${usedModifiers.map((m) => `${m}:`).join(", ")}) can only be used on compatible components (Pressable, TextInput). Found on unsupported element at ${state.file.opts.filename ?? "unknown"}`
2173
2577
  );
2174
2578
  }
2175
2579
  }
2176
2580
  }
2177
- const styleObject = parseClassName2(className, state.customColors);
2178
- const styleKey = generateStyleKey2(className);
2581
+ const classNameForStyle = baseClasses.join(" ");
2582
+ if (!classNameForStyle) {
2583
+ path2.remove();
2584
+ return;
2585
+ }
2586
+ const styleObject = parseClassName(classNameForStyle, state.customColors);
2587
+ const styleKey = generateStyleKey(classNameForStyle);
2179
2588
  state.styleRegistry.set(styleKey, styleObject);
2180
- const parent = path2.parent;
2181
- const styleAttribute = parent.attributes.find(
2182
- (attr) => t.isJSXAttribute(attr) && attr.name.name === targetStyleProp
2183
- );
2589
+ const styleAttribute = findStyleAttribute(path2, targetStyleProp, t);
2184
2590
  if (styleAttribute) {
2185
- mergeStyleAttribute(path2, styleAttribute, styleKey, t);
2591
+ mergeStyleAttribute(path2, styleAttribute, styleKey, state.stylesIdentifier, t);
2186
2592
  } else {
2187
- replaceWithStyleAttribute(path2, styleKey, targetStyleProp, t);
2593
+ replaceWithStyleAttribute(path2, styleKey, targetStyleProp, state.stylesIdentifier, t);
2188
2594
  }
2189
2595
  return;
2190
2596
  }
@@ -2194,13 +2600,10 @@ function reactNativeTailwindBabelPlugin({
2194
2600
  return;
2195
2601
  }
2196
2602
  try {
2197
- const result = processDynamicExpression(expression, state, t);
2603
+ const result = processDynamicExpression(expression, state, parseClassName, generateStyleKey, t);
2198
2604
  if (result) {
2199
2605
  state.hasClassNames = true;
2200
- const parent = path2.parent;
2201
- const styleAttribute = parent.attributes.find(
2202
- (attr) => t.isJSXAttribute(attr) && attr.name.name === targetStyleProp
2203
- );
2606
+ const styleAttribute = findStyleAttribute(path2, targetStyleProp, t);
2204
2607
  if (styleAttribute) {
2205
2608
  mergeDynamicStyleAttribute(path2, styleAttribute, result, t);
2206
2609
  } else {
@@ -2226,101 +2629,3 @@ function reactNativeTailwindBabelPlugin({
2226
2629
  }
2227
2630
  };
2228
2631
  }
2229
- function addStyleSheetImport(path2, t) {
2230
- const importDeclaration = t.importDeclaration(
2231
- [t.importSpecifier(t.identifier("StyleSheet"), t.identifier("StyleSheet"))],
2232
- t.stringLiteral("react-native")
2233
- );
2234
- path2.unshiftContainer("body", importDeclaration);
2235
- }
2236
- function replaceWithStyleAttribute(classNamePath, styleKey, targetStyleProp, t) {
2237
- const styleAttribute = t.jsxAttribute(
2238
- t.jsxIdentifier(targetStyleProp),
2239
- t.jsxExpressionContainer(t.memberExpression(t.identifier(STYLES_IDENTIFIER), t.identifier(styleKey)))
2240
- );
2241
- classNamePath.replaceWith(styleAttribute);
2242
- }
2243
- function mergeStyleAttribute(classNamePath, styleAttribute, styleKey, t) {
2244
- const existingStyle = styleAttribute.value.expression;
2245
- const styleArray = t.arrayExpression([
2246
- t.memberExpression(t.identifier(STYLES_IDENTIFIER), t.identifier(styleKey)),
2247
- existingStyle
2248
- ]);
2249
- styleAttribute.value = t.jsxExpressionContainer(styleArray);
2250
- classNamePath.remove();
2251
- }
2252
- function replaceDynamicWithStyleAttribute(classNamePath, result, targetStyleProp, t) {
2253
- const styleAttribute = t.jsxAttribute(
2254
- t.jsxIdentifier(targetStyleProp),
2255
- t.jsxExpressionContainer(result.expression)
2256
- );
2257
- classNamePath.replaceWith(styleAttribute);
2258
- }
2259
- function mergeDynamicStyleAttribute(classNamePath, styleAttribute, result, t) {
2260
- const existingStyle = styleAttribute.value.expression;
2261
- let styleArray;
2262
- if (t.isArrayExpression(existingStyle)) {
2263
- styleArray = t.arrayExpression([result.expression, ...existingStyle.elements]);
2264
- } else {
2265
- styleArray = t.arrayExpression([result.expression, existingStyle]);
2266
- }
2267
- styleAttribute.value = t.jsxExpressionContainer(styleArray);
2268
- classNamePath.remove();
2269
- }
2270
- function replaceWithStyleFunctionAttribute(classNamePath, styleFunctionExpression, targetStyleProp, t) {
2271
- const styleAttribute = t.jsxAttribute(
2272
- t.jsxIdentifier(targetStyleProp),
2273
- t.jsxExpressionContainer(styleFunctionExpression)
2274
- );
2275
- classNamePath.replaceWith(styleAttribute);
2276
- }
2277
- function mergeStyleFunctionAttribute(classNamePath, styleAttribute, styleFunctionExpression, t) {
2278
- const existingStyle = styleAttribute.value.expression;
2279
- if (t.isArrowFunctionExpression(existingStyle) || t.isFunctionExpression(existingStyle)) {
2280
- const paramIdentifier = t.identifier("_state");
2281
- const newFunctionCall = t.callExpression(styleFunctionExpression, [paramIdentifier]);
2282
- const existingFunctionCall = t.callExpression(existingStyle, [paramIdentifier]);
2283
- const mergedArray = t.arrayExpression([newFunctionCall, existingFunctionCall]);
2284
- const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
2285
- styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
2286
- } else {
2287
- const paramIdentifier = t.identifier("_state");
2288
- const functionCall = t.callExpression(styleFunctionExpression, [paramIdentifier]);
2289
- const mergedArray = t.arrayExpression([functionCall, existingStyle]);
2290
- const wrapperFunction = t.arrowFunctionExpression([paramIdentifier], mergedArray);
2291
- styleAttribute.value = t.jsxExpressionContainer(wrapperFunction);
2292
- }
2293
- classNamePath.remove();
2294
- }
2295
- function injectStyles(path2, styleRegistry, t) {
2296
- const styleProperties = [];
2297
- for (const [key, styleObject] of styleRegistry) {
2298
- const properties = Object.entries(styleObject).map(([styleProp, styleValue]) => {
2299
- let valueNode;
2300
- if (typeof styleValue === "number") {
2301
- valueNode = t.numericLiteral(styleValue);
2302
- } else if (typeof styleValue === "string") {
2303
- valueNode = t.stringLiteral(styleValue);
2304
- } else {
2305
- valueNode = t.valueToNode(styleValue);
2306
- }
2307
- return t.objectProperty(t.identifier(styleProp), valueNode);
2308
- });
2309
- styleProperties.push(t.objectProperty(t.identifier(key), t.objectExpression(properties)));
2310
- }
2311
- const styleSheet = t.variableDeclaration("const", [
2312
- t.variableDeclarator(
2313
- t.identifier(STYLES_IDENTIFIER),
2314
- t.callExpression(t.memberExpression(t.identifier("StyleSheet"), t.identifier("create")), [
2315
- t.objectExpression(styleProperties)
2316
- ])
2317
- )
2318
- ]);
2319
- path2.pushContainer("body", styleSheet);
2320
- }
2321
- function parseClassName2(className, customColors) {
2322
- return parseClassName(className, customColors);
2323
- }
2324
- function generateStyleKey2(className) {
2325
- return generateStyleKey(className);
2326
- }