@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.
- package/README.md +406 -1
- package/dist/babel/config-loader.ts +1 -23
- package/dist/babel/index.cjs +516 -211
- package/dist/babel/index.d.ts +4 -15
- package/dist/babel/index.test.ts +481 -0
- package/dist/babel/index.ts +4 -861
- package/dist/babel/plugin.d.ts +42 -0
- package/dist/babel/plugin.test.ts +482 -0
- package/dist/babel/plugin.ts +491 -0
- package/dist/babel/utils/attributeMatchers.d.ts +23 -0
- package/dist/babel/utils/attributeMatchers.ts +71 -0
- package/dist/babel/utils/componentSupport.d.ts +18 -0
- package/dist/babel/utils/componentSupport.ts +68 -0
- package/dist/babel/utils/dynamicProcessing.d.ts +32 -0
- package/dist/babel/utils/dynamicProcessing.ts +223 -0
- package/dist/babel/utils/modifierProcessing.d.ts +26 -0
- package/dist/babel/utils/modifierProcessing.ts +118 -0
- package/dist/babel/utils/styleInjection.d.ts +15 -0
- package/dist/babel/utils/styleInjection.ts +80 -0
- package/dist/babel/utils/styleTransforms.d.ts +39 -0
- package/dist/babel/utils/styleTransforms.test.ts +349 -0
- package/dist/babel/utils/styleTransforms.ts +258 -0
- package/dist/babel/utils/twProcessing.d.ts +28 -0
- package/dist/babel/utils/twProcessing.ts +124 -0
- package/dist/components/TextInput.d.ts +171 -14
- package/dist/config/tailwind.d.ts +302 -0
- package/dist/config/tailwind.js +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +1 -1
- package/dist/parser/__snapshots__/colors.test.js.snap +242 -90
- package/dist/parser/__snapshots__/transforms.test.js.snap +58 -0
- package/dist/parser/colors.js +1 -1
- package/dist/parser/index.d.ts +1 -0
- package/dist/parser/index.js +1 -1
- package/dist/parser/modifiers.d.ts +2 -2
- package/dist/parser/modifiers.js +1 -1
- package/dist/parser/placeholder.d.ts +36 -0
- package/dist/parser/placeholder.js +1 -0
- package/dist/parser/placeholder.test.js +1 -0
- package/dist/parser/typography.d.ts +1 -0
- package/dist/parser/typography.js +1 -1
- package/dist/parser/typography.test.js +1 -1
- package/dist/runtime.cjs +2 -0
- package/dist/runtime.cjs.map +7 -0
- package/dist/runtime.d.ts +126 -0
- package/dist/runtime.js +2 -0
- package/dist/runtime.js.map +7 -0
- package/dist/runtime.test.js +1 -0
- package/dist/stubs/tw.d.ts +47 -0
- package/dist/stubs/tw.js +1 -0
- package/dist/types/core.d.ts +40 -0
- package/dist/types/core.js +0 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +1 -0
- package/dist/types/runtime.d.ts +15 -0
- package/dist/types/runtime.js +1 -0
- package/dist/types/util.d.ts +3 -0
- package/dist/types/util.js +0 -0
- package/dist/utils/flattenColors.d.ts +16 -0
- package/dist/utils/flattenColors.js +1 -0
- package/dist/utils/flattenColors.test.js +1 -0
- package/dist/utils/modifiers.d.ts +29 -0
- package/dist/utils/modifiers.js +1 -0
- package/dist/utils/modifiers.test.js +1 -0
- package/dist/utils/styleKey.test.js +1 -0
- package/package.json +15 -3
- package/src/babel/config-loader.ts +1 -23
- package/src/babel/index.ts +4 -861
- package/src/babel/plugin.test.ts +482 -0
- package/src/babel/plugin.ts +491 -0
- package/src/babel/utils/attributeMatchers.ts +71 -0
- package/src/babel/utils/componentSupport.ts +68 -0
- package/src/babel/utils/dynamicProcessing.ts +223 -0
- package/src/babel/utils/modifierProcessing.ts +118 -0
- package/src/babel/utils/styleInjection.ts +80 -0
- package/src/babel/utils/styleTransforms.test.ts +349 -0
- package/src/babel/utils/styleTransforms.ts +258 -0
- package/src/babel/utils/twProcessing.ts +124 -0
- package/src/components/TextInput.tsx +17 -14
- package/src/config/{palettes.ts → tailwind.ts} +2 -2
- package/src/index.ts +9 -1
- package/src/parser/colors.ts +9 -23
- package/src/parser/index.ts +1 -0
- package/src/parser/modifiers.ts +10 -4
- package/src/parser/placeholder.test.ts +105 -0
- package/src/parser/placeholder.ts +78 -0
- package/src/parser/typography.test.ts +11 -0
- package/src/parser/typography.ts +20 -2
- package/src/runtime.test.ts +325 -0
- package/src/runtime.ts +265 -0
- package/src/stubs/tw.ts +65 -0
- package/src/{types.ts → types/core.ts} +0 -4
- package/src/types/index.ts +2 -0
- package/src/types/runtime.ts +17 -0
- package/src/types/util.ts +1 -0
- package/src/utils/flattenColors.test.ts +361 -0
- package/src/utils/flattenColors.ts +32 -0
- package/src/utils/modifiers.test.ts +286 -0
- package/src/utils/modifiers.ts +63 -0
- package/src/utils/styleKey.test.ts +168 -0
package/dist/babel/index.cjs
CHANGED
|
@@ -258,8 +258,8 @@ function parseBorderRadius(cls) {
|
|
|
258
258
|
return null;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
// src/config/
|
|
262
|
-
var
|
|
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/
|
|
552
|
-
function flattenColors() {
|
|
553
|
-
const
|
|
554
|
-
for (const [
|
|
555
|
-
|
|
556
|
-
|
|
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
|
-
|
|
560
|
-
flat.black = "#000000";
|
|
561
|
-
flat.transparent = "transparent";
|
|
562
|
-
return flat;
|
|
562
|
+
return result;
|
|
563
563
|
}
|
|
564
|
-
|
|
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 = [
|
|
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
|
|
1876
|
+
return flattenColors(colors);
|
|
1833
1877
|
}
|
|
1834
1878
|
|
|
1835
|
-
// src/babel/
|
|
1836
|
-
var
|
|
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
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
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
|
-
|
|
1856
|
-
|
|
1898
|
+
return { exactMatches, patterns };
|
|
1899
|
+
}
|
|
1900
|
+
function isAttributeSupported(attributeName, exactMatches, patterns) {
|
|
1901
|
+
if (exactMatches.has(attributeName)) {
|
|
1902
|
+
return true;
|
|
1857
1903
|
}
|
|
1858
|
-
|
|
1859
|
-
|
|
1904
|
+
for (const pattern of patterns) {
|
|
1905
|
+
if (pattern.test(attributeName)) {
|
|
1906
|
+
return true;
|
|
1907
|
+
}
|
|
1860
1908
|
}
|
|
1861
|
-
return
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
1987
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
2058
|
-
|
|
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
|
-
|
|
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 (!
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
2178
|
-
|
|
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
|
|
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
|
|
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
|
-
}
|