polyhorn-ios 0.4.0

Polyhorn for iOS.
Documentation
use polyhorn_core::CommandBuffer;
use polyhorn_ios_sys::coregraphics::CGRect;
use polyhorn_ios_sys::polykit::{PLYScrollView, PLYView};
use polyhorn_ui::geometry::{Dimension, Size};
use polyhorn_ui::styles::{FlexDirection, Position, ViewStyle};

use crate::prelude::*;
use crate::raw::{Apply, Builtin, Container, OpaqueContainer};
use crate::Key;

impl Container for PLYScrollView {
    fn mount(&mut self, child: &mut OpaqueContainer) {
        if let Some(view) = child.container().to_view() {
            PLYScrollView::to_view(self).add_subview(&view);
        }
    }

    fn unmount(&mut self) {
        PLYScrollView::to_view(self).remove_from_superview();
    }

    fn to_view(&self) -> Option<PLYView> {
        Some(PLYScrollView::to_view(self))
    }
}

impl Component for Scrollable {
    fn render(&self, manager: &mut Manager) -> Element {
        let view_ref = use_reference!(manager, None);

        let style = self.style;

        let content_style = ViewStyle {
            flex_direction: FlexDirection::Column,
            position: Position::Absolute(Default::default()),
            min_size: Size {
                width: Dimension::Percentage(1.0),
                height: Dimension::Percentage(1.0),
            },
            max_size: Size {
                width: Dimension::Percentage(1.0),
                height: Dimension::Undefined,
            },
            ..Default::default()
        };

        use_layout_effect!(manager, move |link, buffer| {
            let id = match view_ref.apply(link, |view| view.to_owned()) {
                Some(id) => id,
                None => return,
            };

            buffer.mutate(&[id], move |containers, _| {
                let container = &mut containers[0];

                let layout = match container.layout() {
                    Some(layout) => layout.clone(),
                    None => return,
                };

                let content_layout = match container.content_layout() {
                    Some(layout) => layout.clone(),
                    None => return,
                };

                if let Some(mut view) = container.container().to_view() {
                    style.view.apply(&mut view);

                    view.set_layout(move || {
                        let current = layout.current();

                        CGRect::new(
                            current.origin.x as _,
                            current.origin.y as _,
                            current.size.width as _,
                            current.size.height as _,
                        )
                    });
                }

                if let Some(view) = container.downcast_mut::<PLYScrollView>() {
                    style.scrollable.apply(view);

                    view.set_content_layout(move || {
                        let current = content_layout.current();

                        CGRect::new(
                            current.origin.x as _,
                            current.origin.y as _,
                            current.size.width as _,
                            current.size.height as _,
                        )
                    });
                }
            });
        });

        Element::builtin(
            Key::new(()),
            Builtin::ScrollView {
                self_style: self.style.view,
                content_style,
            },
            manager.children(),
            Some(view_ref.weak(manager)),
        )
    }
}