Skip to content

Commit 3c28eb7

Browse files
committed
Implement class prefix
1 parent 3ccdfa0 commit 3c28eb7

File tree

6 files changed

+1024
-832
lines changed

6 files changed

+1024
-832
lines changed

bindings/devup-ui-wasm/src/lib.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,56 @@ pub fn is_debug() -> bool {
101101
css::debug::is_debug()
102102
}
103103

104+
/// Set the CSS class name prefix
105+
///
106+
/// # Example (Vite Config)
107+
/// ```javascript
108+
/// import init, { setPrefix, codeExtract } from 'devup-ui-wasm';
109+
///
110+
/// export default {
111+
/// plugins: [
112+
/// {
113+
/// name: 'devup-ui',
114+
/// apply: 'pre',
115+
/// async configResolved() {
116+
/// await init();
117+
/// setPrefix('du-'); // Set prefix to 'du-'
118+
/// },
119+
/// // ... other plugin code
120+
/// }
121+
/// ]
122+
/// }
123+
/// ```
124+
///
125+
/// # Example (Next.js Plugin)
126+
/// ```typescript
127+
/// import init, { setPrefix } from 'devup-ui-wasm';
128+
///
129+
/// const withDevupUI = (nextConfig) => {
130+
/// return {
131+
/// ...nextConfig,
132+
/// webpack: (config, options) => {
133+
/// if (!options.isServer && !global.devupUIInitialized) {
134+
/// init().then(() => {
135+
/// setPrefix('du-');
136+
/// global.devupUIInitialized = true;
137+
/// });
138+
/// }
139+
/// return config;
140+
/// }
141+
/// };
142+
/// };
143+
/// ```
144+
#[wasm_bindgen(js_name = "setPrefix")]
145+
pub fn set_prefix(prefix: Option<String>) {
146+
css::set_prefix(prefix);
147+
}
148+
149+
#[wasm_bindgen(js_name = "getPrefix")]
150+
pub fn get_prefix() -> Option<String> {
151+
css::get_prefix()
152+
}
153+
104154
#[wasm_bindgen(js_name = "importSheet")]
105155
pub fn import_sheet(sheet_object: JsValue) -> Result<(), JsValue> {
106156
*GLOBAL_STYLE_SHEET.lock().unwrap() = serde_wasm_bindgen::from_value(sheet_object)
@@ -517,6 +567,16 @@ mod tests {
517567
assert!(!is_debug());
518568
}
519569

570+
#[test]
571+
#[serial]
572+
fn test_prefix() {
573+
assert_eq!(get_prefix(), None);
574+
set_prefix(Some("du-".to_string()));
575+
assert_eq!(get_prefix(), Some("du-".to_string()));
576+
set_prefix(None);
577+
assert_eq!(get_prefix(), None);
578+
}
579+
520580
#[test]
521581
#[serial]
522582
fn test_default_theme() {

libs/css/src/lib.rs

Lines changed: 143 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub mod utils;
1313

1414
use std::collections::BTreeMap;
1515
use std::hash::{DefaultHasher, Hash, Hasher};
16+
use once_cell::sync::Lazy;
17+
use std::sync::Mutex;
1618

1719
use crate::class_map::GLOBAL_CLASS_MAP;
1820
use crate::constant::{
@@ -25,6 +27,16 @@ use crate::optimize_value::optimize_value;
2527
use crate::style_selector::StyleSelector;
2628
use crate::utils::to_kebab_case;
2729

30+
static GLOBAL_PREFIX: Lazy<Mutex<Option<String>>> = Lazy::new(|| Mutex::new(None));
31+
32+
pub fn set_prefix(prefix: Option<String>) {
33+
*GLOBAL_PREFIX.lock().unwrap() = prefix;
34+
}
35+
36+
pub fn get_prefix() -> Option<String> {
37+
GLOBAL_PREFIX.lock().unwrap().clone()
38+
}
39+
2840
pub fn merge_selector(class_name: &str, selector: Option<&StyleSelector>) -> String {
2941
if let Some(selector) = selector {
3042
match selector {
@@ -114,8 +126,9 @@ pub fn get_enum_property_map(property: &str) -> Option<BTreeMap<&str, BTreeMap<&
114126
}
115127

116128
pub fn keyframes_to_keyframes_name(keyframes: &str, filename: Option<&str>) -> String {
129+
let prefix = get_prefix().unwrap_or_default();
117130
if is_debug() {
118-
format!("k-{keyframes}")
131+
format!("{}k-{keyframes}", prefix)
119132
} else {
120133
let key = format!("k-{keyframes}");
121134
let mut map = GLOBAL_CLASS_MAP.lock().unwrap();
@@ -133,12 +146,16 @@ pub fn keyframes_to_keyframes_name(keyframes: &str, filename: Option<&str>) -> S
133146
});
134147
if !filename.is_empty() {
135148
format!(
136-
"{}-{}",
137-
num_to_nm_base(get_file_num_by_filename(&filename)),
138-
class_num
149+
"{}{}",
150+
prefix,
151+
format!(
152+
"{}-{}",
153+
num_to_nm_base(get_file_num_by_filename(&filename)),
154+
class_num
155+
)
139156
)
140157
} else {
141-
class_num
158+
format!("{}{}", prefix, class_num)
142159
}
143160
}
144161
}
@@ -151,6 +168,7 @@ pub fn sheet_to_classname(
151168
style_order: Option<u8>,
152169
filename: Option<&str>,
153170
) -> String {
171+
let prefix = get_prefix().unwrap_or_default();
154172
// base style
155173
let filename = if style_order == Some(0) {
156174
None
@@ -160,21 +178,25 @@ pub fn sheet_to_classname(
160178
if is_debug() {
161179
let selector = selector.unwrap_or_default().trim();
162180
format!(
163-
"{}-{}-{}-{}-{}{}",
164-
property.trim(),
165-
level,
166-
optimize_value(value.unwrap_or_default()),
167-
if selector.is_empty() {
168-
"".to_string()
169-
} else {
170-
let mut hasher = DefaultHasher::new();
171-
selector.hash(&mut hasher);
172-
hasher.finish().to_string()
173-
},
174-
style_order.unwrap_or(255),
175-
filename
176-
.map(|v| format!("-{}", get_file_num_by_filename(v)))
177-
.unwrap_or_default(),
181+
"{}{}",
182+
prefix,
183+
format!(
184+
"{}-{}-{}-{}-{}{}",
185+
property.trim(),
186+
level,
187+
optimize_value(value.unwrap_or_default()),
188+
if selector.is_empty() {
189+
"".to_string()
190+
} else {
191+
let mut hasher = DefaultHasher::new();
192+
selector.hash(&mut hasher);
193+
hasher.finish().to_string()
194+
},
195+
style_order.unwrap_or(255),
196+
filename
197+
.map(|v| format!("-{}", get_file_num_by_filename(v)))
198+
.unwrap_or_default(),
199+
)
178200
)
179201
} else {
180202
let key = format!(
@@ -203,30 +225,39 @@ pub fn sheet_to_classname(
203225
});
204226
if !filename.is_empty() {
205227
format!(
206-
"{}-{}",
207-
num_to_nm_base(get_file_num_by_filename(&filename)),
208-
clas_num
228+
"{}{}",
229+
prefix,
230+
format!(
231+
"{}-{}",
232+
num_to_nm_base(get_file_num_by_filename(&filename)),
233+
clas_num
234+
)
209235
)
210236
} else {
211-
clas_num
237+
format!("{}{}", prefix, clas_num)
212238
}
213239
}
214240
}
215241

216242
pub fn sheet_to_variable_name(property: &str, level: u8, selector: Option<&str>) -> String {
243+
let prefix = get_prefix().unwrap_or_default();
217244
if is_debug() {
218245
let selector = selector.unwrap_or_default().trim();
219246
format!(
220-
"--{}-{}-{}",
221-
property,
222-
level,
223-
if selector.is_empty() {
224-
"".to_string()
225-
} else {
226-
let mut hasher = DefaultHasher::new();
227-
selector.hash(&mut hasher);
228-
hasher.finish().to_string()
229-
}
247+
"--{}{}",
248+
prefix,
249+
format!(
250+
"{}-{}-{}",
251+
property,
252+
level,
253+
if selector.is_empty() {
254+
"".to_string()
255+
} else {
256+
let mut hasher = DefaultHasher::new();
257+
selector.hash(&mut hasher);
258+
hasher.finish().to_string()
259+
}
260+
)
230261
)
231262
} else {
232263
let key = format!(
@@ -239,12 +270,12 @@ pub fn sheet_to_variable_name(property: &str, level: u8, selector: Option<&str>)
239270
map.entry("".to_string())
240271
.or_default()
241272
.get(&key)
242-
.map(|v| format!("--{}", num_to_nm_base(*v)))
273+
.map(|v| format!("--{}{}", prefix, num_to_nm_base(*v)))
243274
.unwrap_or_else(|| {
244275
let m = map.entry("".to_string()).or_default();
245276
let len = m.len();
246277
m.insert(key, len);
247-
format!("--{}", num_to_nm_base(len))
278+
format!("--{}{}", prefix, num_to_nm_base(len))
248279
})
249280
}
250281
}
@@ -718,4 +749,80 @@ mod tests {
718749
}
719750
);
720751
}
752+
753+
#[test]
754+
#[serial]
755+
fn test_sheet_to_classname_with_prefix() {
756+
set_debug(false);
757+
reset_class_map();
758+
set_prefix(Some("app-".to_string()));
759+
760+
let class1 = sheet_to_classname("background", 0, Some("red"), None, None, None);
761+
assert!(class1.starts_with("app-"));
762+
assert_eq!(class1, "app-a");
763+
764+
let class2 = sheet_to_classname("color", 0, Some("blue"), None, None, None);
765+
assert!(class2.starts_with("app-"));
766+
767+
set_prefix(None);
768+
reset_class_map();
769+
}
770+
771+
#[test]
772+
#[serial]
773+
fn test_debug_sheet_to_classname_with_prefix() {
774+
set_debug(true);
775+
set_prefix(Some("my-".to_string()));
776+
777+
let class_name = sheet_to_classname("background", 0, Some("red"), None, None, None);
778+
assert_eq!(class_name, "my-background-0-red--255");
779+
780+
let with_selector =
781+
sheet_to_classname("background", 0, Some("red"), Some("hover"), None, None);
782+
assert!(with_selector.starts_with("my-"));
783+
784+
set_prefix(None);
785+
}
786+
787+
#[test]
788+
#[serial]
789+
fn test_sheet_to_variable_name_with_prefix() {
790+
set_debug(false);
791+
reset_class_map();
792+
set_prefix(Some("app-".to_string()));
793+
794+
assert_eq!(sheet_to_variable_name("background", 0, None), "--app-a");
795+
796+
set_prefix(None);
797+
reset_class_map();
798+
}
799+
800+
#[test]
801+
#[serial]
802+
fn test_keyframes_with_prefix() {
803+
reset_class_map();
804+
set_debug(false);
805+
set_prefix(Some("app-".to_string()));
806+
807+
let name = keyframes_to_keyframes_name("spin", None);
808+
assert!(name.starts_with("app-"));
809+
810+
set_prefix(None);
811+
}
812+
813+
#[test]
814+
#[serial]
815+
fn test_empty_prefix_is_same_as_none() {
816+
set_debug(false);
817+
reset_class_map();
818+
819+
set_prefix(Some("".to_string()));
820+
let class1 = sheet_to_classname("background", 0, Some("red"), None, None, None);
821+
822+
reset_class_map();
823+
set_prefix(None);
824+
let class2 = sheet_to_classname("background", 0, Some("red"), None, None, None);
825+
826+
assert_eq!(class1, class2);
827+
}
721828
}

0 commit comments

Comments
 (0)