stylex_transform/shared/transformers/
stylex_position_try.rs1use std::fmt::Write;
2use std::rc::Rc;
3
4use stylex_macros::stylex_panic;
5use swc_core::ecma::ast::{Expr, PropOrSpread};
6
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::functions::{FunctionConfig, FunctionType};
10use crate::shared::structures::state_manager::StateManager;
11use crate::shared::structures::types::FlatCompiledStyles;
12use crate::shared::utils::ast::convertors::{convert_lit_to_string, create_string_expr};
13use crate::shared::utils::common::{create_hash, dashify};
14use crate::shared::utils::css::common::transform_value_cached;
15use crate::shared::utils::object::{
16 Pipe, obj_map, obj_map_keys_string, preprocess_object_properties,
17};
18use crate::shared::{
19 enums::data_structures::evaluate_result_value::EvaluateResultValue,
20 utils::common::downcast_style_options_to_state_manager,
21};
22use stylex_ast::ast::factories::{create_object_lit, create_string_key_value_prop};
23use stylex_constants::constants::messages::{
24 ENTRY_MUST_BE_TUPLE, THEME_VAR_TUPLE, VALUE_MUST_BE_STRING, VALUES_MUST_BE_OBJECT,
25};
26use stylex_css::css::generate_ltr::generate_ltr;
27use stylex_css::css::generate_rtl::generate_rtl;
28use stylex_structures::pair::Pair;
29use stylex_types::enums::data_structures::injectable_style::InjectableStyleKind;
30use stylex_types::structures::injectable_style::InjectableStyle;
31
32pub(crate) fn stylex_position_try(
33 styles: &EvaluateResultValue,
34 state: &mut StateManager,
35) -> (String, InjectableStyleKind) {
36 let mut class_name_prefix = state.options.class_name_prefix.clone();
37
38 if class_name_prefix.is_empty() {
39 class_name_prefix = "x".to_string();
40 }
41
42 let Some(styles) = styles.as_expr().and_then(|expr| expr.as_object()) else {
43 stylex_panic!("{}", VALUES_MUST_BE_OBJECT)
44 };
45
46 let extended_object = {
47 let pipe_result = Pipe::create(styles.clone())
48 .pipe(|styles| preprocess_object_properties(&Expr::Object(styles), state))
49 .pipe(|entries| obj_map_keys_string(&entries, dashify))
50 .pipe(|entries| {
51 obj_map(
52 ObjMapType::Map(entries),
53 state,
54 |entry, state| match entry.as_ref() {
55 FlatCompiledStylesValue::KeyValue(pair) => Rc::new(FlatCompiledStylesValue::String(
56 transform_value_cached(pair.key.as_str(), pair.value.as_str(), state),
57 )),
58 _ => stylex_panic!("{}", ENTRY_MUST_BE_TUPLE),
59 },
60 )
61 })
62 .done();
63
64 create_object_lit(
65 pipe_result
66 .into_iter()
67 .map(|(key, value)| {
68 let value = match value.as_string() {
69 Some(s) => s.clone(),
70 None => stylex_panic!("{}", VALUE_MUST_BE_STRING),
71 };
72
73 create_string_key_value_prop(&key, &value)
74 })
75 .collect::<Vec<PropOrSpread>>(),
76 )
77 };
78
79 let options = state.options.clone();
80
81 let ltr_styles = obj_map(
82 ObjMapType::Object(extended_object.clone()),
83 state,
84 |style, _| {
85 let Some(tuple) = style.as_tuple() else {
86 stylex_panic!("{}", THEME_VAR_TUPLE)
87 };
88
89 let ltr_values = generate_ltr(
90 &Pair {
91 key: tuple.0.clone(),
92 value: convert_lit_to_string(match tuple.1.clone().as_lit() {
93 Some(lit) => lit,
94 None => stylex_panic!("{}", VALUE_MUST_BE_STRING),
95 })
96 .unwrap_or_default(),
97 },
98 &options,
99 );
100
101 Rc::new(FlatCompiledStylesValue::KeyValue(ltr_values))
102 },
103 );
104
105 let rtl_styles = obj_map(
106 ObjMapType::Object(extended_object.clone()),
107 state,
108 |style, _| {
109 let Some(tuple) = style.as_tuple() else {
110 stylex_panic!("{}", THEME_VAR_TUPLE)
111 };
112
113 let value = convert_lit_to_string(match tuple.1.clone().as_lit() {
114 Some(lit) => lit,
115 None => stylex_panic!("{}", VALUE_MUST_BE_STRING),
116 })
117 .unwrap_or_default();
118
119 let key = tuple.0.clone();
120
121 let rtl_values = generate_rtl(
122 &Pair {
123 key: key.clone(),
124 value: value.clone(),
125 },
126 &options,
127 );
128
129 match rtl_values {
130 Some(rtl_value) => Rc::new(FlatCompiledStylesValue::KeyValue(rtl_value)),
131 None => Rc::new(FlatCompiledStylesValue::KeyValue(Pair { key, value })),
132 }
133 },
134 );
135
136 let ltr_string = construct_position_try_obj(ltr_styles);
137 let rtl_string = construct_position_try_obj(rtl_styles);
138
139 let position_try_name = format!("--{}{}", class_name_prefix, create_hash(<r_string));
140
141 let ltr = format!("@position-try {}{{{}}}", position_try_name, ltr_string);
142 let rtl = if ltr_string == rtl_string {
143 None
144 } else {
145 Some(format!(
146 "@position-try {}{{{}}}",
147 position_try_name, rtl_string
148 ))
149 };
150
151 (
152 position_try_name,
153 InjectableStyleKind::Regular(InjectableStyle {
154 ltr,
155 rtl,
156 priority: Some(0.0),
157 }),
158 )
159}
160
161pub(crate) fn get_position_try_fn() -> FunctionConfig {
162 FunctionConfig {
163 fn_ptr: FunctionType::StylexExprFn(
164 |expr: Expr, local_state: &mut dyn stylex_types::traits::StyleOptions| -> Expr {
165 let state = downcast_style_options_to_state_manager(local_state);
166
167 let (position_try_name, injected_style) =
168 stylex_position_try(&EvaluateResultValue::Expr(expr), state);
169
170 state
171 .other_injected_css_rules
172 .insert(position_try_name.clone(), Rc::new(injected_style));
173
174 create_string_expr(position_try_name.as_str())
175 },
176 ),
177 takes_path: false,
178 }
179}
180
181fn construct_position_try_obj(styles: FlatCompiledStyles) -> String {
182 let mut sorted_keys = styles.keys().cloned().collect::<Vec<String>>();
184 sorted_keys.sort();
185
186 sorted_keys
187 .into_iter()
188 .map(|k| {
189 let v = match styles.get(&k) {
190 Some(v) => v,
191 None => stylex_panic!("Expected property key to exist in compiled styles."),
192 };
193 match v.as_ref() {
194 FlatCompiledStylesValue::String(val) => format!("{}:{};", k, val),
195 FlatCompiledStylesValue::KeyValue(pair) => {
196 format!("{}:{};{}:{};", k, k, pair.key, pair.value)
197 },
198 FlatCompiledStylesValue::KeyValues(pairs) => {
199 let mut strng = String::new();
200 for pair in pairs {
201 let _ = write!(strng, "{}:{};{}:{};", k, k, pair.key, pair.value);
202 }
203 strng
204 },
205 _ => String::default(),
206 }
207 })
208 .collect::<Vec<String>>()
209 .join("")
210}