Skip to content

Commit b33b1c2

Browse files
authored
Merge pull request #527 from dev-five-git/add-prefix
Implement class prefix
2 parents 3ccdfa0 + 2c949b1 commit b33b1c2

File tree

11 files changed

+2605
-2378
lines changed

11 files changed

+2605
-2378
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": {
3+
"packages/webpack-plugin/package.json": "Patch",
4+
"packages/rsbuild-plugin/package.json": "Patch",
5+
"packages/next-plugin/package.json": "Patch",
6+
"packages/vite-plugin/package.json": "Patch",
7+
"bindings/devup-ui-wasm/package.json": "Patch"
8+
},
9+
"note": "Implement prefix option",
10+
"date": "2025-12-29T06:55:43.116377700Z"
11+
}

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: 104 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ mod selector_separator;
1111
pub mod style_selector;
1212
pub mod utils;
1313

14+
use once_cell::sync::Lazy;
1415
use std::collections::BTreeMap;
1516
use std::hash::{DefaultHasher, Hash, Hasher};
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,13 @@ pub fn keyframes_to_keyframes_name(keyframes: &str, filename: Option<&str>) -> S
133146
});
134147
if !filename.is_empty() {
135148
format!(
136-
"{}-{}",
149+
"{}{}-{}",
150+
prefix,
137151
num_to_nm_base(get_file_num_by_filename(&filename)),
138152
class_num
139153
)
140154
} else {
141-
class_num
155+
format!("{}{}", prefix, class_num)
142156
}
143157
}
144158
}
@@ -151,6 +165,7 @@ pub fn sheet_to_classname(
151165
style_order: Option<u8>,
152166
filename: Option<&str>,
153167
) -> String {
168+
let prefix = get_prefix().unwrap_or_default();
154169
// base style
155170
let filename = if style_order == Some(0) {
156171
None
@@ -160,7 +175,8 @@ pub fn sheet_to_classname(
160175
if is_debug() {
161176
let selector = selector.unwrap_or_default().trim();
162177
format!(
163-
"{}-{}-{}-{}-{}{}",
178+
"{}{}-{}-{}-{}-{}{}",
179+
prefix,
164180
property.trim(),
165181
level,
166182
optimize_value(value.unwrap_or_default()),
@@ -203,21 +219,24 @@ pub fn sheet_to_classname(
203219
});
204220
if !filename.is_empty() {
205221
format!(
206-
"{}-{}",
222+
"{}{}-{}",
223+
prefix,
207224
num_to_nm_base(get_file_num_by_filename(&filename)),
208225
clas_num
209226
)
210227
} else {
211-
clas_num
228+
format!("{}{}", prefix, clas_num)
212229
}
213230
}
214231
}
215232

216233
pub fn sheet_to_variable_name(property: &str, level: u8, selector: Option<&str>) -> String {
234+
let prefix = get_prefix().unwrap_or_default();
217235
if is_debug() {
218236
let selector = selector.unwrap_or_default().trim();
219237
format!(
220-
"--{}-{}-{}",
238+
"--{}{}-{}-{}",
239+
prefix,
221240
property,
222241
level,
223242
if selector.is_empty() {
@@ -239,12 +258,12 @@ pub fn sheet_to_variable_name(property: &str, level: u8, selector: Option<&str>)
239258
map.entry("".to_string())
240259
.or_default()
241260
.get(&key)
242-
.map(|v| format!("--{}", num_to_nm_base(*v)))
261+
.map(|v| format!("--{}{}", prefix, num_to_nm_base(*v)))
243262
.unwrap_or_else(|| {
244263
let m = map.entry("".to_string()).or_default();
245264
let len = m.len();
246265
m.insert(key, len);
247-
format!("--{}", num_to_nm_base(len))
266+
format!("--{}{}", prefix, num_to_nm_base(len))
248267
})
249268
}
250269
}
@@ -718,4 +737,80 @@ mod tests {
718737
}
719738
);
720739
}
740+
741+
#[test]
742+
#[serial]
743+
fn test_sheet_to_classname_with_prefix() {
744+
set_debug(false);
745+
reset_class_map();
746+
set_prefix(Some("app-".to_string()));
747+
748+
let class1 = sheet_to_classname("background", 0, Some("red"), None, None, None);
749+
assert!(class1.starts_with("app-"));
750+
assert_eq!(class1, "app-a");
751+
752+
let class2 = sheet_to_classname("color", 0, Some("blue"), None, None, None);
753+
assert!(class2.starts_with("app-"));
754+
755+
set_prefix(None);
756+
reset_class_map();
757+
}
758+
759+
#[test]
760+
#[serial]
761+
fn test_debug_sheet_to_classname_with_prefix() {
762+
set_debug(true);
763+
set_prefix(Some("my-".to_string()));
764+
765+
let class_name = sheet_to_classname("background", 0, Some("red"), None, None, None);
766+
assert_eq!(class_name, "my-background-0-red--255");
767+
768+
let with_selector =
769+
sheet_to_classname("background", 0, Some("red"), Some("hover"), None, None);
770+
assert!(with_selector.starts_with("my-"));
771+
772+
set_prefix(None);
773+
}
774+
775+
#[test]
776+
#[serial]
777+
fn test_sheet_to_variable_name_with_prefix() {
778+
set_debug(false);
779+
reset_class_map();
780+
set_prefix(Some("app-".to_string()));
781+
782+
assert_eq!(sheet_to_variable_name("background", 0, None), "--app-a");
783+
784+
set_prefix(None);
785+
reset_class_map();
786+
}
787+
788+
#[test]
789+
#[serial]
790+
fn test_keyframes_with_prefix() {
791+
reset_class_map();
792+
set_debug(false);
793+
set_prefix(Some("app-".to_string()));
794+
795+
let name = keyframes_to_keyframes_name("spin", None);
796+
assert!(name.starts_with("app-"));
797+
798+
set_prefix(None);
799+
}
800+
801+
#[test]
802+
#[serial]
803+
fn test_empty_prefix_is_same_as_none() {
804+
set_debug(false);
805+
reset_class_map();
806+
807+
set_prefix(Some("".to_string()));
808+
let class1 = sheet_to_classname("background", 0, Some("red"), None, None, None);
809+
810+
reset_class_map();
811+
set_prefix(None);
812+
let class2 = sheet_to_classname("background", 0, Some("red"), None, None, None);
813+
814+
assert_eq!(class1, class2);
815+
}
721816
}

0 commit comments

Comments
 (0)