Issue with selecting a child of a recipe
leo-petrucci opened this issue · comments
Describe the bug
I'm attempting to move away from styled-components
and I think I've come across a bug.
In my codebase I have an outer container which can have multiple variants (primary
, secondary
, etc.). The element then has an internal element which has styles that depend on which variant
the parent has.
In css it would be something like:
.button.primary .inner_container {
// styles specific to the inner_container of a primary button
}
.button.secondary .inner_container {
// styles specific to the inner_container of a secondary button
}
So in vanilla-extract
I replicated it like this:
import { recipe } from '@vanilla-extract/recipes';
import { style } from '@vanilla-extract/css';
export const VanillaButton = recipe({
base: {
padding: '1rem',
cursor: 'pointer',
},
variants: {
variant: {
primary: {
background: 'red',
},
},
},
});
export const VanillaButtonInternal = style({
selectors: {
[`${VanillaButton({ variant: 'primary' })} &`]: {
color: 'blue',
},
},
});
I think this should work, however when I go check the generated css for VanillaButtonInternal
in my browser it looks like this:
.mojo_VanillaButton__17vmkuy0 .mojo_VanillaButton_variant_primary__17vmkuy1 .mojo_VanillaButtonInternal__17vmkuy2 {
color: blue;
}
I think vanilla extract should generate the class as .mojo_VanillaButton__17vmkuy0.mojo_VanillaButton_variant_primary__17vmkuy1
(without the space). Since it's trying to target VanillaButton
with the primary
variant, not VanillaButton
with a child that has primary
variant.
Please let me know if I've misunderstood how this works or if I'm not supposed to do this!
Checking in the reproduction:
You should be able to use the developer tools to inspect the button, which should then allow you to open the page.css
file generated for that specific component.
It should look something like this:
/*!***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** css ./node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[14].oneOf[0].use[1]!./node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[14].oneOf[0].use[2]!./node_modules/@vanilla-extract/webpack-plugin/virtualNextFileLoader/dist/vanilla-extract-webpack-plugin-virtualNextFileLoader.cjs.js!./node_modules/@vanilla-extract/webpack-plugin/vanilla.virtual.css?%7B%22fileName%22%3A%22components%2FButton%2FButton.css.ts.vanilla.css%22%2C%22source%22%3A%22LkJ1dHRvbl9WYW5pbGxhQnV0dG9uX18ycWRvZWMwIHsKICBwYWRkaW5nOiAxcmVtOwogIGN1cnNvcjogcG9pbnRlcjsKfQouQnV0dG9uX1ZhbmlsbGFCdXR0b25fdmFyaWFudF9wcmltYXJ5X18ycWRvZWMxIHsKICBiYWNrZ3JvdW5kOiByZWQ7Cn0KLkJ1dHRvbl9WYW5pbGxhQnV0dG9uX18ycWRvZWMwIC5CdXR0b25fVmFuaWxsYUJ1dHRvbl92YXJpYW50X3ByaW1hcnlfXzJxZG9lYzEgLkJ1dHRvbl9WYW5pbGxhQnV0dG9uSW50ZXJuYWxfXzJxZG9lYzIgewogIGNvbG9yOiBibHVlOwp9%22%7D ***!
\***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
.Button_VanillaButton__2qdoec0 {
padding: 1rem;
cursor: pointer;
}
.Button_VanillaButton_variant_primary__2qdoec1 {
background: red;
}
.Button_VanillaButton__2qdoec0 .Button_VanillaButton_variant_primary__2qdoec1 .Button_VanillaButtonInternal__2qdoec2 {
color: blue;
}
Reproduction
https://stackblitz.com/edit/stackblitz-starters-vqe2d9?file=app%2Fpage.tsx
System Info
System:
OS: Linux 5.0 undefined
CPU: (6) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Memory: 0 Bytes / 0 Bytes
Shell: 1.0 - /bin/jsh
Binaries:
Node: 18.18.0 - /usr/local/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 10.2.3 - /usr/local/bin/npm
pnpm: 8.15.3 - /usr/local/bin/pnpm
npmPackages:
@vanilla-extract/css: ^1.14.1 => 1.14.1
@vanilla-extract/next-plugin: ^2.3.7 => 2.3.7
@vanilla-extract/recipes: ^0.5.2 => 0.5.2
Used Package Manager
npm
Logs
No response
Validations
- Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- The provided reproduction is a minimal reproducible example of the bug.
I did some digging and I think the issue comes from this line:
I think that at the moment there's an assumption that css classes should look the same when they're printed in the html as when they're printed into CSS. In HTML it's fine to have the space, but a space between two classes means something else entirely in CSS. If this function is used for both situations it'll work for one but not the other.
Is there a way to understand which context createRuntimeFn
is being run? i.e. to create classes for HTML or classes for CSS?
I know somewhere .
gets stripped out of the output of that function, I just have no idea where 🤣
Let me know, I'd love to merge a fix if this is indeed a bug.
This is silly, but this is a much easier solution:
export const VanillaButtonInternal = style({
selectors: {
[`${VanillaButton.classNames.variants.variant.primary} &`]: {
color: 'blue',
},
},
});