ben-rogerson / twin.macro

πŸ¦Ήβ€β™‚οΈ Twin blends the magic of Tailwind with the flexibility of css-in-js (emotion, styled-components, solid-styled-components, stitches and goober) at build time.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error when passing props to the css attribute in solid/stitches

benash opened this issue Β· comments

When using the SolidJS integration, the following results in Uncaught ReferenceError: props is not defined in the browser:

const BrokenInput = (props: InputProps) => (
  <input
    css={{
      ...tw`border`,
      ...(props.hasHover && tw`hover:border-red-600`),
    }}
  />
)

On the other hand, this works fine:

const WorkingInput = styled.input((props: InputProps) => ({
  ...tw`border`,
  ...(props.hasHover && tw`hover:border-red-600`),
}))

Thanks for posting this bug, I've seen the issue too and I haven't settled on a good solution yet.

Here's the broken transformation:

const BrokenInput = (props) => (
  <input css={{ ...(props.hasHover && tw`block`) }} /> // < Any conditionals like `props` here will lose their reference
)

// ↓ ↓ ↓ ↓ ↓ ↓

import { styled } from "solid-styled-components";

const TwComponent = styled("input")({
  ...(props.hasHover && { "display": "block" }) // < `props` reference is lost
});

const BrokenInput = props => <TwComponent />; // < `props` isn't passed to the component

The css prop doesn't exist in solid-styled-components so twin converts the element into a styled component.
The problem is that during that process all the variables used in the conditional are severed and rather than chasing a complex solution in babel I'm looking into adding a new conversion type instead.

The new conversion for the css prop would use the css import from solid-styled-components:

const BrokenInput = (props) => (
  <input css={{ ...(props.hasHover && tw`block`) }} />
)

// ↓ ↓ ↓ ↓ ↓ ↓

import { css } from "solid-styled-components";

const BrokenInput = props => (
  <input class={css({ ...(props.hasHover && { display: "block" }) })} />
)

This option would simplify the conversion and the conditionals wouldn't be affected.

One issue is that if there's already a class on the element then a merge needs to happen - perhaps something as simple as this would work:

<input class="box" css={{ ... }} />
// ↓ ↓ ↓ ↓ ↓ ↓
<input class={"box " + css({ ... }) } />

and if css is defined before the class attribute:

<input css={{ ... }} class="box" />
// ↓ ↓ ↓ ↓ ↓ ↓
<input class={css({ ... }) + " box" } />

Thanks for the explanation. Would Solid's classList help with that merge?

<div classList={{ ...{ [css`color: rebeccapurple;`]: true }, ...{ myClass: true, otherClass: false } }}>My text</div>
commented

mark. same problem.