Skip to main content

biji_ui/
lib.rs

1//! # Biji UI
2//!
3//! Effortless headless UI components for your [Leptos](https://leptos.dev/) projects.
4//!
5//! Biji UI provides a collection of accessible, unstyled UI components that integrate
6//! seamlessly with any CSS framework. Focus on building the core functionality of your
7//! application while Biji UI handles the UI foundation.
8//!
9//! ## Components
10//!
11//! - **Accordion** – Collapsible content sections with keyboard navigation.
12//! - **Dialog** – Modal dialogs with focus trapping and overlay support.
13//! - **Menu** – Standalone dropdown menus with nested submenus.
14//! - **Menubar** – Horizontal menu bars with keyboard-driven navigation.
15//! - **Tooltip** – Hover/focus tooltips with configurable positioning.
16//!
17//! ## Quick Start
18//!
19//! ```rust
20//! use leptos::prelude::*;
21//! use biji_ui::components::accordion;
22//!
23//! #[component]
24//! pub fn Example() -> impl IntoView {
25//!     view! {
26//!         <accordion::Root>
27//!             <accordion::Item>
28//!                 <accordion::Toggle>"Toggle"</accordion::Toggle>
29//!                 <accordion::Content>"Content"</accordion::Content>
30//!             </accordion::Item>
31//!         </accordion::Root>
32//!     }
33//! }
34//! ```
35
36/// UI component modules (accordion, dialog, menu, menubar, tooltip).
37pub mod components;
38
39/// Custom animated show/hide wrapper component with CSS class transitions.
40pub mod custom_animated_show;
41
42/// Traits and helpers for item navigation, focus management, and toggling.
43pub mod items;
44
45/// Utility modules for positioning, scroll prevention, and polygon math.
46pub mod utils;
47
48/// A trait for converting a value into a CSS class string.
49///
50/// This trait is used by the [`cn!`] macro to normalize different string types
51/// into a single `String` suitable for use as a CSS class list.
52///
53/// # Implementations
54///
55/// - `String` – returns itself.
56/// - `&str` – converts to an owned `String`.
57/// - `Option<String>` – returns the inner value or an empty string.
58pub trait Style {
59    /// Produce a CSS class string from this value.
60    fn style(&self) -> String;
61}
62
63impl Style for String {
64    fn style(&self) -> String {
65        self.to_string()
66    }
67}
68
69impl Style for Option<String> {
70    fn style(&self) -> String {
71        self.as_ref().map(|s| s.style()).unwrap_or_default()
72    }
73}
74
75impl Style for &str {
76    fn style(&self) -> String {
77        self.to_string()
78    }
79}
80
81/// Concatenate multiple CSS class expressions into a single space-separated string.
82///
83/// Each argument must implement the [`Style`] trait. Empty values are automatically
84/// filtered out so you never end up with leading/trailing/double spaces.
85///
86/// # Examples
87///
88/// ```rust
89/// use biji_ui::cn;
90///
91/// let base = "px-4 py-2";
92/// let active = String::from("bg-blue-500");
93/// let empty: Option<String> = None;
94///
95/// // Produces "px-4 py-2 bg-blue-500" (empty option is skipped)
96/// let classes = cn!(base, active, empty);
97/// ```
98#[macro_export]
99macro_rules! cn {
100    ($($styles: expr),*) => {
101        {
102            use $crate::Style;
103            let parts: Vec<String> = vec![$($styles.style()),*];
104            parts.into_iter()
105                .filter(|s| !s.is_empty())
106                .collect::<Vec<_>>()
107                .join(" ")
108        }
109    };
110}