diff --git a/apps/pigment-css-next-app/.eslintrc b/apps/pigment-css-next-app/.eslintrc index 327cf67d..73d03ea1 100644 --- a/apps/pigment-css-next-app/.eslintrc +++ b/apps/pigment-css-next-app/.eslintrc @@ -3,6 +3,7 @@ "rules": { "import/prefer-default-export": "off", "import/extensions": "off", - "import/no-unresolved": "off" - } + "import/no-unresolved": "off", + "react/no-unknown-property": ["error", { "ignore": ["sx"] }], + }, } diff --git a/apps/pigment-css-next-app/next.config.js b/apps/pigment-css-next-app/next.config.js index 70facd06..4dcc9476 100644 --- a/apps/pigment-css-next-app/next.config.js +++ b/apps/pigment-css-next-app/next.config.js @@ -101,7 +101,7 @@ theme.getColorSchemeSelector = (colorScheme) => { */ const pigmentOptions = { theme, - transformLibraries: ['local-ui-lib'], + transformLibraries: ['local-ui-lib', '@mui/material'], sourceMap: true, displayName: true, }; diff --git a/apps/pigment-css-next-app/src/app/page.tsx b/apps/pigment-css-next-app/src/app/page.tsx index 0a9b3811..467529a6 100644 --- a/apps/pigment-css-next-app/src/app/page.tsx +++ b/apps/pigment-css-next-app/src/app/page.tsx @@ -1,7 +1,17 @@ import Image from 'next/image'; import { styled, css } from '@pigment-css/react'; +import Chip from '@mui/material/Chip'; import styles from './page.module.css'; +declare global { + namespace React { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface HTMLAttributes { + sx?: any; + } + } +} + const visuallyHidden = css({ border: 0, clip: 'rect(0 0 0 0)', @@ -93,8 +103,16 @@ export default function Home() { return (
I am invisible
- -

+ +

Get started by editing  src/app/page.tsx

@@ -117,7 +135,12 @@ export default function Home() {
-
+

Instantly deploy your Next.js site to a shareable URL with Vercel.

+
); diff --git a/apps/pigment-css-next-app/tsconfig.json b/apps/pigment-css-next-app/tsconfig.json index 49a98502..2342c64b 100644 --- a/apps/pigment-css-next-app/tsconfig.json +++ b/apps/pigment-css-next-app/tsconfig.json @@ -25,15 +25,6 @@ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"], "references": [ - { - "path": "../../packages/mui-system/tsconfig.build.json" - }, - { - "path": "../../packages/mui-base/tsconfig.build.json" - }, - { - "path": "../../packages/mui-material/tsconfig.build.json" - }, { "path": "../../packages/pigment-css-react/tsconfig.json" } diff --git a/package.json b/package.json index c79fe2da..d94fb9d5 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "dependencies": { "@googleapis/sheets": "^5.0.5", "@slack/bolt": "^3.17.1", + "@pigment-css/react": "workspace:^", "execa": "^8.0.1", "google-auth-library": "^9.7.0", "util": "^0.12.5" diff --git a/packages/pigment-css-react/.gitignore b/packages/pigment-css-react/.gitignore index 3b446081..ce226001 100644 --- a/packages/pigment-css-react/.gitignore +++ b/packages/pigment-css-react/.gitignore @@ -1,4 +1,3 @@ /processors/ /utils/ LICENSE -/private-runtime/ diff --git a/packages/pigment-css-react/package.json b/packages/pigment-css-react/package.json index 528d78d4..ea83ab63 100644 --- a/packages/pigment-css-react/package.json +++ b/packages/pigment-css-react/package.json @@ -91,7 +91,6 @@ "files": [ "build", "exports", - "private-runtime", "processors", "theme", "utils", @@ -149,15 +148,6 @@ }, "require": "./build/RtlProvider.js", "default": "./build/RtlProvider.js" - }, - "./private-runtime": { - "types": "./private-runtime/index.d.ts", - "import": { - "types": "./private-runtime/index.d.mts", - "default": "./private-runtime/index.mjs" - }, - "require": "./private-runtime/index.js", - "default": "./private-runtime/index.js" } }, "nx": { diff --git a/packages/pigment-css-react/src/private-runtime/ForwardSx.js b/packages/pigment-css-react/src/private-runtime/ForwardSx.js deleted file mode 100644 index 2201ae8a..00000000 --- a/packages/pigment-css-react/src/private-runtime/ForwardSx.js +++ /dev/null @@ -1,32 +0,0 @@ -import * as React from 'react'; -import clsx from 'clsx'; - -function useSx(sx, className, style) { - const sxClass = typeof sx === 'string' ? sx : sx?.className; - const sxVars = sx && typeof sx !== 'string' ? sx.vars : undefined; - const varStyles = {}; - - if (sxVars) { - Object.entries(sxVars).forEach(([cssVariable, [value, isUnitLess]]) => { - if (typeof value === 'string' || isUnitLess) { - varStyles[`--${cssVariable}`] = value; - } else { - varStyles[`--${cssVariable}`] = `${value}px`; - } - }); - } - - return { - className: clsx(sxClass, className), - style: { - ...varStyles, - ...style, - }, - }; -} - -/* eslint-disable-next-line react/prop-types */ -export const ForwardSx = React.forwardRef(({ sx, sxComponent, className, style, ...rest }, ref) => { - const Component = sxComponent; - return ; -}); diff --git a/packages/pigment-css-react/src/private-runtime/index.ts b/packages/pigment-css-react/src/private-runtime/index.ts deleted file mode 100644 index b8e8215a..00000000 --- a/packages/pigment-css-react/src/private-runtime/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './ForwardSx'; diff --git a/packages/pigment-css-react/src/processors/sx.ts b/packages/pigment-css-react/src/processors/sx.ts index 141c470e..401d71ed 100644 --- a/packages/pigment-css-react/src/processors/sx.ts +++ b/packages/pigment-css-react/src/processors/sx.ts @@ -1,4 +1,5 @@ -import type { Expression } from '@babel/types'; +import type { NodePath } from '@babel/core'; +import type { CallExpression, Expression } from '@babel/types'; import { validateParams, type Params, @@ -10,31 +11,7 @@ import type { IOptions } from './styled'; import { processCssObject } from '../utils/processCssObject'; import { cssFnValueToVariable } from '../utils/cssFnValueToVariable'; import BaseProcessor from './base-processor'; - -// @TODO: Maybe figure out a better way allow imports. -const allowedSxTransformImports = [`${process.env.PACKAGE_NAME}/Box`]; - -/** - * Specifically looks for whether the sx prop should be transformed or not. - * If it's a Pigment CSS styled component, the value of `argumentValue` will - * be a string className starting with "." - * In other cases, it explicitly checks if the import is allowed for sx transformation. - */ -function allowSxTransform(argumentExpression: ExpressionValue, argumentValue?: string) { - if (!argumentExpression) { - return false; - } - if ( - argumentExpression.kind === ValueType.LAZY && - argumentExpression.importedFrom?.some((i) => allowedSxTransformImports.includes(i)) - ) { - return true; - } - if (argumentValue && argumentValue[0] === '.') { - return true; - } - return false; -} +import spreadSxProp from '../utils/spreadSxProp'; export class SxProcessor extends BaseProcessor { sxArguments: ExpressionValue[] = []; @@ -66,10 +43,6 @@ export class SxProcessor extends BaseProcessor { } } - if (!allowSxTransform(elementClassExpression, this.elementClassName)) { - return; - } - let cssText: string = ''; if (sxStyle.kind === ValueType.CONST) { if (sxStyle.ex.type === 'StringLiteral') { @@ -79,16 +52,13 @@ export class SxProcessor extends BaseProcessor { const styleObjOrFn = values.get(sxStyle.ex.name); cssText = this.processCss(styleObjOrFn, sxStyle); } - const selector = this.elementClassName - ? `${this.elementClassName}${this.asSelector}` - : this.asSelector; if (!cssText) { return; } const rules: Rules = { - [selector]: { + [this.asSelector]: { className: this.className, cssText, displayName: this.displayName, @@ -123,6 +93,7 @@ export class SxProcessor extends BaseProcessor { if (this.artifacts.length === 0) { return; } + let result = this.value; if (this.collectedVariables.length) { const varProperties: ReturnType[] = this.collectedVariables.map( ([variableId, expression, isUnitLess]) => { @@ -156,10 +127,31 @@ export class SxProcessor extends BaseProcessor { t.objectProperty(t.identifier('className'), t.stringLiteral(this.className)), t.objectProperty(t.identifier('vars'), t.objectExpression(varProperties)), ]); - this.replacer(obj, false); - } else { - this.replacer(this.value, false); + result = obj; } + + /** + * Replace the sx call with the transformed result. It works for both JSX and non-JSX calls. + * + * For example: + * to + * to + */ + this.replacer((_tagPath) => { + const tagPath = _tagPath as NodePath; + return t.callExpression(tagPath.get('callee').node, [result]); + }, false); + + /** + * Replace the sx prop with runtime sx + */ + this.replacer((_tagPath) => { + const tagPath = _tagPath as NodePath; + + spreadSxProp(tagPath); + + return tagPath.node; + }, false); } get asSelector(): string { diff --git a/packages/pigment-css-react/src/styled.js b/packages/pigment-css-react/src/styled.js index e4a18631..d4ba3d07 100644 --- a/packages/pigment-css-react/src/styled.js +++ b/packages/pigment-css-react/src/styled.js @@ -27,7 +27,7 @@ function isHtmlTag(tag) { ); } -const slotShouldForwardProp = (key) => key !== 'sx' && key !== 'as' && key !== 'ownerState'; +const slotShouldForwardProp = (key) => key !== 'as' && key !== 'ownerState'; const rootShouldForwardProp = (key) => slotShouldForwardProp(key) && key !== 'classes'; /** @@ -103,25 +103,8 @@ export default function styled(tag, componentMeta = {}) { }, {}, ); - const sxClass = typeof sx === 'string' ? sx : sx?.className; - const sxVars = sx && typeof sx !== 'string' ? sx.vars : undefined; - if (sxVars) { - Object.entries(sxVars).forEach(([cssVariable, [value, isUnitLess]]) => { - if (typeof value === 'string' || isUnitLess) { - varStyles[`--${cssVariable}`] = value; - } else { - varStyles[`--${cssVariable}`] = `${value}px`; - } - }); - } - - const finalClassName = clsx( - classes, - sxClass, - className, - getVariantClasses(inProps, variants), - ); + const finalClassName = clsx(classes, className, getVariantClasses(inProps, variants)); if (inProps.as && !shouldForwardProp) { // Reassign `shouldForwardProp` if incoming `as` prop is a React component diff --git a/packages/pigment-css-react/src/sx.js b/packages/pigment-css-react/src/sx.js index 4d9091f5..ee0bcfe0 100644 --- a/packages/pigment-css-react/src/sx.js +++ b/packages/pigment-css-react/src/sx.js @@ -1,3 +1,24 @@ -export default function sx(styleObj) { - return styleObj; +export default function sx(transformedSx, { className, style }) { + const sxClass = typeof transformedSx === 'string' ? transformedSx : transformedSx?.className; + const sxVars = + transformedSx && typeof transformedSx !== 'string' ? transformedSx.vars : undefined; + const varStyles = {}; + + if (sxVars) { + Object.entries(sxVars).forEach(([cssVariable, [value, isUnitLess]]) => { + if (typeof value === 'string' || isUnitLess) { + varStyles[`--${cssVariable}`] = value; + } else { + varStyles[`--${cssVariable}`] = `${value}px`; + } + }); + } + + return { + className: `${sxClass}${className ? ` ${className}` : ''}`, + style: { + ...varStyles, + ...style, + }, + }; } diff --git a/packages/pigment-css-react/src/utils/spreadSxProp.ts b/packages/pigment-css-react/src/utils/spreadSxProp.ts new file mode 100644 index 00000000..57caff21 --- /dev/null +++ b/packages/pigment-css-react/src/utils/spreadSxProp.ts @@ -0,0 +1,130 @@ +import { NodePath, types as astService } from '@babel/core'; +import { + CallExpression, + Expression, + JSXAttribute, + JSXOpeningElement, + JSXSpreadAttribute, + ObjectExpression, + ObjectMethod, + ObjectProperty, + SpreadElement, +} from '@babel/types'; + +function isSxProp(path: NodePath) { + if (path.isJSXAttribute() && path.node.name.name === 'sx') { + return true; + } + if ( + path.isObjectProperty() && + path.node.key.type === 'Identifier' && + path.node.key.name === 'sx' + ) { + return true; + } + return false; +} + +function isSpreadExpression(path: NodePath) { + return path.isSpreadElement() || path.isJSXSpreadAttribute(); +} + +function getProps(paths: NodePath[]) { + const props: Array = []; + let sxPath: undefined | NodePath | NodePath; + paths.forEach((attr) => { + if (isSxProp(attr)) { + sxPath = attr as NodePath | NodePath; + } else if (isSpreadExpression(attr)) { + let containRuntimeSx = false; + attr.traverse({ + CallExpression(path) { + const callee = path.get('callee'); + if (callee.isIdentifier() && callee.node.name.startsWith('_sx')) { + containRuntimeSx = true; + } + }, + }); + if (!containRuntimeSx) { + props.push( + astService.spreadElement( + (attr as NodePath).node.argument, + ), + ); + } + } else if ( + attr.isJSXAttribute() && + (attr.node.name.name === 'className' || attr.node.name.name === 'style') + ) { + const value = attr.get('value'); + if (value.isJSXExpressionContainer()) { + props.push( + astService.objectProperty( + astService.identifier(attr.node.name.name), + value.get('expression').node as any, + ), + ); + } else { + props.push( + astService.objectProperty( + astService.identifier(attr.node.name.name), + attr.node.value as any, + ), + ); + } + } else if ( + attr.isObjectProperty() && + attr.node.key.type === 'Identifier' && + (attr.node.key.name === 'className' || attr.node.key.name === 'style') + ) { + props.push( + astService.objectProperty( + astService.identifier(attr.node.key.name), + attr.node.value as any, + ), + ); + } + }); + return { props, sxPath }; +} + +/** + * Convert the sx prop that contains the sx() call to runtime {...sx()} spread. + * + * It will try to find the sibling `className` and `style` props and put them in the second argument of + * the runtime sx call. + */ +export default function spreadSxProp(tagPath: NodePath) { + const target = tagPath.findParent((p) => p.isJSXOpeningElement() || p.isObjectExpression()) as + | NodePath + | NodePath + | null; + if (!target) { + return; + } + let paths: + | NodePath[] + | NodePath[] = []; + if (target.isJSXOpeningElement()) { + paths = target.get('attributes'); + } + if (target.isObjectExpression()) { + paths = target.get('properties'); + } + const { props, sxPath } = getProps(paths); + if (sxPath) { + const expression = sxPath.get('value'); + if ('node' in expression) { + if (target.isObjectExpression()) { + target.node.properties.push(astService.spreadElement(expression.node as Expression)); + } + if (target.isJSXOpeningElement() && expression.isJSXExpressionContainer()) { + target.node.attributes.push( + astService.jsxSpreadAttribute(expression.node.expression as Expression), + ); + } + } + sxPath.remove(); + } + tagPath.node.arguments.push(astService.objectExpression(props)); +} diff --git a/packages/pigment-css-react/src/utils/sx-plugin.ts b/packages/pigment-css-react/src/utils/sx-plugin.ts index d10e781c..145b12e5 100644 --- a/packages/pigment-css-react/src/utils/sx-plugin.ts +++ b/packages/pigment-css-react/src/utils/sx-plugin.ts @@ -24,81 +24,6 @@ function convertJsxMemberExpressionToMemberExpression( ); } -function wrapWithJsxElement( - t: typeof Types, - tagNamePath: NodePath, - sxComponentName: string, -) { - const sxComponent = addNamed( - tagNamePath, - sxComponentName, - `${process.env.PACKAGE_NAME}/private-runtime`, - ); - const jsxElement = tagNamePath.findParent((p) => p.isJSXElement()); - if (!jsxElement?.isJSXElement()) { - return; - } - const component = t.jsxIdentifier(sxComponent.name); - - const newChildren = (jsxElement.get('children') ?? []).map((child) => child.node); - let sxComponentValue: Types.Identifier | Types.MemberExpression | null = null; - - if (tagNamePath.isJSXIdentifier()) { - sxComponentValue = t.identifier(tagNamePath.node.name); - } else if (tagNamePath.isJSXMemberExpression()) { - sxComponentValue = convertJsxMemberExpressionToMemberExpression(t, tagNamePath); - } - - const newElement = t.jsxElement( - t.jsxOpeningElement( - component, - [ - t.jsxAttribute( - t.jsxIdentifier('sxComponent'), - t.jsxExpressionContainer(sxComponentValue ?? t.nullLiteral()), - ), - ...jsxElement - .get('openingElement') - .get('attributes') - .map((attr) => attr.node), - ], - !newChildren.length, - ), - newChildren.length ? t.jsxClosingElement(component) : null, - newChildren, - !newChildren.length, - ); - jsxElement.replaceWith(newElement); -} - -function wrapWithJsxCall( - t: typeof Types, - tagNamePath: NodePath, - sxComponentName: string, -) { - const sxComponent = addNamed( - tagNamePath, - sxComponentName, - `${process.env.PACKAGE_NAME}/private-runtime`, - ); - const jsxCall = tagNamePath.findParent((p) => p.isCallExpression()); - if (!jsxCall?.isCallExpression()) { - return; - } - const originalTag = tagNamePath.node; - const callArgs = jsxCall.get('arguments'); - callArgs[0].replaceWith(sxComponent); - const props = callArgs[1]; - if (props.isObjectExpression()) { - const properties = props.get('properties'); - const newProps = t.objectExpression([ - t.objectProperty(t.identifier('sxComponent'), originalTag), - ...properties.map((p) => p.node), - ]); - props.replaceWith(newProps); - } -} - function replaceNodePath( expressionPath: NodePath, namePath: NodePath, @@ -107,10 +32,8 @@ function replaceNodePath( tagNamePath: NodePath< Types.JSXIdentifier | Types.Identifier | Types.JSXMemberExpression | Types.MemberExpression >, - sxComponentName: string, ) { const sxIdentifier = addNamed(namePath, importName, process.env.PACKAGE_NAME as string); - let wasSxTransformed = false; const wrapWithSxCall = (expPath: NodePath) => { let tagNameArg: Types.Identifier | Types.MemberExpression | null = null; @@ -122,25 +45,16 @@ function replaceNodePath( tagNameArg = tagNamePath.node as Types.Identifier | Types.MemberExpression; } expPath.replaceWith(t.callExpression(sxIdentifier, [expPath.node, tagNameArg])); - wasSxTransformed = true; }; sxPropConverter(expressionPath, wrapWithSxCall); - - if (wasSxTransformed) { - if (tagNamePath.isJSXIdentifier() || tagNamePath.isJSXMemberExpression()) { - wrapWithJsxElement(t, tagNamePath, sxComponentName); - } else if (tagNamePath.isIdentifier() || tagNamePath.isMemberExpression()) { - wrapWithJsxCall(t, tagNamePath, sxComponentName); - } - } } export const babelPlugin = declare<{ propName?: string; importName?: string; sxComponentName?: string; -}>((api, { propName = 'sx', importName = 'sx', sxComponentName = 'ForwardSx' }) => { +}>((api, { propName = 'sx', importName = 'sx' }) => { api.assertVersion(7); const { types: t } = api; return { @@ -167,7 +81,7 @@ export const babelPlugin = declare<{ return; } // @ts-ignore - replaceNodePath(expressionPath, namePath, importName, t, tagName, sxComponentName); + replaceNodePath(expressionPath, namePath, importName, t, tagName); }, ObjectProperty(path) { // @TODO - Maybe add support for React.createElement calls as well. @@ -177,7 +91,12 @@ export const babelPlugin = declare<{ return; } const valuePath = path.get('value'); - if (!valuePath.isObjectExpression() && !valuePath.isArrowFunctionExpression()) { + if ( + !valuePath.isObjectExpression() && + !valuePath.isArrowFunctionExpression() && + !valuePath.isConditionalExpression() && + !valuePath.isLogicalExpression() + ) { return; } const parentJsxCall = path.findParent((p) => p.isCallExpression()); @@ -189,7 +108,7 @@ export const babelPlugin = declare<{ return; } const jsxElement = parentJsxCall.get('arguments')[0] as NodePath; - replaceNodePath(valuePath, keyPath, importName, t, jsxElement, sxComponentName); + replaceNodePath(valuePath, keyPath, importName, t, jsxElement); }, }, }; diff --git a/packages/pigment-css-react/tests/Box/fixtures/box-jsx.input.js b/packages/pigment-css-react/tests/Box/fixtures/box-jsx.input.js index 8d4a759c..acc90d6d 100644 --- a/packages/pigment-css-react/tests/Box/fixtures/box-jsx.input.js +++ b/packages/pigment-css-react/tests/Box/fixtures/box-jsx.input.js @@ -17,3 +17,24 @@ export function App(props) { children: 'Hello Box', }); } + +function App2(props) { + return /*#__PURE__*/ _jsxDEV( + Box, + { + sx: { + display: 'flex', + flexDirection: 'column', + }, + children: 'Test', + }, + void 0, + false, + { + fileName: '', + lineNumber: 11, + columnNumber: 11, + }, + this, + ); +} diff --git a/packages/pigment-css-react/tests/Box/fixtures/box-jsx.output.css b/packages/pigment-css-react/tests/Box/fixtures/box-jsx.output.css index 8a99d69c..181b1abe 100644 --- a/packages/pigment-css-react/tests/Box/fixtures/box-jsx.output.css +++ b/packages/pigment-css-react/tests/Box/fixtures/box-jsx.output.css @@ -7,3 +7,7 @@ flex-direction: column; gap: 0.5rem; } +.sk625fs { + display: flex; + flex-direction: column; +} diff --git a/packages/pigment-css-react/tests/Box/fixtures/box-jsx.output.js b/packages/pigment-css-react/tests/Box/fixtures/box-jsx.output.js index eb330c06..47a9f092 100644 --- a/packages/pigment-css-react/tests/Box/fixtures/box-jsx.output.js +++ b/packages/pigment-css-react/tests/Box/fixtures/box-jsx.output.js @@ -1,12 +1,28 @@ -import { ForwardSx as _ForwardSx } from '@pigment-css/react/private-runtime'; +import { sx as _sx, sx as _sx2 } from '@pigment-css/react'; import Box from '@pigment-css/react/Box'; import { jsx as _jsx } from 'react/jsx-runtime'; export function App(props) { - return /*#__PURE__*/ _jsx(_ForwardSx, { - sxComponent: Box, + return /*#__PURE__*/ _jsx(Box, { as: 'ul', 'aria-label': props.label, - sx: 'sd5jss7', children: 'Hello Box', + ..._sx('sd5jss7', {}), }); } +function App2(props) { + return /*#__PURE__*/ _jsxDEV( + Box, + { + children: 'Test', + ..._sx2('sk625fs', {}), + }, + void 0, + false, + { + fileName: '', + lineNumber: 11, + columnNumber: 11, + }, + this, + ); +} diff --git a/packages/pigment-css-react/tests/Box/fixtures/box.output.css b/packages/pigment-css-react/tests/Box/fixtures/box.output.css index 20e66550..d332a878 100644 --- a/packages/pigment-css-react/tests/Box/fixtures/box.output.css +++ b/packages/pigment-css-react/tests/Box/fixtures/box.output.css @@ -1,5 +1,5 @@ -._c1d15y { - color: var(--_c1d15y-0); +.bc1d15y { + color: var(--bc1d15y-0); margin: 0; margin-block: 1rem; padding: 0; diff --git a/packages/pigment-css-react/tests/Box/fixtures/box.output.js b/packages/pigment-css-react/tests/Box/fixtures/box.output.js index dc83809e..9b4c632c 100644 --- a/packages/pigment-css-react/tests/Box/fixtures/box.output.js +++ b/packages/pigment-css-react/tests/Box/fixtures/box.output.js @@ -1,20 +1,21 @@ -import { sx as _sx2 } from '@pigment-css/react'; -import { ForwardSx as _ForwardSx } from '@pigment-css/react/private-runtime'; +import { sx as _sx } from '@pigment-css/react'; import Box from '@pigment-css/react/Box'; export function App(props) { return ( - <_ForwardSx - sxComponent={Box} + Hello Box - + ); } diff --git a/packages/pigment-css-react/tests/sx/fixtures/sx-jsx.input.js b/packages/pigment-css-react/tests/sx/fixtures/sx-jsx.input.js new file mode 100644 index 00000000..a98ae099 --- /dev/null +++ b/packages/pigment-css-react/tests/sx/fixtures/sx-jsx.input.js @@ -0,0 +1,65 @@ +function App() { + return /*#__PURE__*/ _jsx( + 'div', + { + sx: { + display: 'flex', + flexDirection: 'column', + }, + children: 'Test', + className: 'foo', + style: { textAlign: 'center' }, + }, + void 0, + false, + { + fileName: '', + lineNumber: 11, + columnNumber: 11, + }, + this, + ); +} + +function App2(props) { + return /*#__PURE__*/ _jsx('div', { + sx: { + display: 'flex', + flexDirection: 'column', + }, + className: props.className, + style: props.style, + children: /*#__PURE__*/ _jsx('p', { + sx: ({ theme }) => ({ + color: (theme.vars || theme).palette.primary.main, + ...theme.applyStyles('dark', { + color: 'white', + }), + }), + children: 'Test', + }), + }); +} + +function App3(props) { + return /*#__PURE__*/ _jsx('div', { + sx: props.disabled + ? { + opacity: 0.4, + } + : { + color: 'red', + }, + children: 'test', + ...props, + }); +} + +function App4(props) { + return /*#__PURE__*/ _jsx('div', { + sx: props.variant === 'secondary' && { color: props.isRed ? 'red' : 'blue' }, + className: `foo ${props.className}`, + ...props, + children: 'test', + }); +} diff --git a/packages/pigment-css-react/tests/sx/fixtures/sx-jsx.output.css b/packages/pigment-css-react/tests/sx/fixtures/sx-jsx.output.css new file mode 100644 index 00000000..35b51edb --- /dev/null +++ b/packages/pigment-css-react/tests/sx/fixtures/sx-jsx.output.css @@ -0,0 +1,25 @@ +.s5molx8 { + display: flex; + flex-direction: column; +} +.s7fszdm { + display: flex; + flex-direction: column; +} +.s2bbd3t { + color: red; +} +@media (prefers-color-scheme: dark) { + .s2bbd3t { + color: white; + } +} +.s1ou6jyi { + opacity: 0.4; +} +.s1lqy6hu { + color: red; +} +.swssabr { + color: var(--swssabr-0); +} diff --git a/packages/pigment-css-react/tests/sx/fixtures/sx-jsx.output.js b/packages/pigment-css-react/tests/sx/fixtures/sx-jsx.output.js new file mode 100644 index 00000000..3277161a --- /dev/null +++ b/packages/pigment-css-react/tests/sx/fixtures/sx-jsx.output.js @@ -0,0 +1,74 @@ +import { sx as _sx, sx as _sx2, sx as _sx3, sx as _sx4, sx as _sx5 } from '@pigment-css/react'; +function App() { + return /*#__PURE__*/ _jsx( + 'div', + { + children: 'Test', + className: 'foo', + style: { + textAlign: 'center', + }, + ..._sx('s5molx8', { + className: 'foo', + style: { + textAlign: 'center', + }, + }), + }, + void 0, + false, + { + fileName: '', + lineNumber: 11, + columnNumber: 11, + }, + this, + ); +} +function App2(props) { + return /*#__PURE__*/ _jsx('div', { + className: props.className, + style: props.style, + children: /*#__PURE__*/ _jsx('p', { + children: 'Test', + ..._sx3('s2bbd3t', {}), + }), + ..._sx2('s7fszdm', { + className: props.className, + style: props.style, + }), + }); +} +function App3(props) { + return /*#__PURE__*/ _jsx('div', { + children: 'test', + ...props, + ...(props.disabled + ? _sx4('s1ou6jyi', { + ...props, + }) + : _sx4('s1lqy6hu', { + ...props, + })), + }); +} +function App4(props) { + return /*#__PURE__*/ _jsx('div', { + className: `foo ${props.className}`, + ...props, + children: 'test', + ...(props.variant === 'secondary' && + _sx5( + { + className: 'swssabr', + vars: { + 'swssabr-0': [props.isRed ? 'red' : 'blue', false], + }, + }, + { + className: `foo ${props.className}`, + ...props, + }, + )), + }); +} diff --git a/packages/pigment-css-react/tests/sx/fixtures/sxProps.input.js b/packages/pigment-css-react/tests/sx/fixtures/sxProps.input.js index 0d8f4e16..3bc08e0e 100644 --- a/packages/pigment-css-react/tests/sx/fixtures/sxProps.input.js +++ b/packages/pigment-css-react/tests/sx/fixtures/sxProps.input.js @@ -12,13 +12,14 @@ export const SliderRail = styled('span', { font-size: ${({ theme }) => (theme.vars ?? theme).size.font.h1}; `; -function App() { - return ; +function App(props) { + return ; } function App2(props) { return ( + ); } diff --git a/packages/pigment-css-react/tests/sx/fixtures/sxProps.output.css b/packages/pigment-css-react/tests/sx/fixtures/sxProps.output.css index 6d7384b2..6bb6b310 100644 --- a/packages/pigment-css-react/tests/sx/fixtures/sxProps.output.css +++ b/packages/pigment-css-react/tests/sx/fixtures/sxProps.output.css @@ -9,20 +9,20 @@ .sjfloo5-1 { font-size: 3rem; } -.sjfloo5._1o8xp19 { +.s1o8xp19 { color: red; } -.sjfloo5._1xbsywq { - color: var(--_1xbsywq-0); +.s1xbsywq { + color: var(--s1xbsywq-0); } -.sjfloo5._1wnk6s5 { +.s1wnk6s5 { background-color: blue; color: white; } -.sjfloo5._tzaibv { - color: var(--_tzaibv-0); +.stzaibv { + color: var(--stzaibv-0); } -.sjfloo5._azg8ol { +.sazg8ol { margin-bottom: 8px; text-align: center; } diff --git a/packages/pigment-css-react/tests/sx/fixtures/sxProps.output.js b/packages/pigment-css-react/tests/sx/fixtures/sxProps.output.js index 5aefa5d9..3cf5b0e3 100644 --- a/packages/pigment-css-react/tests/sx/fixtures/sxProps.output.js +++ b/packages/pigment-css-react/tests/sx/fixtures/sxProps.output.js @@ -1,52 +1,81 @@ -import { sx as _sx8, styled as _styled } from '@pigment-css/react'; -import { ForwardSx as _ForwardSx4 } from '@pigment-css/react/private-runtime'; -import { sx as _sx6 } from '@pigment-css/react'; -import { ForwardSx as _ForwardSx3 } from '@pigment-css/react/private-runtime'; -import { sx as _sx4 } from '@pigment-css/react'; -import { ForwardSx as _ForwardSx2 } from '@pigment-css/react/private-runtime'; -import { sx as _sx2 } from '@pigment-css/react'; -import { ForwardSx as _ForwardSx } from '@pigment-css/react/private-runtime'; +import { + sx as _sx, + sx as _sx2, + sx as _sx3, + sx as _sx4, + styled as _styled, +} from '@pigment-css/react'; export const SliderRail = /*#__PURE__*/ _styled('span', { name: 'MuiSlider', slot: 'Rail', })({ classes: ['sjfloo5', 'sjfloo5-1'], }); -function App() { - return <_ForwardSx sxComponent={SliderRail} sx={'_1o8xp19'} />; +function App(props) { + return ( + + ); } function App2(props) { return ( - <_ForwardSx2 - sxComponent={SliderRail} - sx={ - props.variant === 'secondary' - ? { - className: '_1xbsywq', + ); } function App3(props) { return ( - <_ForwardSx3 - sxComponent={SliderRail} - sx={ - props.variant === 'secondary' && { - className: '_tzaibv', - vars: { - '_tzaibv-0': [props.isRed ? 'red' : 'blue', false], + ); } function App4(props) { - return <_ForwardSx4 sxComponent={SliderRail} sx={'_azg8ol'} />; + return ; } diff --git a/packages/pigment-css-react/tests/sx/fixtures/sxProps2.output.css b/packages/pigment-css-react/tests/sx/fixtures/sxProps2.output.css index 90b60e9e..a31e4248 100644 --- a/packages/pigment-css-react/tests/sx/fixtures/sxProps2.output.css +++ b/packages/pigment-css-react/tests/sx/fixtures/sxProps2.output.css @@ -9,38 +9,38 @@ .sdbmcs3-1 { font-size: 3rem; } -.sdbmcs3._i7ulc4 { +.si7ulc4 { margin-bottom: 8px; } @media (prefers-color-scheme: dark) { - .sdbmcs3._i7ulc4 { + .si7ulc4 { color: white; } } -.sdbmcs3._liig2s { +.sliig2s { border-radius: 8px; margin: 5px; } -.sdbmcs3._liig2s.MuiAutocomplete-option { +.sliig2s.MuiAutocomplete-option { padding: 8px; } -.sdbmcs3._o956n { +.so956n { color: red; - font-size: var(--_o956n-0); + font-size: var(--so956n-0); } @media (min-width: 0px) { - .sdbmcs3._o956n :hover { + .so956n :hover { background-color: red; } } @media (min-width: 600px) { - .sdbmcs3._o956n :hover { + .so956n :hover { background-color: blue; color: red; } } @media (min-width: 900px) { - .sdbmcs3._o956n :hover { + .so956n :hover { color: blue; } } diff --git a/packages/pigment-css-react/tests/sx/fixtures/sxProps2.output.js b/packages/pigment-css-react/tests/sx/fixtures/sxProps2.output.js index 7c8a5ca1..19bf63cb 100644 --- a/packages/pigment-css-react/tests/sx/fixtures/sxProps2.output.js +++ b/packages/pigment-css-react/tests/sx/fixtures/sxProps2.output.js @@ -1,9 +1,4 @@ -import { sx as _sx6, styled as _styled } from '@pigment-css/react'; -import { ForwardSx as _ForwardSx3 } from '@pigment-css/react/private-runtime'; -import { sx as _sx4 } from '@pigment-css/react'; -import { ForwardSx as _ForwardSx2 } from '@pigment-css/react/private-runtime'; -import { sx as _sx2 } from '@pigment-css/react'; -import { ForwardSx as _ForwardSx } from '@pigment-css/react/private-runtime'; +import { sx as _sx, sx as _sx2, sx as _sx3, styled as _styled } from '@pigment-css/react'; const SliderRail = /*#__PURE__*/ _styled('span', { name: 'MuiSlider', slot: 'Rail', @@ -14,21 +9,31 @@ const A = { SliderRail, }; function App(props) { - return <_ForwardSx sxComponent={SliderRail} sx={'_i7ulc4'} />; + return ; } function App2() { - return <_ForwardSx2 sxComponent={SliderRail} sx={'_liig2s'} component="li" {...props} />; + return ( + + ); } function App3(props) { return ( - <_ForwardSx3 - sxComponent={A.SliderRail} - sx={{ - className: '_o956n', - vars: { - '_o956n-0': [props.isRed ? 'h1-fontSize' : 'h2-fontSize', false], + ); } diff --git a/packages/pigment-css-react/tests/sx/sx.test.ts b/packages/pigment-css-react/tests/sx/sx.test.ts index 20b36d95..a61bf45a 100644 --- a/packages/pigment-css-react/tests/sx/sx.test.ts +++ b/packages/pigment-css-react/tests/sx/sx.test.ts @@ -46,6 +46,20 @@ describe('Pigment CSS - sx prop', () => { expect(output.css).to.equal(fixture.css); }); + it('jsx sx-prop with logical and conditional expressions', async () => { + const { output, fixture } = await runTransformation( + path.join(__dirname, 'fixtures/sx-jsx.input.js'), + { + themeArgs: { + theme, + }, + }, + ); + + expect(output.js).to.equal(fixture.js); + expect(output.css).to.equal(fixture.css); + }); + it('sx prop with theme spread', async () => { const { output, fixture } = await runTransformation( path.join(__dirname, 'fixtures/sxProps2.input.js'), diff --git a/packages/pigment-css-react/tsup.config.ts b/packages/pigment-css-react/tsup.config.ts index fe170a40..5fd52716 100644 --- a/packages/pigment-css-react/tsup.config.ts +++ b/packages/pigment-css-react/tsup.config.ts @@ -31,9 +31,4 @@ export default defineConfig([ ], outDir: 'utils', }, - { - ...baseConfig, - entry: ['./src/private-runtime/index.ts'], - outDir: 'private-runtime', - }, ]); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 55b0fd67..8acf406e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,6 +33,9 @@ importers: '@googleapis/sheets': specifier: ^5.0.5 version: 5.0.5 + '@pigment-css/react': + specifier: workspace:^ + version: link:packages/pigment-css-react '@slack/bolt': specifier: ^3.17.1 version: 3.17.1