Skip to content

Commit c8124d3

Browse files
fix(emotion): use plain label string for keyframes, not CSS label property
`keyframes` expects a plain name string (e.g. "pulse"), not a CSS label property (e.g. "label:pulse;"). Add `ExprKind::Keyframes` variant and map `keyframes` to it so label injection uses `create_label(false)` instead of `create_label(true)`, preventing the `animation-` prefix regression introduced in #597. Fixes #607 Co-authored-by: Donny/강동윤 <kdy1@users.noreply.github.com>
1 parent 540f533 commit c8124d3

4 files changed

Lines changed: 69 additions & 23 deletions

File tree

packages/emotion/transform/src/import_map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static EMOTION_OFFICIAL_LIBRARIES: Lazy<Arc<Vec<EmotionModuleConfig>>> = Lazy::n
4848
},
4949
ExportItem {
5050
name: "keyframes".to_owned(),
51-
kind: ExprKind::Css,
51+
kind: ExprKind::Keyframes,
5252
},
5353
ExportItem {
5454
name: "Global".to_owned(),

packages/emotion/transform/src/lib.rs

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ enum ImportType {
102102
enum ExprKind {
103103
#[default]
104104
Css,
105+
Keyframes,
105106
Styled,
106107
GlobalJSX,
107108
}
@@ -565,10 +566,17 @@ impl<C: Comments> Fold for EmotionTransformer<'_, C> {
565566
if let Some(package) = self.import_packages.get(&i.to_id()) {
566567
if !expr.args.is_empty() {
567568
if let PackageMeta::Named(kind) = package {
568-
if matches!(kind, ExprKind::Css) && !self.in_jsx_element {
569+
if matches!(kind, ExprKind::Css | ExprKind::Keyframes)
570+
&& !self.in_jsx_element
571+
{
569572
self.comments.add_pure_comment(expr.span.lo());
570573
if self.options.auto_label.unwrap_or(false) {
571-
expr.args.push(self.create_label(true).as_arg());
574+
let label = if matches!(kind, ExprKind::Keyframes) {
575+
self.create_label(false)
576+
} else {
577+
self.create_label(true)
578+
};
579+
expr.args.push(label.as_arg());
572580
}
573581
if let Some(cm) = self.create_sourcemap(expr.span.lo) {
574582
expr.args.push(cm.as_arg());
@@ -702,13 +710,17 @@ impl<C: Comments> Fold for EmotionTransformer<'_, C> {
702710
}
703711
}
704712
if let PackageMeta::Namespace(c) = package {
705-
if c.exported_names
706-
.iter()
707-
.any(|n| match_css_export(n, &m.prop))
713+
if let Some(kind) =
714+
find_css_export_kind(&c.exported_names, &m.prop)
708715
{
709716
self.comments.add_pure_comment(expr.span.lo());
710717
if self.options.auto_label.unwrap_or(false) {
711-
expr.args.push(self.create_label(true).as_arg());
718+
let label = if matches!(kind, ExprKind::Keyframes) {
719+
self.create_label(false)
720+
} else {
721+
self.create_label(true)
722+
};
723+
expr.args.push(label.as_arg());
712724
}
713725
if let Some(cm) = self.create_sourcemap(expr.span.lo()) {
714726
expr.args.push(cm.as_arg());
@@ -840,16 +852,24 @@ impl<C: Comments> Fold for EmotionTransformer<'_, C> {
840852
}
841853
}
842854
}
843-
// css``
855+
// css`` or keyframes``
844856
Expr::Ident(i) => {
845-
if let Some(PackageMeta::Named(ExprKind::Css)) =
857+
if let Some(PackageMeta::Named(kind @ (ExprKind::Css | ExprKind::Keyframes))) =
846858
self.import_packages.get(&i.to_id())
847859
{
860+
let kind = *kind;
848861
let mut args = self.create_args_from_tagged_tpl(&mut tagged_tpl.tpl);
849862
if !self.in_jsx_element {
850863
self.comments.add_pure_comment(i.span.lo());
851864
if self.options.auto_label.unwrap_or(false) {
852-
args.push(self.create_tagged_tpl_label_arg());
865+
if matches!(kind, ExprKind::Keyframes) {
866+
let label = self.create_label(false);
867+
if !label.is_empty() {
868+
args.push(label.as_arg());
869+
}
870+
} else {
871+
args.push(self.create_tagged_tpl_label_arg());
872+
}
853873
}
854874
if let Some(cm) = self.create_sourcemap(tagged_tpl.span.lo()) {
855875
args.push(cm.as_arg());
@@ -913,10 +933,10 @@ impl<C: Comments> Fold for EmotionTransformer<'_, C> {
913933
}
914934
}
915935
PackageMeta::Namespace(c) => {
916-
if c.exported_names
917-
.iter()
918-
.any(|item| match_css_export(item, &member_expr.prop))
919-
{
936+
if let Some(kind) = find_css_export_kind(
937+
&c.exported_names,
938+
&member_expr.prop,
939+
) {
920940
self.comments.add_pure_comment(member_expr.span.lo());
921941
return Expr::Call(CallExpr {
922942
callee: member_expr.take().as_callee(),
@@ -925,7 +945,16 @@ impl<C: Comments> Fold for EmotionTransformer<'_, C> {
925945
&mut tagged_tpl.tpl,
926946
);
927947
if self.options.auto_label.unwrap_or(false) {
928-
args.push(self.create_tagged_tpl_label_arg());
948+
if matches!(kind, ExprKind::Keyframes) {
949+
let label = self.create_label(false);
950+
if !label.is_empty() {
951+
args.push(label.as_arg());
952+
}
953+
} else {
954+
args.push(
955+
self.create_tagged_tpl_label_arg(),
956+
);
957+
}
929958
}
930959
if let Some(cm) =
931960
self.create_sourcemap(tagged_tpl.span.lo())
@@ -1046,15 +1075,18 @@ impl<C: Comments> Fold for EmotionTransformer<'_, C> {
10461075
}
10471076
}
10481077

1049-
fn match_css_export(item: &ExportItem, prop: &MemberProp) -> bool {
1050-
if matches!(item.kind, ExprKind::Css) {
1051-
if let MemberProp::Ident(prop) = prop {
1052-
if item.name.as_str() == prop.sym.as_ref() {
1053-
return true;
1054-
}
1055-
}
1078+
fn find_css_export_kind(items: &[ExportItem], prop: &MemberProp) -> Option<ExprKind> {
1079+
if let MemberProp::Ident(ident) = prop {
1080+
items
1081+
.iter()
1082+
.find(|item| {
1083+
matches!(item.kind, ExprKind::Css | ExprKind::Keyframes)
1084+
&& item.name.as_str() == ident.sym.as_ref()
1085+
})
1086+
.map(|item| item.kind)
1087+
} else {
1088+
None
10561089
}
1057-
false
10581090
}
10591091

10601092
#[inline]

packages/emotion/transform/tests/labels/emotion-js/keyframes.js

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// https://github.com/swc-project/plugins/issues/607
2+
// keyframes label should be plain name string, not "label:name;" CSS property
3+
4+
import { keyframes } from "@emotion/react";
5+
6+
const pulse = keyframes`
7+
0% { opacity: 1; }
8+
50% { opacity: 0.5; }
9+
100% { opacity: 1; }
10+
`;

0 commit comments

Comments
 (0)