Skip to content

Commit

Permalink
feat: support css prop on automatic runtime compiled jsx elements
Browse files Browse the repository at this point in the history
  • Loading branch information
jquense committed Oct 18, 2021
1 parent 386a73b commit 021e6df
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 33 deletions.
32 changes: 29 additions & 3 deletions src/features/css-prop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import wrapInClass from '../utils/wrapInClass';

const HAS_JSX = Symbol('Astroturf has jsx');
const HAS_CREATE_ELEMENT = Symbol('Astroturf has createElement call');
const IS_JSX = Symbol('Is a JSX call expression');

type CssPropPluginState = PluginState & {
[JSX_IDENTS]: {
Expand All @@ -31,6 +32,15 @@ const isCssPropTag = (tagPath: NodePath, options: ResolvedOptions) =>
? isStylesheetTag(tagPath, options)
: isCssTag(tagPath, options);

const isJsxCallExpression = (p: NodePath<any>) => {
const result =
p.isCallExpression() &&
// @ts-ignore
p.get('callee').referencesImport('react/jsx-runtime');

return result;
};

export const isCreateElementCall = (p: NodePath<any>) =>
p.isCallExpression() &&
(p.get('callee.property') as any).node &&
Expand Down Expand Up @@ -164,6 +174,14 @@ const cssPropertyVisitors = {
state.processed = true;
}
},
CallExpression(path: NodePath<t.CallExpression>) {
// prevent the inner traversal from finding nested css props, on `children:` keys
// but mark the path so we can skip the check when the outer traversal finds it
if (isCreateElementCall(path) || isJsxCallExpression(path)) {
path[IS_JSX] = true;
path.skip();
}
},
};

export default {
Expand Down Expand Up @@ -193,7 +211,12 @@ export default {
const { file } = state;
const pluginOptions = state.defaultedOptions;

if (!isCreateElementCall(path)) return;
if (
!path[IS_JSX] &&
!isCreateElementCall(path) &&
!isJsxCallExpression(path)
)
return;

const typeName = getNameFromPath(path.get('arguments')[0]);

Expand All @@ -208,10 +231,12 @@ export default {
};

// We aren't checking very hard that this is a React createElement call
if (propsPath) {
propsPath.traverse(cssPropertyVisitors, innerState);
if (!propsPath) {
return;
}

propsPath.traverse(cssPropertyVisitors, innerState);

if (innerState.processed) {
const { jsx } = state[JSX_IDENTS];
const { changeset } = file.get(STYLES);
Expand All @@ -223,6 +248,7 @@ export default {
end: callee.node.end,
});

// console.log('HERE', callee.node);
callee.replaceWith(t.identifier(jsx.name));
file.set(HAS_CREATE_ELEMENT, true);
}
Expand Down
7 changes: 5 additions & 2 deletions src/runtime/react.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,15 @@ export interface StyledOptions {
export type mapper<TInner, TOuter> = (input: TInner) => TOuter;

export interface CreateStyled extends StyledTags {
<C extends string | React.ComponentType<any>>(
<C extends IntrinsicElementsKeys | React.ComponentType<any>>(
component: C,
options?: StyledOptions,
): StyledFunction<C>;

<C extends string | React.ComponentType<any>, OtherProps extends object>(
<
C extends IntrinsicElementsKeys | React.ComponentType<any>,
OtherProps extends object
>(
component: C,
options?: StyledOptions | undefined,
): StyledFunction<C, OtherProps>;
Expand Down
22 changes: 3 additions & 19 deletions test/__file_snapshots__/integration-js.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"use strict";
(self["webpackChunk"] = self["webpackChunk"] || []).push([["main"],{

/***/ "./integration/Button.js":
Expand All @@ -6,7 +7,6 @@
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "styles": () => (/* binding */ styles),
Expand All @@ -33,7 +33,6 @@ const Button = /*#__PURE__*/(0,astroturf_react__WEBPACK_IMPORTED_MODULE_0__.defa
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "MyComponent": () => (/* binding */ MyComponent),
Expand Down Expand Up @@ -94,7 +93,6 @@ function MyComponent() {
\********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -117,7 +115,6 @@ const Widget = /*#__PURE__*/(0,astroturf_react__WEBPACK_IMPORTED_MODULE_0__.defa
\************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -140,7 +137,6 @@ const Doodad = /*#__PURE__*/(0,astroturf_react__WEBPACK_IMPORTED_MODULE_0__.defa
\****************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -156,7 +152,6 @@ __webpack_require__.r(__webpack_exports__);
\***********************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -172,7 +167,6 @@ __webpack_require__.r(__webpack_exports__);
\*******************************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -188,7 +182,6 @@ __webpack_require__.r(__webpack_exports__);
\*********************************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -204,7 +197,6 @@ __webpack_require__.r(__webpack_exports__);
\***************************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -220,7 +212,6 @@ __webpack_require__.r(__webpack_exports__);
\***********************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -236,7 +227,6 @@ __webpack_require__.r(__webpack_exports__);
\*******************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -252,7 +242,6 @@ __webpack_require__.r(__webpack_exports__);
\*****************************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -268,7 +257,6 @@ __webpack_require__.r(__webpack_exports__);
\****************************************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -284,7 +272,6 @@ __webpack_require__.r(__webpack_exports__);
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "stylesheet": () => (/* binding */ stylesheet),
Expand Down Expand Up @@ -313,7 +300,6 @@ const css = () => {
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "resolveVariants": () => (/* binding */ resolveVariants),
Expand Down Expand Up @@ -370,7 +356,6 @@ jsx.F = react__WEBPACK_IMPORTED_MODULE_0__.Fragment;
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
Expand Down Expand Up @@ -499,9 +484,8 @@ function styled(type, options, settings) {

},
/******/ __webpack_require__ => { // webpackRuntimeModules
/******/ "use strict";
/******/
/******/ var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["vendors-node_modules_react_index_js"], () => (__webpack_exec__("./integration/main.js")));
/******/ __webpack_require__.O(0, ["vendors-node_modules_react_index_js"], () => (__webpack_exec__("./integration/main.js")));
/******/ var __webpack_exports__ = __webpack_require__.O();
/******/ }
]);
12 changes: 3 additions & 9 deletions test/__file_snapshots__/issue-365-js.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"use strict";
(self["webpackChunk"] = self["webpackChunk"] || []).push([["main"],{

/***/ "./integration/issue-365.js":
Expand All @@ -6,7 +7,6 @@
\**********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var astroturf_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! astroturf/react */ "../src/runtime/react.js");
/* harmony import */ var issue_365_mixins_module_css_astroturf_inline_loader_style_Users_jquense_src_astroturf_test_integration_issue_365_js_mixins__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! issue-365-mixins.module.css!=!astroturf/inline-loader?style!./integration/issue-365.js?mixins */ "issue-365-mixins.module.css!=!../src/inline-loader.ts?style!./integration/issue-365.js?mixins");
Expand All @@ -31,7 +31,6 @@ const BlockStyled = /*#__PURE__*/(0,astroturf_react__WEBPACK_IMPORTED_MODULE_0__
\***************************************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -47,7 +46,6 @@ __webpack_require__.r(__webpack_exports__);
\*****************************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
Expand All @@ -63,7 +61,6 @@ __webpack_require__.r(__webpack_exports__);
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "stylesheet": () => (/* binding */ stylesheet),
Expand Down Expand Up @@ -92,7 +89,6 @@ const css = () => {
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "resolveVariants": () => (/* binding */ resolveVariants),
Expand Down Expand Up @@ -149,7 +145,6 @@ jsx.F = react__WEBPACK_IMPORTED_MODULE_0__.Fragment;
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
Expand Down Expand Up @@ -278,9 +273,8 @@ function styled(type, options, settings) {

},
/******/ __webpack_require__ => { // webpackRuntimeModules
/******/ "use strict";
/******/
/******/ var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["vendors-node_modules_react_index_js"], () => (__webpack_exec__("./integration/issue-365.js")));
/******/ __webpack_require__.O(0, ["vendors-node_modules_react_index_js"], () => (__webpack_exec__("./integration/issue-365.js")));
/******/ var __webpack_exports__ = __webpack_require__.O();
/******/ }
]);
36 changes: 36 additions & 0 deletions test/css-prop.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ describe('css prop', () => {
`,
);

// expect(code).toMatchSnapshot();
expect(code).not.toMatch('React.createElement');
expect(code).not.toContain('/** @jsx');
expect(code).not.toContain('/** @jsxFrag');
Expand All @@ -118,6 +119,41 @@ describe('css prop', () => {
},
);

testAllRunners(
'should find when used with automatic runtime',
async (runner) => {
const [code, styles] = await runner(
`
import { css } from 'astroturf';
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const Widget = React.forwardRef((props, ref) => {
return /*#__PURE__*/_jsxs('div', _extends({}, props, {
tabIndex: -1,
css: css\`
color: red
\`,
children: [/*#__PURE__*/_jsx('span', { css: 'width: 3rem' }), children]
}))
})
`,
);

expect(code).not.toMatch('_jsxs(');
expect(code).not.toMatch('_jsx(');
expect(code).not.toContain('/** @jsx');
expect(code).not.toContain('/** @jsxFrag');

expect(code).toMatch('import _j from "astroturf/jsx";');
expect(code).toMatch('_j(');
expect(styles).toHaveLength(2);
expect(styles[0].identifier).toEqual('CssProp1_div');
},
);

testAllRunners(
'should inject imports in the right order',
async (runner, { requirePath }) => {
Expand Down

0 comments on commit 021e6df

Please sign in to comment.