I am trying to make a HOC that uses the Emotion library to return a React component that accepts any CSS property as a prop and styles it with Emotion as well as accepting a prop called css, also injecting that into Emotion's own css prop.
Here is what that looks like:
/** @jsx jsx */
/** @jsxRuntime classic */
import React from "react"
import { jsx, type CSSObject } from '@emotion/react'
// Returns the type of CSS style properties, like 'marginTop' or 'backgroundColor'
type HOCProps = Partial<React.CSSProperties> & {
css?: CSSObject | string
}
// Converts a string of css into an object for Emotion
const cssStringToObject = (css: string): CSSObject => {
const r = /(?<=^|;)\s*([^:]+)\s*:\s*([^;]+)\s*/g, o = {}
css.replace(r, (_, p, v) => o[p.replace(/-(.)/g, (m,p) => p.toUpperCase())] = v)
return o
}
export default function withStyles<T>(Component: React.ComponentType<T>) {
return (props: T & HOCProps) =>
<Component
{...props}
css={{
...props,
...(props.css && (
typeof props.css === 'string'
? cssStringToObject(props.css)
: props.css
))
}}
/>
}
This is then used like this:
// AnotherFile.jsx
import React from 'react';
import withStyles from './withStyles'
const ButtonComponent = (props: React.HTMLAttributes<HTMLButtonElement>) => {
return (
<button {...props}>
{props.children}
</button>
)
}
const Button = withStyles(ButtonComponent)
function App() {
return (
<div className="App">
<Button
padding="5em"
marginLeft="10em"
marginTop="10em"
backgroundColor="lightblue"
css={{
borderRadius: '5em'
}}
onClick={() => alert("Hello")}
>
Click Me
</Button>
</div>
);
}
This works fine as far as styling the component, but in the DOM it produces an element that looks like this:
<button class="css-1nsumwm" padding="5em" marginleft="10em" margintop="10em" backgroundcolor="lightblue">Click Me</button>
which is throwing React errors:
Warning: React does not recognize the `backgroundColor` prop on a DOM element.
How can I prevent these props from being attached in this way?