pax_runtime/
slot.rs

1use std::rc::{Rc, Weak};
2use_RefCell!();
3
4use pax_runtime_api::{use_RefCell, ImplToFromPaxAny, Numeric, Property};
5
6use crate::api::Layer;
7use crate::{
8    BaseInstance, ExpandedNode, InstanceFlags, InstanceNode, InstantiationArgs, RuntimeContext,
9};
10
11/// A special "control-flow" primitive (a la `yield` or perhaps `goto`) — represents a slot into which
12/// an slot_child can be rendered.  Slot relies on `slot_children` being present
13/// on the [`Runtime`] stack and will not render any content if there are no `slot_children` found.
14///
15/// Consider a Stacker:  the owner of a Stacker passes the Stacker some nodes to render
16/// inside the cells of the Stacker.  To the owner of the Stacker, those nodes might seem like
17/// "children," but to the Stacker they are "slot_children" — children provided from
18/// the outside.  Inside Stacker's template, there are a number of Slots — this primitive —
19/// that become the final rendered home of those slot_children.  This same technique
20/// is portable and applicable elsewhere via Slot.
21pub struct SlotInstance {
22    base: BaseInstance,
23}
24
25impl ImplToFromPaxAny for Slot {}
26
27///Contains the index value for slot, either a literal or an expression.
28#[derive(Default)]
29pub struct Slot {
30    // HACK: these two properties are being used in update:
31    pub index: Property<Numeric>,
32    pub last_node_id: Property<usize>,
33    // to compute this:
34    pub showing_node: Property<Weak<ExpandedNode>>,
35}
36
37impl InstanceNode for SlotInstance {
38    fn instantiate(args: InstantiationArgs) -> Rc<Self>
39    where
40        Self: Sized,
41    {
42        Rc::new(Self {
43            base: BaseInstance::new(
44                args,
45                InstanceFlags {
46                    invisible_to_slot: false,
47                    invisible_to_raycasting: true,
48                    layer: Layer::DontCare,
49                    is_component: false,
50                    is_slot: true,
51                },
52            ),
53        })
54    }
55
56    fn handle_mount(
57        self: Rc<Self>,
58        expanded_node: &Rc<ExpandedNode>,
59        context: &Rc<RuntimeContext>,
60    ) {
61        let weak_ref_self = Rc::downgrade(expanded_node);
62        let cloned_context = Rc::clone(context);
63
64        let containing = expanded_node.containing_component.upgrade();
65        let containing = &containing
66            .as_ref()
67            .expect("slot to have a containing component");
68
69        let nodes = containing.expanded_and_flattened_slot_children.clone();
70        let listener = containing.slot_child_attached_listener.clone();
71
72        let index = expanded_node
73            .with_properties_unwrapped(|properties: &mut Slot| properties.index.clone());
74        let deps = vec![index.untyped(), nodes.untyped()];
75
76        expanded_node
77            .children
78            .replace_with(Property::computed_with_name(
79                move || {
80                    let Some(cloned_expanded_node) = weak_ref_self.upgrade() else {
81                        panic!("ran evaluator after expanded node dropped (repeat elem)")
82                    };
83                    let node_rc =
84                        nodes.read(|nodes| nodes.get(index.get().to_int() as usize).cloned());
85                    let node = match &node_rc {
86                        Some(rc) => Rc::downgrade(rc),
87                        None => Weak::new(),
88                    };
89                    let ret = cloned_expanded_node.attach_children(
90                        node.upgrade().as_slice().to_vec(),
91                        &cloned_context,
92                        &cloned_expanded_node.parent_frame,
93                    );
94                    listener.set(());
95                    ret
96                },
97                &deps,
98                &format!("slot_children (node id: {})", expanded_node.id.0),
99            ));
100    }
101
102    fn resolve_debug(
103        &self,
104        f: &mut std::fmt::Formatter,
105        _expanded_node: Option<&ExpandedNode>,
106    ) -> std::fmt::Result {
107        f.debug_struct("Slot").finish()
108    }
109
110    fn base(&self) -> &BaseInstance {
111        &self.base
112    }
113}