From d0a0bec55fa7e692d6cf7b5a2ace71d5bead8937 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Sun, 15 Aug 2021 15:46:15 +0200 Subject: [PATCH] [styled-engine] Add support for goober --- .codesandbox/ci.json | 4 +- babel.config.js | 1 + docs/babel.config.js | 4 +- docs/next.config.js | 2 - docs/package.json | 2 + .../modules/components/AppNavDrawerItem.js | 6 +- docs/src/modules/utils/helpers.ts | 1 - .../README.md | 23 +++++ .../package.json | 54 ++++++++++++ .../src/GlobalStyles/GlobalStyles.ts | 23 +++++ .../src/GlobalStyles/index.ts | 2 + .../StyledEngineProvider.tsx | 3 + .../src/StyledEngineProvider/index.ts | 2 + .../src/index.tsx | 84 +++++++++++++++++++ .../tsconfig.json | 4 + .../material-ui-system/src/createStyled.js | 2 +- packages/material-ui/scripts/rollup.config.js | 9 -- scripts/sizeSnapshot/webpack.config.js | 4 - test/karma.tests.js | 7 ++ tsconfig.json | 2 + webpackBaseConfig.js | 4 + yarn.lock | 5 ++ 22 files changed, 226 insertions(+), 22 deletions(-) create mode 100644 packages/material-ui-styled-engine-goober/README.md create mode 100644 packages/material-ui-styled-engine-goober/package.json create mode 100644 packages/material-ui-styled-engine-goober/src/GlobalStyles/GlobalStyles.ts create mode 100644 packages/material-ui-styled-engine-goober/src/GlobalStyles/index.ts create mode 100644 packages/material-ui-styled-engine-goober/src/StyledEngineProvider/StyledEngineProvider.tsx create mode 100644 packages/material-ui-styled-engine-goober/src/StyledEngineProvider/index.ts create mode 100644 packages/material-ui-styled-engine-goober/src/index.tsx create mode 100644 packages/material-ui-styled-engine-goober/tsconfig.json diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json index 6dae83fb6a85b5..78dff475afaed9 100644 --- a/.codesandbox/ci.json +++ b/.codesandbox/ci.json @@ -14,7 +14,8 @@ "packages/material-ui-utils", "packages/material-ui-unstyled", "packages/material-ui-styled-engine", - "packages/material-ui-styled-engine-sc" + "packages/material-ui-styled-engine-sc", + "packages/material-ui-styled-engine-goober" ], "publishDirectory": { "@material-ui/codemod": "packages/material-ui-codemod/build", @@ -24,6 +25,7 @@ "@material-ui/styles": "packages/material-ui-styles/build", "@material-ui/styled-engine": "packages/material-ui-styled-engine/build", "@material-ui/styled-engine-sc": "packages/material-ui-styled-engine-sc/build", + "@material-ui/styled-engine-goober": "packages/material-ui-styled-engine-goober/build", "@material-ui/system": "packages/material-ui-system/build", "@material-ui/private-theming": "packages/material-ui-private-theming/build", "@material-ui/types": "packages/material-ui-types/build", diff --git a/babel.config.js b/babel.config.js index 7c3ba507ed0bee..e1a7dc60ac35fb 100644 --- a/babel.config.js +++ b/babel.config.js @@ -15,6 +15,7 @@ const defaultAlias = { '@material-ui/lab': resolveAliasPath('./packages/material-ui-lab/src'), '@material-ui/styled-engine': resolveAliasPath('./packages/material-ui-styled-engine/src'), '@material-ui/styled-engine-sc': resolveAliasPath('./packages/material-ui-styled-engine-sc/src'), + '@material-ui/styled-engine-goober': resolveAliasPath('./packages/material-ui-styled-engine-goober/src'), '@material-ui/styles': resolveAliasPath('./packages/material-ui-styles/src'), '@material-ui/system': resolveAliasPath('./packages/material-ui-system/src'), '@material-ui/private-theming': resolveAliasPath('./packages/material-ui-private-theming/src'), diff --git a/docs/babel.config.js b/docs/babel.config.js index c9e98edcca5209..843ba61d0debde 100644 --- a/docs/babel.config.js +++ b/docs/babel.config.js @@ -19,10 +19,10 @@ const alias = { '@material-ui/icons': '../packages/material-ui-icons/lib', '@material-ui/lab': '../packages/material-ui-lab/src', '@material-ui/styles': '../packages/material-ui-styles/src', - '@material-ui/styled-engine-sc': '../packages/material-ui-styled-engine-sc/src', // Swap the comments on the next two lines for using the styled-components as style engine - '@material-ui/styled-engine': '../packages/material-ui-styled-engine/src', + // '@material-ui/styled-engine': '../packages/material-ui-styled-engine/src', // '@material-ui/styled-engine': '../packages/material-ui-styled-engine-sc/src', + '@material-ui/styled-engine': '../packages/material-ui-styled-engine-goober/src', '@material-ui/system': '../packages/material-ui-system/src', '@material-ui/private-theming': '../packages/material-ui-private-theming/src', '@material-ui/utils': '../packages/material-ui-utils/src', diff --git a/docs/next.config.js b/docs/next.config.js index 0efe39056e2625..e4fba2e05f8113 100644 --- a/docs/next.config.js +++ b/docs/next.config.js @@ -124,8 +124,6 @@ module.exports = { '@material-ui/icons': '../packages/material-ui-icons/lib', '@material-ui/lab': '../packages/material-ui-lab/src', '@material-ui/styled-engine': '../packages/material-ui-styled-engine/src', - '@material-ui/styled-engine-sc': - '../packages/material-ui-styled-engine-sc/src', '@material-ui/styles': '../packages/material-ui-styles/src', '@material-ui/system': '../packages/material-ui-system/src', '@material-ui/private-theming': diff --git a/docs/package.json b/docs/package.json index 13982691c3579c..df4b0c0988d272 100644 --- a/docs/package.json +++ b/docs/package.json @@ -37,6 +37,7 @@ "@material-ui/lab": "5.0.0-alpha.43", "@material-ui/styled-engine": "5.0.0-beta.4", "@material-ui/styled-engine-sc": "5.0.0-beta.1", + "@material-ui/styled-engine-goober": "5.0.0-beta.1", "@material-ui/styles": "5.0.0-beta.4", "@material-ui/system": "5.0.0-beta.4", "@material-ui/types": "6.0.2", @@ -77,6 +78,7 @@ "final-form": "^4.18.5", "flexsearch": "^0.7.0", "fs-extra": "^10.0.0", + "goober": "^2.0.0", "json2mq": "^0.2.0", "jss": "^10.0.3", "jss-plugin-template": "^10.0.3", diff --git a/docs/src/modules/components/AppNavDrawerItem.js b/docs/src/modules/components/AppNavDrawerItem.js index 59d2ca85eb0359..0fb0bbf8a35110 100644 --- a/docs/src/modules/components/AppNavDrawerItem.js +++ b/docs/src/modules/components/AppNavDrawerItem.js @@ -38,7 +38,7 @@ const Item = styled('div', { }; }); -const ItemLink = styled(Item.withComponent(Link), { +const ItemLink = styled(Item, { shouldForwardProp: (prop) => prop !== 'depth', })(({ depth, theme }) => { return { @@ -78,7 +78,7 @@ const ItemButtonIcon = styled(ArrowRightIcon, { }; }); -const ItemButton = styled(Item.withComponent(ButtonBase), { +const ItemButton = styled(Item, { shouldForwardProp: (prop) => prop !== 'depth', })(({ depth, theme }) => { return { @@ -120,6 +120,7 @@ export default function AppNavDrawerItem(props) { return ( =12.0.0" + } +} diff --git a/packages/material-ui-styled-engine-goober/src/GlobalStyles/GlobalStyles.ts b/packages/material-ui-styled-engine-goober/src/GlobalStyles/GlobalStyles.ts new file mode 100644 index 00000000000000..fbdbb00276ab0c --- /dev/null +++ b/packages/material-ui-styled-engine-goober/src/GlobalStyles/GlobalStyles.ts @@ -0,0 +1,23 @@ +import PropTypes from 'prop-types'; +import { createGlobalStyles } from 'goober/global'; + +function isEmpty(obj) { + return obj === undefined || obj === null || Object.keys(obj).length === 0; +} + +const GlobalStyles = createGlobalStyles((props) => { + const { styles, defaultTheme = {} } = props; + + if (typeof styles === 'function') { + return styles(isEmpty(props.theme) ? defaultTheme : props.theme); + } + + return styles; +}); + +GlobalStyles.propTypes = { + defaultTheme: PropTypes.object, + styles: PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.func]), +}; + +export default GlobalStyles; diff --git a/packages/material-ui-styled-engine-goober/src/GlobalStyles/index.ts b/packages/material-ui-styled-engine-goober/src/GlobalStyles/index.ts new file mode 100644 index 00000000000000..a815f5c4a572b2 --- /dev/null +++ b/packages/material-ui-styled-engine-goober/src/GlobalStyles/index.ts @@ -0,0 +1,2 @@ +export { default } from './GlobalStyles'; +export * from './GlobalStyles'; diff --git a/packages/material-ui-styled-engine-goober/src/StyledEngineProvider/StyledEngineProvider.tsx b/packages/material-ui-styled-engine-goober/src/StyledEngineProvider/StyledEngineProvider.tsx new file mode 100644 index 00000000000000..087e736373a426 --- /dev/null +++ b/packages/material-ui-styled-engine-goober/src/StyledEngineProvider/StyledEngineProvider.tsx @@ -0,0 +1,3 @@ +export default function StyledEngineProvider(props) { + return props.children; +} diff --git a/packages/material-ui-styled-engine-goober/src/StyledEngineProvider/index.ts b/packages/material-ui-styled-engine-goober/src/StyledEngineProvider/index.ts new file mode 100644 index 00000000000000..7fdd272b28e6ca --- /dev/null +++ b/packages/material-ui-styled-engine-goober/src/StyledEngineProvider/index.ts @@ -0,0 +1,2 @@ +export { default } from './StyledEngineProvider'; +export * from './StyledEngineProvider'; diff --git a/packages/material-ui-styled-engine-goober/src/index.tsx b/packages/material-ui-styled-engine-goober/src/index.tsx new file mode 100644 index 00000000000000..9cf97cbb58c372 --- /dev/null +++ b/packages/material-ui-styled-engine-goober/src/index.tsx @@ -0,0 +1,84 @@ +import * as React from 'react'; +import { styled as styledGoober, setup } from 'goober'; +import unitless from '@emotion/unitless'; +import { prefix } from 'goober/prefixer'; + +export const ThemeContext = React.createContext({}); + +// TODO drop hard coded function +function shouldForwardProp(prop: string) { + return prop !== 'styleProps' && prop !== 'theme' && prop !== 'sx' && prop !== 'as'; +} + +const useTheme = () => React.useContext(ThemeContext); + +function forwardProps(props: object) { + Object.keys(props).forEach((prop) => { + // Or any other conditions. + // This could also check if this is a dev build and not remove the props + if (!shouldForwardProp(prop)) { + // @ts-ignore + delete props[prop]; + } + }); +} + +function isCustomProperty(property: string) { + // 45 is - + return property.charCodeAt(1) === 45; +} + +function camelize(str: string) { + return str.replace(/-./g, (chunk) => chunk[1].toUpperCase()); +} + +function plugins(property: string, inValue: any) { + // Add default px unit when needed + let value = inValue; + const key = camelize(property); + if ( + unitless[key] !== 1 && + !isCustomProperty(property) && + typeof value === 'number' && + value !== 0 + ) { + value = `${value}px`; + } + + return prefix(property, value); +} + +// @ts-expect-error Wrong type /~https://github.com/cristianbote/goober/pull/364 +setup(React.createElement, plugins, useTheme, forwardProps); + +// TODO hanle options +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export default function styled(tag: any, options: any) { + const stylesFactory = styledGoober(tag, React.forwardRef); + + if (process.env.NODE_ENV !== 'production') { + return (...styles: any[]) => { + const component = typeof tag === 'string' ? `"${tag}"` : 'component'; + if (styles.length === 0) { + console.error( + [ + `Material-UI: Seems like you called \`styled(${component})()\` without a \`style\` argument.`, + 'You must provide a `styles` argument: `styled("div")(styleYouForgotToPass)`.', + ].join('\n'), + ); + } else if (styles.some((style) => style === undefined)) { + console.error( + `Material-UI: the styled(${component})(...args) API requires all its args to be defined.`, + ); + } + // @ts-ignore + return stylesFactory(...styles); + }; + } + + return stylesFactory; +} + +export { keyframes, css } from 'goober'; +export { default as StyledEngineProvider } from './StyledEngineProvider'; +export { default as GlobalStyles } from './GlobalStyles'; diff --git a/packages/material-ui-styled-engine-goober/tsconfig.json b/packages/material-ui-styled-engine-goober/tsconfig.json new file mode 100644 index 00000000000000..57220954971e1e --- /dev/null +++ b/packages/material-ui-styled-engine-goober/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig", + "include": ["src/**/*", "test/**/*"] +} diff --git a/packages/material-ui-system/src/createStyled.js b/packages/material-ui-system/src/createStyled.js index 892d08d8d77c7a..75d9106c588d9d 100644 --- a/packages/material-ui-system/src/createStyled.js +++ b/packages/material-ui-system/src/createStyled.js @@ -5,7 +5,7 @@ import styleFunctionSx from './styleFunctionSx'; import propsToClassKey from './propsToClassKey'; function isEmpty(obj) { - return Object.keys(obj).length === 0; + return obj == null || Object.keys(obj).length === 0; } const getStyleOverrides = (name, theme) => { diff --git a/packages/material-ui/scripts/rollup.config.js b/packages/material-ui/scripts/rollup.config.js index cb073ea7394523..0008f3cf46298a 100644 --- a/packages/material-ui/scripts/rollup.config.js +++ b/packages/material-ui/scripts/rollup.config.js @@ -105,15 +105,6 @@ const nestedFolder = { return resolved; } - if (importee.indexOf('@material-ui/styled-engine-sc/') === 0) { - const folder = importee.split('/')[2]; - const resolved = path.resolve( - __dirname, - `../../../packages/material-ui-styled-engine-sc/src/${folder}/index.js`, - ); - return resolved; - } - if (importee.indexOf('@material-ui/system/') === 0) { const folder = importee.split('/')[2]; const resolved = path.resolve( diff --git a/scripts/sizeSnapshot/webpack.config.js b/scripts/sizeSnapshot/webpack.config.js index 1826208a380b7a..286e6a584a2957 100644 --- a/scripts/sizeSnapshot/webpack.config.js +++ b/scripts/sizeSnapshot/webpack.config.js @@ -168,10 +168,6 @@ module.exports = async function webpackConfig(webpack, environment) { workspaceRoot, 'packages/material-ui-styled-engine/build', ), - '@material-ui/styled-engine-sc': path.join( - workspaceRoot, - 'packages/material-ui-styles-sc/build', - ), '@material-ui/styles': path.join(workspaceRoot, 'packages/material-ui-styles/build'), '@material-ui/system': path.join(workspaceRoot, 'packages/material-ui-system/build'), '@material-ui/private-theming': path.join( diff --git a/test/karma.tests.js b/test/karma.tests.js index 0d9e3477dd9e56..bc9638dd454160 100644 --- a/test/karma.tests.js +++ b/test/karma.tests.js @@ -36,6 +36,13 @@ const styledEngineSCContext = require.context( ); styledEngineSCContext.keys().forEach(styledEngineSCContext); +const styledEngineGooberContext = require.context( + '../packages/material-ui-styled-engine-goober/src/', + true, + /\.test\.(js|ts|tsx)$/, +); +styledEngineGooberContext.keys().forEach(styledEngineGooberContext); + const systemContext = require.context( '../packages/material-ui-system/src/', true, diff --git a/tsconfig.json b/tsconfig.json index ded72cb01a3a2d..0563e0f195dc41 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,6 +23,8 @@ "@material-ui/styled-engine/*": ["./packages/material-ui-styled-engine/src/*"], "@material-ui/styled-engine-sc": ["./packages/material-ui-styled-engine-sc/src"], "@material-ui/styled-engine-sc/*": ["./packages/material-ui-styled-engine-sc/src/*"], + "@material-ui/styled-engine-goober": ["./packages/material-ui-styled-engine-goober/src"], + "@material-ui/styled-engine-goober/*": ["./packages/material-ui-styled-engine-goober/src/*"], "@material-ui/styles": ["./packages/material-ui-styles/src"], "@material-ui/styles/*": ["./packages/material-ui-styles/src/*"], "@material-ui/system": ["./packages/material-ui-system/src"], diff --git a/webpackBaseConfig.js b/webpackBaseConfig.js index d41bffde4cd26a..d7f0151cb04bb3 100644 --- a/webpackBaseConfig.js +++ b/webpackBaseConfig.js @@ -21,6 +21,10 @@ module.exports = { __dirname, './packages/material-ui-styled-engine-sc/src', ), + '@material-ui/styled-engine-goober': path.resolve( + __dirname, + './packages/material-ui-styled-engine-goober/src', + ), '@material-ui/styles': path.resolve(__dirname, './packages/material-ui-styles/src'), '@material-ui/system': path.resolve(__dirname, './packages/material-ui-system/src'), '@material-ui/private-theming': path.resolve( diff --git a/yarn.lock b/yarn.lock index df018e84ef1bcd..1977db51d7d473 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8674,6 +8674,11 @@ gonzales-pe@^4.3.0: dependencies: minimist "^1.2.5" +goober@^2.0.0: + version "2.0.40" + resolved "https://registry.yarnpkg.com/goober/-/goober-2.0.40.tgz#7f3d4cafdf6854da55460a639e9b3a15848aaaf3" + integrity sha512-LnYclgtz+t2Q9fDEIEdMKCoh5+JyBwG6ORJme52Av18ZrajhqEtzACXWhL/+IIB0SegvwXLcGG7FH+BJ/Z3Ljw== + good-listener@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"