pub(crate) const FOCUS_RING: &str =
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2";
pub(crate) const MOTION_FAST: &str = "transition-colors duration-fast ease-base";
pub(crate) const MOTION_BASE: &str = "transition-opacity duration-base ease-base";
pub(crate) const DISABLED_BASE: &str = "disabled:opacity-50 disabled:pointer-events-none";
pub(crate) const TOAST_TONE_NEUTRAL: &str = "bg-primary/70 text-primary-foreground";
pub(crate) const TOAST_TONE_SUCCESS: &str = "bg-success/70 text-primary-foreground";
pub(crate) const TOAST_TONE_WARNING: &str = "bg-warning/70 text-primary-foreground";
pub(crate) const TOAST_TONE_DESTRUCTIVE: &str = "bg-destructive/70 text-primary-foreground";
pub(crate) const INTERACTIVE_BASE: &str = concat!(
"transition-colors duration-fast ease-base ",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
);
pub const TOUCH_ACTION: &str = "touch-manipulation";
pub const HIT_TARGET_MIN: &str = "min-h-[44px] min-w-[44px]";
pub const HIT_TARGET_NUMPAD: &str = "min-h-[56px] min-w-[56px]";
pub const PRESS_ACTIVE: &str = "active:scale-95 active:bg-border";
pub const OVERSCROLL_CONTAIN: &str = "overscroll-contain";
pub const TAP_HIGHLIGHT: &str = "pos-tap-highlight";
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn interactive_base_is_motion_fast_plus_focus_ring() {
assert_eq!(INTERACTIVE_BASE, format!("{MOTION_FAST} {FOCUS_RING}"));
}
#[test]
fn fragments_use_token_utilities() {
assert!(FOCUS_RING.contains("focus-visible:ring-ring"));
assert!(MOTION_FAST.contains("duration-fast") && MOTION_FAST.contains("ease-base"));
assert!(MOTION_BASE.contains("duration-base") && MOTION_BASE.contains("ease-base"));
assert!(DISABLED_BASE.contains("disabled:pointer-events-none"));
}
#[test]
fn render_functions_use_constants_not_literals() {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR");
let render_dir = std::path::Path::new(&manifest_dir).join("src/render");
let guarded = [
"touch-manipulation",
"min-h-[44px] min-w-[44px]",
"min-h-[56px] min-w-[56px]",
];
for entry in std::fs::read_dir(&render_dir).expect("src/render readable") {
let path = entry.unwrap().path();
if path.extension().and_then(|e| e.to_str()) != Some("rs") {
continue;
}
let filename = path.file_name().unwrap().to_str().unwrap().to_string();
if filename == "classes.rs" {
continue;
}
let source = std::fs::read_to_string(&path).unwrap();
for lit in &guarded {
assert!(
!source.contains(lit),
"{filename}: raw POS literal {lit:?} — import from render::classes instead"
);
}
}
}
#[test]
fn touch_constants_are_full_literals_and_token_compliant() {
assert_eq!(TOUCH_ACTION, "touch-manipulation");
assert_eq!(HIT_TARGET_MIN, "min-h-[44px] min-w-[44px]");
assert_eq!(HIT_TARGET_NUMPAD, "min-h-[56px] min-w-[56px]");
assert_eq!(OVERSCROLL_CONTAIN, "overscroll-contain");
assert_eq!(TAP_HIGHLIGHT, "pos-tap-highlight");
assert!(PRESS_ACTIVE.contains("active:scale-95"));
assert!(PRESS_ACTIVE.contains("active:bg-border"));
for raw in ["red-", "blue-", "orange-", "zinc-", "gray-", "slate-"] {
assert!(
!PRESS_ACTIVE.contains(raw),
"raw palette class in PRESS_ACTIVE"
);
}
}
}