jantimon/next-yak

dynamic css property name can't generate expected css

Closed this issue · 6 comments

Let's say we have a styled component like following:

const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: #BF4F74;
  ${'height'}: 40px;
`;

it seems that it will generate css uncorrectly:

.page_yak_0__p1crE {
    font-size: 1.5em;
    text-align: center;
    color: #BF4F74;
}

.page_yak_0__p1crE {
    : 40px; }

I'm not sure if this usage is supported(It's true that this usage should be relatively rare), in styled-components it's ok

hey @await-ovo

thanks for your feedback!

right now dynamic property values are using css variables under the hood.

so for example

const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: #BF4F74;
  height: ${someValue}
`;

is compiled to the following static css:

.generated-class-name {
  font-size: 1.5em;
  text-align: center;
  color: #BF4F74;
  height: var(--some-value);
}

Unfortunately css does allows dynamic properties only for values but not for names.
Therefore such a feature is also for next-yak very hard to achieve.

So for now the only work around is:

const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: #BF4F74;
  ${property === "height" ? css`height: 40px` : css`width: 40px`}
`;

@await-ovo we might add a way to allow this feature - could you please give a more realistic example? :)

Sorry, I don't have a real use case for this at the moment, I was just curious if next-yak could support this pattern.

But I do have a real use case that may not be related to the above ( whick is called component selector in styled components.):

onst Link = styled.a`
  display: flex;
  align-items: center;
  padding: 5px 10px;
  background: papayawhip;
  color: #BF4F74;
`;

const Icon = styled.svg`
  flex: none;
  transition: fill 0.25s;
  width: 48px;
  height: 48px;

  ${Link}:hover & {
    fill: rebeccapurple;
  }
`;

const Label = styled.span`
  display: flex;
  align-items: center;
  line-height: 1.2;

  &::before {
    content: '◀';
    margin: 0 10px;
  }
`;

render(
  <Link href="#">
    <Icon viewBox="0 0 20 20">
      <path d="M10 15h8c1 0 2-1 2-2V3c0-1-1-2-2-2H2C1 1 0 2 0 3v10c0 1 1 2 2 2h4v4l4-4zM5 7h2v2H5V7zm4 0h2v2H9V7zm4 0h2v2h-2V7z"/>
    </Icon>
    <Label>Hovering my parent changes my style!</Label>
  </Link>
);

apologies for the delay in getting back to you!

first off, thanks for bringing up a real use case :)

one approach you can consider is using unique identifiers or class names for your components and then targeting them in your yak styles. panda actually recommends this way

however, we understand that this might not be the most developer-friendly experience. in fact, we weren't completely satisfied with this approach, so we ventured into finding an alternative solution

good news: we managed to allow targeting components inside the same file - see pr #33.
this enhancement will enable you to write code exactly like the example you provided

cross-file targeting is a bit trickier due to module resolution, side effects, and barrel files so we excluded it (at least for now).
but there is a workaround which helps to solve at least some cases:

import { Link } from "./some/other/file";

const CustomLink = styled(Link)``;

const Icon = styled.svg`
  flex: none;
  transition: fill 0.25s;
  width: 48px;
  height: 48px;

  ${CustomLink}:hover & {
    fill: rebeccapurple;
  }
`;

export const Demo = () => (
  <CustomLink>
    <Icon />
  </CustomLink>
);

if you have more questions or if there's anything else we can help you with let us know :)

Thank you for such a detailed response, this looks fantastic!