Skip to content

Commit

Permalink
implement object name
Browse files Browse the repository at this point in the history
  • Loading branch information
jantimon committed Oct 7, 2024
1 parent 86773cf commit 73e4778
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 12 deletions.
59 changes: 56 additions & 3 deletions packages/yak-swc/yak_swc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use std::path::Path;
use std::vec;
use swc_core::atoms::atom;

use swc_core::atoms::Atom;
use swc_core::common::comments::Comment;
use swc_core::common::comments::Comments;
use swc_core::common::{Spanned, SyntaxContext, DUMMY_SP};
Expand Down Expand Up @@ -277,6 +276,24 @@ where
self.process_yak_literal(&mut tagged_tpl.clone(), css_state.clone());
runtime_expressions.extend(inline_runtime_exprs);
runtime_css_variables.extend(inline_runtime_css_vars);
}
// keyframes - of animations which have not been parsed yet
// const Button = styled.button`animation: ${highlight};`
// const highlight = keyframes`from { color: red; }`
else if is_valid_tagged_tpl(
&tagged_tpl,
self.yak_library_imports.yak_keyframes_idents.clone(),
) {
// Create a unique name for the keyframe
let keyframe_name = self
.naming_convention
.generate_unique_name_for_variable(&scoped_name);
// Store the keyframe for the later keyframe declaration
self
.variable_name_selector_mapping
.insert(scoped_name.clone(), keyframe_name.clone());
let (new_state, _) = parse_css(keyframe_name.as_str(), css_state);
css_state = Some(new_state);
} else {
HANDLER.with(|handler| {
handler
Expand Down Expand Up @@ -522,6 +539,38 @@ where
}
}

/// Visit object member value declarations
/// To store the current name which can be used for class names
/// e.g. Button for const obj = { Button: styled.button`color: red;` }
fn visit_mut_object_lit(&mut self, n: &mut ObjectLit) {
if !self.yak_library_imports.is_using_next_yak() {
return;
}
if self.current_variable_name.is_none() {
n.visit_mut_children_with(self);
return;
}
let current_variable_name = self.current_variable_name.clone().unwrap();
for props_or_spread in &mut n.props {
if let PropOrSpread::Prop(prop) = props_or_spread {
if let Some(key_value) = prop.as_key_value() {
if let PropName::Ident(value) = &key_value.key {
let mut new_parts = current_variable_name.parts.clone();
new_parts.push(value.sym.clone());
self.current_variable_name = Some(ScopedVariableReference::new(
current_variable_name.id.clone(),
new_parts,
));
prop.visit_mut_with(self);
self.current_variable_name = Some(current_variable_name.clone());
continue;
}
}
}
props_or_spread.visit_mut_with(self);
}
}

// Visit ternary expressions
// To store the current condition which can be used for class names of nested css expressions
fn visit_mut_expr(&mut self, n: &mut Expr) {
Expand Down Expand Up @@ -614,12 +663,17 @@ where
}

let is_top_level = !self.is_inside_css_expression();
let current_variable_id = self.get_current_component_id();

let mut transform: Box<dyn YakTransform> = match yak_library_function_name.as_deref() {
// Styled Components transform works only on top level
Some("styled") if is_top_level => Box::new(TransformStyled::new()),
// Keyframes transform works only on top level
Some("keyframes") if is_top_level => Box::new(TransformKeyframes::new()),
Some("keyframes") if is_top_level => Box::new(TransformKeyframes::new(
self
.variable_name_selector_mapping
.get(&current_variable_id),
)),
// CSS Mixin e.g. const highlight = css`color: red;`
Some("css") if is_top_level => Box::new(TransformCssMixin::new(self.current_exported)),
// CSS Inline mixin e.g. styled.button`${() => css`color: red;`}`
Expand All @@ -643,7 +697,6 @@ where
}
};

let current_variable_id = self.get_current_component_id();
// Remove the scope postfix to make the variable name easier to read
let current_variable_name = current_variable_id.id.0.to_string();

Expand Down
18 changes: 14 additions & 4 deletions packages/yak-swc/yak_swc/src/naming_convention.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::utils::murmur_hash::murmurhash2_32_gc;
use crate::{utils::murmur_hash::murmurhash2_32_gc, variable_visitor::ScopedVariableReference};
use rustc_hash::FxHashMap;

pub struct NamingConvention {
Expand Down Expand Up @@ -52,6 +52,15 @@ impl NamingConvention {
}
}

// Generate a unique name for a variable reference
// e.g "foo.bar" -> "foo_bar-01"
pub fn generate_unique_name_for_variable(
&mut self,
variable: &ScopedVariableReference,
) -> String {
self.generate_unique_name(&variable.to_readable_string())
}

/// Generate a unique CSS variable name based on the file name and a base name
pub fn get_css_variable_name(&mut self, base_name: &str, dev_mode: bool) -> String {
let name: &str = if dev_mode {
Expand All @@ -75,12 +84,12 @@ fn escape_css_identifier(input: &str) -> String {
for c in chars {
match c {
'a'..='z' | 'A'..='Z' | '-' | '_' | '$' | '\\' => result.push(c),
// Whitespace
' ' | '\t' => {
// Whitespace and member expression separator
' ' | '\t' | '.' => {
result.push('_');
}
// Remove control characters
'\0'..='\x1F' | '\x7F' | '.' => continue,
'\0'..='\x1F' | '\x7F' => continue,
// Escape Unicode characters
c if c > '\u{00FF}' => {
result.push('\\');
Expand Down Expand Up @@ -118,6 +127,7 @@ mod tests {
assert_eq!(escape_css_identifier("foo\\bar"), "foo\\bar");
assert_eq!(escape_css_identifier("foo💩bar"), "foo\\💩bar");
assert_eq!(escape_css_identifier("foo bar"), "foo_bar");
assert_eq!(escape_css_identifier("foo.bar"), "foo_bar");
assert_eq!(escape_css_identifier("foo\tbar"), "foo_bar");
assert_eq!(escape_css_identifier("foo\nbar"), "foobar");
assert_eq!(escape_css_identifier("1foo"), "_1foo");
Expand Down
2 changes: 1 addition & 1 deletion packages/yak-swc/yak_swc/src/variable_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub struct VariableVisitor {
/// - a variable e.g. foo -> (foo#3, [foo])
/// - a member expression e.g. foo.bar -> (foo#3, [foo, bar])
pub struct ScopedVariableReference {
/// The swc id of the variable
/// The swc id of the variable
pub id: Id,
/// The parts of the variable reference
/// - e.g. foo.bar.baz -> [foo, bar, baz]
Expand Down
13 changes: 9 additions & 4 deletions packages/yak-swc/yak_swc/src/yak_transforms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,9 @@ pub struct TransformKeyframes {
}

impl TransformKeyframes {
pub fn new() -> TransformKeyframes {
pub fn new(animation_name: Option<&String>) -> TransformKeyframes {
TransformKeyframes {
animation_name: None,
animation_name: animation_name.cloned(),
}
}
}
Expand All @@ -328,8 +328,13 @@ impl YakTransform for TransformKeyframes {
declaration_name: &str,
_previous_parser_state: Option<ParserState>,
) -> ParserState {
let css_identifier = naming_convention.generate_unique_name(declaration_name);
self.animation_name = Some(css_identifier.clone());
let css_identifier = if self.animation_name.is_none() {
let new_identifier = naming_convention.generate_unique_name(declaration_name);
self.animation_name = Some(new_identifier.clone());
new_identifier
} else {
self.animation_name.clone().unwrap()
};
let mut parser_state = ParserState::new();
parser_state.current_scopes = vec![CssScope {
name: format!("@keyframes {}", css_identifier),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { styled, css, keyframes } from "next-yak";

export const FadeInText = styled.p<{ $reverse?: boolean }>`
${({ $reverse }) => $reverse ? css`
animation: ${fadeOut} 1s ease-in;
` : css`
animation: ${fadeIn} 1s ease-in;
`}
font-size: 18px;
color: #333;
`;

const fadeIn = keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`;

const fadeOut = keyframes`
from {
opacity: 1;
}
to {
opacity: 0;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { styled, css, keyframes } from "next-yak/internal";
import __styleYak from "./input.yak.module.css!=!./input?./input.yak.module.css";
export const FadeInText = /*YAK Extracted CSS:
.FadeInText__$reverse {
animation: fadeOut 1s ease-in;
}
.FadeInText__not_$reverse {
animation: fadeIn 1s ease-in;
}
.FadeInText {
font-size: 18px;
color: #333;
}
*/ /*#__PURE__*/ styled.p(__styleYak.FadeInText, ({ $reverse })=>$reverse ? /*#__PURE__*/ css(__styleYak.FadeInText__$reverse) : /*#__PURE__*/ css(__styleYak.FadeInText__not_$reverse));
const fadeIn = /*YAK Extracted CSS:
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
*/ /*#__PURE__*/ keyframes(__styleYak.fadeIn);
const fadeOut = /*YAK Extracted CSS:
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
*/ /*#__PURE__*/ keyframes(__styleYak.fadeOut);
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { styled, css, keyframes } from "next-yak";

export const FadeInText = styled.p<{ $reverse?: boolean }>`
${({ $reverse }) =>
$reverse
? css`
animation: ${animations.fadeOut} 1s ease-in;
`
: css`
animation: ${animations.fadeIn} 1s ease-in;
`}
font-size: 18px;
color: #333;
`;

const animations = {
fadeIn: keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`,
fadeOut: keyframes`
from {
opacity: 1;
}
to {
opacity: 0;
}
`,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { styled, css, keyframes } from "next-yak/internal";
import __styleYak from "./input.yak.module.css!=!./input?./input.yak.module.css";
export const FadeInText = /*YAK Extracted CSS:
.FadeInText__$reverse {
animation: animations_fadeOut 1s ease-in;
}
.FadeInText__not_$reverse {
animation: animations_fadeIn 1s ease-in;
}
.FadeInText {
font-size: 18px;
color: #333;
}
*/ /*#__PURE__*/ styled.p(__styleYak.FadeInText, ({ $reverse })=>$reverse ? /*#__PURE__*/ css(__styleYak.FadeInText__$reverse) : /*#__PURE__*/ css(__styleYak.FadeInText__not_$reverse));
const animations = {
fadeIn: /*YAK Extracted CSS:
@keyframes animations_fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
*/ /*#__PURE__*/ keyframes(__styleYak.animations_fadeIn),
fadeOut: /*YAK Extracted CSS:
@keyframes animations_fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
*/ /*#__PURE__*/ keyframes(__styleYak.animations_fadeOut)
};

0 comments on commit 73e4778

Please sign in to comment.