Skip to main content

polyhorn_ios/components/
text_input.rs

1use polyhorn_core::CommandBuffer;
2use polyhorn_ios_sys::coregraphics::CGRect;
3use polyhorn_ios_sys::polykit::{PLYTextInputView, PLYView};
4use polyhorn_ui::styles::TextStyle;
5
6use crate::prelude::*;
7use crate::raw::{attributed_string, Builtin, Container, ContainerID, OpaqueContainer};
8use crate::{Key, Reference};
9
10/// Accepts user input.
11#[derive(Default)]
12pub struct TextInput {
13    /// Placeholder string to use when the text input is empty.
14    pub placeholder: String,
15
16    /// Text style to apply to the placeholder string.
17    pub placeholder_style: TextStyle,
18}
19
20impl Container for PLYTextInputView {
21    fn mount(&mut self, child: &mut OpaqueContainer) {
22        if let Some(view) = child.container().to_view() {
23            PLYTextInputView::to_view(self).add_subview(&view)
24        }
25    }
26
27    fn unmount(&mut self) {
28        PLYTextInputView::to_view(self).remove_from_superview();
29    }
30
31    fn to_view(&self) -> Option<PLYView> {
32        Some(PLYTextInputView::to_view(self))
33    }
34}
35
36impl Component for TextInput {
37    fn render(&self, manager: &mut Manager) -> Element {
38        let view_ref: Reference<Option<ContainerID>> = use_reference!(manager, None);
39
40        let placeholder = self.placeholder.clone();
41        let placeholder_style = self.placeholder_style.clone();
42
43        use_layout_effect!(manager, move |link, buffer| {
44            let id = match view_ref.apply(link, |&mut id| id) {
45                Some(id) => id,
46                None => return,
47            };
48
49            buffer.mutate(&[id], move |containers, _| {
50                let container = &mut containers[0];
51
52                let layout = match container.layout() {
53                    Some(layout) => layout.clone(),
54                    None => return,
55                };
56
57                assert!(container.downcast_mut::<PLYTextInputView>().is_some());
58
59                if let Some(view) = container.downcast_mut::<PLYTextInputView>() {
60                    view.set_attributed_placeholder(&attributed_string(
61                        &placeholder,
62                        &placeholder_style,
63                    ));
64
65                    view.to_view().set_layout(move || {
66                        let current = layout.current();
67
68                        CGRect::new(
69                            current.origin.x as _,
70                            current.origin.y as _,
71                            current.size.width as _,
72                            current.size.height as _,
73                        )
74                    });
75                }
76            });
77        });
78
79        Element::builtin(
80            Key::new(()),
81            Builtin::TextInput,
82            manager.children(),
83            Some(view_ref.weak(manager)),
84        )
85    }
86}