revue 2.71.1

A Vue-style TUI framework for Rust with CSS styling
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
//! Widget traits and common types for Revue components
//!
//! This module defines the core traits that all widgets implement, along with
//! supporting types for rendering, events, and state management.
//!
//! # Core Traits
//!
//! | Trait | Description | Use Case |
//! |-------|-------------|----------|
//! | [`View`] | Core rendering trait | All renderable widgets |
//! | [`StyledView`] | View with CSS styling | Styled widgets |
//! | [`Interactive`] | Handle keyboard/mouse | Interactive widgets |
//! | [`Draggable`] | Drag and drop support | Draggable widgets |
//!
//! # View Trait
//!
//! The [`View`] trait is the foundation of all widgets:
//!
//! ```rust,ignore
//! use revue::widget::View;
//!
//! pub struct MyWidget;
//!
//! impl View for MyWidget {
//!     fn render(&self, ctx: &mut RenderContext) {
//!         // Render widget to context
//!         Text::new("Hello").render(ctx);
//!     }
//! }
//! ```
//!
//! # StyledView Trait
//!
//! [`StyledView`] extends View with CSS styling support:
//!
//! ```rust,ignore
//! use revue::widget::StyledView;
//!
//! impl StyledView for MyWidget {
//!     // Inherit CSS styling support
//!     fn style(&self) -> Style {
//!         Style::default()
//!     }
//! }
//! ```
//!
//! # Interactive Trait
//!
//! [`Interactive`] enables keyboard and mouse event handling:
//!
//! ```rust,ignore
//! use revue::widget::Interactive;
//!
//! impl Interactive for MyWidget {
//!     fn handle_key(&mut self, key: &KeyEvent) -> EventResult {
//!         match key.key {
//!             Key::Enter => EventResult::Consumed,
//!             _ => EventResult::Ignored,
//!         }
//!     }
//! }
//! ```
//!
//! # Common Types
//!
//! | Type | Description |
//! |------|-------------|
//! | [`Element`] | Widget element container |
//! | [`RenderContext`] | Rendering context and utilities |
//! | [`WidgetState`] | Common widget state (focus, disabled, colors) |
//! | [`EventResult`] | Event handling result |
//! | [`FocusStyle`] | Focus indicator style |
//!
//! # Builder Macros
//!
//! The `impl_state_builders!` macro generates builder methods for widgets:
//!
//! ```rust,ignore
//! struct MyWidget {
//!     state: WidgetState,
//! }
//!
//! impl_state_builders!(MyWidget);
//!
//! // Now available:
//! let widget = MyWidget { state: WidgetState::default() }
//!     .focused(true)
//!     .disabled(false)
//!     .fg(Color::Blue)
//!     .bg(Color::Black);
//! ```

mod element;
mod event;
mod render_context;
mod symbols;
mod timeout;
mod view;
mod widget_state;

// Re-export all public types
pub use element::Element;
pub use event::{EventResult, FocusStyle};
pub use render_context::{OverlayEntry, OverlayQueue, ProgressBarConfig, RenderContext};
pub use symbols::Symbols;
pub use timeout::Timeout;
pub use view::{Draggable, Interactive, StyledView, View};
pub use widget_state::{WidgetProps, WidgetState, DISABLED_BG, DISABLED_FG};

// =============================================================================
// Builder Macros
// =============================================================================

/// Generate builder methods for widgets with `state: WidgetState` field.
///
/// This macro generates the following methods:
/// - `focused(self, bool) -> Self` - Set focused state
/// - `disabled(self, bool) -> Self` - Set disabled state
/// - `fg(self, Color) -> Self` - Set foreground color
/// - `bg(self, Color) -> Self` - Set background color
/// - `is_focused(&self) -> bool` - Check if focused
/// - `is_disabled(&self) -> bool` - Check if disabled
/// - `set_focused(&mut self, bool)` - Mutably set focused state
///
/// # Example
/// ```rust,ignore
/// struct MyWidget {
///     state: WidgetState,
///     props: WidgetProps,
/// }
///
/// impl_state_builders!(MyWidget);
/// ```
#[macro_export]
macro_rules! impl_state_builders {
    ($widget:ty) => {
        impl $widget {
            /// Set focused state
            pub fn focused(mut self, focused: bool) -> Self {
                self.state.focused = focused;
                self
            }

            /// Set disabled state
            pub fn disabled(mut self, disabled: bool) -> Self {
                self.state.disabled = disabled;
                self
            }

            /// Set foreground color
            pub fn fg(mut self, color: $crate::style::Color) -> Self {
                self.state.fg = Some(color);
                self
            }

            /// Set background color
            pub fn bg(mut self, color: $crate::style::Color) -> Self {
                self.state.bg = Some(color);
                self
            }

            /// Check if widget is focused
            pub fn is_focused(&self) -> bool {
                self.state.focused
            }

            /// Check if widget is disabled
            pub fn is_disabled(&self) -> bool {
                self.state.disabled
            }

            /// Set focused state (mutable)
            pub fn set_focused(&mut self, focused: bool) {
                self.state.focused = focused;
            }
        }
    };
}

/// Generate builder methods for widgets with `props: WidgetProps` field.
///
/// This macro generates the following methods:
/// - `element_id(self, impl Into<String>) -> Self` - Set CSS element ID
/// - `class(self, impl Into<String>) -> Self` - Add a CSS class
/// - `classes(self, IntoIterator<Item=S>) -> Self` - Add multiple CSS classes
///
/// # Example
/// ```rust,ignore
/// struct MyWidget {
///     props: WidgetProps,
/// }
///
/// impl_props_builders!(MyWidget);
/// ```
#[macro_export]
macro_rules! impl_props_builders {
    ($widget:ty) => {
        impl $widget {
            /// Set element ID for CSS selector (#id)
            pub fn element_id(mut self, id: impl Into<String>) -> Self {
                self.props.id = Some(id.into());
                self
            }

            /// Add a CSS class
            pub fn class(mut self, class: impl Into<String>) -> Self {
                let class_str = class.into();
                if !self.props.classes.contains(&class_str) {
                    self.props.classes.push(class_str);
                }
                self
            }

            /// Add multiple CSS classes
            pub fn classes<I, S>(mut self, classes: I) -> Self
            where
                I: IntoIterator<Item = S>,
                S: Into<String>,
            {
                for class in classes {
                    let class_str = class.into();
                    if !self.props.classes.contains(&class_str) {
                        self.props.classes.push(class_str);
                    }
                }
                self
            }
        }
    };
}

/// Generate all common builder methods for widgets with both `state: WidgetState`
/// and `props: WidgetProps` fields.
///
/// This is a convenience macro that combines `impl_state_builders!` and
/// `impl_props_builders!`.
///
/// Generated methods:
/// - State: `focused`, `disabled`, `fg`, `bg`, `is_focused`, `is_disabled`, `set_focused`
/// - Props: `element_id`, `class`, `classes`
///
/// # Example
/// ```rust,ignore
/// struct MyWidget {
///     label: String,
///     state: WidgetState,
///     props: WidgetProps,
/// }
///
/// impl MyWidget {
///     pub fn new(label: impl Into<String>) -> Self {
///         Self {
///             label: label.into(),
///             state: WidgetState::new(),
///             props: WidgetProps::new(),
///         }
///     }
/// }
///
/// // Generates: focused, disabled, fg, bg, is_focused, is_disabled,
/// //            set_focused, element_id, class, classes
/// impl_widget_builders!(MyWidget);
/// ```
#[macro_export]
macro_rules! impl_widget_builders {
    ($widget:ty) => {
        $crate::impl_state_builders!($widget);
        $crate::impl_props_builders!($widget);
    };
}

/// Generate View trait id(), classes(), and meta() methods for widgets with props.
///
/// This macro generates the id(), classes(), and meta() methods for the View trait
/// that delegate to WidgetProps.
///
/// # Example
/// ```rust,ignore
/// impl View for MyWidget {
///     fn render(&self, ctx: &mut RenderContext) {
///         // ... rendering logic
///     }
///
///     crate::impl_view_meta!("MyWidget");
/// }
/// ```
#[macro_export]
macro_rules! impl_view_meta {
    ($name:expr) => {
        fn id(&self) -> Option<&str> {
            self.props.id.as_deref()
        }

        fn classes(&self) -> &[String] {
            &self.props.classes
        }

        fn meta(&self) -> $crate::dom::WidgetMeta {
            let mut meta = $crate::dom::WidgetMeta::new($name);
            if let Some(ref id) = self.props.id {
                meta.id = Some(id.clone());
            }
            for class in &self.props.classes {
                meta.classes.insert(class.clone());
            }
            meta
        }
    };
}

/// Generate View trait implementation for StyledView widgets.
///
/// This macro generates View trait methods that delegate to WidgetProps
/// for id() and classes() methods.
///
/// # Example
/// ```rust,ignore
/// struct MyWidget {
///     props: WidgetProps,
/// }
///
/// impl View for MyWidget {
///     fn render(&self, ctx: &mut RenderContext) {
///         // ... rendering logic
///     }
/// }
///
/// impl_styled_view!(MyWidget);
/// ```
#[macro_export]
macro_rules! impl_styled_view {
    ($widget:ty) => {
        impl $crate::widget::traits::StyledView for $widget {
            fn set_id(&mut self, id: impl Into<String>) {
                self.props.id = Some(id.into());
            }

            fn add_class(&mut self, class: impl Into<String>) {
                let class_str = class.into();
                if !self.props.classes.contains(&class_str) {
                    self.props.classes.push(class_str);
                }
            }

            fn remove_class(&mut self, class: &str) {
                self.props.classes.retain(|c| c != class);
            }

            fn toggle_class(&mut self, class: &str) {
                if self.props.classes.contains(&class.to_string()) {
                    self.remove_class(class);
                } else {
                    self.add_class(class);
                }
            }

            fn has_class(&self, class: &str) -> bool {
                self.props.classes.contains(&class.to_string())
            }
        }
    };
}

/// Generate standard `Interactive` focus management methods for widgets.
///
/// Use inside an `impl Interactive` block. Generates `focusable()`,
/// `on_focus()`, and `on_blur()` methods.
///
/// # Variants
///
/// - `impl_focus_handlers!(state)` — for widgets with `state: WidgetState`
/// - `impl_focus_handlers!(direct)` — for widgets with direct `disabled`/`focused` fields
/// - `impl_focus_handlers!(state, no_blur)` / `impl_focus_handlers!(direct, no_blur)` —
///   same but omits `on_blur()` so you can provide a custom implementation
///
/// # Example
/// ```rust,ignore
/// impl Interactive for MyWidget {
///     fn handle_key(&mut self, event: &KeyEvent) -> EventResult { /* ... */ }
///     crate::impl_focus_handlers!(state);
/// }
///
/// // With custom on_blur:
/// impl Interactive for MyDropdown {
///     fn handle_key(&mut self, event: &KeyEvent) -> EventResult { /* ... */ }
///     crate::impl_focus_handlers!(direct, no_blur);
///     fn on_blur(&mut self) {
///         self.focused = false;
///         self.close_dropdown();
///     }
/// }
/// ```
#[macro_export]
macro_rules! impl_focus_handlers {
    (state) => {
        fn focusable(&self) -> bool {
            !self.state.disabled
        }
        fn on_focus(&mut self) {
            self.state.focused = true;
        }
        fn on_blur(&mut self) {
            self.state.focused = false;
        }
    };
    (direct) => {
        fn focusable(&self) -> bool {
            !self.disabled
        }
        fn on_focus(&mut self) {
            self.focused = true;
        }
        fn on_blur(&mut self) {
            self.focused = false;
        }
    };
    (state, no_blur) => {
        fn focusable(&self) -> bool {
            !self.state.disabled
        }
        fn on_focus(&mut self) {
            self.state.focused = true;
        }
    };
    (direct, no_blur) => {
        fn focusable(&self) -> bool {
            !self.disabled
        }
        fn on_focus(&mut self) {
            self.focused = true;
        }
    };
}