From 52b19b3b36983a1209021aa6fea82516f7f6b0b9 Mon Sep 17 00:00:00 2001
From: Alex <8125011+alex-kinokon@users.noreply.github.com>
Date: Mon, 10 Feb 2025 02:29:07 -0500
Subject: [PATCH] Fix wrapper
---
package.json | 2 +-
src/__tests__/merge.test.ts | 23 +++++++-
src/__tests__/utils.ts | 2 +-
src/babel/index.ts | 105 ++++++++++++++++--------------------
4 files changed, 70 insertions(+), 62 deletions(-)
diff --git a/package.json b/package.json
index cb12805..8d04ff1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@aet/tailwind",
- "version": "1.0.28",
+ "version": "1.0.31",
"license": "MIT",
"type": "module",
"scripts": {
diff --git a/src/__tests__/merge.test.ts b/src/__tests__/merge.test.ts
index f56f0ff..ecf4dc5 100644
--- a/src/__tests__/merge.test.ts
+++ b/src/__tests__/merge.test.ts
@@ -68,10 +68,29 @@ describe("merges with existing className attribute", () => {
const clsName = getClassName("text-center");
expect(files.js.text).toContain(
- `import { composeRenderProps as _composeRenderProps } from "react-aria-component";`
+ `{ ...props, className: typeof _className === "function" ? (...args) => _cx("${clsName}", _className(...args)) : _cx("${clsName}", _className),`
);
+ });
+
+ it("supports composeRenderProps (2)", async () => {
+ const { files } = await compileESBuild({
+ clsx: "clsx",
+ expectFiles: 2,
+ composeRenderProps: true,
+ javascript: /* tsx */ `
+ export function Hello({ className, ...props }) {
+ return (
+
+ Hello, world!
+
+ );
+ }
+ `,
+ });
+
+ const clsName = getClassName("text-center");
expect(files.js.text).toContain(
- `...props, className: _composeRenderProps(_className, (n) => _cx("${clsName}", n)),`
+ `{ className: typeof className === "function" ? (...args) => _cx("${clsName}", className(...args)) : _cx("${clsName}", className),`
);
});
diff --git a/src/__tests__/utils.ts b/src/__tests__/utils.ts
index 6365f48..db736d5 100644
--- a/src/__tests__/utils.ts
+++ b/src/__tests__/utils.ts
@@ -52,7 +52,7 @@ export function getBuild(name: string) {
external: [
"react",
"react/jsx-runtime",
- "react-aria-component",
+ "react-aria-components",
"@emotion/css",
"clsx",
"tslib",
diff --git a/src/babel/index.ts b/src/babel/index.ts
index 6519093..7cdf797 100644
--- a/src/babel/index.ts
+++ b/src/babel/index.ts
@@ -53,7 +53,6 @@ function getUtils({
let styleImport: t.Identifier;
let classedImport: t.Identifier;
let cssModuleImport: t.Identifier;
- let composeRenderPropsImport: t.Identifier;
const cssMap = new Map();
const jsMap = new Map();
@@ -177,24 +176,6 @@ function getUtils({
return t.cloneNode(tslibImport);
},
- getComposeRenderPropsImport: () => {
- if (composeRenderPropsImport == null) {
- composeRenderPropsImport = path.scope.generateUidIdentifier("composeRenderProps");
- path.node.body.unshift(
- t.importDeclaration(
- [
- t.importSpecifier(
- composeRenderPropsImport,
- t.identifier("composeRenderProps")
- ),
- ],
- t.stringLiteral("react-aria-component")
- )
- );
- }
- return t.cloneNode(composeRenderPropsImport);
- },
-
getClassedImport: () => {
if (classedImport == null) {
classedImport = path.scope.generateUidIdentifier("classed");
@@ -357,6 +338,16 @@ export function babelTailwind(
},
}));
+ const $eq = (left: t.Expression, right: t.Expression) =>
+ t.binaryExpression("===", left, right);
+ const $typeof = (expr: t.Expression) => t.unaryExpression("typeof", expr);
+ const {
+ identifier: id,
+ jsxExpressionContainer: jsxBox,
+ jsxIdentifier: jsxId,
+ callExpression: call,
+ } = t;
+
let valuePathNode = extractJSXContainer(valuePath.node);
if (
t.isArrayExpression(valuePathNode) &&
@@ -368,11 +359,30 @@ export function babelTailwind(
);
}
+ const wrap = (existing: b.types.Expression) => {
+ const callExp = call(_.getCx(path.scope), [valuePathNode, existing]);
+
+ return composeRenderProps
+ ? // typeof className === "function"
+ // ? (...args) => clsx("${clsName}", className(...args))
+ // : clsx("${clsName}", className)
+ t.conditionalExpression(
+ $eq($typeof(existing), t.stringLiteral("function")),
+ t.arrowFunctionExpression(
+ [t.restElement(id("args"))],
+ call(_.getCx(path.scope), [
+ valuePathNode,
+ call(existing, [t.spreadElement(id("args"))]),
+ ])
+ ),
+ /* else */ callExp
+ )
+ : callExp;
+ };
+
// There is an existing className attribute
if (classNameAttribute) {
const attrValue = classNameAttribute.value!;
- const wrap = (...originalValue: (b.types.Expression | b.types.SpreadElement)[]) =>
- t.callExpression(_.getCx(path.scope), [valuePathNode, ...originalValue]);
// If both are string literals, we can merge them directly here
if (t.isStringLiteral(attrValue) && t.isStringLiteral(valuePathNode)) {
@@ -398,31 +408,17 @@ export function babelTailwind(
?.referencePaths.map(p => p.node)
.includes(internal.callee)
) {
- classNameAttribute.value = t.jsxExpressionContainer(
- wrap(
- ...(internal.arguments as (b.types.Expression | b.types.SpreadElement)[])
- )
+ classNameAttribute.value = jsxBox(
+ call(_.getCx(path.scope), [
+ valuePathNode,
+ ...(internal.arguments as (b.types.Expression | b.types.SpreadElement)[]),
+ ])
);
} else {
- classNameAttribute.value = t.jsxExpressionContainer(wrap(internal));
+ classNameAttribute.value = jsxBox(wrap(internal));
}
}
} else {
- const wrap = (originalValue: b.types.Expression) =>
- composeRenderProps
- ? // composeRenderProps(className, n => cn("...", n))
- t.callExpression(_.getComposeRenderPropsImport(), [
- originalValue,
- t.arrowFunctionExpression(
- [t.identifier("n")],
- t.callExpression(_.getCx(path.scope), [
- valuePathNode,
- t.identifier("n"),
- ])
- ),
- ])
- : t.callExpression(_.getCx(path.scope), [valuePathNode, originalValue]);
-
const rest = parent.attributes.filter(attr => t.isJSXSpreadAttribute(attr));
let arg;
// if there is only one JSX spread attribute and it's an identifier
@@ -447,36 +443,29 @@ export function babelTailwind(
// (props) => ...
// ↪ ({ className, ...props }) => ...
scope.path.parent.params[index] = t.objectPattern([
- t.objectProperty(t.identifier("className"), clsVar),
+ t.objectProperty(id("className"), clsVar),
t.restElement(node),
]);
} else {
// ({ ...props }) => ...
// ↪ ({ className, ...props }) => ...
- node.properties.unshift(
- t.objectProperty(t.identifier("className"), clsVar)
- );
+ node.properties.unshift(t.objectProperty(id("className"), clsVar));
}
parent.attributes.push(
- t.jsxAttribute(
- t.jsxIdentifier("className"),
- t.jsxExpressionContainer(wrap(clsVar))
- )
+ t.jsxAttribute(jsxId("className"), jsxBox(wrap(clsVar)))
);
} else {
const tslibImport = _.getTSlibImport();
- rest[0].argument = t.callExpression(
- t.memberExpression(tslibImport, t.identifier("__rest")),
- [arg, t.arrayExpression([t.stringLiteral("className")])]
- );
+ rest[0].argument = call(t.memberExpression(tslibImport, id("__rest")), [
+ arg,
+ t.arrayExpression([t.stringLiteral("className")]),
+ ]);
parent.attributes.push(
t.jsxAttribute(
- t.jsxIdentifier("className"),
- t.jsxExpressionContainer(
- wrap(t.memberExpression(arg, t.identifier("className")))
- )
+ jsxId("className"),
+ jsxBox(wrap(t.memberExpression(arg, id("className"))))
)
);
}
@@ -484,7 +473,7 @@ export function babelTailwind(
// Fallback
const containerValue = t.isStringLiteral(valuePathNode)
? valuePathNode
- : t.callExpression(_.getCx(path.scope), [valuePathNode]);
+ : call(_.getCx(path.scope), [valuePathNode]);
parent.attributes.push(
t.jsxAttribute(