stylex_transform/shared/transformers/
stylex_view_transition_class.rs1use 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}