Skip to content

Commit

Permalink
Merge branch 'main' into feat/animated-overflow-content-component
Browse files Browse the repository at this point in the history
  • Loading branch information
marc2332 authored Dec 21, 2024
2 parents a9c0447 + f12fbaa commit b20e1d9
Show file tree
Hide file tree
Showing 31 changed files with 3,930 additions and 2,747 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
rustup component add llvm-tools-preview
curl -L https://github.com/mozilla/grcov/releases/latest/download/grcov-x86_64-unknown-linux-gnu.tar.bz2 | tar jxf -
./grcov . --binary-path ./target/debug/deps -s . -t lcov --branch --ignore-not-existing --ignore "../*" --ignore "/*" -o cov.lcov
- uses: codecov/codecov-action@v4
- uses: codecov/codecov-action@v5
if: runner.os == 'Linux'
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
163 changes: 163 additions & 0 deletions crates/components/src/animated_position.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
use std::time::Duration;

use dioxus::prelude::*;
use freya_elements::elements as dioxus_elements;
use freya_hooks::{
use_animation_with_dependencies,
use_node_signal_with_prev,
AnimDirection,
AnimNum,
Ease,
Function,
};

#[component]
pub fn AnimatedPosition(
children: Element,
width: String,
height: String,
#[props(default = Function::default())] function: Function,
#[props(default = Duration::from_millis(250))] duration: Duration,
#[props(default = Ease::default())] ease: Ease,
) -> Element {
let mut render_element = use_signal(|| false);
let (reference, size, old_size) = use_node_signal_with_prev();

let animations = use_animation_with_dependencies(
&(function, duration, ease),
move |ctx, (function, duration, ease)| {
let old_size = old_size().unwrap_or_default();
let size = size().unwrap_or_default();
(
ctx.with(
AnimNum::new(size.area.origin.x, old_size.area.origin.x)
.duration(duration)
.ease(ease)
.function(function),
),
ctx.with(
AnimNum::new(size.area.origin.y, old_size.area.origin.y)
.duration(duration)
.ease(ease)
.function(function),
),
)
},
);

use_effect(move || {
if animations.is_running() {
render_element.set(true);
}
});

use_effect(move || {
let has_size = size.read().is_some();
let has_old_size = old_size.read().is_some();
if has_size && has_old_size {
animations.run(AnimDirection::Reverse);
} else if has_size {
render_element.set(true);
}
});

let (offset_x, offset_y) = animations.get();
let offset_x = offset_x.read().as_f32();
let offset_y = offset_y.read().as_f32();

rsx!(
rect {
reference,
width: "{width}",
height: "{height}",
rect {
width: "0",
height: "0",
offset_x: "{offset_x}",
offset_y: "{offset_y}",
position: "global",
if render_element() {
rect {
width: "{size.read().as_ref().unwrap().area.width()}",
height: "{size.read().as_ref().unwrap().area.height()}",
{children}
}
}
}
}
)
}

#[cfg(test)]
mod test {
use std::time::Duration;

use freya::prelude::*;
use freya_testing::prelude::*;

#[tokio::test]
pub async fn animated_position() {
fn animated_position_app() -> Element {
let mut padding = use_signal(|| (100., 100.));

rsx!(
rect {
padding: "{padding().0} {padding().1}",
onclick: move |_| {
padding.write().0 += 10.;
padding.write().1 += 10.;
},
AnimatedPosition {
width: "50",
height: "50",
function: Function::Linear
}
}
)
}

let mut utils = launch_test(animated_position_app);

// Disable event loop ticker
utils.config().event_loop_ticker = false;

let root = utils.root();
utils.wait_for_update().await;
utils.wait_for_update().await;

let get_positions = || {
root.get(0)
.get(0)
.get(0)
.get(0)
.layout()
.unwrap()
.area
.origin
};

assert_eq!(get_positions().x, 100.);
assert_eq!(get_positions().y, 100.);

utils.click_cursor((5.0, 5.0)).await;
utils.wait_for_update().await;
utils.wait_for_update().await;
tokio::time::sleep(Duration::from_millis(125)).await;
utils.wait_for_update().await;
utils.wait_for_update().await;

assert!(get_positions().x < 106.);
assert!(get_positions().x > 105.);

assert!(get_positions().y < 106.);
assert!(get_positions().y > 105.);

utils.config().event_loop_ticker = true;

utils.wait_for_update().await;
tokio::time::sleep(Duration::from_millis(125)).await;
utils.wait_for_update().await;

assert_eq!(get_positions().x, 110.);
}
}
11 changes: 10 additions & 1 deletion crates/components/src/drag_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,21 @@ pub struct DropZoneProps<T: 'static + PartialEq + Clone> {
children: Element,
/// Handler for the `ondrop` event.
ondrop: EventHandler<T>,
/// Width of the [DropZone].
#[props(default = "auto".to_string())]
width: String,
/// Height of the [DropZone].
#[props(default = "auto".to_string())]
height: String,
}

/// Elements from [`DragZone`]s can be dropped here.
#[allow(non_snake_case)]
pub fn DropZone<T: 'static + Clone + PartialEq>(props: DropZoneProps<T>) -> Element {
let mut drags = use_context::<Signal<Option<T>>>();

let onmouseup = move |_: MouseEvent| {
let onmouseup = move |e: MouseEvent| {
e.stop_propagation();
if let Some(current_drags) = &*drags.read() {
props.ondrop.call(current_drags.clone());
}
Expand All @@ -134,6 +141,8 @@ pub fn DropZone<T: 'static + Clone + PartialEq>(props: DropZoneProps<T>) -> Elem
rsx!(
rect {
onmouseup,
width: props.width,
height: props.height,
{props.children}
}
)
Expand Down
2 changes: 2 additions & 0 deletions crates/components/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
mod accordion;
mod activable_route;
mod animated_position;
mod animated_router;
mod body;
mod button;
Expand Down Expand Up @@ -43,6 +44,7 @@ mod window_drag_area;

pub use accordion::*;
pub use activable_route::*;
pub use animated_position::*;
pub use animated_router::*;
pub use body::*;
pub use button::*;
Expand Down
27 changes: 26 additions & 1 deletion crates/core/src/dom/mutations_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ use freya_node_state::{
CustomAttributeValues,
LayerState,
};
use torin::torin::Torin;
use torin::torin::{
DirtyReason,
Torin,
};

use crate::prelude::{
Compositor,
Expand Down Expand Up @@ -160,12 +163,34 @@ impl<'a> WriteMutations for MutationsWriter<'a> {

fn insert_nodes_after(&mut self, id: dioxus_core::ElementId, m: usize) {
if m > 0 {
self.layout.invalidate_with_reason(
self.native_writer.state.element_to_node_id(id),
DirtyReason::Reorder,
);
let new_nodes =
&self.native_writer.state.stack[self.native_writer.state.stack.len() - m..];
for new in new_nodes {
self.layout
.invalidate_with_reason(*new, DirtyReason::Reorder);
}

self.native_writer.insert_nodes_after(id, m);
}
}

fn insert_nodes_before(&mut self, id: dioxus_core::ElementId, m: usize) {
if m > 0 {
self.layout.invalidate_with_reason(
self.native_writer.state.element_to_node_id(id),
DirtyReason::Reorder,
);
let new_nodes =
&self.native_writer.state.stack[self.native_writer.state.stack.len() - m..];
for new in new_nodes {
self.layout
.invalidate_with_reason(*new, DirtyReason::Reorder);
}

self.native_writer.insert_nodes_before(id, m);
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub fn process_layout(
let mut dirty_accessibility_tree = fdom.accessibility_dirty_nodes();
let mut compositor_dirty_nodes = fdom.compositor_dirty_nodes();
let mut compositor_dirty_area = fdom.compositor_dirty_area();
let mut buffer = layout.dirty.iter().copied().collect_vec();
let mut buffer = layout.dirty.keys().copied().collect_vec();
while let Some(node_id) = buffer.pop() {
if let Some(node) = rdom.get(node_id) {
if let Some(area) =
Expand Down
Loading

0 comments on commit b20e1d9

Please sign in to comment.