Skip to main content

BoxBuilder

Struct BoxBuilder 

Source
pub struct BoxBuilder { /* private fields */ }
Expand description

Builder for Box views.

Implementations§

Source§

impl BoxBuilder

Source

pub fn new() -> Self

Source

pub fn child(self, view: View) -> Self

Examples found in repository?
examples/09_syntax_comparison.rs (lines 72-76)
24    fn render(&self, cx: Scope) -> View {
25        let use_jsx = state!(cx, || false);
26        let show_help = state!(cx, || false);
27
28        // F1 toggles help
29        cx.use_command(
30            KeyBinding::key(KeyCode::F(1)),
31            with!(show_help => move || show_help.update(|v| *v = !*v)),
32        );
33
34        let toggle = with!(use_jsx => move || use_jsx.set(!use_jsx.get()));
35
36        // Show which syntax is currently displayed
37        let syntax_name = if use_jsx.get() {
38            "view! macro (JSX-like)"
39        } else {
40            "Builder pattern"
41        };
42
43        View::vstack()
44            .child(
45                View::styled_text("Syntax Comparison")
46                    .color(Color::Cyan)
47                    .bold()
48                    .build(),
49            )
50            .child(
51                View::styled_text("Same UI, two ways to write it")
52                    .dim()
53                    .build(),
54            )
55            .child(View::gap(1))
56            .child(
57                View::hstack()
58                    .child(View::text("Current syntax: "))
59                    .child(
60                        View::styled_text(syntax_name)
61                            .color(Color::Yellow)
62                            .bold()
63                            .build(),
64                    )
65                    .build(),
66            )
67            .child(View::gap(1))
68            .child(
69                View::boxed()
70                    .border(true)
71                    .padding(1)
72                    .child(if use_jsx.get() {
73                        counter_jsx(cx.clone())
74                    } else {
75                        counter_builder(cx.clone())
76                    })
77                    .build(),
78            )
79            .child(View::gap(1))
80            .child(
81                View::button()
82                    .label("Toggle Syntax")
83                    .on_press(toggle)
84                    .build(),
85            )
86            .child(View::gap(1))
87            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
88            .child(
89                View::modal()
90                    .visible(show_help.get())
91                    .title("Example 09: Syntax Comparison")
92                    .on_dismiss(with!(show_help => move || show_help.set(false)))
93                    .child(
94                        View::vstack()
95                            .child(View::styled_text("What you're seeing").bold().build())
96                            .child(View::text("• Two syntaxes that produce identical output"))
97                            .child(View::text("• Builder: View::vstack().child(...).build()"))
98                            .child(View::text("• Macro: view! { <VStack>...</VStack> }"))
99                            .child(View::gap(1))
100                            .child(View::styled_text("Key concepts").bold().build())
101                            .child(View::text("• Builder is Rust-native, IDE-friendly"))
102                            .child(View::text("• view! macro is JSX-like, less boilerplate"))
103                            .child(View::text("• Choose based on your preference"))
104                            .child(View::gap(1))
105                            .child(View::styled_text("Try this").bold().build())
106                            .child(View::text("• Toggle between syntaxes"))
107                            .child(View::text("• Notice the output is identical"))
108                            .child(View::text("• Check the source code to see both styles"))
109                            .child(View::gap(1))
110                            .child(View::styled_text("Next up").bold().build())
111                            .child(View::text("→ 10_state_explained: deep dive into state"))
112                            .child(View::gap(1))
113                            .child(View::styled_text("Press Escape to close").dim().build())
114                            .build(),
115                    )
116                    .build(),
117            )
118            .build()
119    }
More examples
Hide additional examples
examples/15_markdown.rs (lines 75-106)
54    fn render(&self, cx: Scope) -> View {
55        let show_help = state!(cx, || false);
56
57        // F1 toggles help
58        cx.use_command(
59            KeyBinding::key(KeyCode::F(1)),
60            with!(show_help => move || show_help.update(|v| *v = !*v)),
61        );
62
63        let rendered = telex::markdown::render(DEMO_MARKDOWN);
64
65        View::vstack()
66            .child(
67                View::styled_text("Markdown Rendering Demo")
68                    .color(Color::Cyan)
69                    .bold()
70                    .build(),
71            )
72            .child(
73                View::boxed()
74                    .flex(1)
75                    .child(
76                        View::split()
77                            .horizontal()
78                            .ratio(0.4)
79                            .first(
80                                View::vstack()
81                                    .child(View::styled_text(" Source ").bold().build())
82                                    .child(
83                                        View::boxed()
84                                            .flex(1)
85                                            .border(true)
86                                            .scroll(true)
87                                            .child(View::text(DEMO_MARKDOWN))
88                                            .build(),
89                                    )
90                                    .build(),
91                            )
92                            .second(
93                                View::vstack()
94                                    .child(View::styled_text(" Rendered ").bold().build())
95                                    .child(
96                                        View::boxed()
97                                            .flex(1)
98                                            .border(true)
99                                            .scroll(true)
100                                            .child(rendered)
101                                            .build(),
102                                    )
103                                    .build(),
104                            )
105                            .build(),
106                    )
107                    .build(),
108            )
109            .child(
110                View::styled_text("Tab: switch panes | ↑↓/jk: scroll | F1 help | Ctrl+Q: quit")
111                    .dim()
112                    .build(),
113            )
114            .child(
115                View::modal()
116                    .visible(show_help.get())
117                    .title("Example 15: Markdown")
118                    .on_dismiss(with!(show_help => move || show_help.set(false)))
119                    .child(
120                        View::vstack()
121                            .child(View::styled_text("What you're seeing").bold().build())
122                            .child(View::text("• Side-by-side markdown source and rendered"))
123                            .child(View::text("• Full markdown syntax support"))
124                            .child(View::text("• Scrollable panes for long content"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Key concepts").bold().build())
127                            .child(View::text("• telex::markdown::render() parses markdown"))
128                            .child(View::text("• Returns a View tree with styled text"))
129                            .child(View::text("• Code blocks, lists, quotes, headers"))
130                            .child(View::text("• Split view for comparison"))
131                            .child(View::gap(1))
132                            .child(View::styled_text("Try this").bold().build())
133                            .child(View::text("• Tab between source and rendered panes"))
134                            .child(View::text("• Scroll with arrow keys or j/k"))
135                            .child(View::text("• Compare source with rendered output"))
136                            .child(View::gap(1))
137                            .child(View::styled_text("Next up").bold().build())
138                            .child(View::text("→ 16_progress: progress bars"))
139                            .child(View::gap(1))
140                            .child(View::styled_text("Press Escape to close").dim().build())
141                            .build(),
142                    )
143                    .build(),
144            )
145            .build()
146    }
examples/16_tree.rs (lines 80-87)
20    fn render(&self, cx: Scope) -> View {
21        let show_help = state!(cx, || false);
22
23        // F1 toggles help
24        cx.use_command(
25            KeyBinding::key(KeyCode::F(1)),
26            with!(show_help => move || show_help.update(|v| *v = !*v)),
27        );
28
29        // Track selected path
30        let selected = state!(cx, || vec![0usize]);
31
32        // Track expanded state for each node (by path prefix)
33        let expanded_paths = state!(cx, || {
34            vec![
35                vec![0],    // src/ expanded
36                vec![0, 0], // src/components/ expanded
37            ]
38        });
39
40        // Build tree items with current expanded state
41        let items = build_tree(&expanded_paths.get());
42
43        let on_select = with!(selected => move |path: TreePath| {
44            selected.set(path);
45        });
46
47        let on_activate = with!(expanded_paths => move |path: TreePath| {
48            // Toggle expand/collapse for the activated item
49            let mut paths = expanded_paths.get().clone();
50            if let Some(pos) = paths.iter().position(|p| *p == path) {
51                // Currently expanded, collapse it
52                paths.remove(pos);
53            } else {
54                // Currently collapsed, expand it
55                paths.push(path.clone());
56            }
57            expanded_paths.set(paths);
58        });
59
60        let selected_label = get_item_at_path(&items, &selected.get())
61            .map(|item| item.label.clone())
62            .unwrap_or_else(|| "Nothing".to_string());
63
64        View::vstack()
65            .child(
66                View::styled_text("File Browser")
67                    .color(Color::Cyan)
68                    .bold()
69                    .build(),
70            )
71            .child(
72                View::styled_text(format!("Selected: {}", selected_label))
73                    .dim()
74                    .build(),
75            )
76            .child(
77                View::boxed()
78                    .flex(1)
79                    .border(true)
80                    .child(
81                        View::tree()
82                            .items(items)
83                            .selected(selected.get().clone())
84                            .on_select(on_select)
85                            .on_activate(on_activate)
86                            .build(),
87                    )
88                    .build(),
89            )
90            .child(
91                View::styled_text(
92                    "↑↓/jk: navigate | Enter: expand/collapse | F1 help | Ctrl+Q: quit",
93                )
94                .dim()
95                .build(),
96            )
97            .child(
98                View::modal()
99                    .visible(show_help.get())
100                    .title("Example 16: Tree View")
101                    .on_dismiss(with!(show_help => move || show_help.set(false)))
102                    .child(
103                        View::vstack()
104                            .child(View::styled_text("What you're seeing").bold().build())
105                            .child(View::text("• Hierarchical tree widget"))
106                            .child(View::text("• Expand/collapse folders"))
107                            .child(View::text("• Path-based selection tracking"))
108                            .child(View::gap(1))
109                            .child(View::styled_text("Key concepts").bold().build())
110                            .child(View::text("• View::tree() for hierarchical data"))
111                            .child(View::text("• TreeItem::new().child() builds hierarchy"))
112                            .child(View::text("• on_select returns TreePath (Vec<usize>)"))
113                            .child(View::text("• on_activate for expand/collapse"))
114                            .child(View::gap(1))
115                            .child(View::styled_text("Try this").bold().build())
116                            .child(View::text("• Navigate with arrow keys"))
117                            .child(View::text("• Press Enter to expand/collapse folders"))
118                            .child(View::text("• Watch the 'Selected:' text update"))
119                            .child(View::gap(1))
120                            .child(View::styled_text("Next up").bold().build())
121                            .child(View::text("→ 17_table: data tables with sorting"))
122                            .child(View::gap(1))
123                            .child(View::styled_text("Press Escape to close").dim().build())
124                            .build(),
125                    )
126                    .build(),
127            )
128            .build()
129    }
examples/10_state_explained.rs (lines 68-80)
21    fn render(&self, cx: Scope) -> View {
22        let count = state!(cx, || 0i32);
23        let show_help = state!(cx, || false);
24
25        // F1 toggles help
26        cx.use_command(
27            KeyBinding::key(KeyCode::F(1)),
28            with!(show_help => move || show_help.update(|v| *v = !*v)),
29        );
30
31        // Clone handles for closures (this is the pattern being explained)
32        let count_for_increment = count.clone();
33        let count_for_decrement = count.clone();
34        let count_for_reset = count.clone();
35
36        let increment = move || {
37            let current = count_for_increment.get();
38            count_for_increment.set(current + 1);
39        };
40
41        let decrement = move || {
42            let current = count_for_decrement.get();
43            count_for_decrement.set(current - 1);
44        };
45
46        let reset = move || {
47            count_for_reset.set(0);
48        };
49
50        let current_value = count.get();
51
52        // Hook ordering demo
53        let _always_called_1 = state!(cx, || "hook 1");
54        let _always_called_2 = state!(cx, || "hook 2");
55
56        View::vstack()
57            .spacing(1)
58            .child(
59                View::styled_text("State Explained")
60                    .color(Color::Cyan)
61                    .bold()
62                    .build(),
63            )
64            .child(
65                View::boxed()
66                    .border(true)
67                    .padding(1)
68                    .child(
69                        View::vstack()
70                            .child(View::styled_text("The Mental Model:").bold().build())
71                            .child(View::gap(1))
72                            .child(View::text("  State<T> is a HANDLE, not data"))
73                            .child(View::text("  clone() copies the handle, not the data"))
74                            .child(View::text("  All handles point to ONE value"))
75                            .child(View::gap(1))
76                            .child(View::text("  count ──────┐"))
77                            .child(View::text("              ├──► i32: 0  (shared!)"))
78                            .child(View::text("  count2 ─────┘"))
79                            .build(),
80                    )
81                    .build(),
82            )
83            .child(
84                View::hstack()
85                    .spacing(1)
86                    .child(View::text("Current value:"))
87                    .child(
88                        View::styled_text(format!("{}", current_value))
89                            .color(Color::Yellow)
90                            .bold()
91                            .build(),
92                    )
93                    .build(),
94            )
95            .child(
96                View::hstack()
97                    .spacing(1)
98                    .child(View::button().label(" - ").on_press(decrement).build())
99                    .child(View::button().label(" + ").on_press(increment).build())
100                    .child(View::button().label("Reset").on_press(reset).build())
101                    .build(),
102            )
103            .child(
104                View::styled_text("All three buttons modify the SAME underlying i32")
105                    .dim()
106                    .build(),
107            )
108            .child(View::gap(1))
109            .child(
110                View::styled_text("Tab navigate • F1 help • Ctrl+Q quit")
111                    .dim()
112                    .build(),
113            )
114            .child(
115                View::modal()
116                    .visible(show_help.get())
117                    .title("Example 10: State Explained")
118                    .on_dismiss(with!(show_help => move || show_help.set(false)))
119                    .child(
120                        View::vstack()
121                            .child(View::styled_text("What you're seeing").bold().build())
122                            .child(View::text("• State<T> as a handle/pointer concept"))
123                            .child(View::text("• Multiple closures sharing one value"))
124                            .child(View::text("• Visual diagram of the mental model"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Key concepts").bold().build())
127                            .child(View::text("• clone() copies handle, not data"))
128                            .child(View::text("• All handles point to same underlying value"))
129                            .child(View::text(
130                                "• Hooks must be called in same order every render",
131                            ))
132                            .child(View::gap(1))
133                            .child(View::styled_text("Important rule").bold().build())
134                            .child(View::text("• NEVER put use_state inside an if block"))
135                            .child(View::text("• Use with!() macro to simplify cloning"))
136                            .child(View::gap(1))
137                            .child(View::styled_text("Next up").bold().build())
138                            .child(View::text("→ 11_checkbox: toggle controls"))
139                            .child(View::gap(1))
140                            .child(View::styled_text("Press Escape to close").dim().build())
141                            .build(),
142                    )
143                    .build(),
144            )
145            .build()
146    }
examples/13_split_panes.rs (lines 59-100)
20    fn render(&self, cx: Scope) -> View {
21        let show_help = state!(cx, || false);
22
23        // F1 toggles help
24        cx.use_command(
25            KeyBinding::key(KeyCode::F(1)),
26            with!(show_help => move || show_help.update(|v| *v = !*v)),
27        );
28
29        let selected_item = state!(cx, || 0usize);
30
31        let items = vec![
32            "README.md".to_string(),
33            "Cargo.toml".to_string(),
34            "src/".to_string(),
35            "src/main.rs".to_string(),
36            "src/lib.rs".to_string(),
37            "tests/".to_string(),
38        ];
39
40        let on_select = with!(selected_item => move |idx: usize| {
41            selected_item.set(idx);
42        });
43
44        let detail_text = match selected_item.get() {
45            0 => "# README\n\nThis is a demo of split panes.\n\nThe left panel shows a file list,\nthe right panel shows details.",
46            1 => "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
47            2 => "Directory: src/\n\nContains the main source files.",
48            3 => "fn main() {\n    println!(\"Hello, world!\");\n}",
49            4 => "pub mod utils;\npub mod widgets;",
50            5 => "Directory: tests/\n\nContains integration tests.",
51            _ => "Select an item to see details.",
52        };
53
54        // Horizontal split: file list on left, details on right
55        View::vstack()
56            .child(
57                View::boxed()
58                    .flex(1)
59                    .child(
60                        View::split()
61                            .horizontal()
62                            .ratio(0.3)
63                            .min_first(15)
64                            .first(
65                                View::vstack()
66                                    .child(
67                                        View::styled_text("Files")
68                                            .color(Color::Cyan)
69                                            .bold()
70                                            .build(),
71                                    )
72                                    .child(
73                                        View::list()
74                                            .items(items)
75                                            .selected(selected_item.get())
76                                            .on_select(on_select)
77                                            .build(),
78                                    )
79                                    .child(View::gap(1))
80                                    .build(),
81                            )
82                            .second(
83                                View::vstack()
84                                    .child(
85                                        View::styled_text("Details")
86                                            .color(Color::Green)
87                                            .bold()
88                                            .build(),
89                                    )
90                                    .child(
91                                        View::boxed()
92                                            .border(true)
93                                            .flex(1)
94                                            .child(View::text(detail_text))
95                                            .build(),
96                                    )
97                                    .build(),
98                            )
99                            .build(),
100                    )
101                    .build(),
102            )
103            .child(
104                View::styled_text("↑↓: select file | F1 help | Ctrl+Q: quit")
105                    .dim()
106                    .build(),
107            )
108            .child(
109                View::modal()
110                    .visible(show_help.get())
111                    .title("Example 13: Split Panes")
112                    .on_dismiss(with!(show_help => move || show_help.set(false)))
113                    .child(
114                        View::vstack()
115                            .child(View::styled_text("What you're seeing").bold().build())
116                            .child(View::text("• Horizontal split: file list / details"))
117                            .child(View::text("• ratio(0.3) = 30% left, 70% right"))
118                            .child(View::text("• min_first(15) sets minimum pane width"))
119                            .child(View::gap(1))
120                            .child(View::styled_text("Key concepts").bold().build())
121                            .child(View::text("• View::split() creates resizable panes"))
122                            .child(View::text("• .horizontal() or .vertical() orientation"))
123                            .child(View::text("• .first() and .second() set pane content"))
124                            .child(View::text("• Splits can be nested"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Try this").bold().build())
127                            .child(View::text("• Select different files to see details"))
128                            .child(View::text("• Resize terminal to see layout adapt"))
129                            .child(View::gap(1))
130                            .child(View::styled_text("Next up").bold().build())
131                            .child(View::text("→ 14_tabs: tabbed interfaces"))
132                            .child(View::gap(1))
133                            .child(View::styled_text("Press Escape to close").dim().build())
134                            .build(),
135                    )
136                    .build(),
137            )
138            .build()
139    }
examples/06_log_viewer.rs (line 114)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Stream log entries
31        let logs = text_stream!(cx, || {
32            let log_messages = vec![
33                "[INFO]  Application started",
34                "[INFO]  Loading configuration...",
35                "[OK]    Config loaded successfully",
36                "[INFO]  Connecting to database...",
37                "[OK]    Database connected",
38                "[INFO]  Starting web server on :8080",
39                "[OK]    Server listening",
40                "[INFO]  Processing request GET /api/users",
41                "[OK]    Response 200 in 45ms",
42                "[INFO]  Processing request POST /api/login",
43                "[OK]    Response 200 in 120ms",
44                "[WARN]  High memory usage detected: 85%",
45                "[INFO]  Running garbage collection...",
46                "[OK]    Memory freed: 200MB",
47                "[INFO]  Processing request GET /api/data",
48                "[ERROR] Database timeout after 5000ms",
49                "[INFO]  Retrying database connection...",
50                "[OK]    Database reconnected",
51                "[OK]    Response 200 in 5045ms",
52                "[INFO]  Scheduled backup starting...",
53                "[OK]    Backup completed: 1.2GB",
54                "[INFO]  Processing request GET /api/health",
55                "[OK]    Response 200 in 12ms",
56                "[INFO]  Processing request PUT /api/users/123",
57                "[OK]    Response 200 in 89ms",
58                "[INFO]  Cache invalidation triggered",
59                "[OK]    Cache cleared: 50MB",
60                "[WARN]  Slow query detected: 1200ms",
61                "[INFO]  Query optimization suggested",
62                "[INFO]  Processing request DELETE /api/sessions",
63                "[OK]    Response 204 in 34ms",
64                "[INFO]  SSL certificate check",
65                "[OK]    Certificate valid for 45 days",
66                "[INFO]  Processing request POST /api/upload",
67                "[OK]    File uploaded: 15MB",
68                "[WARN]  Disk usage at 78%",
69                "[INFO]  Processing request GET /api/reports",
70                "[OK]    Response 200 in 230ms",
71                "[INFO]  Metrics exported to monitoring",
72                "[OK]    Heartbeat sent successfully",
73                "------- Log stream completed -------",
74            ];
75
76            log_messages.into_iter().map(|msg| {
77                std::thread::sleep(Duration::from_millis(500));
78                format!("{}\n", msg)
79            })
80        });
81
82        let log_text = logs.get();
83        let is_streaming = logs.is_loading();
84
85        // Color the status indicator
86        let status = if is_streaming {
87            View::styled_text(" [LIVE]")
88                .color(Color::Green)
89                .bold()
90                .build()
91        } else {
92            View::styled_text(" [END]").dim().build()
93        };
94
95        View::vstack()
96            .child(
97                View::hstack()
98                    .child(
99                        View::styled_text("Log Viewer")
100                            .color(Color::Cyan)
101                            .bold()
102                            .build(),
103                    )
104                    .child(status)
105                    .build(),
106            )
107            .child(View::gap(1))
108            .child(
109                View::boxed()
110                    .scroll(true)
111                    .auto_scroll_bottom(true)
112                    .min_height(15)
113                    .max_height(15)
114                    .child(View::text(&log_text))
115                    .build(),
116            )
117            .child(View::gap(1))
118            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
119            .child(
120                View::modal()
121                    .visible(show_help.get())
122                    .title("Example 06: Log Viewer")
123                    .on_dismiss(with!(show_help => move || show_help.set(false)))
124                    .child(
125                        View::vstack()
126                            .child(View::styled_text("What you're seeing").bold().build())
127                            .child(View::text("• text_stream!() macro for accumulating text"))
128                            .child(View::text("• Auto-scrolling box that follows new content"))
129                            .child(View::text("• Live/End indicator based on stream state"))
130                            .child(View::gap(1))
131                            .child(View::styled_text("Key concepts").bold().build())
132                            .child(View::text("• text_stream! concatenates yielded strings"))
133                            .child(View::text(
134                                "• auto_scroll_bottom(true) keeps newest visible",
135                            ))
136                            .child(View::text("• Simulates tailing a log file"))
137                            .child(View::gap(1))
138                            .child(View::styled_text("Try this").bold().build())
139                            .child(View::text("• Watch the [LIVE] indicator change to [END]"))
140                            .child(View::text("• Notice auto-scroll keeps up with new entries"))
141                            .child(View::gap(1))
142                            .child(View::styled_text("Next up").bold().build())
143                            .child(View::text("→ 07_file_browser: real filesystem navigation"))
144                            .child(View::gap(1))
145                            .child(View::styled_text("Press Escape to close").dim().build())
146                            .build(),
147                    )
148                    .build(),
149            )
150            .build()
151    }
Source

pub fn border(self, border: bool) -> Self

Examples found in repository?
examples/09_syntax_comparison.rs (line 70)
24    fn render(&self, cx: Scope) -> View {
25        let use_jsx = state!(cx, || false);
26        let show_help = state!(cx, || false);
27
28        // F1 toggles help
29        cx.use_command(
30            KeyBinding::key(KeyCode::F(1)),
31            with!(show_help => move || show_help.update(|v| *v = !*v)),
32        );
33
34        let toggle = with!(use_jsx => move || use_jsx.set(!use_jsx.get()));
35
36        // Show which syntax is currently displayed
37        let syntax_name = if use_jsx.get() {
38            "view! macro (JSX-like)"
39        } else {
40            "Builder pattern"
41        };
42
43        View::vstack()
44            .child(
45                View::styled_text("Syntax Comparison")
46                    .color(Color::Cyan)
47                    .bold()
48                    .build(),
49            )
50            .child(
51                View::styled_text("Same UI, two ways to write it")
52                    .dim()
53                    .build(),
54            )
55            .child(View::gap(1))
56            .child(
57                View::hstack()
58                    .child(View::text("Current syntax: "))
59                    .child(
60                        View::styled_text(syntax_name)
61                            .color(Color::Yellow)
62                            .bold()
63                            .build(),
64                    )
65                    .build(),
66            )
67            .child(View::gap(1))
68            .child(
69                View::boxed()
70                    .border(true)
71                    .padding(1)
72                    .child(if use_jsx.get() {
73                        counter_jsx(cx.clone())
74                    } else {
75                        counter_builder(cx.clone())
76                    })
77                    .build(),
78            )
79            .child(View::gap(1))
80            .child(
81                View::button()
82                    .label("Toggle Syntax")
83                    .on_press(toggle)
84                    .build(),
85            )
86            .child(View::gap(1))
87            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
88            .child(
89                View::modal()
90                    .visible(show_help.get())
91                    .title("Example 09: Syntax Comparison")
92                    .on_dismiss(with!(show_help => move || show_help.set(false)))
93                    .child(
94                        View::vstack()
95                            .child(View::styled_text("What you're seeing").bold().build())
96                            .child(View::text("• Two syntaxes that produce identical output"))
97                            .child(View::text("• Builder: View::vstack().child(...).build()"))
98                            .child(View::text("• Macro: view! { <VStack>...</VStack> }"))
99                            .child(View::gap(1))
100                            .child(View::styled_text("Key concepts").bold().build())
101                            .child(View::text("• Builder is Rust-native, IDE-friendly"))
102                            .child(View::text("• view! macro is JSX-like, less boilerplate"))
103                            .child(View::text("• Choose based on your preference"))
104                            .child(View::gap(1))
105                            .child(View::styled_text("Try this").bold().build())
106                            .child(View::text("• Toggle between syntaxes"))
107                            .child(View::text("• Notice the output is identical"))
108                            .child(View::text("• Check the source code to see both styles"))
109                            .child(View::gap(1))
110                            .child(View::styled_text("Next up").bold().build())
111                            .child(View::text("→ 10_state_explained: deep dive into state"))
112                            .child(View::gap(1))
113                            .child(View::styled_text("Press Escape to close").dim().build())
114                            .build(),
115                    )
116                    .build(),
117            )
118            .build()
119    }
More examples
Hide additional examples
examples/15_markdown.rs (line 85)
54    fn render(&self, cx: Scope) -> View {
55        let show_help = state!(cx, || false);
56
57        // F1 toggles help
58        cx.use_command(
59            KeyBinding::key(KeyCode::F(1)),
60            with!(show_help => move || show_help.update(|v| *v = !*v)),
61        );
62
63        let rendered = telex::markdown::render(DEMO_MARKDOWN);
64
65        View::vstack()
66            .child(
67                View::styled_text("Markdown Rendering Demo")
68                    .color(Color::Cyan)
69                    .bold()
70                    .build(),
71            )
72            .child(
73                View::boxed()
74                    .flex(1)
75                    .child(
76                        View::split()
77                            .horizontal()
78                            .ratio(0.4)
79                            .first(
80                                View::vstack()
81                                    .child(View::styled_text(" Source ").bold().build())
82                                    .child(
83                                        View::boxed()
84                                            .flex(1)
85                                            .border(true)
86                                            .scroll(true)
87                                            .child(View::text(DEMO_MARKDOWN))
88                                            .build(),
89                                    )
90                                    .build(),
91                            )
92                            .second(
93                                View::vstack()
94                                    .child(View::styled_text(" Rendered ").bold().build())
95                                    .child(
96                                        View::boxed()
97                                            .flex(1)
98                                            .border(true)
99                                            .scroll(true)
100                                            .child(rendered)
101                                            .build(),
102                                    )
103                                    .build(),
104                            )
105                            .build(),
106                    )
107                    .build(),
108            )
109            .child(
110                View::styled_text("Tab: switch panes | ↑↓/jk: scroll | F1 help | Ctrl+Q: quit")
111                    .dim()
112                    .build(),
113            )
114            .child(
115                View::modal()
116                    .visible(show_help.get())
117                    .title("Example 15: Markdown")
118                    .on_dismiss(with!(show_help => move || show_help.set(false)))
119                    .child(
120                        View::vstack()
121                            .child(View::styled_text("What you're seeing").bold().build())
122                            .child(View::text("• Side-by-side markdown source and rendered"))
123                            .child(View::text("• Full markdown syntax support"))
124                            .child(View::text("• Scrollable panes for long content"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Key concepts").bold().build())
127                            .child(View::text("• telex::markdown::render() parses markdown"))
128                            .child(View::text("• Returns a View tree with styled text"))
129                            .child(View::text("• Code blocks, lists, quotes, headers"))
130                            .child(View::text("• Split view for comparison"))
131                            .child(View::gap(1))
132                            .child(View::styled_text("Try this").bold().build())
133                            .child(View::text("• Tab between source and rendered panes"))
134                            .child(View::text("• Scroll with arrow keys or j/k"))
135                            .child(View::text("• Compare source with rendered output"))
136                            .child(View::gap(1))
137                            .child(View::styled_text("Next up").bold().build())
138                            .child(View::text("→ 16_progress: progress bars"))
139                            .child(View::gap(1))
140                            .child(View::styled_text("Press Escape to close").dim().build())
141                            .build(),
142                    )
143                    .build(),
144            )
145            .build()
146    }
examples/16_tree.rs (line 79)
20    fn render(&self, cx: Scope) -> View {
21        let show_help = state!(cx, || false);
22
23        // F1 toggles help
24        cx.use_command(
25            KeyBinding::key(KeyCode::F(1)),
26            with!(show_help => move || show_help.update(|v| *v = !*v)),
27        );
28
29        // Track selected path
30        let selected = state!(cx, || vec![0usize]);
31
32        // Track expanded state for each node (by path prefix)
33        let expanded_paths = state!(cx, || {
34            vec![
35                vec![0],    // src/ expanded
36                vec![0, 0], // src/components/ expanded
37            ]
38        });
39
40        // Build tree items with current expanded state
41        let items = build_tree(&expanded_paths.get());
42
43        let on_select = with!(selected => move |path: TreePath| {
44            selected.set(path);
45        });
46
47        let on_activate = with!(expanded_paths => move |path: TreePath| {
48            // Toggle expand/collapse for the activated item
49            let mut paths = expanded_paths.get().clone();
50            if let Some(pos) = paths.iter().position(|p| *p == path) {
51                // Currently expanded, collapse it
52                paths.remove(pos);
53            } else {
54                // Currently collapsed, expand it
55                paths.push(path.clone());
56            }
57            expanded_paths.set(paths);
58        });
59
60        let selected_label = get_item_at_path(&items, &selected.get())
61            .map(|item| item.label.clone())
62            .unwrap_or_else(|| "Nothing".to_string());
63
64        View::vstack()
65            .child(
66                View::styled_text("File Browser")
67                    .color(Color::Cyan)
68                    .bold()
69                    .build(),
70            )
71            .child(
72                View::styled_text(format!("Selected: {}", selected_label))
73                    .dim()
74                    .build(),
75            )
76            .child(
77                View::boxed()
78                    .flex(1)
79                    .border(true)
80                    .child(
81                        View::tree()
82                            .items(items)
83                            .selected(selected.get().clone())
84                            .on_select(on_select)
85                            .on_activate(on_activate)
86                            .build(),
87                    )
88                    .build(),
89            )
90            .child(
91                View::styled_text(
92                    "↑↓/jk: navigate | Enter: expand/collapse | F1 help | Ctrl+Q: quit",
93                )
94                .dim()
95                .build(),
96            )
97            .child(
98                View::modal()
99                    .visible(show_help.get())
100                    .title("Example 16: Tree View")
101                    .on_dismiss(with!(show_help => move || show_help.set(false)))
102                    .child(
103                        View::vstack()
104                            .child(View::styled_text("What you're seeing").bold().build())
105                            .child(View::text("• Hierarchical tree widget"))
106                            .child(View::text("• Expand/collapse folders"))
107                            .child(View::text("• Path-based selection tracking"))
108                            .child(View::gap(1))
109                            .child(View::styled_text("Key concepts").bold().build())
110                            .child(View::text("• View::tree() for hierarchical data"))
111                            .child(View::text("• TreeItem::new().child() builds hierarchy"))
112                            .child(View::text("• on_select returns TreePath (Vec<usize>)"))
113                            .child(View::text("• on_activate for expand/collapse"))
114                            .child(View::gap(1))
115                            .child(View::styled_text("Try this").bold().build())
116                            .child(View::text("• Navigate with arrow keys"))
117                            .child(View::text("• Press Enter to expand/collapse folders"))
118                            .child(View::text("• Watch the 'Selected:' text update"))
119                            .child(View::gap(1))
120                            .child(View::styled_text("Next up").bold().build())
121                            .child(View::text("→ 17_table: data tables with sorting"))
122                            .child(View::gap(1))
123                            .child(View::styled_text("Press Escape to close").dim().build())
124                            .build(),
125                    )
126                    .build(),
127            )
128            .build()
129    }
examples/10_state_explained.rs (line 66)
21    fn render(&self, cx: Scope) -> View {
22        let count = state!(cx, || 0i32);
23        let show_help = state!(cx, || false);
24
25        // F1 toggles help
26        cx.use_command(
27            KeyBinding::key(KeyCode::F(1)),
28            with!(show_help => move || show_help.update(|v| *v = !*v)),
29        );
30
31        // Clone handles for closures (this is the pattern being explained)
32        let count_for_increment = count.clone();
33        let count_for_decrement = count.clone();
34        let count_for_reset = count.clone();
35
36        let increment = move || {
37            let current = count_for_increment.get();
38            count_for_increment.set(current + 1);
39        };
40
41        let decrement = move || {
42            let current = count_for_decrement.get();
43            count_for_decrement.set(current - 1);
44        };
45
46        let reset = move || {
47            count_for_reset.set(0);
48        };
49
50        let current_value = count.get();
51
52        // Hook ordering demo
53        let _always_called_1 = state!(cx, || "hook 1");
54        let _always_called_2 = state!(cx, || "hook 2");
55
56        View::vstack()
57            .spacing(1)
58            .child(
59                View::styled_text("State Explained")
60                    .color(Color::Cyan)
61                    .bold()
62                    .build(),
63            )
64            .child(
65                View::boxed()
66                    .border(true)
67                    .padding(1)
68                    .child(
69                        View::vstack()
70                            .child(View::styled_text("The Mental Model:").bold().build())
71                            .child(View::gap(1))
72                            .child(View::text("  State<T> is a HANDLE, not data"))
73                            .child(View::text("  clone() copies the handle, not the data"))
74                            .child(View::text("  All handles point to ONE value"))
75                            .child(View::gap(1))
76                            .child(View::text("  count ──────┐"))
77                            .child(View::text("              ├──► i32: 0  (shared!)"))
78                            .child(View::text("  count2 ─────┘"))
79                            .build(),
80                    )
81                    .build(),
82            )
83            .child(
84                View::hstack()
85                    .spacing(1)
86                    .child(View::text("Current value:"))
87                    .child(
88                        View::styled_text(format!("{}", current_value))
89                            .color(Color::Yellow)
90                            .bold()
91                            .build(),
92                    )
93                    .build(),
94            )
95            .child(
96                View::hstack()
97                    .spacing(1)
98                    .child(View::button().label(" - ").on_press(decrement).build())
99                    .child(View::button().label(" + ").on_press(increment).build())
100                    .child(View::button().label("Reset").on_press(reset).build())
101                    .build(),
102            )
103            .child(
104                View::styled_text("All three buttons modify the SAME underlying i32")
105                    .dim()
106                    .build(),
107            )
108            .child(View::gap(1))
109            .child(
110                View::styled_text("Tab navigate • F1 help • Ctrl+Q quit")
111                    .dim()
112                    .build(),
113            )
114            .child(
115                View::modal()
116                    .visible(show_help.get())
117                    .title("Example 10: State Explained")
118                    .on_dismiss(with!(show_help => move || show_help.set(false)))
119                    .child(
120                        View::vstack()
121                            .child(View::styled_text("What you're seeing").bold().build())
122                            .child(View::text("• State<T> as a handle/pointer concept"))
123                            .child(View::text("• Multiple closures sharing one value"))
124                            .child(View::text("• Visual diagram of the mental model"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Key concepts").bold().build())
127                            .child(View::text("• clone() copies handle, not data"))
128                            .child(View::text("• All handles point to same underlying value"))
129                            .child(View::text(
130                                "• Hooks must be called in same order every render",
131                            ))
132                            .child(View::gap(1))
133                            .child(View::styled_text("Important rule").bold().build())
134                            .child(View::text("• NEVER put use_state inside an if block"))
135                            .child(View::text("• Use with!() macro to simplify cloning"))
136                            .child(View::gap(1))
137                            .child(View::styled_text("Next up").bold().build())
138                            .child(View::text("→ 11_checkbox: toggle controls"))
139                            .child(View::gap(1))
140                            .child(View::styled_text("Press Escape to close").dim().build())
141                            .build(),
142                    )
143                    .build(),
144            )
145            .build()
146    }
examples/13_split_panes.rs (line 92)
20    fn render(&self, cx: Scope) -> View {
21        let show_help = state!(cx, || false);
22
23        // F1 toggles help
24        cx.use_command(
25            KeyBinding::key(KeyCode::F(1)),
26            with!(show_help => move || show_help.update(|v| *v = !*v)),
27        );
28
29        let selected_item = state!(cx, || 0usize);
30
31        let items = vec![
32            "README.md".to_string(),
33            "Cargo.toml".to_string(),
34            "src/".to_string(),
35            "src/main.rs".to_string(),
36            "src/lib.rs".to_string(),
37            "tests/".to_string(),
38        ];
39
40        let on_select = with!(selected_item => move |idx: usize| {
41            selected_item.set(idx);
42        });
43
44        let detail_text = match selected_item.get() {
45            0 => "# README\n\nThis is a demo of split panes.\n\nThe left panel shows a file list,\nthe right panel shows details.",
46            1 => "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
47            2 => "Directory: src/\n\nContains the main source files.",
48            3 => "fn main() {\n    println!(\"Hello, world!\");\n}",
49            4 => "pub mod utils;\npub mod widgets;",
50            5 => "Directory: tests/\n\nContains integration tests.",
51            _ => "Select an item to see details.",
52        };
53
54        // Horizontal split: file list on left, details on right
55        View::vstack()
56            .child(
57                View::boxed()
58                    .flex(1)
59                    .child(
60                        View::split()
61                            .horizontal()
62                            .ratio(0.3)
63                            .min_first(15)
64                            .first(
65                                View::vstack()
66                                    .child(
67                                        View::styled_text("Files")
68                                            .color(Color::Cyan)
69                                            .bold()
70                                            .build(),
71                                    )
72                                    .child(
73                                        View::list()
74                                            .items(items)
75                                            .selected(selected_item.get())
76                                            .on_select(on_select)
77                                            .build(),
78                                    )
79                                    .child(View::gap(1))
80                                    .build(),
81                            )
82                            .second(
83                                View::vstack()
84                                    .child(
85                                        View::styled_text("Details")
86                                            .color(Color::Green)
87                                            .bold()
88                                            .build(),
89                                    )
90                                    .child(
91                                        View::boxed()
92                                            .border(true)
93                                            .flex(1)
94                                            .child(View::text(detail_text))
95                                            .build(),
96                                    )
97                                    .build(),
98                            )
99                            .build(),
100                    )
101                    .build(),
102            )
103            .child(
104                View::styled_text("↑↓: select file | F1 help | Ctrl+Q: quit")
105                    .dim()
106                    .build(),
107            )
108            .child(
109                View::modal()
110                    .visible(show_help.get())
111                    .title("Example 13: Split Panes")
112                    .on_dismiss(with!(show_help => move || show_help.set(false)))
113                    .child(
114                        View::vstack()
115                            .child(View::styled_text("What you're seeing").bold().build())
116                            .child(View::text("• Horizontal split: file list / details"))
117                            .child(View::text("• ratio(0.3) = 30% left, 70% right"))
118                            .child(View::text("• min_first(15) sets minimum pane width"))
119                            .child(View::gap(1))
120                            .child(View::styled_text("Key concepts").bold().build())
121                            .child(View::text("• View::split() creates resizable panes"))
122                            .child(View::text("• .horizontal() or .vertical() orientation"))
123                            .child(View::text("• .first() and .second() set pane content"))
124                            .child(View::text("• Splits can be nested"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Try this").bold().build())
127                            .child(View::text("• Select different files to see details"))
128                            .child(View::text("• Resize terminal to see layout adapt"))
129                            .child(View::gap(1))
130                            .child(View::styled_text("Next up").bold().build())
131                            .child(View::text("→ 14_tabs: tabbed interfaces"))
132                            .child(View::gap(1))
133                            .child(View::styled_text("Press Escape to close").dim().build())
134                            .build(),
135                    )
136                    .build(),
137            )
138            .build()
139    }
examples/24_async_data.rs (line 78)
38    fn render(&self, cx: Scope) -> View {
39        let show_help = state!(cx, || false);
40
41        // F1 toggles help
42        cx.use_command(
43            KeyBinding::key(KeyCode::F(1)),
44            with!(show_help => move || show_help.update(|v| *v = !*v)),
45        );
46
47        // Simulate fetching user profile (slow - 2 seconds)
48        let profile = async_data!(cx, || {
49            thread::sleep(Duration::from_secs(2));
50            Ok(UserProfile {
51                name: "Alice Johnson".to_string(),
52                email: "alice@example.com".to_string(),
53                member_since: "January 2024".to_string(),
54            })
55        });
56
57        // Simulate fetching user stats (medium - 1 second)
58        let stats = async_data!(cx, || {
59            thread::sleep(Duration::from_secs(1));
60            Ok(Stats {
61                posts: 142,
62                followers: 1234,
63                following: 567,
64            })
65        });
66
67        // Simulate a failing request
68        let failing_data = async_data!(cx, || {
69            thread::sleep(Duration::from_millis(500));
70            Err::<String, _>("Network error: Connection refused".to_string())
71        });
72
73        View::vstack()
74            .spacing(1)
75            .child(
76                // Header
77                View::boxed()
78                    .border(true)
79                    .padding(1)
80                    .child(
81                        View::vstack()
82                            .child(View::styled_text("Async Data Loading Demo").bold().build())
83                            .child(
84                                View::styled_text(
85                                    "Demonstrates use_async for loading data with loading/error states",
86                                )
87                                .dim()
88                                .build(),
89                            )
90                            .build(),
91                    )
92                    .build(),
93            )
94            .child(
95                // Main content - three columns
96                View::hstack()
97                    .spacing(1)
98                    // Profile section
99                    .child(
100                        View::boxed()
101                            .flex(1)
102                            .border(true)
103                            .padding(1)
104                            .child(render_profile_section(&profile))
105                            .build(),
106                    )
107                    // Stats section
108                    .child(
109                        View::boxed()
110                            .flex(1)
111                            .border(true)
112                            .padding(1)
113                            .child(render_stats_section(&stats))
114                            .build(),
115                    )
116                    // Error section
117                    .child(
118                        View::boxed()
119                            .flex(1)
120                            .border(true)
121                            .padding(1)
122                            .child(render_error_section(&failing_data))
123                            .build(),
124                    )
125                    .build(),
126            )
127            .child(
128                // Status footer
129                View::boxed()
130                    .border(true)
131                    .padding(1)
132                    .child(
133                        View::vstack()
134                            .child(View::text(format!(
135                                "Overall status: {}",
136                                if profile.is_loading() || stats.is_loading() {
137                                    "Loading..."
138                                } else if profile.is_error() || stats.is_error() || failing_data.is_error() {
139                                    "Some requests failed"
140                                } else {
141                                    "All data loaded"
142                                }
143                            )))
144                            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
145                            .build(),
146                    )
147                    .build(),
148            )
149            .child(
150                View::modal()
151                    .visible(show_help.get())
152                    .title("Example 24: Async Data")
153                    .on_dismiss(with!(show_help => move || show_help.set(false)))
154                    .child(
155                        View::vstack()
156                            .child(View::styled_text("What you're seeing").bold().build())
157                            .child(View::text("• Three async data loads in parallel"))
158                            .child(View::text("• Loading, success, and error states"))
159                            .child(View::text("• Different load times for each"))
160                            .child(View::gap(1))
161                            .child(View::styled_text("Key concepts").bold().build())
162                            .child(View::text("• async_data!() macro runs in background"))
163                            .child(View::text("• Returns Async<T> enum"))
164                            .child(View::text("• .is_loading() / .is_error() helpers"))
165                            .child(View::text("• Pattern match for state handling"))
166                            .child(View::gap(1))
167                            .child(View::styled_text("Try this").bold().build())
168                            .child(View::text("• Watch data load progressively"))
169                            .child(View::text("• Notice the failing request"))
170                            .child(View::gap(1))
171                            .child(View::styled_text("Next up").bold().build())
172                            .child(View::text("→ 25_context: context API"))
173                            .child(View::gap(1))
174                            .child(View::styled_text("Press Escape to close").dim().build())
175                            .build()
176                    )
177                    .build()
178            )
179            .build()
180    }
Source

pub fn padding(self, padding: u16) -> Self

Examples found in repository?
examples/09_syntax_comparison.rs (line 71)
24    fn render(&self, cx: Scope) -> View {
25        let use_jsx = state!(cx, || false);
26        let show_help = state!(cx, || false);
27
28        // F1 toggles help
29        cx.use_command(
30            KeyBinding::key(KeyCode::F(1)),
31            with!(show_help => move || show_help.update(|v| *v = !*v)),
32        );
33
34        let toggle = with!(use_jsx => move || use_jsx.set(!use_jsx.get()));
35
36        // Show which syntax is currently displayed
37        let syntax_name = if use_jsx.get() {
38            "view! macro (JSX-like)"
39        } else {
40            "Builder pattern"
41        };
42
43        View::vstack()
44            .child(
45                View::styled_text("Syntax Comparison")
46                    .color(Color::Cyan)
47                    .bold()
48                    .build(),
49            )
50            .child(
51                View::styled_text("Same UI, two ways to write it")
52                    .dim()
53                    .build(),
54            )
55            .child(View::gap(1))
56            .child(
57                View::hstack()
58                    .child(View::text("Current syntax: "))
59                    .child(
60                        View::styled_text(syntax_name)
61                            .color(Color::Yellow)
62                            .bold()
63                            .build(),
64                    )
65                    .build(),
66            )
67            .child(View::gap(1))
68            .child(
69                View::boxed()
70                    .border(true)
71                    .padding(1)
72                    .child(if use_jsx.get() {
73                        counter_jsx(cx.clone())
74                    } else {
75                        counter_builder(cx.clone())
76                    })
77                    .build(),
78            )
79            .child(View::gap(1))
80            .child(
81                View::button()
82                    .label("Toggle Syntax")
83                    .on_press(toggle)
84                    .build(),
85            )
86            .child(View::gap(1))
87            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
88            .child(
89                View::modal()
90                    .visible(show_help.get())
91                    .title("Example 09: Syntax Comparison")
92                    .on_dismiss(with!(show_help => move || show_help.set(false)))
93                    .child(
94                        View::vstack()
95                            .child(View::styled_text("What you're seeing").bold().build())
96                            .child(View::text("• Two syntaxes that produce identical output"))
97                            .child(View::text("• Builder: View::vstack().child(...).build()"))
98                            .child(View::text("• Macro: view! { <VStack>...</VStack> }"))
99                            .child(View::gap(1))
100                            .child(View::styled_text("Key concepts").bold().build())
101                            .child(View::text("• Builder is Rust-native, IDE-friendly"))
102                            .child(View::text("• view! macro is JSX-like, less boilerplate"))
103                            .child(View::text("• Choose based on your preference"))
104                            .child(View::gap(1))
105                            .child(View::styled_text("Try this").bold().build())
106                            .child(View::text("• Toggle between syntaxes"))
107                            .child(View::text("• Notice the output is identical"))
108                            .child(View::text("• Check the source code to see both styles"))
109                            .child(View::gap(1))
110                            .child(View::styled_text("Next up").bold().build())
111                            .child(View::text("→ 10_state_explained: deep dive into state"))
112                            .child(View::gap(1))
113                            .child(View::styled_text("Press Escape to close").dim().build())
114                            .build(),
115                    )
116                    .build(),
117            )
118            .build()
119    }
More examples
Hide additional examples
examples/10_state_explained.rs (line 67)
21    fn render(&self, cx: Scope) -> View {
22        let count = state!(cx, || 0i32);
23        let show_help = state!(cx, || false);
24
25        // F1 toggles help
26        cx.use_command(
27            KeyBinding::key(KeyCode::F(1)),
28            with!(show_help => move || show_help.update(|v| *v = !*v)),
29        );
30
31        // Clone handles for closures (this is the pattern being explained)
32        let count_for_increment = count.clone();
33        let count_for_decrement = count.clone();
34        let count_for_reset = count.clone();
35
36        let increment = move || {
37            let current = count_for_increment.get();
38            count_for_increment.set(current + 1);
39        };
40
41        let decrement = move || {
42            let current = count_for_decrement.get();
43            count_for_decrement.set(current - 1);
44        };
45
46        let reset = move || {
47            count_for_reset.set(0);
48        };
49
50        let current_value = count.get();
51
52        // Hook ordering demo
53        let _always_called_1 = state!(cx, || "hook 1");
54        let _always_called_2 = state!(cx, || "hook 2");
55
56        View::vstack()
57            .spacing(1)
58            .child(
59                View::styled_text("State Explained")
60                    .color(Color::Cyan)
61                    .bold()
62                    .build(),
63            )
64            .child(
65                View::boxed()
66                    .border(true)
67                    .padding(1)
68                    .child(
69                        View::vstack()
70                            .child(View::styled_text("The Mental Model:").bold().build())
71                            .child(View::gap(1))
72                            .child(View::text("  State<T> is a HANDLE, not data"))
73                            .child(View::text("  clone() copies the handle, not the data"))
74                            .child(View::text("  All handles point to ONE value"))
75                            .child(View::gap(1))
76                            .child(View::text("  count ──────┐"))
77                            .child(View::text("              ├──► i32: 0  (shared!)"))
78                            .child(View::text("  count2 ─────┘"))
79                            .build(),
80                    )
81                    .build(),
82            )
83            .child(
84                View::hstack()
85                    .spacing(1)
86                    .child(View::text("Current value:"))
87                    .child(
88                        View::styled_text(format!("{}", current_value))
89                            .color(Color::Yellow)
90                            .bold()
91                            .build(),
92                    )
93                    .build(),
94            )
95            .child(
96                View::hstack()
97                    .spacing(1)
98                    .child(View::button().label(" - ").on_press(decrement).build())
99                    .child(View::button().label(" + ").on_press(increment).build())
100                    .child(View::button().label("Reset").on_press(reset).build())
101                    .build(),
102            )
103            .child(
104                View::styled_text("All three buttons modify the SAME underlying i32")
105                    .dim()
106                    .build(),
107            )
108            .child(View::gap(1))
109            .child(
110                View::styled_text("Tab navigate • F1 help • Ctrl+Q quit")
111                    .dim()
112                    .build(),
113            )
114            .child(
115                View::modal()
116                    .visible(show_help.get())
117                    .title("Example 10: State Explained")
118                    .on_dismiss(with!(show_help => move || show_help.set(false)))
119                    .child(
120                        View::vstack()
121                            .child(View::styled_text("What you're seeing").bold().build())
122                            .child(View::text("• State<T> as a handle/pointer concept"))
123                            .child(View::text("• Multiple closures sharing one value"))
124                            .child(View::text("• Visual diagram of the mental model"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Key concepts").bold().build())
127                            .child(View::text("• clone() copies handle, not data"))
128                            .child(View::text("• All handles point to same underlying value"))
129                            .child(View::text(
130                                "• Hooks must be called in same order every render",
131                            ))
132                            .child(View::gap(1))
133                            .child(View::styled_text("Important rule").bold().build())
134                            .child(View::text("• NEVER put use_state inside an if block"))
135                            .child(View::text("• Use with!() macro to simplify cloning"))
136                            .child(View::gap(1))
137                            .child(View::styled_text("Next up").bold().build())
138                            .child(View::text("→ 11_checkbox: toggle controls"))
139                            .child(View::gap(1))
140                            .child(View::styled_text("Press Escape to close").dim().build())
141                            .build(),
142                    )
143                    .build(),
144            )
145            .build()
146    }
examples/24_async_data.rs (line 79)
38    fn render(&self, cx: Scope) -> View {
39        let show_help = state!(cx, || false);
40
41        // F1 toggles help
42        cx.use_command(
43            KeyBinding::key(KeyCode::F(1)),
44            with!(show_help => move || show_help.update(|v| *v = !*v)),
45        );
46
47        // Simulate fetching user profile (slow - 2 seconds)
48        let profile = async_data!(cx, || {
49            thread::sleep(Duration::from_secs(2));
50            Ok(UserProfile {
51                name: "Alice Johnson".to_string(),
52                email: "alice@example.com".to_string(),
53                member_since: "January 2024".to_string(),
54            })
55        });
56
57        // Simulate fetching user stats (medium - 1 second)
58        let stats = async_data!(cx, || {
59            thread::sleep(Duration::from_secs(1));
60            Ok(Stats {
61                posts: 142,
62                followers: 1234,
63                following: 567,
64            })
65        });
66
67        // Simulate a failing request
68        let failing_data = async_data!(cx, || {
69            thread::sleep(Duration::from_millis(500));
70            Err::<String, _>("Network error: Connection refused".to_string())
71        });
72
73        View::vstack()
74            .spacing(1)
75            .child(
76                // Header
77                View::boxed()
78                    .border(true)
79                    .padding(1)
80                    .child(
81                        View::vstack()
82                            .child(View::styled_text("Async Data Loading Demo").bold().build())
83                            .child(
84                                View::styled_text(
85                                    "Demonstrates use_async for loading data with loading/error states",
86                                )
87                                .dim()
88                                .build(),
89                            )
90                            .build(),
91                    )
92                    .build(),
93            )
94            .child(
95                // Main content - three columns
96                View::hstack()
97                    .spacing(1)
98                    // Profile section
99                    .child(
100                        View::boxed()
101                            .flex(1)
102                            .border(true)
103                            .padding(1)
104                            .child(render_profile_section(&profile))
105                            .build(),
106                    )
107                    // Stats section
108                    .child(
109                        View::boxed()
110                            .flex(1)
111                            .border(true)
112                            .padding(1)
113                            .child(render_stats_section(&stats))
114                            .build(),
115                    )
116                    // Error section
117                    .child(
118                        View::boxed()
119                            .flex(1)
120                            .border(true)
121                            .padding(1)
122                            .child(render_error_section(&failing_data))
123                            .build(),
124                    )
125                    .build(),
126            )
127            .child(
128                // Status footer
129                View::boxed()
130                    .border(true)
131                    .padding(1)
132                    .child(
133                        View::vstack()
134                            .child(View::text(format!(
135                                "Overall status: {}",
136                                if profile.is_loading() || stats.is_loading() {
137                                    "Loading..."
138                                } else if profile.is_error() || stats.is_error() || failing_data.is_error() {
139                                    "Some requests failed"
140                                } else {
141                                    "All data loaded"
142                                }
143                            )))
144                            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
145                            .build(),
146                    )
147                    .build(),
148            )
149            .child(
150                View::modal()
151                    .visible(show_help.get())
152                    .title("Example 24: Async Data")
153                    .on_dismiss(with!(show_help => move || show_help.set(false)))
154                    .child(
155                        View::vstack()
156                            .child(View::styled_text("What you're seeing").bold().build())
157                            .child(View::text("• Three async data loads in parallel"))
158                            .child(View::text("• Loading, success, and error states"))
159                            .child(View::text("• Different load times for each"))
160                            .child(View::gap(1))
161                            .child(View::styled_text("Key concepts").bold().build())
162                            .child(View::text("• async_data!() macro runs in background"))
163                            .child(View::text("• Returns Async<T> enum"))
164                            .child(View::text("• .is_loading() / .is_error() helpers"))
165                            .child(View::text("• Pattern match for state handling"))
166                            .child(View::gap(1))
167                            .child(View::styled_text("Try this").bold().build())
168                            .child(View::text("• Watch data load progressively"))
169                            .child(View::text("• Notice the failing request"))
170                            .child(View::gap(1))
171                            .child(View::styled_text("Next up").bold().build())
172                            .child(View::text("→ 25_context: context API"))
173                            .child(View::gap(1))
174                            .child(View::styled_text("Press Escape to close").dim().build())
175                            .build()
176                    )
177                    .build()
178            )
179            .build()
180    }
examples/25_context.rs (line 131)
71    fn render(&self, cx: Scope) -> View {
72        let show_help = state!(cx, || false);
73
74        // F1 toggles help
75        cx.use_command(
76            KeyBinding::key(KeyCode::F(1)),
77            with!(show_help => move || show_help.update(|v| *v = !*v)),
78        );
79
80        // State that we'll provide via context
81        let theme = state!(cx, || ColorTheme::Default);
82        let user = state!(cx, || User {
83            name: "Guest".to_string(),
84            logged_in: false,
85        });
86
87        // Provide static config via context
88        cx.provide_context(AppConfig {
89            app_name: "Context Demo".to_string(),
90            version: "1.0.0".to_string(),
91        });
92
93        // Provide dynamic state via context (current values)
94        cx.provide_context(theme.get());
95        cx.provide_context(user.get());
96
97        // Theme switching handlers
98        let set_default = with!(theme => move || theme.set(ColorTheme::Default));
99        let set_ocean = with!(theme => move || theme.set(ColorTheme::Ocean));
100        let set_forest = with!(theme => move || theme.set(ColorTheme::Forest));
101        let set_sunset = with!(theme => move || theme.set(ColorTheme::Sunset));
102
103        // Login/logout handlers
104        let toggle_login = with!(user => move || {
105            let current = user.get();
106            if current.logged_in {
107                user.set(User {
108                    name: "Guest".to_string(),
109                    logged_in: false,
110                });
111            } else {
112                user.set(User {
113                    name: "Alice".to_string(),
114                    logged_in: true,
115                });
116            }
117        });
118
119        // Get current theme for styling
120        let current_theme = theme.get();
121
122        View::vstack()
123            .spacing(1)
124            // Header - uses context
125            .child(render_header(&cx))
126            .child(
127                // Main content
128                View::boxed()
129                    .flex(1)
130                    .border(true)
131                    .padding(1)
132                    .child(
133                        View::vstack()
134                            .spacing(1)
135                            .child(
136                                View::styled_text("Theme Selection:")
137                                    .color(current_theme.primary())
138                                    .bold()
139                                    .build(),
140                            )
141                            .child(
142                                View::hstack()
143                                    .spacing(2)
144                                    .child(
145                                        View::button()
146                                            .label("Default")
147                                            .on_press(set_default)
148                                            .build(),
149                                    )
150                                    .child(
151                                        View::button().label("Ocean").on_press(set_ocean).build(),
152                                    )
153                                    .child(
154                                        View::button().label("Forest").on_press(set_forest).build(),
155                                    )
156                                    .child(
157                                        View::button().label("Sunset").on_press(set_sunset).build(),
158                                    )
159                                    .build(),
160                            )
161                            .child(View::gap(1))
162                            .child(
163                                View::styled_text("User Actions:")
164                                    .color(current_theme.primary())
165                                    .bold()
166                                    .build(),
167                            )
168                            .child(
169                                View::button()
170                                    .label(if user.get().logged_in {
171                                        "Logout"
172                                    } else {
173                                        "Login as Alice"
174                                    })
175                                    .on_press(toggle_login)
176                                    .build(),
177                            )
178                            .child(View::spacer())
179                            // User info panel - uses context
180                            .child(render_user_panel(&cx))
181                            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
182                            .build(),
183                    )
184                    .build(),
185            )
186            // Status bar - uses context
187            .child(render_status_bar(&cx))
188            .child(
189                View::modal()
190                    .visible(show_help.get())
191                    .title("Example 25: Context")
192                    .on_dismiss(with!(show_help => move || show_help.set(false)))
193                    .child(
194                        View::vstack()
195                            .child(View::styled_text("What you're seeing").bold().build())
196                            .child(View::text("• Context API for global state"))
197                            .child(View::text("• Theme colors propagate everywhere"))
198                            .child(View::text("• User state shared across components"))
199                            .child(View::gap(1))
200                            .child(View::styled_text("Key concepts").bold().build())
201                            .child(View::text("• cx.provide_context() adds to context"))
202                            .child(View::text("• cx.use_context::<T>() reads context"))
203                            .child(View::text("• Avoids prop drilling"))
204                            .child(View::text("• Great for themes, user, config"))
205                            .child(View::gap(1))
206                            .child(View::styled_text("Try this").bold().build())
207                            .child(View::text("• Switch themes - colors update"))
208                            .child(View::text("• Login/logout - panel updates"))
209                            .child(View::text("• Header and status bar read context"))
210                            .child(View::gap(1))
211                            .child(View::styled_text("Next up").bold().build())
212                            .child(View::text("→ 26_radio_buttons: radio selections"))
213                            .child(View::gap(1))
214                            .child(View::styled_text("Press Escape to close").dim().build())
215                            .build(),
216                    )
217                    .build(),
218            )
219            .build()
220    }
221}
222
223// Helper function that reads from context
224fn render_header(cx: &Scope) -> View {
225    // Read config and theme from context
226    let config = cx.use_context::<AppConfig>();
227    let theme = cx
228        .use_context::<ColorTheme>()
229        .unwrap_or(ColorTheme::Default);
230
231    let title = config
232        .map(|c| format!("{} v{}", c.app_name, c.version))
233        .unwrap_or_else(|| "No config".to_string());
234
235    View::boxed()
236        .border(true)
237        .padding(1)
238        .child(
239            View::vstack()
240                .child(
241                    View::styled_text(title)
242                        .bold()
243                        .color(theme.primary())
244                        .build(),
245                )
246                .child(
247                    View::styled_text("Demonstrates provide_context and use_context")
248                        .dim()
249                        .build(),
250                )
251                .build(),
252        )
253        .build()
254}
255
256// Helper function that reads user from context
257fn render_user_panel(cx: &Scope) -> View {
258    let user = cx.use_context::<User>();
259    let theme = cx
260        .use_context::<ColorTheme>()
261        .unwrap_or(ColorTheme::Default);
262
263    let (status_text, status_color) = match &user {
264        Some(u) if u.logged_in => (format!("Logged in as: {}", u.name), theme.accent()),
265        Some(_) => ("Not logged in".to_string(), Color::DarkGrey),
266        None => ("User context not available".to_string(), Color::Red),
267    };
268
269    View::boxed()
270        .border(true)
271        .padding(1)
272        .child(
273            View::vstack()
274                .child(
275                    View::styled_text("User Panel (reads from context)")
276                        .bold()
277                        .color(theme.primary())
278                        .build(),
279                )
280                .child(View::styled_text(status_text).color(status_color).build())
281                .build(),
282        )
283        .build()
284}
examples/11_checkbox.rs (line 53)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Settings state
31        let dark_mode = state!(cx, || true);
32        let notifications = state!(cx, || true);
33        let auto_save = state!(cx, || false);
34        let telemetry = state!(cx, || false);
35
36        View::vstack()
37            .spacing(1)
38            .child(
39                View::styled_text("Settings")
40                    .color(Color::Cyan)
41                    .bold()
42                    .build(),
43            )
44            .child(
45                View::styled_text("Use Tab to navigate, Enter/Space to toggle")
46                    .dim()
47                    .build(),
48            )
49            .child(View::gap(1))
50            .child(
51                View::boxed()
52                    .border(true)
53                    .padding(1)
54                    .child(
55                        View::vstack()
56                            .spacing(1)
57                            .child(View::styled_text("Appearance").bold().build())
58                            .child(
59                                View::checkbox()
60                                    .checked(dark_mode.get())
61                                    .label("Dark mode")
62                                    .on_toggle(with!(dark_mode => move |checked| {
63                                        dark_mode.set(checked);
64                                        if checked {
65                                            set_theme(Theme::dark());
66                                        } else {
67                                            set_theme(Theme::light());
68                                        }
69                                    }))
70                                    .build(),
71                            )
72                            .build(),
73                    )
74                    .build(),
75            )
76            .child(
77                View::boxed()
78                    .border(true)
79                    .padding(1)
80                    .child(
81                        View::vstack()
82                            .spacing(1)
83                            .child(View::styled_text("Behavior").bold().build())
84                            .child(
85                                View::checkbox()
86                                    .checked(notifications.get())
87                                    .label("Enable notifications")
88                                    .on_toggle(with!(notifications => move |checked| {
89                                        notifications.set(checked);
90                                    }))
91                                    .build(),
92                            )
93                            .child(
94                                View::checkbox()
95                                    .checked(auto_save.get())
96                                    .label("Auto-save documents")
97                                    .on_toggle(with!(auto_save => move |checked| {
98                                        auto_save.set(checked);
99                                    }))
100                                    .build(),
101                            )
102                            .build(),
103                    )
104                    .build(),
105            )
106            .child(
107                View::boxed()
108                    .border(true)
109                    .padding(1)
110                    .child(
111                        View::vstack()
112                            .spacing(1)
113                            .child(View::styled_text("Privacy").bold().build())
114                            .child(
115                                View::checkbox()
116                                    .checked(telemetry.get())
117                                    .label("Send anonymous usage data")
118                                    .on_toggle(with!(telemetry => move |checked| {
119                                        telemetry.set(checked);
120                                    }))
121                                    .build(),
122                            )
123                            .build(),
124                    )
125                    .build(),
126            )
127            .child(View::gap(1))
128            .child(
129                View::hstack()
130                    .spacing(2)
131                    .child(View::text("Current settings:"))
132                    .child(
133                        View::styled_text(format!(
134                            "dark={} notify={} autosave={} telemetry={}",
135                            dark_mode.get(),
136                            notifications.get(),
137                            auto_save.get(),
138                            telemetry.get()
139                        ))
140                        .color(Color::Yellow)
141                        .build(),
142                    )
143                    .build(),
144            )
145            .child(View::gap(1))
146            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
147            .child(
148                View::modal()
149                    .visible(show_help.get())
150                    .title("Example 11: Checkbox")
151                    .on_dismiss(with!(show_help => move || show_help.set(false)))
152                    .child(
153                        View::vstack()
154                            .child(View::styled_text("What you're seeing").bold().build())
155                            .child(View::text("• Checkbox widget for boolean toggles"))
156                            .child(View::text("• Grouped settings in boxed sections"))
157                            .child(View::text("• Dark mode toggle that changes theme live"))
158                            .child(View::gap(1))
159                            .child(View::styled_text("Key concepts").bold().build())
160                            .child(View::text("• View::checkbox() with checked state"))
161                            .child(View::text("• on_toggle callback receives new value"))
162                            .child(View::text("• set_theme() for live theme switching"))
163                            .child(View::gap(1))
164                            .child(View::styled_text("Try this").bold().build())
165                            .child(View::text("• Toggle Dark mode to see theme change"))
166                            .child(View::text("• Watch the status line update"))
167                            .child(View::text("• Tab between checkboxes"))
168                            .child(View::gap(1))
169                            .child(View::styled_text("Next up").bold().build())
170                            .child(View::text("→ 12_text_area: multi-line text editing"))
171                            .child(View::gap(1))
172                            .child(View::styled_text("Press Escape to close").dim().build())
173                            .build(),
174                    )
175                    .build(),
176            )
177            .build()
178    }
examples/20_menu_bar.rs (line 139)
26    fn render(&self, cx: Scope) -> View {
27        let show_help = state!(cx, || false);
28
29        // F1 toggles help
30        cx.use_command(
31            KeyBinding::key(KeyCode::F(1)),
32            with!(show_help => move || show_help.update(|v| *v = !*v)),
33        );
34
35        // Menu state
36        let active_menu = state!(cx, || Option::<usize>::None);
37        let highlighted_menu = state!(cx, || 0usize);
38        let selected_item = state!(cx, || 0usize);
39
40        // App state
41        let message = state!(cx, || "Use Tab to focus menu bar, then Enter to open".to_string());
42        let counter = state!(cx, || 0i32);
43
44        // Command handler - executes menu commands
45        let handle_command = with!(message, counter, active_menu, selected_item => move |cmd_id: &'static str| {
46            let msg = match cmd_id {
47                "file.new" => "Created new file".to_string(),
48                "file.open" => "Opening file...".to_string(),
49                "file.save" => "File saved".to_string(),
50                "file.quit" => "Use Ctrl+Q to quit".to_string(),
51                "edit.undo" => "Undone".to_string(),
52                "edit.redo" => "Redone".to_string(),
53                "edit.cut" => "Cut to clipboard".to_string(),
54                "edit.copy" => "Copied to clipboard".to_string(),
55                "edit.paste" => "Pasted from clipboard".to_string(),
56                "counter.increment" => {
57                    counter.update(|n| *n += 1);
58                    format!("Counter: {}", counter.get())
59                }
60                "counter.decrement" => {
61                    counter.update(|n| *n -= 1);
62                    format!("Counter: {}", counter.get())
63                }
64                "counter.reset" => {
65                    counter.set(0);
66                    "Counter reset".to_string()
67                }
68                _ => format!("Unknown: {}", cmd_id),
69            };
70            message.set(msg);
71            // Close menu after executing command
72            active_menu.set(None);
73            selected_item.set(0);
74        });
75
76        // Menu change handler - opens/closes menus
77        let on_menu_change = with!(active_menu, highlighted_menu, selected_item => move |idx: usize| {
78            if active_menu.get() == Some(idx) {
79                // Clicking same menu toggles it closed
80                active_menu.set(None);
81            } else {
82                active_menu.set(Some(idx));
83                highlighted_menu.set(idx); // Keep highlight in sync
84                selected_item.set(0);
85            }
86        });
87
88        // Highlight change handler - arrow key navigation when no menu is open
89        let on_highlight_change = with!(highlighted_menu => move |idx: usize| {
90            highlighted_menu.set(idx);
91        });
92
93        // Item change handler - navigates within menu
94        let on_item_change = with!(selected_item => move |idx: usize| {
95            selected_item.set(idx);
96        });
97
98        // Build menus
99        let file_menu = Menu::new("File")
100            .command_with_shortcut("file.new", "New", "Ctrl+N")
101            .command_with_shortcut("file.open", "Open", "Ctrl+O")
102            .command_with_shortcut("file.save", "Save", "Ctrl+S")
103            .separator()
104            .command_with_shortcut("file.quit", "Quit", "Ctrl+Q");
105
106        let edit_menu = Menu::new("Edit")
107            .command_with_shortcut("edit.undo", "Undo", "Ctrl+Z")
108            .command_with_shortcut("edit.redo", "Redo", "Ctrl+Y")
109            .separator()
110            .command_with_shortcut("edit.cut", "Cut", "Ctrl+X")
111            .command_with_shortcut("edit.copy", "Copy", "Ctrl+C")
112            .command_with_shortcut("edit.paste", "Paste", "Ctrl+V");
113
114        let counter_menu = Menu::new("Counter")
115            .command("counter.increment", "Increment")
116            .command("counter.decrement", "Decrement")
117            .separator()
118            .command("counter.reset", "Reset to Zero");
119
120        View::vstack()
121            .child(
122                View::menu_bar()
123                    .menu(file_menu)
124                    .menu(edit_menu)
125                    .menu(counter_menu)
126                    .active_menu(active_menu.get())
127                    .highlighted_menu(highlighted_menu.get())
128                    .selected_item(selected_item.get())
129                    .on_select(handle_command)
130                    .on_menu_change(on_menu_change)
131                    .on_highlight_change(on_highlight_change)
132                    .on_item_change(on_item_change)
133                    .build(),
134            )
135            .child(
136                View::boxed()
137                    .flex(1)
138                    .border(true)
139                    .padding(2)
140                    .child(
141                        View::vstack()
142                            .spacing(1)
143                            .child(View::styled_text("Menu Bar Demo").bold().build())
144                            .child(
145                                View::styled_text(format!("Counter: {}", counter.get()))
146                                    .color(Color::Cyan)
147                                    .bold()
148                                    .build(),
149                            )
150                            .child(
151                                View::styled_text(format!("Status: {}", message.get()))
152                                    .dim()
153                                    .build(),
154                            )
155                            .child(View::spacer())
156                            .child(View::styled_text("Keyboard Navigation:").bold().build())
157                            .child(View::text("  Tab         Focus menu bar"))
158                            .child(View::text("  Enter       Open menu / Execute item"))
159                            .child(View::text("  Up/Down     Navigate menu items"))
160                            .child(View::text("  Left/Right  Switch between menus"))
161                            .child(View::text("  Escape      Close menu"))
162                            .child(View::text("  Ctrl+Q      Quit"))
163                            .child(View::text("  F1          Help"))
164                            .build(),
165                    )
166                    .build(),
167            )
168            .child(
169                View::modal()
170                    .visible(show_help.get())
171                    .title("Example 20: Menu Bar")
172                    .on_dismiss(with!(show_help => move || show_help.set(false)))
173                    .child(
174                        View::vstack()
175                            .child(View::styled_text("What you're seeing").bold().build())
176                            .child(View::text("• Dropdown menu bar with keyboard nav"))
177                            .child(View::text("• Menu items with shortcuts"))
178                            .child(View::text("• Separators in menus"))
179                            .child(View::gap(1))
180                            .child(View::styled_text("Key concepts").bold().build())
181                            .child(View::text("• View::menu_bar() creates menu system"))
182                            .child(View::text("• Menu::new().command() adds items"))
183                            .child(View::text("• .command_with_shortcut() shows key hints"))
184                            .child(View::text("• on_select receives command ID"))
185                            .child(View::gap(1))
186                            .child(View::styled_text("Try this").bold().build())
187                            .child(View::text("• Tab to menu, Enter to open"))
188                            .child(View::text("• Arrow keys navigate menus"))
189                            .child(View::text("• Try the Counter menu"))
190                            .child(View::gap(1))
191                            .child(View::styled_text("Next up").bold().build())
192                            .child(View::text("→ 21_toasts: toast notifications"))
193                            .child(View::gap(1))
194                            .child(View::styled_text("Press Escape to close").dim().build())
195                            .build(),
196                    )
197                    .build(),
198            )
199            .build()
200    }
Source

pub fn flex(self, flex: u16) -> Self

Examples found in repository?
examples/15_markdown.rs (line 74)
54    fn render(&self, cx: Scope) -> View {
55        let show_help = state!(cx, || false);
56
57        // F1 toggles help
58        cx.use_command(
59            KeyBinding::key(KeyCode::F(1)),
60            with!(show_help => move || show_help.update(|v| *v = !*v)),
61        );
62
63        let rendered = telex::markdown::render(DEMO_MARKDOWN);
64
65        View::vstack()
66            .child(
67                View::styled_text("Markdown Rendering Demo")
68                    .color(Color::Cyan)
69                    .bold()
70                    .build(),
71            )
72            .child(
73                View::boxed()
74                    .flex(1)
75                    .child(
76                        View::split()
77                            .horizontal()
78                            .ratio(0.4)
79                            .first(
80                                View::vstack()
81                                    .child(View::styled_text(" Source ").bold().build())
82                                    .child(
83                                        View::boxed()
84                                            .flex(1)
85                                            .border(true)
86                                            .scroll(true)
87                                            .child(View::text(DEMO_MARKDOWN))
88                                            .build(),
89                                    )
90                                    .build(),
91                            )
92                            .second(
93                                View::vstack()
94                                    .child(View::styled_text(" Rendered ").bold().build())
95                                    .child(
96                                        View::boxed()
97                                            .flex(1)
98                                            .border(true)
99                                            .scroll(true)
100                                            .child(rendered)
101                                            .build(),
102                                    )
103                                    .build(),
104                            )
105                            .build(),
106                    )
107                    .build(),
108            )
109            .child(
110                View::styled_text("Tab: switch panes | ↑↓/jk: scroll | F1 help | Ctrl+Q: quit")
111                    .dim()
112                    .build(),
113            )
114            .child(
115                View::modal()
116                    .visible(show_help.get())
117                    .title("Example 15: Markdown")
118                    .on_dismiss(with!(show_help => move || show_help.set(false)))
119                    .child(
120                        View::vstack()
121                            .child(View::styled_text("What you're seeing").bold().build())
122                            .child(View::text("• Side-by-side markdown source and rendered"))
123                            .child(View::text("• Full markdown syntax support"))
124                            .child(View::text("• Scrollable panes for long content"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Key concepts").bold().build())
127                            .child(View::text("• telex::markdown::render() parses markdown"))
128                            .child(View::text("• Returns a View tree with styled text"))
129                            .child(View::text("• Code blocks, lists, quotes, headers"))
130                            .child(View::text("• Split view for comparison"))
131                            .child(View::gap(1))
132                            .child(View::styled_text("Try this").bold().build())
133                            .child(View::text("• Tab between source and rendered panes"))
134                            .child(View::text("• Scroll with arrow keys or j/k"))
135                            .child(View::text("• Compare source with rendered output"))
136                            .child(View::gap(1))
137                            .child(View::styled_text("Next up").bold().build())
138                            .child(View::text("→ 16_progress: progress bars"))
139                            .child(View::gap(1))
140                            .child(View::styled_text("Press Escape to close").dim().build())
141                            .build(),
142                    )
143                    .build(),
144            )
145            .build()
146    }
More examples
Hide additional examples
examples/16_tree.rs (line 78)
20    fn render(&self, cx: Scope) -> View {
21        let show_help = state!(cx, || false);
22
23        // F1 toggles help
24        cx.use_command(
25            KeyBinding::key(KeyCode::F(1)),
26            with!(show_help => move || show_help.update(|v| *v = !*v)),
27        );
28
29        // Track selected path
30        let selected = state!(cx, || vec![0usize]);
31
32        // Track expanded state for each node (by path prefix)
33        let expanded_paths = state!(cx, || {
34            vec![
35                vec![0],    // src/ expanded
36                vec![0, 0], // src/components/ expanded
37            ]
38        });
39
40        // Build tree items with current expanded state
41        let items = build_tree(&expanded_paths.get());
42
43        let on_select = with!(selected => move |path: TreePath| {
44            selected.set(path);
45        });
46
47        let on_activate = with!(expanded_paths => move |path: TreePath| {
48            // Toggle expand/collapse for the activated item
49            let mut paths = expanded_paths.get().clone();
50            if let Some(pos) = paths.iter().position(|p| *p == path) {
51                // Currently expanded, collapse it
52                paths.remove(pos);
53            } else {
54                // Currently collapsed, expand it
55                paths.push(path.clone());
56            }
57            expanded_paths.set(paths);
58        });
59
60        let selected_label = get_item_at_path(&items, &selected.get())
61            .map(|item| item.label.clone())
62            .unwrap_or_else(|| "Nothing".to_string());
63
64        View::vstack()
65            .child(
66                View::styled_text("File Browser")
67                    .color(Color::Cyan)
68                    .bold()
69                    .build(),
70            )
71            .child(
72                View::styled_text(format!("Selected: {}", selected_label))
73                    .dim()
74                    .build(),
75            )
76            .child(
77                View::boxed()
78                    .flex(1)
79                    .border(true)
80                    .child(
81                        View::tree()
82                            .items(items)
83                            .selected(selected.get().clone())
84                            .on_select(on_select)
85                            .on_activate(on_activate)
86                            .build(),
87                    )
88                    .build(),
89            )
90            .child(
91                View::styled_text(
92                    "↑↓/jk: navigate | Enter: expand/collapse | F1 help | Ctrl+Q: quit",
93                )
94                .dim()
95                .build(),
96            )
97            .child(
98                View::modal()
99                    .visible(show_help.get())
100                    .title("Example 16: Tree View")
101                    .on_dismiss(with!(show_help => move || show_help.set(false)))
102                    .child(
103                        View::vstack()
104                            .child(View::styled_text("What you're seeing").bold().build())
105                            .child(View::text("• Hierarchical tree widget"))
106                            .child(View::text("• Expand/collapse folders"))
107                            .child(View::text("• Path-based selection tracking"))
108                            .child(View::gap(1))
109                            .child(View::styled_text("Key concepts").bold().build())
110                            .child(View::text("• View::tree() for hierarchical data"))
111                            .child(View::text("• TreeItem::new().child() builds hierarchy"))
112                            .child(View::text("• on_select returns TreePath (Vec<usize>)"))
113                            .child(View::text("• on_activate for expand/collapse"))
114                            .child(View::gap(1))
115                            .child(View::styled_text("Try this").bold().build())
116                            .child(View::text("• Navigate with arrow keys"))
117                            .child(View::text("• Press Enter to expand/collapse folders"))
118                            .child(View::text("• Watch the 'Selected:' text update"))
119                            .child(View::gap(1))
120                            .child(View::styled_text("Next up").bold().build())
121                            .child(View::text("→ 17_table: data tables with sorting"))
122                            .child(View::gap(1))
123                            .child(View::styled_text("Press Escape to close").dim().build())
124                            .build(),
125                    )
126                    .build(),
127            )
128            .build()
129    }
examples/13_split_panes.rs (line 58)
20    fn render(&self, cx: Scope) -> View {
21        let show_help = state!(cx, || false);
22
23        // F1 toggles help
24        cx.use_command(
25            KeyBinding::key(KeyCode::F(1)),
26            with!(show_help => move || show_help.update(|v| *v = !*v)),
27        );
28
29        let selected_item = state!(cx, || 0usize);
30
31        let items = vec![
32            "README.md".to_string(),
33            "Cargo.toml".to_string(),
34            "src/".to_string(),
35            "src/main.rs".to_string(),
36            "src/lib.rs".to_string(),
37            "tests/".to_string(),
38        ];
39
40        let on_select = with!(selected_item => move |idx: usize| {
41            selected_item.set(idx);
42        });
43
44        let detail_text = match selected_item.get() {
45            0 => "# README\n\nThis is a demo of split panes.\n\nThe left panel shows a file list,\nthe right panel shows details.",
46            1 => "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
47            2 => "Directory: src/\n\nContains the main source files.",
48            3 => "fn main() {\n    println!(\"Hello, world!\");\n}",
49            4 => "pub mod utils;\npub mod widgets;",
50            5 => "Directory: tests/\n\nContains integration tests.",
51            _ => "Select an item to see details.",
52        };
53
54        // Horizontal split: file list on left, details on right
55        View::vstack()
56            .child(
57                View::boxed()
58                    .flex(1)
59                    .child(
60                        View::split()
61                            .horizontal()
62                            .ratio(0.3)
63                            .min_first(15)
64                            .first(
65                                View::vstack()
66                                    .child(
67                                        View::styled_text("Files")
68                                            .color(Color::Cyan)
69                                            .bold()
70                                            .build(),
71                                    )
72                                    .child(
73                                        View::list()
74                                            .items(items)
75                                            .selected(selected_item.get())
76                                            .on_select(on_select)
77                                            .build(),
78                                    )
79                                    .child(View::gap(1))
80                                    .build(),
81                            )
82                            .second(
83                                View::vstack()
84                                    .child(
85                                        View::styled_text("Details")
86                                            .color(Color::Green)
87                                            .bold()
88                                            .build(),
89                                    )
90                                    .child(
91                                        View::boxed()
92                                            .border(true)
93                                            .flex(1)
94                                            .child(View::text(detail_text))
95                                            .build(),
96                                    )
97                                    .build(),
98                            )
99                            .build(),
100                    )
101                    .build(),
102            )
103            .child(
104                View::styled_text("↑↓: select file | F1 help | Ctrl+Q: quit")
105                    .dim()
106                    .build(),
107            )
108            .child(
109                View::modal()
110                    .visible(show_help.get())
111                    .title("Example 13: Split Panes")
112                    .on_dismiss(with!(show_help => move || show_help.set(false)))
113                    .child(
114                        View::vstack()
115                            .child(View::styled_text("What you're seeing").bold().build())
116                            .child(View::text("• Horizontal split: file list / details"))
117                            .child(View::text("• ratio(0.3) = 30% left, 70% right"))
118                            .child(View::text("• min_first(15) sets minimum pane width"))
119                            .child(View::gap(1))
120                            .child(View::styled_text("Key concepts").bold().build())
121                            .child(View::text("• View::split() creates resizable panes"))
122                            .child(View::text("• .horizontal() or .vertical() orientation"))
123                            .child(View::text("• .first() and .second() set pane content"))
124                            .child(View::text("• Splits can be nested"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Try this").bold().build())
127                            .child(View::text("• Select different files to see details"))
128                            .child(View::text("• Resize terminal to see layout adapt"))
129                            .child(View::gap(1))
130                            .child(View::styled_text("Next up").bold().build())
131                            .child(View::text("→ 14_tabs: tabbed interfaces"))
132                            .child(View::gap(1))
133                            .child(View::styled_text("Press Escape to close").dim().build())
134                            .build(),
135                    )
136                    .build(),
137            )
138            .build()
139    }
examples/24_async_data.rs (line 101)
38    fn render(&self, cx: Scope) -> View {
39        let show_help = state!(cx, || false);
40
41        // F1 toggles help
42        cx.use_command(
43            KeyBinding::key(KeyCode::F(1)),
44            with!(show_help => move || show_help.update(|v| *v = !*v)),
45        );
46
47        // Simulate fetching user profile (slow - 2 seconds)
48        let profile = async_data!(cx, || {
49            thread::sleep(Duration::from_secs(2));
50            Ok(UserProfile {
51                name: "Alice Johnson".to_string(),
52                email: "alice@example.com".to_string(),
53                member_since: "January 2024".to_string(),
54            })
55        });
56
57        // Simulate fetching user stats (medium - 1 second)
58        let stats = async_data!(cx, || {
59            thread::sleep(Duration::from_secs(1));
60            Ok(Stats {
61                posts: 142,
62                followers: 1234,
63                following: 567,
64            })
65        });
66
67        // Simulate a failing request
68        let failing_data = async_data!(cx, || {
69            thread::sleep(Duration::from_millis(500));
70            Err::<String, _>("Network error: Connection refused".to_string())
71        });
72
73        View::vstack()
74            .spacing(1)
75            .child(
76                // Header
77                View::boxed()
78                    .border(true)
79                    .padding(1)
80                    .child(
81                        View::vstack()
82                            .child(View::styled_text("Async Data Loading Demo").bold().build())
83                            .child(
84                                View::styled_text(
85                                    "Demonstrates use_async for loading data with loading/error states",
86                                )
87                                .dim()
88                                .build(),
89                            )
90                            .build(),
91                    )
92                    .build(),
93            )
94            .child(
95                // Main content - three columns
96                View::hstack()
97                    .spacing(1)
98                    // Profile section
99                    .child(
100                        View::boxed()
101                            .flex(1)
102                            .border(true)
103                            .padding(1)
104                            .child(render_profile_section(&profile))
105                            .build(),
106                    )
107                    // Stats section
108                    .child(
109                        View::boxed()
110                            .flex(1)
111                            .border(true)
112                            .padding(1)
113                            .child(render_stats_section(&stats))
114                            .build(),
115                    )
116                    // Error section
117                    .child(
118                        View::boxed()
119                            .flex(1)
120                            .border(true)
121                            .padding(1)
122                            .child(render_error_section(&failing_data))
123                            .build(),
124                    )
125                    .build(),
126            )
127            .child(
128                // Status footer
129                View::boxed()
130                    .border(true)
131                    .padding(1)
132                    .child(
133                        View::vstack()
134                            .child(View::text(format!(
135                                "Overall status: {}",
136                                if profile.is_loading() || stats.is_loading() {
137                                    "Loading..."
138                                } else if profile.is_error() || stats.is_error() || failing_data.is_error() {
139                                    "Some requests failed"
140                                } else {
141                                    "All data loaded"
142                                }
143                            )))
144                            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
145                            .build(),
146                    )
147                    .build(),
148            )
149            .child(
150                View::modal()
151                    .visible(show_help.get())
152                    .title("Example 24: Async Data")
153                    .on_dismiss(with!(show_help => move || show_help.set(false)))
154                    .child(
155                        View::vstack()
156                            .child(View::styled_text("What you're seeing").bold().build())
157                            .child(View::text("• Three async data loads in parallel"))
158                            .child(View::text("• Loading, success, and error states"))
159                            .child(View::text("• Different load times for each"))
160                            .child(View::gap(1))
161                            .child(View::styled_text("Key concepts").bold().build())
162                            .child(View::text("• async_data!() macro runs in background"))
163                            .child(View::text("• Returns Async<T> enum"))
164                            .child(View::text("• .is_loading() / .is_error() helpers"))
165                            .child(View::text("• Pattern match for state handling"))
166                            .child(View::gap(1))
167                            .child(View::styled_text("Try this").bold().build())
168                            .child(View::text("• Watch data load progressively"))
169                            .child(View::text("• Notice the failing request"))
170                            .child(View::gap(1))
171                            .child(View::styled_text("Next up").bold().build())
172                            .child(View::text("→ 25_context: context API"))
173                            .child(View::gap(1))
174                            .child(View::styled_text("Press Escape to close").dim().build())
175                            .build()
176                    )
177                    .build()
178            )
179            .build()
180    }
examples/25_context.rs (line 129)
71    fn render(&self, cx: Scope) -> View {
72        let show_help = state!(cx, || false);
73
74        // F1 toggles help
75        cx.use_command(
76            KeyBinding::key(KeyCode::F(1)),
77            with!(show_help => move || show_help.update(|v| *v = !*v)),
78        );
79
80        // State that we'll provide via context
81        let theme = state!(cx, || ColorTheme::Default);
82        let user = state!(cx, || User {
83            name: "Guest".to_string(),
84            logged_in: false,
85        });
86
87        // Provide static config via context
88        cx.provide_context(AppConfig {
89            app_name: "Context Demo".to_string(),
90            version: "1.0.0".to_string(),
91        });
92
93        // Provide dynamic state via context (current values)
94        cx.provide_context(theme.get());
95        cx.provide_context(user.get());
96
97        // Theme switching handlers
98        let set_default = with!(theme => move || theme.set(ColorTheme::Default));
99        let set_ocean = with!(theme => move || theme.set(ColorTheme::Ocean));
100        let set_forest = with!(theme => move || theme.set(ColorTheme::Forest));
101        let set_sunset = with!(theme => move || theme.set(ColorTheme::Sunset));
102
103        // Login/logout handlers
104        let toggle_login = with!(user => move || {
105            let current = user.get();
106            if current.logged_in {
107                user.set(User {
108                    name: "Guest".to_string(),
109                    logged_in: false,
110                });
111            } else {
112                user.set(User {
113                    name: "Alice".to_string(),
114                    logged_in: true,
115                });
116            }
117        });
118
119        // Get current theme for styling
120        let current_theme = theme.get();
121
122        View::vstack()
123            .spacing(1)
124            // Header - uses context
125            .child(render_header(&cx))
126            .child(
127                // Main content
128                View::boxed()
129                    .flex(1)
130                    .border(true)
131                    .padding(1)
132                    .child(
133                        View::vstack()
134                            .spacing(1)
135                            .child(
136                                View::styled_text("Theme Selection:")
137                                    .color(current_theme.primary())
138                                    .bold()
139                                    .build(),
140                            )
141                            .child(
142                                View::hstack()
143                                    .spacing(2)
144                                    .child(
145                                        View::button()
146                                            .label("Default")
147                                            .on_press(set_default)
148                                            .build(),
149                                    )
150                                    .child(
151                                        View::button().label("Ocean").on_press(set_ocean).build(),
152                                    )
153                                    .child(
154                                        View::button().label("Forest").on_press(set_forest).build(),
155                                    )
156                                    .child(
157                                        View::button().label("Sunset").on_press(set_sunset).build(),
158                                    )
159                                    .build(),
160                            )
161                            .child(View::gap(1))
162                            .child(
163                                View::styled_text("User Actions:")
164                                    .color(current_theme.primary())
165                                    .bold()
166                                    .build(),
167                            )
168                            .child(
169                                View::button()
170                                    .label(if user.get().logged_in {
171                                        "Logout"
172                                    } else {
173                                        "Login as Alice"
174                                    })
175                                    .on_press(toggle_login)
176                                    .build(),
177                            )
178                            .child(View::spacer())
179                            // User info panel - uses context
180                            .child(render_user_panel(&cx))
181                            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
182                            .build(),
183                    )
184                    .build(),
185            )
186            // Status bar - uses context
187            .child(render_status_bar(&cx))
188            .child(
189                View::modal()
190                    .visible(show_help.get())
191                    .title("Example 25: Context")
192                    .on_dismiss(with!(show_help => move || show_help.set(false)))
193                    .child(
194                        View::vstack()
195                            .child(View::styled_text("What you're seeing").bold().build())
196                            .child(View::text("• Context API for global state"))
197                            .child(View::text("• Theme colors propagate everywhere"))
198                            .child(View::text("• User state shared across components"))
199                            .child(View::gap(1))
200                            .child(View::styled_text("Key concepts").bold().build())
201                            .child(View::text("• cx.provide_context() adds to context"))
202                            .child(View::text("• cx.use_context::<T>() reads context"))
203                            .child(View::text("• Avoids prop drilling"))
204                            .child(View::text("• Great for themes, user, config"))
205                            .child(View::gap(1))
206                            .child(View::styled_text("Try this").bold().build())
207                            .child(View::text("• Switch themes - colors update"))
208                            .child(View::text("• Login/logout - panel updates"))
209                            .child(View::text("• Header and status bar read context"))
210                            .child(View::gap(1))
211                            .child(View::styled_text("Next up").bold().build())
212                            .child(View::text("→ 26_radio_buttons: radio selections"))
213                            .child(View::gap(1))
214                            .child(View::styled_text("Press Escape to close").dim().build())
215                            .build(),
216                    )
217                    .build(),
218            )
219            .build()
220    }
examples/14_tabs.rs (line 69)
22    fn render(&self, cx: Scope) -> View {
23        let show_help = state!(cx, || false);
24
25        // F1 toggles help
26        cx.use_command(
27            KeyBinding::key(KeyCode::F(1)),
28            with!(show_help => move || show_help.update(|v| *v = !*v)),
29        );
30
31        let active_tab = state!(cx, || 0usize);
32
33        // Settings state
34        let notifications = state!(cx, || true);
35        let dark_mode = state!(cx, || true);
36        let auto_save = state!(cx, || true);
37
38        let on_change = with!(active_tab => move |idx: usize| {
39            active_tab.set(idx);
40        });
41
42        // Checkbox handlers
43        let on_notifications = with!(notifications => move |checked: bool| {
44            notifications.set(checked);
45        });
46
47        let on_dark_mode = with!(dark_mode => move |checked: bool| {
48            dark_mode.set(checked);
49            if checked {
50                set_theme(Theme::dark());
51            } else {
52                set_theme(Theme::light());
53            }
54        });
55
56        let on_auto_save = with!(auto_save => move |checked: bool| {
57            auto_save.set(checked);
58        });
59
60        View::vstack()
61            .child(
62                View::styled_text("Tabbed Interface Demo")
63                    .color(Color::Cyan)
64                    .bold()
65                    .build(),
66            )
67            .child(
68                View::boxed()
69                    .flex(1)
70                    .child(
71                        View::tabs()
72                            .tab(
73                                "Overview",
74                                View::vstack()
75                                    .child(View::styled_text("Welcome!").bold().build())
76                                    .child(View::text(
77                                        "\nThis is the Overview tab.\n\n\
78                                         Use the keyboard to switch tabs:\n\
79                                         - Left/Right arrows\n\
80                                         - [ and ] keys\n\
81                                         - Number keys 1-3",
82                                    ))
83                                    .build(),
84                            )
85                            .tab(
86                                "Settings",
87                                View::vstack()
88                                    .child(View::styled_text("Settings").bold().build())
89                                    .child(View::text(""))
90                                    .child(
91                                        View::checkbox()
92                                            .label("Enable notifications")
93                                            .checked(notifications.get())
94                                            .on_toggle(on_notifications)
95                                            .build(),
96                                    )
97                                    .child(
98                                        View::checkbox()
99                                            .label("Dark mode")
100                                            .checked(dark_mode.get())
101                                            .on_toggle(on_dark_mode)
102                                            .build(),
103                                    )
104                                    .child(
105                                        View::checkbox()
106                                            .label("Auto-save")
107                                            .checked(auto_save.get())
108                                            .on_toggle(on_auto_save)
109                                            .build(),
110                                    )
111                                    .build(),
112                            )
113                            .tab(
114                                "About",
115                                View::vstack()
116                                    .child(View::styled_text("About").bold().build())
117                                    .child(View::text(""))
118                                    .child(View::text("Telex TUI Framework"))
119                                    .child(View::text("Version: 0.2.1"))
120                                    .child(View::text(""))
121                                    .child(
122                                        View::styled_text("A React-style TUI framework for Rust")
123                                            .dim()
124                                            .build(),
125                                    )
126                                    .build(),
127                            )
128                            .active(active_tab.get())
129                            .on_change(on_change)
130                            .build(),
131                    )
132                    .build(),
133            )
134            .child(
135                View::styled_text("←→ or []: switch tabs | F1 help | Ctrl+Q: quit")
136                    .dim()
137                    .build(),
138            )
139            .child(
140                View::modal()
141                    .visible(show_help.get())
142                    .title("Example 14: Tabs")
143                    .on_dismiss(with!(show_help => move || show_help.set(false)))
144                    .child(
145                        View::vstack()
146                            .child(View::styled_text("What you're seeing").bold().build())
147                            .child(View::text("• Tabbed interface with three tabs"))
148                            .child(View::text("• Settings tab with checkboxes"))
149                            .child(View::text("• Keyboard navigation between tabs"))
150                            .child(View::gap(1))
151                            .child(View::styled_text("Key concepts").bold().build())
152                            .child(View::text("• View::tabs() creates tabbed container"))
153                            .child(View::text("• .tab(\"Title\", content) adds each tab"))
154                            .child(View::text("• .active() and .on_change() for state"))
155                            .child(View::text("• Arrow keys, [ ], or 1-3 switch tabs"))
156                            .child(View::gap(1))
157                            .child(View::styled_text("Try this").bold().build())
158                            .child(View::text("• Switch tabs with arrow keys"))
159                            .child(View::text("• Toggle checkboxes in Settings"))
160                            .child(View::text("• Try [ and ] keys for tab switching"))
161                            .child(View::gap(1))
162                            .child(View::styled_text("Next up").bold().build())
163                            .child(View::text("→ 15_markdown: markdown rendering"))
164                            .child(View::gap(1))
165                            .child(View::styled_text("Press Escape to close").dim().build())
166                            .build(),
167                    )
168                    .build(),
169            )
170            .build()
171    }
Source

pub fn scroll(self, scroll: bool) -> Self

Examples found in repository?
examples/15_markdown.rs (line 86)
54    fn render(&self, cx: Scope) -> View {
55        let show_help = state!(cx, || false);
56
57        // F1 toggles help
58        cx.use_command(
59            KeyBinding::key(KeyCode::F(1)),
60            with!(show_help => move || show_help.update(|v| *v = !*v)),
61        );
62
63        let rendered = telex::markdown::render(DEMO_MARKDOWN);
64
65        View::vstack()
66            .child(
67                View::styled_text("Markdown Rendering Demo")
68                    .color(Color::Cyan)
69                    .bold()
70                    .build(),
71            )
72            .child(
73                View::boxed()
74                    .flex(1)
75                    .child(
76                        View::split()
77                            .horizontal()
78                            .ratio(0.4)
79                            .first(
80                                View::vstack()
81                                    .child(View::styled_text(" Source ").bold().build())
82                                    .child(
83                                        View::boxed()
84                                            .flex(1)
85                                            .border(true)
86                                            .scroll(true)
87                                            .child(View::text(DEMO_MARKDOWN))
88                                            .build(),
89                                    )
90                                    .build(),
91                            )
92                            .second(
93                                View::vstack()
94                                    .child(View::styled_text(" Rendered ").bold().build())
95                                    .child(
96                                        View::boxed()
97                                            .flex(1)
98                                            .border(true)
99                                            .scroll(true)
100                                            .child(rendered)
101                                            .build(),
102                                    )
103                                    .build(),
104                            )
105                            .build(),
106                    )
107                    .build(),
108            )
109            .child(
110                View::styled_text("Tab: switch panes | ↑↓/jk: scroll | F1 help | Ctrl+Q: quit")
111                    .dim()
112                    .build(),
113            )
114            .child(
115                View::modal()
116                    .visible(show_help.get())
117                    .title("Example 15: Markdown")
118                    .on_dismiss(with!(show_help => move || show_help.set(false)))
119                    .child(
120                        View::vstack()
121                            .child(View::styled_text("What you're seeing").bold().build())
122                            .child(View::text("• Side-by-side markdown source and rendered"))
123                            .child(View::text("• Full markdown syntax support"))
124                            .child(View::text("• Scrollable panes for long content"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Key concepts").bold().build())
127                            .child(View::text("• telex::markdown::render() parses markdown"))
128                            .child(View::text("• Returns a View tree with styled text"))
129                            .child(View::text("• Code blocks, lists, quotes, headers"))
130                            .child(View::text("• Split view for comparison"))
131                            .child(View::gap(1))
132                            .child(View::styled_text("Try this").bold().build())
133                            .child(View::text("• Tab between source and rendered panes"))
134                            .child(View::text("• Scroll with arrow keys or j/k"))
135                            .child(View::text("• Compare source with rendered output"))
136                            .child(View::gap(1))
137                            .child(View::styled_text("Next up").bold().build())
138                            .child(View::text("→ 16_progress: progress bars"))
139                            .child(View::gap(1))
140                            .child(View::styled_text("Press Escape to close").dim().build())
141                            .build(),
142                    )
143                    .build(),
144            )
145            .build()
146    }
More examples
Hide additional examples
examples/06_log_viewer.rs (line 110)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Stream log entries
31        let logs = text_stream!(cx, || {
32            let log_messages = vec![
33                "[INFO]  Application started",
34                "[INFO]  Loading configuration...",
35                "[OK]    Config loaded successfully",
36                "[INFO]  Connecting to database...",
37                "[OK]    Database connected",
38                "[INFO]  Starting web server on :8080",
39                "[OK]    Server listening",
40                "[INFO]  Processing request GET /api/users",
41                "[OK]    Response 200 in 45ms",
42                "[INFO]  Processing request POST /api/login",
43                "[OK]    Response 200 in 120ms",
44                "[WARN]  High memory usage detected: 85%",
45                "[INFO]  Running garbage collection...",
46                "[OK]    Memory freed: 200MB",
47                "[INFO]  Processing request GET /api/data",
48                "[ERROR] Database timeout after 5000ms",
49                "[INFO]  Retrying database connection...",
50                "[OK]    Database reconnected",
51                "[OK]    Response 200 in 5045ms",
52                "[INFO]  Scheduled backup starting...",
53                "[OK]    Backup completed: 1.2GB",
54                "[INFO]  Processing request GET /api/health",
55                "[OK]    Response 200 in 12ms",
56                "[INFO]  Processing request PUT /api/users/123",
57                "[OK]    Response 200 in 89ms",
58                "[INFO]  Cache invalidation triggered",
59                "[OK]    Cache cleared: 50MB",
60                "[WARN]  Slow query detected: 1200ms",
61                "[INFO]  Query optimization suggested",
62                "[INFO]  Processing request DELETE /api/sessions",
63                "[OK]    Response 204 in 34ms",
64                "[INFO]  SSL certificate check",
65                "[OK]    Certificate valid for 45 days",
66                "[INFO]  Processing request POST /api/upload",
67                "[OK]    File uploaded: 15MB",
68                "[WARN]  Disk usage at 78%",
69                "[INFO]  Processing request GET /api/reports",
70                "[OK]    Response 200 in 230ms",
71                "[INFO]  Metrics exported to monitoring",
72                "[OK]    Heartbeat sent successfully",
73                "------- Log stream completed -------",
74            ];
75
76            log_messages.into_iter().map(|msg| {
77                std::thread::sleep(Duration::from_millis(500));
78                format!("{}\n", msg)
79            })
80        });
81
82        let log_text = logs.get();
83        let is_streaming = logs.is_loading();
84
85        // Color the status indicator
86        let status = if is_streaming {
87            View::styled_text(" [LIVE]")
88                .color(Color::Green)
89                .bold()
90                .build()
91        } else {
92            View::styled_text(" [END]").dim().build()
93        };
94
95        View::vstack()
96            .child(
97                View::hstack()
98                    .child(
99                        View::styled_text("Log Viewer")
100                            .color(Color::Cyan)
101                            .bold()
102                            .build(),
103                    )
104                    .child(status)
105                    .build(),
106            )
107            .child(View::gap(1))
108            .child(
109                View::boxed()
110                    .scroll(true)
111                    .auto_scroll_bottom(true)
112                    .min_height(15)
113                    .max_height(15)
114                    .child(View::text(&log_text))
115                    .build(),
116            )
117            .child(View::gap(1))
118            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
119            .child(
120                View::modal()
121                    .visible(show_help.get())
122                    .title("Example 06: Log Viewer")
123                    .on_dismiss(with!(show_help => move || show_help.set(false)))
124                    .child(
125                        View::vstack()
126                            .child(View::styled_text("What you're seeing").bold().build())
127                            .child(View::text("• text_stream!() macro for accumulating text"))
128                            .child(View::text("• Auto-scrolling box that follows new content"))
129                            .child(View::text("• Live/End indicator based on stream state"))
130                            .child(View::gap(1))
131                            .child(View::styled_text("Key concepts").bold().build())
132                            .child(View::text("• text_stream! concatenates yielded strings"))
133                            .child(View::text(
134                                "• auto_scroll_bottom(true) keeps newest visible",
135                            ))
136                            .child(View::text("• Simulates tailing a log file"))
137                            .child(View::gap(1))
138                            .child(View::styled_text("Try this").bold().build())
139                            .child(View::text("• Watch the [LIVE] indicator change to [END]"))
140                            .child(View::text("• Notice auto-scroll keeps up with new entries"))
141                            .child(View::gap(1))
142                            .child(View::styled_text("Next up").bold().build())
143                            .child(View::text("→ 07_file_browser: real filesystem navigation"))
144                            .child(View::gap(1))
145                            .child(View::styled_text("Press Escape to close").dim().build())
146                            .build(),
147                    )
148                    .build(),
149            )
150            .build()
151    }
Source

pub fn auto_scroll_bottom(self, auto_scroll: bool) -> Self

Enable auto-scrolling to bottom (for chat-like UIs).

Examples found in repository?
examples/06_log_viewer.rs (line 111)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Stream log entries
31        let logs = text_stream!(cx, || {
32            let log_messages = vec![
33                "[INFO]  Application started",
34                "[INFO]  Loading configuration...",
35                "[OK]    Config loaded successfully",
36                "[INFO]  Connecting to database...",
37                "[OK]    Database connected",
38                "[INFO]  Starting web server on :8080",
39                "[OK]    Server listening",
40                "[INFO]  Processing request GET /api/users",
41                "[OK]    Response 200 in 45ms",
42                "[INFO]  Processing request POST /api/login",
43                "[OK]    Response 200 in 120ms",
44                "[WARN]  High memory usage detected: 85%",
45                "[INFO]  Running garbage collection...",
46                "[OK]    Memory freed: 200MB",
47                "[INFO]  Processing request GET /api/data",
48                "[ERROR] Database timeout after 5000ms",
49                "[INFO]  Retrying database connection...",
50                "[OK]    Database reconnected",
51                "[OK]    Response 200 in 5045ms",
52                "[INFO]  Scheduled backup starting...",
53                "[OK]    Backup completed: 1.2GB",
54                "[INFO]  Processing request GET /api/health",
55                "[OK]    Response 200 in 12ms",
56                "[INFO]  Processing request PUT /api/users/123",
57                "[OK]    Response 200 in 89ms",
58                "[INFO]  Cache invalidation triggered",
59                "[OK]    Cache cleared: 50MB",
60                "[WARN]  Slow query detected: 1200ms",
61                "[INFO]  Query optimization suggested",
62                "[INFO]  Processing request DELETE /api/sessions",
63                "[OK]    Response 204 in 34ms",
64                "[INFO]  SSL certificate check",
65                "[OK]    Certificate valid for 45 days",
66                "[INFO]  Processing request POST /api/upload",
67                "[OK]    File uploaded: 15MB",
68                "[WARN]  Disk usage at 78%",
69                "[INFO]  Processing request GET /api/reports",
70                "[OK]    Response 200 in 230ms",
71                "[INFO]  Metrics exported to monitoring",
72                "[OK]    Heartbeat sent successfully",
73                "------- Log stream completed -------",
74            ];
75
76            log_messages.into_iter().map(|msg| {
77                std::thread::sleep(Duration::from_millis(500));
78                format!("{}\n", msg)
79            })
80        });
81
82        let log_text = logs.get();
83        let is_streaming = logs.is_loading();
84
85        // Color the status indicator
86        let status = if is_streaming {
87            View::styled_text(" [LIVE]")
88                .color(Color::Green)
89                .bold()
90                .build()
91        } else {
92            View::styled_text(" [END]").dim().build()
93        };
94
95        View::vstack()
96            .child(
97                View::hstack()
98                    .child(
99                        View::styled_text("Log Viewer")
100                            .color(Color::Cyan)
101                            .bold()
102                            .build(),
103                    )
104                    .child(status)
105                    .build(),
106            )
107            .child(View::gap(1))
108            .child(
109                View::boxed()
110                    .scroll(true)
111                    .auto_scroll_bottom(true)
112                    .min_height(15)
113                    .max_height(15)
114                    .child(View::text(&log_text))
115                    .build(),
116            )
117            .child(View::gap(1))
118            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
119            .child(
120                View::modal()
121                    .visible(show_help.get())
122                    .title("Example 06: Log Viewer")
123                    .on_dismiss(with!(show_help => move || show_help.set(false)))
124                    .child(
125                        View::vstack()
126                            .child(View::styled_text("What you're seeing").bold().build())
127                            .child(View::text("• text_stream!() macro for accumulating text"))
128                            .child(View::text("• Auto-scrolling box that follows new content"))
129                            .child(View::text("• Live/End indicator based on stream state"))
130                            .child(View::gap(1))
131                            .child(View::styled_text("Key concepts").bold().build())
132                            .child(View::text("• text_stream! concatenates yielded strings"))
133                            .child(View::text(
134                                "• auto_scroll_bottom(true) keeps newest visible",
135                            ))
136                            .child(View::text("• Simulates tailing a log file"))
137                            .child(View::gap(1))
138                            .child(View::styled_text("Try this").bold().build())
139                            .child(View::text("• Watch the [LIVE] indicator change to [END]"))
140                            .child(View::text("• Notice auto-scroll keeps up with new entries"))
141                            .child(View::gap(1))
142                            .child(View::styled_text("Next up").bold().build())
143                            .child(View::text("→ 07_file_browser: real filesystem navigation"))
144                            .child(View::gap(1))
145                            .child(View::styled_text("Press Escape to close").dim().build())
146                            .build(),
147                    )
148                    .build(),
149            )
150            .build()
151    }
Source

pub fn focusable(self, focusable: bool) -> Self

Set whether this box participates in focus navigation. By default, scrollable boxes are focusable. Use focusable(false) to disable focus for a scrollable box (e.g., auto-scroll chat messages).

Source

pub fn min_width(self, width: u16) -> Self

Examples found in repository?
examples/03_theme_switcher.rs (line 112)
20    fn render(&self, cx: Scope) -> View {
21        let selected = state!(cx, || 0usize);
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        let theme_names = vec![
31            "Dark".to_string(),
32            "Light".to_string(),
33            "Nord".to_string(),
34            "Monokai".to_string(),
35            "Catppuccin Mocha".to_string(),
36            "Catppuccin Latte".to_string(),
37            "Dracula".to_string(),
38            "Gruvbox Dark".to_string(),
39            "Solarized Dark".to_string(),
40            "Rosé Pine".to_string(),
41            "Tokyo Night".to_string(),
42            "HaX0R Blue".to_string(),
43            "HaX0R Green".to_string(),
44            "HaX0R Red".to_string(),
45        ];
46
47        // Apply theme when selection changes
48        let on_select = with!(selected => move |idx: usize| {
49            selected.set(idx);
50            let theme = match idx {
51                0 => Theme::dark(),
52                1 => Theme::light(),
53                2 => Theme::nord(),
54                3 => Theme::monokai(),
55                4 => Theme::catppuccin_mocha(),
56                5 => Theme::catppuccin_latte(),
57                6 => Theme::dracula(),
58                7 => Theme::gruvbox_dark(),
59                8 => Theme::solarized_dark(),
60                9 => Theme::rose_pine(),
61                10 => Theme::tokyo_night(),
62                11 => Theme::hax0r_blue(),
63                12 => Theme::hax0r_green(),
64                _ => Theme::hax0r_red(),
65            };
66            set_theme(theme);
67        });
68
69        let theme = current_theme();
70        let true_color = supports_true_color();
71
72        let mut stack = View::vstack();
73
74        // Show warning if true color isn't supported
75        if !true_color {
76            let term = terminal_name().unwrap_or_else(|| "Unknown".to_string());
77            stack = stack
78                .child(
79                    View::styled_text(format!("Warning: {} doesn't support true color", term))
80                        .color(theme.warning)
81                        .bold()
82                        .build(),
83                )
84                .child(
85                    View::styled_text("Only 'Dark' and 'Light' themes will display correctly")
86                        .color(theme.muted)
87                        .build(),
88                )
89                .child(View::gap(1));
90        }
91
92        stack
93            .child(
94                View::styled_text("Theme Switcher")
95                    .color(theme.primary)
96                    .bold()
97                    .build(),
98            )
99            .child(
100                View::styled_text("Select a theme from the list")
101                    .color(theme.muted)
102                    .italic()
103                    .build(),
104            )
105            .child(View::gap(1))
106            .child(
107                View::hstack()
108                    .spacing(2)
109                    .child(
110                        View::boxed()
111                            .border(true)
112                            .min_width(25)
113                            .child(
114                                View::list()
115                                    .items(theme_names)
116                                    .selected(selected.get())
117                                    .on_select(on_select)
118                                    .build(),
119                            )
120                            .build(),
121                    )
122                    .child(
123                        View::boxed()
124                            .border(true)
125                            .padding(1)
126                            .child(
127                                View::vstack()
128                                    .child(View::styled_text("Preview").bold().build())
129                                    .child(View::gap(1))
130                                    .child(
131                                        View::hstack()
132                                            .child(
133                                                View::styled_text("Primary")
134                                                    .color(theme.primary)
135                                                    .build(),
136                                            )
137                                            .child(View::text("  "))
138                                            .child(
139                                                View::styled_text("Secondary")
140                                                    .color(theme.secondary)
141                                                    .build(),
142                                            )
143                                            .build(),
144                                    )
145                                    .child(
146                                        View::hstack()
147                                            .child(
148                                                View::styled_text("Muted")
149                                                    .color(theme.muted)
150                                                    .build(),
151                                            )
152                                            .child(View::text("  "))
153                                            .child(
154                                                View::styled_text("Success")
155                                                    .color(theme.success)
156                                                    .build(),
157                                            )
158                                            .build(),
159                                    )
160                                    .child(
161                                        View::hstack()
162                                            .child(
163                                                View::styled_text("Warning")
164                                                    .color(theme.warning)
165                                                    .build(),
166                                            )
167                                            .child(View::text("  "))
168                                            .child(
169                                                View::styled_text("Error")
170                                                    .color(theme.error)
171                                                    .build(),
172                                            )
173                                            .build(),
174                                    )
175                                    .build(),
176                            )
177                            .build(),
178                    )
179                    .build(),
180            )
181            .child(View::gap(1))
182            .child(
183                View::styled_text("↑/↓ select • F1 help • Ctrl+Q quit")
184                    .color(theme.muted)
185                    .build(),
186            )
187            .child(
188                View::modal()
189                    .visible(show_help.get())
190                    .title("Example 03: Theme Switcher")
191                    .on_dismiss(with!(show_help => move || show_help.set(false)))
192                    .child(
193                        View::vstack()
194                            .child(View::styled_text("What you're seeing").bold().build())
195                            .child(View::text("• Built-in theme system with 14 themes"))
196                            .child(View::text("• View::list() for selection UI"))
197                            .child(View::text("• Live preview as you navigate"))
198                            .child(View::gap(1))
199                            .child(View::styled_text("Key concepts").bold().build())
200                            .child(View::text("• current_theme() gets active theme colors"))
201                            .child(View::text("• set_theme() changes theme globally"))
202                            .child(View::text(
203                                "• Themes provide semantic colors (primary, error, etc.)",
204                            ))
205                            .child(View::gap(1))
206                            .child(View::styled_text("Try this").bold().build())
207                            .child(View::text(
208                                "• Navigate with ↑/↓ to see themes change instantly",
209                            ))
210                            .child(View::text(
211                                "• Notice the preview panel updates with theme colors",
212                            ))
213                            .child(View::gap(1))
214                            .child(View::styled_text("Next up").bold().build())
215                            .child(View::text("→ 04_timer: streaming data without interaction"))
216                            .child(View::gap(1))
217                            .child(View::styled_text("Press Escape to close").dim().build())
218                            .build(),
219                    )
220                    .build(),
221            )
222            .build()
223    }
Source

pub fn max_width(self, width: u16) -> Self

Examples found in repository?
examples/28_shared_state.rs (line 66)
29    fn render(&self, cx: Scope) -> View {
30        let show_help = state!(cx, || false);
31
32        // F1 toggles help
33        cx.use_command(
34            KeyBinding::key(KeyCode::F(1)),
35            with!(show_help => move || show_help.update(|v| *v = !*v)),
36        );
37
38        // Both panes will use the SAME key type = SAME state
39        // Note: using use_state_keyed directly with an explicit key type
40
41        // PANE A - gets the shared counter
42        let count_a = cx.use_state_keyed::<SharedCounterKey, _>(|| 0);
43        let inc_a = with!(count_a => move || count_a.update(|n| *n += 1));
44
45        // PANE B - uses the SAME key, so gets the SAME state!
46        let count_b = cx.use_state_keyed::<SharedCounterKey, _>(|| 0);
47        let inc_b = with!(count_b => move || count_b.update(|n| *n += 1));
48
49        View::vstack()
50            .spacing(1)
51            .child(
52                View::styled_text("Shared State Demo")
53                    .color(Color::Cyan)
54                    .bold()
55                    .build(),
56            )
57            .child(View::gap(1))
58            .child(
59                View::hstack()
60                    .spacing(2)
61                    // Pane A
62                    .child(
63                        View::boxed()
64                            .border(true)
65                            .padding(1)
66                            .max_width(25)
67                            .child(
68                                View::vstack()
69                                    .child(View::styled_text("Pane A").bold().build())
70                                    .child(View::gap(1))
71                                    .child(
72                                        View::hstack()
73                                            .spacing(1)
74                                            .child(View::text("Value:"))
75                                            .child(
76                                                View::styled_text(format!("{}", count_a.get()))
77                                                    .color(Color::Yellow)
78                                                    .bold()
79                                                    .build(),
80                                            )
81                                            .child(View::button().label("+").on_press(inc_a).build())
82                                            .build(),
83                                    )
84                                    .build(),
85                            )
86                            .build(),
87                    )
88                    // Pane B
89                    .child(
90                        View::boxed()
91                            .border(true)
92                            .padding(1)
93                            .max_width(25)
94                            .child(
95                                View::vstack()
96                                    .child(View::styled_text("Pane B").bold().build())
97                                    .child(View::gap(1))
98                                    .child(
99                                        View::hstack()
100                                            .spacing(1)
101                                            .child(View::text("Value:"))
102                                            .child(
103                                                View::styled_text(format!("{}", count_b.get()))
104                                                    .color(Color::Yellow)
105                                                    .bold()
106                                                    .build(),
107                                            )
108                                            .child(View::button().label("+").on_press(inc_b).build())
109                                            .build(),
110                                    )
111                                    .build(),
112                            )
113                            .build(),
114                    )
115                    .build(),
116            )
117            .child(View::gap(1))
118            .child(View::styled_text("Try this:").bold().build())
119            .child(View::text("  1. Click + on Pane A"))
120            .child(View::text("  2. Watch Pane B update too!"))
121            .child(View::text("  3. Click + on Pane B - same thing"))
122            .child(View::gap(1))
123            .child(
124                View::styled_text("Both panes share the SAME state.")
125                    .color(Color::Green)
126                    .build(),
127            )
128            .child(View::gap(1))
129            .child(
130                View::boxed()
131                    .border(true)
132                    .padding(1)
133                    .child(
134                        View::vstack()
135                            .child(View::styled_text("The code:").bold().build())
136                            .child(View::gap(1))
137                            .child(
138                                View::styled_text("struct SharedCounterKey;  // Named key type")
139                                    .color(Color::Green)
140                                    .build(),
141                            )
142                            .child(View::gap(1))
143                            .child(View::styled_text("// Pane A").color(Color::DarkGrey).build())
144                            .child(
145                                View::styled_text("let count_a = cx.use_state_keyed::<SharedCounterKey, _>(|| 0);")
146                                    .color(Color::Yellow)
147                                    .build(),
148                            )
149                            .child(View::gap(1))
150                            .child(View::styled_text("// Pane B - SAME key type!").color(Color::DarkGrey).build())
151                            .child(
152                                View::styled_text("let count_b = cx.use_state_keyed::<SharedCounterKey, _>(|| 0);")
153                                    .color(Color::Yellow)
154                                    .build(),
155                            )
156                            .child(View::gap(1))
157                            .child(View::text("Same key = same state. Both variables"))
158                            .child(View::text("point to the same underlying value."))
159                            .build(),
160                    )
161                    .build(),
162            )
163            .child(View::gap(1))
164            .child(
165                View::boxed()
166                    .border(true)
167                    .padding(1)
168                    .child(
169                        View::vstack()
170                            .child(View::styled_text("Compare with example 27:").bold().build())
171                            .child(View::gap(1))
172                            .child(View::styled_text("state!(cx, || 0)  // Anonymous key").color(Color::Magenta).build())
173                            .child(View::text("  Each call = unique key = independent state"))
174                            .child(View::gap(1))
175                            .child(View::styled_text("cx.use_state_keyed::<MyKey, _>(|| 0)  // Named key").color(Color::Yellow).build())
176                            .child(View::text("  Same key = same state = shared everywhere"))
177                            .build(),
178                    )
179                    .build(),
180            )
181            .child(View::gap(1))
182            .child(View::styled_text("Tab: navigate | F1 help | Ctrl+Q: quit").dim().build())
183            .child(
184                View::modal()
185                    .visible(show_help.get())
186                    .title("Example 28: Shared State")
187                    .on_dismiss(with!(show_help => move || show_help.set(false)))
188                    .child(
189                        View::vstack()
190                            .child(View::styled_text("What you're seeing").bold().build())
191                            .child(View::text("• Two panes sharing ONE counter"))
192                            .child(View::text("• Both + buttons increment same value"))
193                            .child(View::text("• Named key type = shared state"))
194                            .child(View::gap(1))
195                            .child(View::styled_text("Key concepts").bold().build())
196                            .child(View::text("• struct SharedCounterKey; defines key"))
197                            .child(View::text("• use_state_keyed::<Key, _>() uses it"))
198                            .child(View::text("• Same key = same underlying value"))
199                            .child(View::text("• Opposite of state! (unique keys)"))
200                            .child(View::gap(1))
201                            .child(View::styled_text("Try this").bold().build())
202                            .child(View::text("• Click + on Pane A"))
203                            .child(View::text("• Watch Pane B update too!"))
204                            .child(View::text("• Both buttons modify same state"))
205                            .child(View::gap(1))
206                            .child(View::styled_text("Next up").bold().build())
207                            .child(View::text("→ 29_canvas: pixel graphics"))
208                            .child(View::gap(1))
209                            .child(View::styled_text("Press Escape to close").dim().build())
210                            .build()
211                    )
212                    .build()
213            )
214            .build()
215    }
More examples
Hide additional examples
examples/27_keyed_state.rs (line 113)
42    fn render(&self, cx: Scope) -> View {
43        let show_help = state!(cx, || false);
44
45        // F1 toggles help
46        cx.use_command(
47            KeyBinding::key(KeyCode::F(1)),
48            with!(show_help => move || show_help.update(|v| *v = !*v)),
49        );
50
51        // Two independent toggles
52        let show_a = state!(cx, || true);
53        let show_b = state!(cx, || true);
54
55        // COUNTER A - state created inside conditional
56        let counter_a = if show_a.get() {
57            let count = state!(cx, || 0);
58            let inc = with!(count => move || count.update(|n| *n += 1));
59
60            View::hstack()
61                .spacing(1)
62                .child(
63                    View::styled_text(format!("{}", count.get()))
64                        .color(Color::Yellow)
65                        .bold()
66                        .build(),
67                )
68                .child(View::button().label("+").on_press(inc).build())
69                .build()
70        } else {
71            View::styled_text("--").dim().build()
72        };
73
74        // COUNTER B - state created inside a DIFFERENT conditional
75        let counter_b = if show_b.get() {
76            let count = state!(cx, || 0);
77            let inc = with!(count => move || count.update(|n| *n += 1));
78
79            View::hstack()
80                .spacing(1)
81                .child(
82                    View::styled_text(format!("{}", count.get()))
83                        .color(Color::Magenta)
84                        .bold()
85                        .build(),
86                )
87                .child(View::button().label("+").on_press(inc).build())
88                .build()
89        } else {
90            View::styled_text("--").dim().build()
91        };
92
93        let toggle_a = with!(show_a => move |_: bool| show_a.update(|b| *b = !*b));
94        let toggle_b = with!(show_b => move |_: bool| show_b.update(|b| *b = !*b));
95
96        View::vstack()
97            .spacing(1)
98            .child(
99                View::styled_text("state! Demo")
100                    .color(Color::Cyan)
101                    .bold()
102                    .build(),
103            )
104            .child(View::gap(1))
105            .child(
106                View::hstack()
107                    .spacing(2)
108                    // Counter A box
109                    .child(
110                        View::boxed()
111                            .border(true)
112                            .padding(1)
113                            .max_width(25)
114                            .child(
115                                View::vstack()
116                                    .child(View::styled_text("Counter A").bold().build())
117                                    .child(View::gap(1))
118                                    .child(
119                                        View::hstack()
120                                            .spacing(1)
121                                            .child(View::text("Value:"))
122                                            .child(counter_a)
123                                            .build(),
124                                    )
125                                    .child(
126                                        View::hstack()
127                                            .spacing(1)
128                                            .child(View::text("Show:"))
129                                            .child(
130                                                View::checkbox()
131                                                    .checked(show_a.get())
132                                                    .on_toggle(toggle_a)
133                                                    .build(),
134                                            )
135                                            .build(),
136                                    )
137                                    .build(),
138                            )
139                            .build(),
140                    )
141                    // Counter B box
142                    .child(
143                        View::boxed()
144                            .border(true)
145                            .padding(1)
146                            .max_width(25)
147                            .child(
148                                View::vstack()
149                                    .child(View::styled_text("Counter B").bold().build())
150                                    .child(View::gap(1))
151                                    .child(
152                                        View::hstack()
153                                            .spacing(1)
154                                            .child(View::text("Value:"))
155                                            .child(counter_b)
156                                            .build(),
157                                    )
158                                    .child(
159                                        View::hstack()
160                                            .spacing(1)
161                                            .child(View::text("Show:"))
162                                            .child(
163                                                View::checkbox()
164                                                    .checked(show_b.get())
165                                                    .on_toggle(toggle_b)
166                                                    .build(),
167                                            )
168                                            .build(),
169                                    )
170                                    .build(),
171                            )
172                            .build(),
173                    )
174                    .build(),
175            )
176            .child(View::gap(1))
177            .child(View::styled_text("Try this:").bold().build())
178            .child(View::text(
179                "  1. Increment both counters to different values",
180            ))
181            .child(View::text("  2. Hide counter A (uncheck its box)"))
182            .child(View::text("  3. Counter B continues to work just fine!"))
183            .child(View::text("  4. Show A again - it remembers its value"))
184            .child(View::gap(1))
185            .child(
186                View::styled_text("They don't interfere with each other.")
187                    .color(Color::Green)
188                    .build(),
189            )
190            .child(View::gap(1))
191            .child(
192                View::boxed()
193                    .border(true)
194                    .padding(1)
195                    .child(
196                        View::vstack()
197                            .child(View::styled_text("The code:").bold().build())
198                            .child(View::gap(1))
199                            .child(
200                                View::styled_text("if show_a.get() {")
201                                    .color(Color::DarkGrey)
202                                    .build(),
203                            )
204                            .child(
205                                View::styled_text("    let count = state!(cx, || 0);")
206                                    .color(Color::Yellow)
207                                    .build(),
208                            )
209                            .child(View::styled_text("}").color(Color::DarkGrey).build())
210                            .child(
211                                View::styled_text("if show_b.get() {")
212                                    .color(Color::DarkGrey)
213                                    .build(),
214                            )
215                            .child(
216                                View::styled_text("    let count = state!(cx, || 0);")
217                                    .color(Color::Magenta)
218                                    .build(),
219                            )
220                            .child(View::styled_text("}").color(Color::DarkGrey).build())
221                            .child(View::gap(1))
222                            .child(View::text("With use_state, hiding A would CRASH B"))
223                            .child(View::text("(hook indices would shift)."))
224                            .build(),
225                    )
226                    .build(),
227            )
228            .child(View::gap(1))
229            .child(
230                View::styled_text("Tab: navigate | F1 help | Ctrl+Q: quit")
231                    .dim()
232                    .build(),
233            )
234            .child(
235                View::modal()
236                    .visible(show_help.get())
237                    .title("Example 27: Keyed State")
238                    .on_dismiss(with!(show_help => move || show_help.set(false)))
239                    .child(
240                        View::vstack()
241                            .child(View::styled_text("What you're seeing").bold().build())
242                            .child(View::text("• state! macro for order-independent hooks"))
243                            .child(View::text("• Conditional state that doesn't crash"))
244                            .child(View::text("• Two counters with hide/show toggles"))
245                            .child(View::gap(1))
246                            .child(View::styled_text("Key concepts").bold().build())
247                            .child(View::text("• state!(cx, || init) creates keyed state"))
248                            .child(View::text("• Each call site gets unique key"))
249                            .child(View::text("• Safe to use inside if blocks"))
250                            .child(View::text("• Values persist when hidden/shown"))
251                            .child(View::gap(1))
252                            .child(View::styled_text("Try this").bold().build())
253                            .child(View::text("• Increment both counters"))
254                            .child(View::text("• Hide counter A"))
255                            .child(View::text("• Counter B still works!"))
256                            .child(View::text("• Show A again - value preserved"))
257                            .child(View::gap(1))
258                            .child(View::styled_text("Next up").bold().build())
259                            .child(View::text("→ 28_shared_state: shared state via keys"))
260                            .child(View::gap(1))
261                            .child(View::styled_text("Press Escape to close").dim().build())
262                            .build(),
263                    )
264                    .build(),
265            )
266            .build()
267    }
Source

pub fn min_height(self, height: u16) -> Self

Examples found in repository?
examples/06_log_viewer.rs (line 112)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Stream log entries
31        let logs = text_stream!(cx, || {
32            let log_messages = vec![
33                "[INFO]  Application started",
34                "[INFO]  Loading configuration...",
35                "[OK]    Config loaded successfully",
36                "[INFO]  Connecting to database...",
37                "[OK]    Database connected",
38                "[INFO]  Starting web server on :8080",
39                "[OK]    Server listening",
40                "[INFO]  Processing request GET /api/users",
41                "[OK]    Response 200 in 45ms",
42                "[INFO]  Processing request POST /api/login",
43                "[OK]    Response 200 in 120ms",
44                "[WARN]  High memory usage detected: 85%",
45                "[INFO]  Running garbage collection...",
46                "[OK]    Memory freed: 200MB",
47                "[INFO]  Processing request GET /api/data",
48                "[ERROR] Database timeout after 5000ms",
49                "[INFO]  Retrying database connection...",
50                "[OK]    Database reconnected",
51                "[OK]    Response 200 in 5045ms",
52                "[INFO]  Scheduled backup starting...",
53                "[OK]    Backup completed: 1.2GB",
54                "[INFO]  Processing request GET /api/health",
55                "[OK]    Response 200 in 12ms",
56                "[INFO]  Processing request PUT /api/users/123",
57                "[OK]    Response 200 in 89ms",
58                "[INFO]  Cache invalidation triggered",
59                "[OK]    Cache cleared: 50MB",
60                "[WARN]  Slow query detected: 1200ms",
61                "[INFO]  Query optimization suggested",
62                "[INFO]  Processing request DELETE /api/sessions",
63                "[OK]    Response 204 in 34ms",
64                "[INFO]  SSL certificate check",
65                "[OK]    Certificate valid for 45 days",
66                "[INFO]  Processing request POST /api/upload",
67                "[OK]    File uploaded: 15MB",
68                "[WARN]  Disk usage at 78%",
69                "[INFO]  Processing request GET /api/reports",
70                "[OK]    Response 200 in 230ms",
71                "[INFO]  Metrics exported to monitoring",
72                "[OK]    Heartbeat sent successfully",
73                "------- Log stream completed -------",
74            ];
75
76            log_messages.into_iter().map(|msg| {
77                std::thread::sleep(Duration::from_millis(500));
78                format!("{}\n", msg)
79            })
80        });
81
82        let log_text = logs.get();
83        let is_streaming = logs.is_loading();
84
85        // Color the status indicator
86        let status = if is_streaming {
87            View::styled_text(" [LIVE]")
88                .color(Color::Green)
89                .bold()
90                .build()
91        } else {
92            View::styled_text(" [END]").dim().build()
93        };
94
95        View::vstack()
96            .child(
97                View::hstack()
98                    .child(
99                        View::styled_text("Log Viewer")
100                            .color(Color::Cyan)
101                            .bold()
102                            .build(),
103                    )
104                    .child(status)
105                    .build(),
106            )
107            .child(View::gap(1))
108            .child(
109                View::boxed()
110                    .scroll(true)
111                    .auto_scroll_bottom(true)
112                    .min_height(15)
113                    .max_height(15)
114                    .child(View::text(&log_text))
115                    .build(),
116            )
117            .child(View::gap(1))
118            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
119            .child(
120                View::modal()
121                    .visible(show_help.get())
122                    .title("Example 06: Log Viewer")
123                    .on_dismiss(with!(show_help => move || show_help.set(false)))
124                    .child(
125                        View::vstack()
126                            .child(View::styled_text("What you're seeing").bold().build())
127                            .child(View::text("• text_stream!() macro for accumulating text"))
128                            .child(View::text("• Auto-scrolling box that follows new content"))
129                            .child(View::text("• Live/End indicator based on stream state"))
130                            .child(View::gap(1))
131                            .child(View::styled_text("Key concepts").bold().build())
132                            .child(View::text("• text_stream! concatenates yielded strings"))
133                            .child(View::text(
134                                "• auto_scroll_bottom(true) keeps newest visible",
135                            ))
136                            .child(View::text("• Simulates tailing a log file"))
137                            .child(View::gap(1))
138                            .child(View::styled_text("Try this").bold().build())
139                            .child(View::text("• Watch the [LIVE] indicator change to [END]"))
140                            .child(View::text("• Notice auto-scroll keeps up with new entries"))
141                            .child(View::gap(1))
142                            .child(View::styled_text("Next up").bold().build())
143                            .child(View::text("→ 07_file_browser: real filesystem navigation"))
144                            .child(View::gap(1))
145                            .child(View::styled_text("Press Escape to close").dim().build())
146                            .build(),
147                    )
148                    .build(),
149            )
150            .build()
151    }
Source

pub fn max_height(self, height: u16) -> Self

Examples found in repository?
examples/06_log_viewer.rs (line 113)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Stream log entries
31        let logs = text_stream!(cx, || {
32            let log_messages = vec![
33                "[INFO]  Application started",
34                "[INFO]  Loading configuration...",
35                "[OK]    Config loaded successfully",
36                "[INFO]  Connecting to database...",
37                "[OK]    Database connected",
38                "[INFO]  Starting web server on :8080",
39                "[OK]    Server listening",
40                "[INFO]  Processing request GET /api/users",
41                "[OK]    Response 200 in 45ms",
42                "[INFO]  Processing request POST /api/login",
43                "[OK]    Response 200 in 120ms",
44                "[WARN]  High memory usage detected: 85%",
45                "[INFO]  Running garbage collection...",
46                "[OK]    Memory freed: 200MB",
47                "[INFO]  Processing request GET /api/data",
48                "[ERROR] Database timeout after 5000ms",
49                "[INFO]  Retrying database connection...",
50                "[OK]    Database reconnected",
51                "[OK]    Response 200 in 5045ms",
52                "[INFO]  Scheduled backup starting...",
53                "[OK]    Backup completed: 1.2GB",
54                "[INFO]  Processing request GET /api/health",
55                "[OK]    Response 200 in 12ms",
56                "[INFO]  Processing request PUT /api/users/123",
57                "[OK]    Response 200 in 89ms",
58                "[INFO]  Cache invalidation triggered",
59                "[OK]    Cache cleared: 50MB",
60                "[WARN]  Slow query detected: 1200ms",
61                "[INFO]  Query optimization suggested",
62                "[INFO]  Processing request DELETE /api/sessions",
63                "[OK]    Response 204 in 34ms",
64                "[INFO]  SSL certificate check",
65                "[OK]    Certificate valid for 45 days",
66                "[INFO]  Processing request POST /api/upload",
67                "[OK]    File uploaded: 15MB",
68                "[WARN]  Disk usage at 78%",
69                "[INFO]  Processing request GET /api/reports",
70                "[OK]    Response 200 in 230ms",
71                "[INFO]  Metrics exported to monitoring",
72                "[OK]    Heartbeat sent successfully",
73                "------- Log stream completed -------",
74            ];
75
76            log_messages.into_iter().map(|msg| {
77                std::thread::sleep(Duration::from_millis(500));
78                format!("{}\n", msg)
79            })
80        });
81
82        let log_text = logs.get();
83        let is_streaming = logs.is_loading();
84
85        // Color the status indicator
86        let status = if is_streaming {
87            View::styled_text(" [LIVE]")
88                .color(Color::Green)
89                .bold()
90                .build()
91        } else {
92            View::styled_text(" [END]").dim().build()
93        };
94
95        View::vstack()
96            .child(
97                View::hstack()
98                    .child(
99                        View::styled_text("Log Viewer")
100                            .color(Color::Cyan)
101                            .bold()
102                            .build(),
103                    )
104                    .child(status)
105                    .build(),
106            )
107            .child(View::gap(1))
108            .child(
109                View::boxed()
110                    .scroll(true)
111                    .auto_scroll_bottom(true)
112                    .min_height(15)
113                    .max_height(15)
114                    .child(View::text(&log_text))
115                    .build(),
116            )
117            .child(View::gap(1))
118            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
119            .child(
120                View::modal()
121                    .visible(show_help.get())
122                    .title("Example 06: Log Viewer")
123                    .on_dismiss(with!(show_help => move || show_help.set(false)))
124                    .child(
125                        View::vstack()
126                            .child(View::styled_text("What you're seeing").bold().build())
127                            .child(View::text("• text_stream!() macro for accumulating text"))
128                            .child(View::text("• Auto-scrolling box that follows new content"))
129                            .child(View::text("• Live/End indicator based on stream state"))
130                            .child(View::gap(1))
131                            .child(View::styled_text("Key concepts").bold().build())
132                            .child(View::text("• text_stream! concatenates yielded strings"))
133                            .child(View::text(
134                                "• auto_scroll_bottom(true) keeps newest visible",
135                            ))
136                            .child(View::text("• Simulates tailing a log file"))
137                            .child(View::gap(1))
138                            .child(View::styled_text("Try this").bold().build())
139                            .child(View::text("• Watch the [LIVE] indicator change to [END]"))
140                            .child(View::text("• Notice auto-scroll keeps up with new entries"))
141                            .child(View::gap(1))
142                            .child(View::styled_text("Next up").bold().build())
143                            .child(View::text("→ 07_file_browser: real filesystem navigation"))
144                            .child(View::gap(1))
145                            .child(View::styled_text("Press Escape to close").dim().build())
146                            .build(),
147                    )
148                    .build(),
149            )
150            .build()
151    }
Source

pub fn build(self) -> View

Examples found in repository?
examples/09_syntax_comparison.rs (line 77)
24    fn render(&self, cx: Scope) -> View {
25        let use_jsx = state!(cx, || false);
26        let show_help = state!(cx, || false);
27
28        // F1 toggles help
29        cx.use_command(
30            KeyBinding::key(KeyCode::F(1)),
31            with!(show_help => move || show_help.update(|v| *v = !*v)),
32        );
33
34        let toggle = with!(use_jsx => move || use_jsx.set(!use_jsx.get()));
35
36        // Show which syntax is currently displayed
37        let syntax_name = if use_jsx.get() {
38            "view! macro (JSX-like)"
39        } else {
40            "Builder pattern"
41        };
42
43        View::vstack()
44            .child(
45                View::styled_text("Syntax Comparison")
46                    .color(Color::Cyan)
47                    .bold()
48                    .build(),
49            )
50            .child(
51                View::styled_text("Same UI, two ways to write it")
52                    .dim()
53                    .build(),
54            )
55            .child(View::gap(1))
56            .child(
57                View::hstack()
58                    .child(View::text("Current syntax: "))
59                    .child(
60                        View::styled_text(syntax_name)
61                            .color(Color::Yellow)
62                            .bold()
63                            .build(),
64                    )
65                    .build(),
66            )
67            .child(View::gap(1))
68            .child(
69                View::boxed()
70                    .border(true)
71                    .padding(1)
72                    .child(if use_jsx.get() {
73                        counter_jsx(cx.clone())
74                    } else {
75                        counter_builder(cx.clone())
76                    })
77                    .build(),
78            )
79            .child(View::gap(1))
80            .child(
81                View::button()
82                    .label("Toggle Syntax")
83                    .on_press(toggle)
84                    .build(),
85            )
86            .child(View::gap(1))
87            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
88            .child(
89                View::modal()
90                    .visible(show_help.get())
91                    .title("Example 09: Syntax Comparison")
92                    .on_dismiss(with!(show_help => move || show_help.set(false)))
93                    .child(
94                        View::vstack()
95                            .child(View::styled_text("What you're seeing").bold().build())
96                            .child(View::text("• Two syntaxes that produce identical output"))
97                            .child(View::text("• Builder: View::vstack().child(...).build()"))
98                            .child(View::text("• Macro: view! { <VStack>...</VStack> }"))
99                            .child(View::gap(1))
100                            .child(View::styled_text("Key concepts").bold().build())
101                            .child(View::text("• Builder is Rust-native, IDE-friendly"))
102                            .child(View::text("• view! macro is JSX-like, less boilerplate"))
103                            .child(View::text("• Choose based on your preference"))
104                            .child(View::gap(1))
105                            .child(View::styled_text("Try this").bold().build())
106                            .child(View::text("• Toggle between syntaxes"))
107                            .child(View::text("• Notice the output is identical"))
108                            .child(View::text("• Check the source code to see both styles"))
109                            .child(View::gap(1))
110                            .child(View::styled_text("Next up").bold().build())
111                            .child(View::text("→ 10_state_explained: deep dive into state"))
112                            .child(View::gap(1))
113                            .child(View::styled_text("Press Escape to close").dim().build())
114                            .build(),
115                    )
116                    .build(),
117            )
118            .build()
119    }
More examples
Hide additional examples
examples/15_markdown.rs (line 88)
54    fn render(&self, cx: Scope) -> View {
55        let show_help = state!(cx, || false);
56
57        // F1 toggles help
58        cx.use_command(
59            KeyBinding::key(KeyCode::F(1)),
60            with!(show_help => move || show_help.update(|v| *v = !*v)),
61        );
62
63        let rendered = telex::markdown::render(DEMO_MARKDOWN);
64
65        View::vstack()
66            .child(
67                View::styled_text("Markdown Rendering Demo")
68                    .color(Color::Cyan)
69                    .bold()
70                    .build(),
71            )
72            .child(
73                View::boxed()
74                    .flex(1)
75                    .child(
76                        View::split()
77                            .horizontal()
78                            .ratio(0.4)
79                            .first(
80                                View::vstack()
81                                    .child(View::styled_text(" Source ").bold().build())
82                                    .child(
83                                        View::boxed()
84                                            .flex(1)
85                                            .border(true)
86                                            .scroll(true)
87                                            .child(View::text(DEMO_MARKDOWN))
88                                            .build(),
89                                    )
90                                    .build(),
91                            )
92                            .second(
93                                View::vstack()
94                                    .child(View::styled_text(" Rendered ").bold().build())
95                                    .child(
96                                        View::boxed()
97                                            .flex(1)
98                                            .border(true)
99                                            .scroll(true)
100                                            .child(rendered)
101                                            .build(),
102                                    )
103                                    .build(),
104                            )
105                            .build(),
106                    )
107                    .build(),
108            )
109            .child(
110                View::styled_text("Tab: switch panes | ↑↓/jk: scroll | F1 help | Ctrl+Q: quit")
111                    .dim()
112                    .build(),
113            )
114            .child(
115                View::modal()
116                    .visible(show_help.get())
117                    .title("Example 15: Markdown")
118                    .on_dismiss(with!(show_help => move || show_help.set(false)))
119                    .child(
120                        View::vstack()
121                            .child(View::styled_text("What you're seeing").bold().build())
122                            .child(View::text("• Side-by-side markdown source and rendered"))
123                            .child(View::text("• Full markdown syntax support"))
124                            .child(View::text("• Scrollable panes for long content"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Key concepts").bold().build())
127                            .child(View::text("• telex::markdown::render() parses markdown"))
128                            .child(View::text("• Returns a View tree with styled text"))
129                            .child(View::text("• Code blocks, lists, quotes, headers"))
130                            .child(View::text("• Split view for comparison"))
131                            .child(View::gap(1))
132                            .child(View::styled_text("Try this").bold().build())
133                            .child(View::text("• Tab between source and rendered panes"))
134                            .child(View::text("• Scroll with arrow keys or j/k"))
135                            .child(View::text("• Compare source with rendered output"))
136                            .child(View::gap(1))
137                            .child(View::styled_text("Next up").bold().build())
138                            .child(View::text("→ 16_progress: progress bars"))
139                            .child(View::gap(1))
140                            .child(View::styled_text("Press Escape to close").dim().build())
141                            .build(),
142                    )
143                    .build(),
144            )
145            .build()
146    }
examples/16_tree.rs (line 88)
20    fn render(&self, cx: Scope) -> View {
21        let show_help = state!(cx, || false);
22
23        // F1 toggles help
24        cx.use_command(
25            KeyBinding::key(KeyCode::F(1)),
26            with!(show_help => move || show_help.update(|v| *v = !*v)),
27        );
28
29        // Track selected path
30        let selected = state!(cx, || vec![0usize]);
31
32        // Track expanded state for each node (by path prefix)
33        let expanded_paths = state!(cx, || {
34            vec![
35                vec![0],    // src/ expanded
36                vec![0, 0], // src/components/ expanded
37            ]
38        });
39
40        // Build tree items with current expanded state
41        let items = build_tree(&expanded_paths.get());
42
43        let on_select = with!(selected => move |path: TreePath| {
44            selected.set(path);
45        });
46
47        let on_activate = with!(expanded_paths => move |path: TreePath| {
48            // Toggle expand/collapse for the activated item
49            let mut paths = expanded_paths.get().clone();
50            if let Some(pos) = paths.iter().position(|p| *p == path) {
51                // Currently expanded, collapse it
52                paths.remove(pos);
53            } else {
54                // Currently collapsed, expand it
55                paths.push(path.clone());
56            }
57            expanded_paths.set(paths);
58        });
59
60        let selected_label = get_item_at_path(&items, &selected.get())
61            .map(|item| item.label.clone())
62            .unwrap_or_else(|| "Nothing".to_string());
63
64        View::vstack()
65            .child(
66                View::styled_text("File Browser")
67                    .color(Color::Cyan)
68                    .bold()
69                    .build(),
70            )
71            .child(
72                View::styled_text(format!("Selected: {}", selected_label))
73                    .dim()
74                    .build(),
75            )
76            .child(
77                View::boxed()
78                    .flex(1)
79                    .border(true)
80                    .child(
81                        View::tree()
82                            .items(items)
83                            .selected(selected.get().clone())
84                            .on_select(on_select)
85                            .on_activate(on_activate)
86                            .build(),
87                    )
88                    .build(),
89            )
90            .child(
91                View::styled_text(
92                    "↑↓/jk: navigate | Enter: expand/collapse | F1 help | Ctrl+Q: quit",
93                )
94                .dim()
95                .build(),
96            )
97            .child(
98                View::modal()
99                    .visible(show_help.get())
100                    .title("Example 16: Tree View")
101                    .on_dismiss(with!(show_help => move || show_help.set(false)))
102                    .child(
103                        View::vstack()
104                            .child(View::styled_text("What you're seeing").bold().build())
105                            .child(View::text("• Hierarchical tree widget"))
106                            .child(View::text("• Expand/collapse folders"))
107                            .child(View::text("• Path-based selection tracking"))
108                            .child(View::gap(1))
109                            .child(View::styled_text("Key concepts").bold().build())
110                            .child(View::text("• View::tree() for hierarchical data"))
111                            .child(View::text("• TreeItem::new().child() builds hierarchy"))
112                            .child(View::text("• on_select returns TreePath (Vec<usize>)"))
113                            .child(View::text("• on_activate for expand/collapse"))
114                            .child(View::gap(1))
115                            .child(View::styled_text("Try this").bold().build())
116                            .child(View::text("• Navigate with arrow keys"))
117                            .child(View::text("• Press Enter to expand/collapse folders"))
118                            .child(View::text("• Watch the 'Selected:' text update"))
119                            .child(View::gap(1))
120                            .child(View::styled_text("Next up").bold().build())
121                            .child(View::text("→ 17_table: data tables with sorting"))
122                            .child(View::gap(1))
123                            .child(View::styled_text("Press Escape to close").dim().build())
124                            .build(),
125                    )
126                    .build(),
127            )
128            .build()
129    }
examples/10_state_explained.rs (line 81)
21    fn render(&self, cx: Scope) -> View {
22        let count = state!(cx, || 0i32);
23        let show_help = state!(cx, || false);
24
25        // F1 toggles help
26        cx.use_command(
27            KeyBinding::key(KeyCode::F(1)),
28            with!(show_help => move || show_help.update(|v| *v = !*v)),
29        );
30
31        // Clone handles for closures (this is the pattern being explained)
32        let count_for_increment = count.clone();
33        let count_for_decrement = count.clone();
34        let count_for_reset = count.clone();
35
36        let increment = move || {
37            let current = count_for_increment.get();
38            count_for_increment.set(current + 1);
39        };
40
41        let decrement = move || {
42            let current = count_for_decrement.get();
43            count_for_decrement.set(current - 1);
44        };
45
46        let reset = move || {
47            count_for_reset.set(0);
48        };
49
50        let current_value = count.get();
51
52        // Hook ordering demo
53        let _always_called_1 = state!(cx, || "hook 1");
54        let _always_called_2 = state!(cx, || "hook 2");
55
56        View::vstack()
57            .spacing(1)
58            .child(
59                View::styled_text("State Explained")
60                    .color(Color::Cyan)
61                    .bold()
62                    .build(),
63            )
64            .child(
65                View::boxed()
66                    .border(true)
67                    .padding(1)
68                    .child(
69                        View::vstack()
70                            .child(View::styled_text("The Mental Model:").bold().build())
71                            .child(View::gap(1))
72                            .child(View::text("  State<T> is a HANDLE, not data"))
73                            .child(View::text("  clone() copies the handle, not the data"))
74                            .child(View::text("  All handles point to ONE value"))
75                            .child(View::gap(1))
76                            .child(View::text("  count ──────┐"))
77                            .child(View::text("              ├──► i32: 0  (shared!)"))
78                            .child(View::text("  count2 ─────┘"))
79                            .build(),
80                    )
81                    .build(),
82            )
83            .child(
84                View::hstack()
85                    .spacing(1)
86                    .child(View::text("Current value:"))
87                    .child(
88                        View::styled_text(format!("{}", current_value))
89                            .color(Color::Yellow)
90                            .bold()
91                            .build(),
92                    )
93                    .build(),
94            )
95            .child(
96                View::hstack()
97                    .spacing(1)
98                    .child(View::button().label(" - ").on_press(decrement).build())
99                    .child(View::button().label(" + ").on_press(increment).build())
100                    .child(View::button().label("Reset").on_press(reset).build())
101                    .build(),
102            )
103            .child(
104                View::styled_text("All three buttons modify the SAME underlying i32")
105                    .dim()
106                    .build(),
107            )
108            .child(View::gap(1))
109            .child(
110                View::styled_text("Tab navigate • F1 help • Ctrl+Q quit")
111                    .dim()
112                    .build(),
113            )
114            .child(
115                View::modal()
116                    .visible(show_help.get())
117                    .title("Example 10: State Explained")
118                    .on_dismiss(with!(show_help => move || show_help.set(false)))
119                    .child(
120                        View::vstack()
121                            .child(View::styled_text("What you're seeing").bold().build())
122                            .child(View::text("• State<T> as a handle/pointer concept"))
123                            .child(View::text("• Multiple closures sharing one value"))
124                            .child(View::text("• Visual diagram of the mental model"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Key concepts").bold().build())
127                            .child(View::text("• clone() copies handle, not data"))
128                            .child(View::text("• All handles point to same underlying value"))
129                            .child(View::text(
130                                "• Hooks must be called in same order every render",
131                            ))
132                            .child(View::gap(1))
133                            .child(View::styled_text("Important rule").bold().build())
134                            .child(View::text("• NEVER put use_state inside an if block"))
135                            .child(View::text("• Use with!() macro to simplify cloning"))
136                            .child(View::gap(1))
137                            .child(View::styled_text("Next up").bold().build())
138                            .child(View::text("→ 11_checkbox: toggle controls"))
139                            .child(View::gap(1))
140                            .child(View::styled_text("Press Escape to close").dim().build())
141                            .build(),
142                    )
143                    .build(),
144            )
145            .build()
146    }
examples/13_split_panes.rs (line 95)
20    fn render(&self, cx: Scope) -> View {
21        let show_help = state!(cx, || false);
22
23        // F1 toggles help
24        cx.use_command(
25            KeyBinding::key(KeyCode::F(1)),
26            with!(show_help => move || show_help.update(|v| *v = !*v)),
27        );
28
29        let selected_item = state!(cx, || 0usize);
30
31        let items = vec![
32            "README.md".to_string(),
33            "Cargo.toml".to_string(),
34            "src/".to_string(),
35            "src/main.rs".to_string(),
36            "src/lib.rs".to_string(),
37            "tests/".to_string(),
38        ];
39
40        let on_select = with!(selected_item => move |idx: usize| {
41            selected_item.set(idx);
42        });
43
44        let detail_text = match selected_item.get() {
45            0 => "# README\n\nThis is a demo of split panes.\n\nThe left panel shows a file list,\nthe right panel shows details.",
46            1 => "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
47            2 => "Directory: src/\n\nContains the main source files.",
48            3 => "fn main() {\n    println!(\"Hello, world!\");\n}",
49            4 => "pub mod utils;\npub mod widgets;",
50            5 => "Directory: tests/\n\nContains integration tests.",
51            _ => "Select an item to see details.",
52        };
53
54        // Horizontal split: file list on left, details on right
55        View::vstack()
56            .child(
57                View::boxed()
58                    .flex(1)
59                    .child(
60                        View::split()
61                            .horizontal()
62                            .ratio(0.3)
63                            .min_first(15)
64                            .first(
65                                View::vstack()
66                                    .child(
67                                        View::styled_text("Files")
68                                            .color(Color::Cyan)
69                                            .bold()
70                                            .build(),
71                                    )
72                                    .child(
73                                        View::list()
74                                            .items(items)
75                                            .selected(selected_item.get())
76                                            .on_select(on_select)
77                                            .build(),
78                                    )
79                                    .child(View::gap(1))
80                                    .build(),
81                            )
82                            .second(
83                                View::vstack()
84                                    .child(
85                                        View::styled_text("Details")
86                                            .color(Color::Green)
87                                            .bold()
88                                            .build(),
89                                    )
90                                    .child(
91                                        View::boxed()
92                                            .border(true)
93                                            .flex(1)
94                                            .child(View::text(detail_text))
95                                            .build(),
96                                    )
97                                    .build(),
98                            )
99                            .build(),
100                    )
101                    .build(),
102            )
103            .child(
104                View::styled_text("↑↓: select file | F1 help | Ctrl+Q: quit")
105                    .dim()
106                    .build(),
107            )
108            .child(
109                View::modal()
110                    .visible(show_help.get())
111                    .title("Example 13: Split Panes")
112                    .on_dismiss(with!(show_help => move || show_help.set(false)))
113                    .child(
114                        View::vstack()
115                            .child(View::styled_text("What you're seeing").bold().build())
116                            .child(View::text("• Horizontal split: file list / details"))
117                            .child(View::text("• ratio(0.3) = 30% left, 70% right"))
118                            .child(View::text("• min_first(15) sets minimum pane width"))
119                            .child(View::gap(1))
120                            .child(View::styled_text("Key concepts").bold().build())
121                            .child(View::text("• View::split() creates resizable panes"))
122                            .child(View::text("• .horizontal() or .vertical() orientation"))
123                            .child(View::text("• .first() and .second() set pane content"))
124                            .child(View::text("• Splits can be nested"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Try this").bold().build())
127                            .child(View::text("• Select different files to see details"))
128                            .child(View::text("• Resize terminal to see layout adapt"))
129                            .child(View::gap(1))
130                            .child(View::styled_text("Next up").bold().build())
131                            .child(View::text("→ 14_tabs: tabbed interfaces"))
132                            .child(View::gap(1))
133                            .child(View::styled_text("Press Escape to close").dim().build())
134                            .build(),
135                    )
136                    .build(),
137            )
138            .build()
139    }
examples/06_log_viewer.rs (line 115)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Stream log entries
31        let logs = text_stream!(cx, || {
32            let log_messages = vec![
33                "[INFO]  Application started",
34                "[INFO]  Loading configuration...",
35                "[OK]    Config loaded successfully",
36                "[INFO]  Connecting to database...",
37                "[OK]    Database connected",
38                "[INFO]  Starting web server on :8080",
39                "[OK]    Server listening",
40                "[INFO]  Processing request GET /api/users",
41                "[OK]    Response 200 in 45ms",
42                "[INFO]  Processing request POST /api/login",
43                "[OK]    Response 200 in 120ms",
44                "[WARN]  High memory usage detected: 85%",
45                "[INFO]  Running garbage collection...",
46                "[OK]    Memory freed: 200MB",
47                "[INFO]  Processing request GET /api/data",
48                "[ERROR] Database timeout after 5000ms",
49                "[INFO]  Retrying database connection...",
50                "[OK]    Database reconnected",
51                "[OK]    Response 200 in 5045ms",
52                "[INFO]  Scheduled backup starting...",
53                "[OK]    Backup completed: 1.2GB",
54                "[INFO]  Processing request GET /api/health",
55                "[OK]    Response 200 in 12ms",
56                "[INFO]  Processing request PUT /api/users/123",
57                "[OK]    Response 200 in 89ms",
58                "[INFO]  Cache invalidation triggered",
59                "[OK]    Cache cleared: 50MB",
60                "[WARN]  Slow query detected: 1200ms",
61                "[INFO]  Query optimization suggested",
62                "[INFO]  Processing request DELETE /api/sessions",
63                "[OK]    Response 204 in 34ms",
64                "[INFO]  SSL certificate check",
65                "[OK]    Certificate valid for 45 days",
66                "[INFO]  Processing request POST /api/upload",
67                "[OK]    File uploaded: 15MB",
68                "[WARN]  Disk usage at 78%",
69                "[INFO]  Processing request GET /api/reports",
70                "[OK]    Response 200 in 230ms",
71                "[INFO]  Metrics exported to monitoring",
72                "[OK]    Heartbeat sent successfully",
73                "------- Log stream completed -------",
74            ];
75
76            log_messages.into_iter().map(|msg| {
77                std::thread::sleep(Duration::from_millis(500));
78                format!("{}\n", msg)
79            })
80        });
81
82        let log_text = logs.get();
83        let is_streaming = logs.is_loading();
84
85        // Color the status indicator
86        let status = if is_streaming {
87            View::styled_text(" [LIVE]")
88                .color(Color::Green)
89                .bold()
90                .build()
91        } else {
92            View::styled_text(" [END]").dim().build()
93        };
94
95        View::vstack()
96            .child(
97                View::hstack()
98                    .child(
99                        View::styled_text("Log Viewer")
100                            .color(Color::Cyan)
101                            .bold()
102                            .build(),
103                    )
104                    .child(status)
105                    .build(),
106            )
107            .child(View::gap(1))
108            .child(
109                View::boxed()
110                    .scroll(true)
111                    .auto_scroll_bottom(true)
112                    .min_height(15)
113                    .max_height(15)
114                    .child(View::text(&log_text))
115                    .build(),
116            )
117            .child(View::gap(1))
118            .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
119            .child(
120                View::modal()
121                    .visible(show_help.get())
122                    .title("Example 06: Log Viewer")
123                    .on_dismiss(with!(show_help => move || show_help.set(false)))
124                    .child(
125                        View::vstack()
126                            .child(View::styled_text("What you're seeing").bold().build())
127                            .child(View::text("• text_stream!() macro for accumulating text"))
128                            .child(View::text("• Auto-scrolling box that follows new content"))
129                            .child(View::text("• Live/End indicator based on stream state"))
130                            .child(View::gap(1))
131                            .child(View::styled_text("Key concepts").bold().build())
132                            .child(View::text("• text_stream! concatenates yielded strings"))
133                            .child(View::text(
134                                "• auto_scroll_bottom(true) keeps newest visible",
135                            ))
136                            .child(View::text("• Simulates tailing a log file"))
137                            .child(View::gap(1))
138                            .child(View::styled_text("Try this").bold().build())
139                            .child(View::text("• Watch the [LIVE] indicator change to [END]"))
140                            .child(View::text("• Notice auto-scroll keeps up with new entries"))
141                            .child(View::gap(1))
142                            .child(View::styled_text("Next up").bold().build())
143                            .child(View::text("→ 07_file_browser: real filesystem navigation"))
144                            .child(View::gap(1))
145                            .child(View::styled_text("Press Escape to close").dim().build())
146                            .build(),
147                    )
148                    .build(),
149            )
150            .build()
151    }

Trait Implementations§

Source§

impl Default for BoxBuilder

Source§

fn default() -> BoxBuilder

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.