Skip to main content

stylex_transform/shared/transformers/
stylex_view_transition_class.rs

1use std::fmt::Write;
2use std::rc::Rc;
3
4use stylex_macros::stylex_panic;
5
6use crate::shared::enums::data_structures::evaluate_result_value::EvaluateResultValue;
7use crate::shared::enums::data_structures::flat_compiled_styles_value::FlatCompiledStylesValue;
8use crate::shared::enums::data_structures::obj_map_type::ObjMapType;
9use crate::shared::structures::state_manager::StateManager;
10use crate::shared::structures::types::FlatCompiledStyles;
11use crate::shared::utils::common::{create_hash, dashify};
12use crate::shared::utils::css::common::transform_value_cached;
13use crate::shared::utils::object::{
14  Pipe, obj_map, obj_map_keys_key_value, obj_map_keys_string, preprocess_object_properties,
15};
16use stylex_constants::constants::messages::{
17  ENTRY_MUST_BE_TUPLE, VALUE_MUST_BE_STRING, VALUES_MUST_BE_OBJECT,
18};
19use stylex_structures::pair::Pair;
20use stylex_types::enums::data_structures::injectable_style::InjectableStyleKind;
21use stylex_types::structures::injectable_style::InjectableStyle;
22
23pub(crate) fn stylex_view_transition_class(
24  styles: &EvaluateResultValue,
25  state: &mut StateManager,
26) -> (String, InjectableStyleKind) {
27  let mut class_name_prefix = state.options.class_name_prefix.clone();
28
29  if class_name_prefix.is_empty() {
30    class_name_prefix = "x".to_string();
31  }
32
33  let Some(styles) = styles.as_expr().and_then(|expr| expr.as_object()) else {
34    stylex_panic!("{}", VALUES_MUST_BE_OBJECT)
35  };
36  let preprocessed_object = obj_map(ObjMapType::Object(styles.clone()), state, |style, state| {
37    let Some((_, style, _)) = style.as_tuple() else {
38      stylex_panic!("{}", VALUES_MUST_BE_OBJECT)
39    };
40
41    let pipe_result = Pipe::create(style.clone())
42      .pipe(|style| preprocess_object_properties(&style, state))
43      .pipe(|entries| obj_map_keys_string(&entries, dashify))
44      .pipe(|entries| {
45        obj_map(
46          ObjMapType::Map(entries),
47          state,
48          |entry, state| match entry.as_ref() {
49            FlatCompiledStylesValue::KeyValue(pair) => Rc::new(FlatCompiledStylesValue::String(
50              transform_value_cached(pair.key.as_str(), pair.value.as_str(), state),
51            )),
52            _ => stylex_panic!("{}", ENTRY_MUST_BE_TUPLE),
53          },
54        )
55      })
56      .done();
57
58    let pairs = pipe_result
59      .into_iter()
60      .filter_map(|(key, value)| value.as_string().cloned().map(|v| Pair::new(key, v)))
61      .collect::<Vec<Pair>>();
62
63    Rc::new(FlatCompiledStylesValue::KeyValues(pairs))
64  });
65
66  let expanded_object = obj_map_keys_key_value(&preprocessed_object, |k| {
67    format!("::view-transition-{}", dashify(k))
68  });
69
70  let style_strings = obj_map(
71    ObjMapType::Map(expanded_object),
72    state,
73    construct_view_transition_class_style_str,
74  );
75
76  let string_to_hash = &concat_view_transition_class_style_str(&style_strings, state);
77
78  let view_transition_class_name = class_name_prefix + create_hash(string_to_hash).as_str();
79
80  let style = construct_final_view_transition_css_str(style_strings, &view_transition_class_name);
81
82  (
83    view_transition_class_name,
84    InjectableStyleKind::Regular(InjectableStyle {
85      ltr: style,
86      rtl: None,
87      priority: Some(1.0),
88    }),
89  )
90}
91
92fn construct_view_transition_class_style_str(
93  style_strings: Rc<FlatCompiledStylesValue>,
94  _state: &mut StateManager,
95) -> Rc<FlatCompiledStylesValue> {
96  let fmt_pair = |pair: &Pair| format!("{}:{};", pair.key, pair.value);
97
98  match style_strings.as_ref() {
99    FlatCompiledStylesValue::KeyValue(pair) => {
100      Rc::new(FlatCompiledStylesValue::String(fmt_pair(pair)))
101    },
102    FlatCompiledStylesValue::KeyValues(pairs) => {
103      let mut result_string = String::new();
104      for pair in pairs {
105        result_string.push_str(&fmt_pair(pair));
106      }
107      Rc::new(FlatCompiledStylesValue::String(result_string))
108    },
109    FlatCompiledStylesValue::String(s) => Rc::new(FlatCompiledStylesValue::String(s.clone())),
110    _ => stylex_panic!("Expected KeyValues"),
111  }
112}
113
114fn construct_final_view_transition_css_str(styles: FlatCompiledStyles, class_name: &str) -> String {
115  let mut result = String::new();
116  for (key, value) in styles.iter() {
117    let style_str = match value.as_ref() {
118      FlatCompiledStylesValue::String(s) => s,
119      _ => stylex_panic!("{}", VALUE_MUST_BE_STRING),
120    };
121    let _ = write!(result, "{}(*.{}){{{}}}", key, class_name, style_str);
122  }
123  result
124}
125
126fn concat_view_transition_class_style_str(
127  style_strings: &FlatCompiledStyles,
128  state: &mut StateManager,
129) -> String {
130  let mut result = String::new();
131
132  style_strings.into_iter().for_each(|(k, v)| {
133    let style_str_val = construct_view_transition_class_style_str(Rc::clone(v), state);
134    let style_str = match style_str_val.as_ref() {
135      FlatCompiledStylesValue::String(s) => s,
136      _ => stylex_panic!("{}", VALUE_MUST_BE_STRING),
137    };
138    let _ = write!(result, "{}:{};", k, style_str);
139  });
140
141  result
142}