freya_components/
attached.rs1use freya_core::prelude::*;
2use torin::prelude::{
3 Area,
4 Position,
5};
6
7#[derive(PartialEq, Clone, Copy, Debug, Default)]
9pub enum AttachedPosition {
10 Top,
11 #[default]
12 Bottom,
13 Left,
14 Right,
15}
16
17#[derive(PartialEq)]
39pub struct Attached {
40 inner: Element,
41 children: Vec<Element>,
42 position: AttachedPosition,
43 key: DiffKey,
44}
45
46impl KeyExt for Attached {
47 fn write_key(&mut self) -> &mut DiffKey {
48 &mut self.key
49 }
50}
51
52impl ChildrenExt for Attached {
53 fn get_children(&mut self) -> &mut Vec<Element> {
54 &mut self.children
55 }
56}
57
58impl Attached {
59 pub fn new(inner: impl IntoElement) -> Self {
60 Self {
61 inner: inner.into_element(),
62 children: vec![],
63 position: AttachedPosition::Bottom,
64 key: DiffKey::None,
65 }
66 }
67
68 pub fn position(mut self, position: AttachedPosition) -> Self {
69 self.position = position;
70 self
71 }
72
73 pub fn top(self) -> Self {
74 self.position(AttachedPosition::Top)
75 }
76
77 pub fn bottom(self) -> Self {
78 self.position(AttachedPosition::Bottom)
79 }
80
81 pub fn left(self) -> Self {
82 self.position(AttachedPosition::Left)
83 }
84
85 pub fn right(self) -> Self {
86 self.position(AttachedPosition::Right)
87 }
88}
89
90impl Component for Attached {
91 fn render(&self) -> impl IntoElement {
92 let mut inner_area: State<Option<Area>> = use_state(|| None);
93 let mut attached_area: State<Option<Area>> = use_state(|| None);
94
95 let inner = *inner_area.read();
96 let attached = *attached_area.read();
97
98 let is_measured = inner.is_some() && attached.is_some();
99
100 let inner_width = inner.map(|a| a.width()).unwrap_or_default();
101 let inner_height = inner.map(|a| a.height()).unwrap_or_default();
102 let attached_width = attached.map(|a| a.width()).unwrap_or_default();
103 let attached_height = attached.map(|a| a.height()).unwrap_or_default();
104
105 let position = match self.position {
106 AttachedPosition::Top => Position::new_absolute()
107 .top(-attached_height)
108 .left((inner_width - attached_width) / 2.),
109 AttachedPosition::Bottom => Position::new_absolute()
110 .top(inner_height)
111 .left((inner_width - attached_width) / 2.),
112 AttachedPosition::Left => Position::new_absolute()
113 .top((inner_height - attached_height) / 2.)
114 .left(-attached_width),
115 AttachedPosition::Right => Position::new_absolute()
116 .top((inner_height - attached_height) / 2.)
117 .left(inner_width),
118 };
119
120 rect()
121 .on_sized(move |e: Event<SizedEventData>| inner_area.set(Some(e.area)))
122 .child(self.inner.clone())
123 .maybe_child((!self.children.is_empty()).then(|| {
124 rect()
125 .on_sized(move |e: Event<SizedEventData>| attached_area.set(Some(e.area)))
126 .position(position)
127 .layer(Layer::Overlay)
128 .opacity(if is_measured { 1. } else { 0. })
129 .children(self.children.clone())
130 }))
131 }
132
133 fn render_key(&self) -> DiffKey {
134 self.key.clone().or(self.default_key())
135 }
136}