Fix wrapper

This commit is contained in:
Alex 2025-02-10 02:29:07 -05:00
parent 8e41208a14
commit 52b19b3b36
4 changed files with 70 additions and 62 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@aet/tailwind",
"version": "1.0.28",
"version": "1.0.31",
"license": "MIT",
"type": "module",
"scripts": {

View File

@ -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 (
<div className={className} css="text-center">
<span {...props}>Hello, world!</span>
</div>
);
}
`,
});
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),`
);
});

View File

@ -52,7 +52,7 @@ export function getBuild(name: string) {
external: [
"react",
"react/jsx-runtime",
"react-aria-component",
"react-aria-components",
"@emotion/css",
"clsx",
"tslib",

View File

@ -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<string, StyleMapEntry>();
const jsMap = new Map<string, StyleMapEntry>();
@ -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(