Skip to main content

swiftui_native/view/
accessibility.rs

1//! What VoiceOver is told, and what it can do.
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    // ── What VoiceOver is told ──
12    //
13    // The label says what a control is; everything here says the rest of it —
14    // what it is for, what it currently reads, where it sits in the reading
15    // order. VoiceOver has no other source for any of it.
16
17    /// `.accessibilityHint(_:)` — what happens if the user activates this.
18    pub fn a11y_hint(self, hint: &str) -> Self {
19        Self::new(views::accessibility_hint(&self.handle, hint))
20    }
21
22    /// `.accessibilityValue(_:)` — what the control currently reads as, for one
23    /// whose value is not its label.
24    pub fn a11y_value(self, value: &str) -> Self {
25        Self::new(views::accessibility_value(&self.handle, value, true))
26    }
27
28    /// `.accessibilityIdentifier(_:)` — the name a UI test finds this by, not
29    /// something VoiceOver speaks.
30    pub fn a11y_identifier(self, id: &str) -> Self {
31        Self::new(views::accessibility_identifier(&self.handle, id))
32    }
33
34    /// `.accessibilityAddTraits(_:)`
35    pub fn a11y_add_traits(self, traits: &[views::AccessibilityTrait]) -> Self {
36        Self::new(views::accessibility_add_traits(&self.handle, traits))
37    }
38
39    /// `.accessibilityRemoveTraits(_:)`
40    pub fn a11y_remove_traits(self, traits: &[views::AccessibilityTrait]) -> Self {
41        Self::new(views::accessibility_remove_traits(&self.handle, traits))
42    }
43
44    /// `.accessibilityHeading(_:)` — which heading level this is, so VoiceOver
45    /// can navigate by them.
46    pub fn a11y_heading(self, level: views::HeadingLevel) -> Self {
47        Self::new(views::accessibility_heading(&self.handle, level))
48    }
49
50    /// `.accessibilitySortPriority(_:)` — higher is read first.
51    pub fn a11y_sort_priority(self, priority: f64) -> Self {
52        Self::new(views::accessibility_sort_priority(&self.handle, priority))
53    }
54
55    /// `.accessibilityInputLabels(_:)` — the phrases Voice Control accepts for
56    /// this, when the visible label is awkward to say.
57    pub fn a11y_input_labels(self, labels: &[&str]) -> Self {
58        Self::new(views::accessibility_input_labels(&self.handle, labels, true))
59    }
60
61    /// `.accessibilityRespondsToUserInteraction(_:)`
62    pub fn a11y_responds_to_interaction(self, responds: bool) -> Self {
63        Self::new(views::accessibility_responds_to_user_interaction(&self.handle, responds))
64    }
65
66    /// `.accessibilityTextContentType(_:)` — what kind of text this is, which
67    /// changes how VoiceOver reads it.
68    pub fn a11y_text_content_type(self, kind: views::TextContentType) -> Self {
69        Self::new(views::accessibility_text_content_type(&self.handle, kind))
70    }
71
72    // ── What VoiceOver can do ──
73    //
74    // The attributes above describe a control; these change what VoiceOver can
75    // *do* with it, and how it groups what it finds. Both matter to somebody
76    // who cannot see the screen and neither has any other source.
77
78    /// `.accessibilityAction(_:_:)` — an action VoiceOver can perform without a
79    /// visible control for it.
80    pub fn a11y_action(self, kind: views::ActionKind, action: impl Fn() + 'static) -> Self {
81        Self::new(views::accessibility_action(&self.handle, kind, action))
82    }
83
84    /// `.accessibilityActions(category:content:)` — several, as a group.
85    pub fn a11y_actions(self, category: views::ActionCategory, content: View) -> Self {
86        Self::new(views::accessibility_actions(&self.handle, category, content.handle()))
87    }
88
89    /// `.accessibilityAdjustableAction(_:)` — what a swipe up or down does,
90    /// which is how VoiceOver drives a slider or stepper.
91    pub fn a11y_adjustable_action(self, action: impl Fn(i64) + 'static) -> Self {
92        Self::new(views::accessibility_adjustable_action(&self.handle, action))
93    }
94
95    /// `.accessibilityScrollAction(_:)`
96    pub fn a11y_scroll_action(self, action: impl Fn(i64) + 'static) -> Self {
97        Self::new(views::accessibility_scroll_action(&self.handle, action))
98    }
99
100    /// `.accessibilityZoomAction(_:)`
101    pub fn a11y_zoom_action(self, action: impl Fn() + 'static) -> Self {
102        Self::new(views::accessibility_zoom_action(&self.handle, action))
103    }
104
105    /// `.accessibilityElement(children:)` — whether descendants are merged into
106    /// one element, kept as a container, or dropped.
107    pub fn a11y_element(self, children: views::AccessibilityChildBehavior) -> Self {
108        Self::new(views::accessibility_element(&self.handle, children))
109    }
110
111    /// `.accessibilityChildren(children:)` — a different subtree for VoiceOver
112    /// than the one on screen.
113    pub fn a11y_children(self, children: View) -> Self {
114        Self::new(views::accessibility_children(&self.handle, children.handle()))
115    }
116
117    /// `.accessibilityRepresentation(representation:)` — stand in for this view
118    /// with a description of a standard control.
119    pub fn a11y_representation(self, representation: View) -> Self {
120        Self::new(views::accessibility_representation(&self.handle, representation.handle()))
121    }
122
123    /// `.accessibilityLabeledPair(role:id:)` — tie a label to the thing it
124    /// labels, so they are read together.
125    pub fn a11y_labeled_pair(
126        self,
127        role: views::LabeledPairRole,
128        id: views::HashableValue<'_>,
129    ) -> Self {
130        Self::new(views::accessibility_labeled_pair(&self.handle, role, id))
131    }
132
133    /// `.accessibilityLinkedGroup(id:)`
134    pub fn a11y_linked_group<'h>(self, id: impl views::IntoHashable<'h>) -> Self {
135        Self::new(views::accessibility_linked_group(&self.handle, id.into_hashable()))
136    }
137
138    /// `.accessibilityCustomContent(_:_:importance:)` — extra detail VoiceOver
139    /// reads on request rather than always.
140    pub fn a11y_custom_content(
141        self,
142        key_label: &str,
143        id: &str,
144        value: &str,
145        importance: views::CustomContentImportance,
146    ) -> Self {
147        Self::new(views::accessibility_custom_content(
148            &self.handle,
149            key_label,
150            id,
151            value,
152            importance,
153        ))
154    }
155
156    /// `.accessibilityActivationPoint(_:)` — where a VoiceOver double-tap lands,
157    /// for a control whose centre is not where it should be pressed.
158    pub fn a11y_activation_point(self, x: f64, y: f64) -> Self {
159        Self::new(views::accessibility_activation_point(&self.handle, x, y))
160    }
161
162    /// `.accessibilityDragPoint(_:description:)`
163    pub fn a11y_drag_point(self, x: f64, y: f64, description: &str) -> Self {
164        Self::new(views::accessibility_drag_point(&self.handle, x, y, description, true))
165    }
166
167    /// `.accessibilityDropPoint(_:description:)`
168    pub fn a11y_drop_point(self, x: f64, y: f64, description: &str) -> Self {
169        Self::new(views::accessibility_drop_point(&self.handle, x, y, description, true))
170    }
171
172    /// `.accessibilityDirectTouch(_:options:)` — for a view that handles raw
173    /// touches itself, like an instrument or a drawing canvas.
174    pub fn a11y_direct_touch(
175        self,
176        enabled: bool,
177        options: &[views::DirectTouchOption],
178    ) -> Self {
179        Self::new(views::accessibility_direct_touch(&self.handle, enabled, options))
180    }
181
182    /// `.accessibilityScrollStatus(_:)` — what to announce after a scroll.
183    pub fn a11y_scroll_status(self, status: &str) -> Self {
184        Self::new(views::accessibility_scroll_status(&self.handle, status, true))
185    }
186
187    /// `.accessibilityShowsLargeContentViewer()`
188    pub fn a11y_shows_large_content_viewer(self) -> Self {
189        Self::new(views::accessibility_shows_large_content_viewer(&self.handle))
190    }
191
192}