cranpose_native/
content.rs1use std::{cell::RefCell, rc::Rc};
2
3use cranpose::{
4 native_view::{NativeView as Slot, NativeViewHost},
5 prelude::Modifier,
6};
7use cranpose_core::{CompositionLocal, CompositionLocalProvider, SideEffect, compositionLocalOf};
8
9use crate::NativeEvent;
10
11thread_local! {
12 static CONTEXT: CompositionLocal<Option<NativeContext>> = compositionLocalOf(|| None);
13}
14
15#[derive(Clone)]
16pub(crate) struct NativeContext {
17 pub(crate) views: NativeViewHost,
18 events: Rc<RefCell<Vec<NativeEvent>>>,
19}
20
21impl PartialEq for NativeContext {
22 fn eq(&self, other: &Self) -> bool {
23 Rc::ptr_eq(&self.events, &other.events)
24 }
25}
26
27impl NativeContext {
28 pub(crate) fn new() -> Self {
29 Self {
30 views: NativeViewHost::default(),
31 events: Rc::default(),
32 }
33 }
34
35 pub(crate) fn provide(&self, content: impl FnOnce()) {
36 CONTEXT.with(|local| {
37 CompositionLocalProvider([local.provides(Some(self.clone()))], || {
38 self.views.provide(content);
39 });
40 });
41 }
42
43 pub(crate) fn take_events(&self) -> Vec<NativeEvent> {
44 std::mem::take(&mut *self.events.borrow_mut())
45 }
46
47 fn current() -> Self {
48 CONTEXT
49 .with(CompositionLocal::current)
50 .expect("native content requires a NativeSession")
51 }
52}
53
54pub struct NativeContent {
56 pub(crate) draw: Box<dyn FnMut()>,
57 pub(crate) event: Box<dyn FnMut(NativeEvent)>,
58}
59
60impl NativeContent {
61 pub fn new(content: impl FnMut() + 'static) -> Self {
63 Self {
64 draw: Box::new(content),
65 event: Box::new(|_| {}),
66 }
67 }
68
69 pub fn on_event(mut self, event: impl FnMut(NativeEvent) + 'static) -> Self {
71 self.event = Box::new(event);
72 self
73 }
74}
75
76#[cranpose::prelude::composable]
78pub fn SendToHost(name: impl Into<String>, value: impl Into<String>) {
79 let context = NativeContext::current();
80 let event = NativeEvent {
81 name: name.into(),
82 value: value.into(),
83 };
84 SideEffect(move || context.events.borrow_mut().push(event));
85}
86
87#[cranpose::prelude::composable]
92pub fn NativeView(kind: &str, value: &str, modifier: Modifier, on_event: impl Fn(&str) + 'static) {
93 Slot(
94 NativeContext::current().views,
95 kind,
96 value,
97 modifier,
98 on_event,
99 );
100}