commit edea0bec57287f95dc080863ea0076eef9ad690a
parent 99c644eb61fc8cb0c987318c5bafa61200e425ef
Author: triesap <triesap@radroots.dev>
Date: Wed, 21 Jan 2026 19:54:11 +0000
ui: add event composition helpers
- add compose helpers with default-prevented predicate
- add unchecked compose helper for simple handlers
- add unit tests for ordering and prevention
- export event helpers from ui-core
Diffstat:
2 files changed, 88 insertions(+), 0 deletions(-)
diff --git a/crates/ui-core/src/event.rs b/crates/ui-core/src/event.rs
@@ -0,0 +1,83 @@
+pub fn radroots_app_ui_compose_event_handlers<T, A, B, P>(
+ mut first: Option<A>,
+ mut second: Option<B>,
+ mut is_prevented: P,
+) -> impl FnMut(&T)
+where
+ A: FnMut(&T),
+ B: FnMut(&T),
+ P: FnMut(&T) -> bool,
+{
+ move |event| {
+ if let Some(handler) = first.as_mut() {
+ handler(event);
+ }
+ if is_prevented(event) {
+ return;
+ }
+ if let Some(handler) = second.as_mut() {
+ handler(event);
+ }
+ }
+}
+
+pub fn radroots_app_ui_compose_event_handlers_unchecked<T, A, B>(
+ first: Option<A>,
+ second: Option<B>,
+) -> impl FnMut(&T)
+where
+ A: FnMut(&T),
+ B: FnMut(&T),
+{
+ radroots_app_ui_compose_event_handlers(first, second, |_| false)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{
+ radroots_app_ui_compose_event_handlers,
+ radroots_app_ui_compose_event_handlers_unchecked,
+ };
+
+ #[derive(Default)]
+ struct TestEvent {
+ calls: core::cell::Cell<usize>,
+ prevented: core::cell::Cell<bool>,
+ }
+
+ impl TestEvent {
+ fn mark_called(&self) {
+ self.calls.set(self.calls.get() + 1);
+ }
+
+ fn prevent(&self) {
+ self.prevented.set(true);
+ }
+ }
+
+ #[test]
+ fn compose_calls_handlers_in_order() {
+ let event = TestEvent::default();
+ let mut handler = radroots_app_ui_compose_event_handlers_unchecked(
+ Some(|evt: &TestEvent| evt.mark_called()),
+ Some(|evt: &TestEvent| evt.mark_called()),
+ );
+ handler(&event);
+ assert_eq!(event.calls.get(), 2);
+ }
+
+ #[test]
+ fn compose_skips_second_when_prevented() {
+ let event = TestEvent::default();
+ let mut handler = radroots_app_ui_compose_event_handlers(
+ Some(|evt: &TestEvent| {
+ evt.mark_called();
+ evt.prevent();
+ }),
+ Some(|evt: &TestEvent| evt.mark_called()),
+ |evt: &TestEvent| evt.prevented.get(),
+ );
+ handler(&event);
+ assert_eq!(event.calls.get(), 1);
+ }
+}
diff --git a/crates/ui-core/src/lib.rs b/crates/ui-core/src/lib.rs
@@ -4,5 +4,10 @@
extern crate alloc;
mod id;
+mod event;
+pub use event::{
+ radroots_app_ui_compose_event_handlers,
+ radroots_app_ui_compose_event_handlers_unchecked,
+};
pub use id::{RadrootsAppUiId, RadrootsAppUiIdSequence};