Skip to main content

swiftui_native/view/
navigation.rs

1//! Navigation, toolbars, sheets and search — an app's shell.
2//!
3//! Part of [`crate::view::View`]'s chainable API; Rust allows a type's
4//! inherent methods to be split across modules, and 400 of them in one file
5//! was a file nobody could find anything in.
6
7use super::View;
8use crate::views;
9
10impl View {
11    // ── Navigation ──
12
13    /// `.navigationDestination(isPresented:destination:)` bound to Rust state —
14    /// pushing sets it, and the back button writes `false` back.
15    pub fn navigation_destination(
16        self,
17        state: &views::BoundState<bool>,
18        destination: View,
19    ) -> Self {
20        Self::new(views::navigation_destination(
21            &self.handle,
22            state,
23            destination.handle(),
24        ))
25    }
26
27    /// `.inspector(isPresented:content:)` bound to Rust state.
28    pub fn inspector(self, state: &views::BoundState<bool>, content: View) -> Self {
29        Self::new(views::inspector(&self.handle, state, content.handle()))
30    }
31
32    /// `.inspectorColumnWidth(_:)` — one fixed width for the inspector column.
33    pub fn inspector_column_width(self, width: f64) -> Self {
34        Self::new(views::inspector_column_width(&self.handle, width))
35    }
36
37    /// `.inspectorColumnWidth(min:ideal:max:)` — a width the user can drag
38    /// within.
39    ///
40    /// `None` for a bound leaves the column unconstrained in that direction,
41    /// which is not the same as pinning it to zero. `.inspector_column_width`
42    /// above is the fixed spelling.
43    pub fn inspector_column_width_range(
44        self,
45        min: Option<f64>,
46        ideal: f64,
47        max: Option<f64>,
48    ) -> Self {
49        Self::new(views::inspector_column_width_range(&self.handle, min, ideal, max))
50    }
51
52    /// `.toolbarBackground(_:for:)`
53    pub fn toolbar_background(
54        self,
55        visibility: views::Visibility,
56        placements: &[views::ToolbarPlacement],
57    ) -> Self {
58        Self::new(views::toolbar_background(&self.handle, visibility, placements))
59    }
60
61    /// `.toolbarVisibility(_:for:)` — whether the bar shows at all.
62    ///
63    /// SwiftUI also spells this `.toolbar(_:for:)`; this reaches the named one.
64    pub fn toolbar_visibility(
65        self,
66        visibility: views::Visibility,
67        placements: &[views::ToolbarPlacement],
68    ) -> Self {
69        Self::new(views::toolbar_visibility(&self.handle, visibility, placements))
70    }
71
72    /// `.toolbarTitleDisplayMode(_:)` — large title or inline.
73    pub fn toolbar_title_display_mode(self, mode: views::ToolbarTitleDisplayMode) -> Self {
74        Self::new(views::toolbar_title_display_mode(&self.handle, mode))
75    }
76
77    /// `.toolbarRole(_:)`
78    pub fn toolbar_role(self, role: views::ToolbarRole) -> Self {
79        Self::new(views::toolbar_role(&self.handle, role))
80    }
81
82    /// `.searchable(text:isPresented:placement:prompt:)`, both bindings owned by
83    /// Rust — the query text lands in `text` as it is typed.
84    pub fn searchable(
85        self,
86        text: &views::BoundState<String>,
87        presented: &views::BoundState<bool>,
88        placement: views::SearchFieldPlacement,
89        prompt: &str,
90    ) -> Self {
91        Self::new(views::searchable(&self.handle, text, presented, placement, prompt))
92    }
93
94    /// `.navigationSplitViewStyle(.automatic)`
95    pub fn navigation_split_view_style_automatic(self) -> Self {
96        Self::new(views::navigation_split_view_style_automatic(&self.handle))
97    }
98
99    /// `.navigationViewStyle(.automatic)`
100    pub fn navigation_view_style_automatic(self) -> Self {
101        Self::new(views::navigation_view_style_automatic(&self.handle))
102    }
103
104    /// `.navigationDocument(_:)`
105    pub fn navigation_document(self, item: &str) -> Self {
106        Self::new(views::navigation_document(&self.handle, item))
107    }
108
109    /// `.navigationDocument(_:)` with a URL.
110    pub fn navigation_document_url(self, spec: &str) -> Self {
111        Self::new(views::navigation_document_url(&self.handle, spec))
112    }
113
114    // ── Toolbars ──
115
116    /// `.toolbarBackgroundVisibility(_:for:)` — distinct from
117    /// [`View::toolbar_background`], which sets *what* the background is.
118    pub fn toolbar_background_visibility(
119        self,
120        visibility: views::Visibility,
121        placements: &[views::ToolbarPlacement],
122    ) -> Self {
123        Self::new(views::toolbar_background_visibility(&self.handle, visibility, placements))
124    }
125
126    /// `.toolbarColorScheme(_:in:)` — `None` restores the inherited scheme.
127    pub fn toolbar_color_scheme(
128        self,
129        scheme: Option<views::ColorScheme>,
130        placements: &[views::ToolbarPlacement],
131    ) -> Self {
132        Self::new(views::toolbar_color_scheme(&self.handle, scheme, placements))
133    }
134
135    /// `.toolbarTitleMenu(content:)` — the menu behind a tappable title.
136    pub fn toolbar_title_menu(self, content: View) -> Self {
137        Self::new(views::toolbar_title_menu(&self.handle, content.handle()))
138    }
139
140    /// `.presentationSizing(_:)`
141    pub fn presentation_sizing(self) -> Self {
142        Self::new(views::presentation_sizing(&self.handle))
143    }
144
145    /// `.presentationBackgroundInteraction(_:)` — whether what is behind a
146    /// sheet still takes touches, which is what makes a half-sheet usable.
147    pub fn presentation_background_interaction(
148        self,
149        value: views::PresentationBackgroundInteraction,
150    ) -> Self {
151        Self::new(views::presentation_background_interaction(&self.handle, value))
152    }
153
154    /// `.presentationCompactAdaptation(_:)` — what a popover becomes when the
155    /// size class is compact, which on a phone is always.
156    pub fn presentation_compact_adaptation(self, value: views::PresentationAdaptation) -> Self {
157        Self::new(views::presentation_compact_adaptation(&self.handle, value))
158    }
159
160    /// `.presentationContentInteraction(_:)` — whether a drag resizes the sheet
161    /// or scrolls its content.
162    pub fn presentation_content_interaction(
163        self,
164        value: views::PresentationContentInteraction,
165    ) -> Self {
166        Self::new(views::presentation_content_interaction(&self.handle, value))
167    }
168
169    /// `.navigationTransition(_:)`
170    pub fn navigation_transition(self) -> Self {
171        Self::new(views::navigation_transition(&self.handle))
172    }
173
174    /// `.navigationSplitViewColumnWidth(_:)`
175    pub fn navigation_split_view_column_width(self, width: f64) -> Self {
176        Self::new(views::navigation_split_view_column_width(&self.handle, width))
177    }
178
179    /// `.matchedTransitionSource(id:in:)` — the view a zoom transition grows
180    /// from, paired with [`View::matched_geometry_effect`]'s destination.
181    pub fn matched_transition_source(self, id: views::HashableValue<'_>) -> Self {
182        Self::new(views::matched_transition_source(&self.handle, id))
183    }
184
185    // ── How a sheet presents ──
186
187    /// `.presentationDetents(_:)` — the heights a sheet can rest at, which is
188    /// what makes it a half-sheet rather than a full one.
189    pub fn presentation_detents(self, detents: &[views::PresentationDetent]) -> Self {
190        Self::new(views::presentation_detents(&self.handle, detents))
191    }
192
193    /// `.presentationDragIndicator(_:)`
194    pub fn presentation_drag_indicator(self, visibility: views::Visibility) -> Self {
195        Self::new(views::presentation_drag_indicator(&self.handle, visibility))
196    }
197
198    /// `.presentationCornerRadius(_:)` — `None` restores the system radius.
199    pub fn presentation_corner_radius(self, radius: Option<f64>) -> Self {
200        Self::new(views::presentation_corner_radius(&self.handle, radius))
201    }
202
203    /// `.presentationBackground(alignment:content:)`
204    pub fn presentation_background(self, alignment: views::Alignment, content: View) -> Self {
205        Self::new(views::presentation_background(
206            &self.handle,
207            alignment,
208            content.handle(),
209        ))
210    }
211
212    /// `.tint(_:)` with one of SwiftUI's own colours.
213    ///
214    /// [`View::tint`] takes a literal `Color`; a named colour is not a fixed
215    /// triple, so for an accent — which is what the system draws controls with —
216    /// naming it is usually what is meant.
217    pub fn tint_system(self, c: views::SystemColor) -> Self {
218        Self::new(views::tint_color(&self.handle, views::system_color_value(c)))
219    }
220
221    // ── Search ──
222
223    /// `.searchToolbarBehavior(_:)`
224    pub fn search_toolbar_behavior(self, value: views::SearchToolbarBehavior) -> Self {
225        Self::new(views::search_toolbar_behavior(&self.handle, value))
226    }
227
228    /// `.searchPresentationToolbarBehavior(_:)`
229    pub fn search_presentation_toolbar_behavior(
230        self,
231        value: views::SearchPresentationToolbarBehavior,
232    ) -> Self {
233        Self::new(views::search_presentation_toolbar_behavior(&self.handle, value))
234    }
235
236    /// `.textSelectionAffinity(_:)`
237    pub fn text_selection_affinity(self, value: views::TextSelectionAffinity) -> Self {
238        Self::new(views::text_selection_affinity(&self.handle, value))
239    }
240
241    /// `.typeSelectEquivalent(_:)` — what typing in a list jumps to.
242    pub fn type_select_equivalent(self, text: Option<&str>) -> Self {
243        Self::new(views::type_select_equivalent(&self.handle, text))
244    }
245
246    /// `.searchScopes(_:scopes:)` bound to Rust state — the chosen scope lands
247    /// in `scope`.
248    pub fn search_scopes(self, scope: &views::BoundState<i64>, scopes: View) -> Self {
249        Self::new(views::search_scopes(&self.handle, scope, scopes.handle()))
250    }
251
252    /// `.searchSuggestions(_:for:)` — where suggestions may appear.
253    pub fn search_suggestions(
254        self,
255        visibility: views::Visibility,
256        placements: views::SearchSuggestionsPlacementSet,
257    ) -> Self {
258        Self::new(views::search_suggestions(&self.handle, visibility, placements))
259    }
260
261    /// `.searchSelection(_:)`
262    pub fn search_selection(self, changed: impl Fn() + 'static) -> Self {
263        Self::new(views::search_selection(&self.handle, changed))
264    }
265
266    /// `.searchFocused(_:)`
267    pub fn search_focused(self) -> Self {
268        Self::new(views::search_focused(&self.handle))
269    }
270
271    /// `.textInputSuggestions { … }` — completions offered under a field.
272    pub fn text_input_suggestions(self, count: usize, content: View) -> Self {
273        Self::new(views::text_input_suggestions(&self.handle, count, content.handle()))
274    }
275
276    /// `.findNavigator(isPresented:)` bound to Rust state — the find bar.
277    pub fn find_navigator(self, state: &views::BoundState<bool>) -> Self {
278        Self::new(views::find_navigator(&self.handle, state))
279    }
280
281}