Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[styled-engine] Add support for goober #27776

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .codesandbox/ci.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
3 changes: 3 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ 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'),
Expand Down
4 changes: 2 additions & 2 deletions docs/babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 2 additions & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
65 changes: 32 additions & 33 deletions docs/src/modules/components/AppNavDrawerItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,36 @@ import ButtonBase from '@material-ui/core/ButtonBase';
import ArrowRightIcon from '@material-ui/icons/ArrowRight';
import Link from 'docs/src/modules/components/Link';

const Item = styled('div', {
shouldForwardProp:
// disable `as` prop
() => true,
})(({ theme }) => {
return {
...theme.typography.body2,
display: 'flex',
borderRadius: theme.shape.borderRadius,
outline: 0,
width: '100%',
paddingTop: 8,
paddingBottom: 8,
justifyContent: 'flex-start',
fontWeight: theme.typography.fontWeightMedium,
transition: theme.transitions.create(['color', 'background-color'], {
duration: theme.transitions.duration.shortest,
}),
'&:hover': {
color: theme.palette.text.primary,
backgroundColor: alpha(theme.palette.text.primary, theme.palette.action.hoverOpacity),
},
'&.Mui-focusVisible': {
backgroundColor: theme.palette.action.focus,
},
[theme.breakpoints.up('md')]: {
paddingTop: 6,
paddingBottom: 6,
},
};
});
const Item = styled(({ component: Component = 'div', ...props }) => <Component {...props} />, {
// disable `as` prop
shouldForwardProp: () => true,
})(({ theme }) => ({
...theme.typography.body2,
display: 'flex',
borderRadius: theme.shape.borderRadius,
outline: 0,
width: '100%',
paddingTop: 8,
paddingBottom: 8,
justifyContent: 'flex-start',
fontWeight: theme.typography.fontWeightMedium,
transition: theme.transitions.create(['color', 'background-color'], {
duration: theme.transitions.duration.shortest,
}),
'&:hover': {
color: theme.palette.text.primary,
backgroundColor: alpha(theme.palette.text.primary, theme.palette.action.hoverOpacity),
},
'&.Mui-focusVisible': {
backgroundColor: theme.palette.action.focus,
},
[theme.breakpoints.up('md')]: {
paddingTop: 6,
paddingBottom: 6,
},
}));

const ItemLink = styled(Item.withComponent(Link), {
const ItemLink = styled(Item, {
shouldForwardProp: (prop) => prop !== 'depth',
})(({ depth, theme }) => {
return {
Expand Down Expand Up @@ -78,7 +75,7 @@ const ItemButtonIcon = styled(ArrowRightIcon, {
};
});

const ItemButton = styled(Item.withComponent(ButtonBase), {
const ItemButton = styled(Item, {
shouldForwardProp: (prop) => prop !== 'depth',
})(({ depth, theme }) => {
return {
Expand Down Expand Up @@ -120,6 +117,7 @@ export default function AppNavDrawerItem(props) {
return (
<StyledLi {...other} depth={depth}>
<ItemLink
component={Link}
activeClassName="app-drawer-active"
href={href}
underline="none"
Expand All @@ -136,6 +134,7 @@ export default function AppNavDrawerItem(props) {
return (
<StyledLi {...other} depth={depth}>
<ItemButton
component={ButtonBase}
depth={depth}
disableRipple
className={topLevel && 'algolia-lvl0'}
Expand Down
2 changes: 1 addition & 1 deletion docs/src/modules/components/ThemeContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export function ThemeProvider(props) {
components: {
MuiCssBaseline: {
styleOverrides: {
body: paletteMode === 'dark' ? darkScrollbar() : null,
body: paletteMode === 'dark' ? darkScrollbar() : {},
},
},
},
Expand Down
23 changes: 23 additions & 0 deletions packages/material-ui-styled-engine-goober/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# @material-ui/styled-engine-goober

This package is a wrapper around the `goober` package.
It is created to be used as alias for the `@material-ui/styled-engine` package, for the developers who would like to use `goober` as a styled engine instead of `@emotion/styled`.

## Installation

The installation of the dependency in your package is slightly different from the usual.
You need to alias the default `emotion` implementation to the `goober` one.
Depending on the bundler you are using, you made add it like this:

### webpack

```js
module.exports = {
//...
resolve: {
alias: {
'@material-ui/styled-engine': '@material-ui/styled-engine-goober',
},
},
};
```
54 changes: 54 additions & 0 deletions packages/material-ui-styled-engine-goober/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "@material-ui/styled-engine-goober",
"version": "5.0.0-beta.1",
"private": false,
"author": "Material-UI Team",
"description": "styled() API wrapper package for goober.",
"main": "./src/index.js",
"keywords": [
"react",
"react-component",
"material-ui",
"goober"
],
"repository": {
"type": "git",
"url": "https://github.com/mui-org/material-ui.git",
"directory": "packages/material-ui-styled-engine-goober"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/mui-org/material-ui/issues"
},
"homepage": "https://next.material-ui.com/guides/styled-engine/",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/material-ui"
},
"scripts": {
"build": "yarn build:legacy && yarn build:modern && yarn build:node && yarn build:stable && yarn build:copy-files",
"build:legacy": "node ../../scripts/build legacy",
"build:modern": "node ../../scripts/build modern",
"build:node": "node ../../scripts/build node",
"build:stable": "node ../../scripts/build stable",
"build:copy-files": "node ../../scripts/copy-files.js",
"prebuild": "rimraf build",
"release": "yarn build && npm publish build --tag next",
"test": "cd ../../ && cross-env NODE_ENV=test mocha 'packages/material-ui-styled-engine-goober/**/*.test.{js,ts,tsx}'",
"typescript": "tslint -p tsconfig.json \"{src,test}/**/*.{spec,d}.{ts,tsx}\" && tsc -p tsconfig.json"
},
"dependencies": {
"@emotion/unitless": "^0.7.5",
"prop-types": "^15.7.2"
},
"peerDependencies": {
"goober": "^5.0.0"
},
"sideEffects": false,
"publishConfig": {
"access": "public"
},
"engines": {
"node": ">=12.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import PropTypes from 'prop-types';
import { deepmerge } from '@material-ui/utils';
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') {
const globalStyles = styles(isEmpty(props.theme) ? defaultTheme : props.theme);
const mergeStyles = Array.isArray(globalStyles)
? globalStyles.reduce((acc, item) => deepmerge(acc, item), {})
: globalStyles;

return mergeStyles;
}

return styles;
});

GlobalStyles.propTypes = {
defaultTheme: PropTypes.object,
styles: PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.func]),
};

export default GlobalStyles;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './GlobalStyles';
export * from './GlobalStyles';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function StyledEngineProvider(props) {
return props.children;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './StyledEngineProvider';
export * from './StyledEngineProvider';
83 changes: 83 additions & 0 deletions packages/material-ui-styled-engine-goober/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
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);

return (...styles: any[]) => {
if (process.env.NODE_ENV !== 'production') {
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);
};
}

export { keyframes, css } from 'goober';
export { default as StyledEngineProvider } from './StyledEngineProvider';
export { default as GlobalStyles } from './GlobalStyles';
4 changes: 4 additions & 0 deletions packages/material-ui-styled-engine-goober/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig",
"include": ["src/**/*", "test/**/*"]
}
12 changes: 1 addition & 11 deletions packages/material-ui-system/src/createStyled.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,7 @@ export type Overwrapped<T, U> = Pick<T, Extract<keyof T, keyof U>>;

export interface StyledComponent<InnerProps, StyleProps, Theme extends object>
extends React.FunctionComponent<InnerProps & StyleProps & { theme?: Theme }>,
ComponentSelector {
/**
* @desc this method is type-unsafe
*/
withComponent<NewTag extends keyof JSX.IntrinsicElements>(
tag: NewTag,
): StyledComponent<JSX.IntrinsicElements[NewTag], StyleProps, Theme>;
withComponent<Tag extends React.JSXElementConstructor<any>>(
tag: Tag,
): StyledComponent<PropsOf<Tag>, StyleProps, Theme>;
}
ComponentSelector {}

export interface StyledOptions {
label?: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/material-ui-system/src/createStyled.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
Loading