1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Tab bar — horizontal selector for switching between sibling views.
//!
//! Like [`crate::menu`] and [`crate::sidebar`], the tab bar is described
//! as plain data here and rendered by `snora-widgets::app_tab_bar`. The
//! engine never inspects these types directly; they exist so that
//! applications and widget engines speak the same shape.
//!
//! # Choosing between tabs and a sidebar
//!
//! Both let users switch among sibling views, but they imply different
//! information density and depth:
//!
//! * **Tabs** — flat, horizontal, label-first. Three to seven peer views
//! that the user expects to switch among frequently. Sits below the
//! header.
//! * **Sidebar** ([`crate::SideBar`]) — vertical, icon-first, scales to
//! more entries. Use when the navigation is the primary structural
//! element of the app.
//!
//! Use both at once when tabs subdivide a sidebar-selected workspace.
use crateIcon;
/// One tab in a [`TabBar`]. Carries an application-defined `TabId` so
/// that the application is the source of truth for which tab is which.
///
/// # Example
///
/// ```
/// use snora_core::Tab;
///
/// #[derive(Clone, PartialEq, Eq, Debug)]
/// enum WorkspaceTab { Library, Editor, Settings }
///
/// let editor = Tab {
/// id: WorkspaceTab::Editor,
/// label: "Editor".into(),
/// icon: None,
/// };
/// assert_eq!(editor.label, "Editor");
/// assert_eq!(editor.id, WorkspaceTab::Editor);
/// ```
/// A horizontal tab strip.
///
/// `TabBar` is generic over `TabId` so that applications can use any
/// `Clone + PartialEq` type — typically a small enum.
///
/// # Example
///
/// ```
/// use snora_core::{Tab, TabBar};
///
/// #[derive(Clone, PartialEq, Eq, Debug)]
/// enum WorkspaceTab { Library, Editor }
///
/// let bar = TabBar {
/// tabs: vec![
/// Tab { id: WorkspaceTab::Library, label: "Library".into(), icon: None },
/// Tab { id: WorkspaceTab::Editor, label: "Editor".into(), icon: None },
/// ],
/// active: WorkspaceTab::Library,
/// };
/// assert_eq!(bar.tabs.len(), 2);
/// assert_eq!(bar.active, WorkspaceTab::Library);
/// ```
/// What happens when the user interacts with a tab.
///
/// Tab bars only emit one kind of event — a tab being pressed. We
/// still wrap it in an enum (rather than a bare `TabId`) so that
/// future extensions (close button on a tab, drag-to-reorder) can be
/// added without breaking the existing handler shape.
///
/// # Example
///
/// ```
/// use snora_core::TabAction;
///
/// #[derive(Clone, Debug, PartialEq, Eq)]
/// enum WorkspaceTab { Library, Editor }
///
/// // Application code typically maps `TabAction` into its own message
/// // enum; here we just match on it directly.
/// let received: TabAction<WorkspaceTab> = TabAction::Pressed(WorkspaceTab::Editor);
/// match received {
/// TabAction::Pressed(id) => assert_eq!(id, WorkspaceTab::Editor),
/// }
/// ```