Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Popup component #372

Merged
merged 35 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d4c2edc
feat: Proper event bubbling
marc2332 Jul 2, 2023
7db5f05
chore: Organize torin tests
marc2332 Nov 4, 2023
7f7d447
feat: Absolute positioning
marc2332 Nov 5, 2023
de626e5
feat: Popup component
marc2332 Nov 6, 2023
c7fbd6b
resolve conflicts
marc2332 Nov 11, 2023
a7c7eb6
resolve conflicts
marc2332 Nov 11, 2023
43ad4ff
update
marc2332 Nov 12, 2023
744f62c
ux improvements
marc2332 Nov 12, 2023
53d1908
improvements
marc2332 Nov 12, 2023
200057e
Merge branch 'feat/updated-dioxus' of https://github.com/marc2332/fre…
marc2332 Nov 12, 2023
53bbe5e
fixes and improvements
marc2332 Nov 12, 2023
e4cea32
fix
marc2332 Nov 12, 2023
c39754a
Merge branch 'feat/updated-dioxus' into feat/event-bubbling
marc2332 Dec 20, 2023
e89f856
resolve conflicts
marc2332 Jan 24, 2024
7f81afc
clean up
marc2332 Jan 24, 2024
730da99
resolve conflicts
marc2332 Jan 24, 2024
4a1b024
fixes
marc2332 Jan 24, 2024
8cbd760
Merge branch 'feat/updated-dioxus' into feat/event-bubbling
marc2332 Jan 24, 2024
2e7a6b6
Merge branch 'feat/event-bubbling' into feat/popup-component
marc2332 Jan 24, 2024
28b927e
improvements
marc2332 Jan 24, 2024
2eddbf7
Merge branch 'feat/updated-dioxus' into feat/event-bubbling
marc2332 Jan 25, 2024
1368a7b
Merge branch 'feat/event-bubbling' into feat/popup-component
marc2332 Jan 25, 2024
f14e9c0
cleanup
marc2332 Jan 25, 2024
216ba7f
Merge branch 'feat/updated-dioxus' into feat/event-bubbling
marc2332 Jan 26, 2024
b248414
fixes and improvements
marc2332 Jan 26, 2024
dd1161e
fixes
marc2332 Jan 27, 2024
cba6053
Merge branch 'feat/updated-dioxus' into feat/event-bubbling
marc2332 Jan 28, 2024
4e3fb2e
Merge branch 'feat/event-bubbling' into feat/popup-component
marc2332 Jan 29, 2024
fd9c743
typo
marc2332 Jan 29, 2024
f71cc1b
resolve conflicts
marc2332 Feb 24, 2024
d8a954a
fmt
marc2332 Feb 24, 2024
9fe112d
improvements and fixes
marc2332 Feb 24, 2024
cdfa46e
unit test
marc2332 Feb 24, 2024
65b62e2
fix
marc2332 Feb 24, 2024
f0e0733
docs
marc2332 Mar 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/components/src/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub fn Button(props: ButtonProps) -> Element {
width,
height,
font_theme,
shadow,
} = use_applied_theme!(&props.theme, button);

let onclick = {
Expand Down Expand Up @@ -131,7 +132,7 @@ pub fn Button(props: ButtonProps) -> Element {
overflow: "clip",
role: "button",
color: "{font_theme.color}",
shadow: "0 4 5 0 rgb(0, 0, 0, 0.1)",
shadow: "{shadow}",
border: "{border}",
corner_radius: "{corner_radius}",
background: "{background}",
Expand Down
6 changes: 3 additions & 3 deletions crates/components/src/dropdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use freya_elements::events::keyboard::Key;
use freya_elements::events::{KeyboardEvent, MouseEvent};

use freya_hooks::{
theme_with, use_applied_theme, use_focus, use_platform, ArrowIconThemeWith,
DropdownItemThemeWith, DropdownTheme, DropdownThemeWith,
theme_with, use_applied_theme, use_focus, use_platform, DropdownItemThemeWith, DropdownTheme,
DropdownThemeWith, IconThemeWith,
};
use winit::window::CursorIcon;

Expand Down Expand Up @@ -278,7 +278,7 @@ where
ArrowIcon {
rotate: "0",
fill: "{arrow_fill}",
theme: theme_with!(ArrowIconTheme {
theme: theme_with!(IconTheme {
margin : "0 0 0 8".into(),
})
}
Expand Down
8 changes: 4 additions & 4 deletions crates/components/src/icons/arrow.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use dioxus::prelude::*;
use freya_elements::elements as dioxus_elements;

use freya_hooks::{use_applied_theme, ArrowIconTheme, ArrowIconThemeWith};
use freya_hooks::{use_applied_theme, IconTheme, IconThemeWith};

#[derive(Props, Clone, PartialEq)]
pub struct ArrowIconProps {
/// Theme override.
pub theme: Option<ArrowIconThemeWith>,
pub theme: Option<IconThemeWith>,
#[props(into)]
pub rotate: String,
#[props(into)]
Expand All @@ -21,11 +21,11 @@ pub fn ArrowIcon(
fill,
}: ArrowIconProps,
) -> Element {
let ArrowIconTheme {
let IconTheme {
height,
width,
margin,
} = use_applied_theme!(&theme, arrow_icon);
} = use_applied_theme!(&theme, icon);

rsx!(svg {
height: "{height}",
Expand Down
33 changes: 33 additions & 0 deletions crates/components/src/icons/cross.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use dioxus::prelude::*;
use freya_elements::elements as dioxus_elements;

use freya_hooks::{use_applied_theme, IconTheme, IconThemeWith};

#[derive(Props, Clone, PartialEq)]
pub struct CrossIconProps {
/// Theme override.
pub theme: Option<IconThemeWith>,
#[props(into)]
pub fill: String,
}

#[allow(non_snake_case)]
pub fn CrossIcon(CrossIconProps { theme, fill }: CrossIconProps) -> Element {
let IconTheme {
height,
width,
margin,
} = use_applied_theme!(&theme, icon);

rsx!(svg {
height: "{height}",
width: "{width}",
margin: "{margin}",
svg_content: r#"
<svg viewBox="0 0 292 292" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.0366211 268.737L268.737 0.0366211L291.365 22.664L22.664 291.365L0.0366211 268.737Z" fill="{fill}"/>
<path d="M268.737 291.365L0.0366211 22.664L22.664 0.0366211L291.365 268.737L268.737 291.365Z" fill="{fill}"/>
</svg>
"#
})
}
2 changes: 2 additions & 0 deletions crates/components/src/icons/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod arrow;
mod cross;

pub use arrow::*;
pub use cross::*;
2 changes: 2 additions & 0 deletions crates/components/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod input;
mod link;
mod loader;
mod network_image;
mod popup;
mod progress_bar;
mod scroll_views;
mod sidebar;
Expand All @@ -38,6 +39,7 @@ pub use input::*;
pub use link::*;
pub use loader::*;
pub use network_image::*;
pub use popup::*;
pub use progress_bar::*;
pub use scroll_views::*;
pub use sidebar::*;
Expand Down
200 changes: 200 additions & 0 deletions crates/components/src/popup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
use crate::{Button, CrossIcon};
use dioxus::prelude::*;
use freya_elements::elements as dioxus_elements;
use freya_hooks::{theme_with, use_applied_theme, ButtonThemeWith, PopupTheme, PopupThemeWith};

#[allow(non_snake_case)]
#[component]
pub fn PopupBackground(children: Element) -> Element {
rsx!(rect {
height: "100v",
width: "100v",
background: "rgb(0, 0, 0, 150)",
position: "absolute",
position_top: "0",
position_left: "0",
layer: "-99",
main_align: "center",
cross_align: "center",
{children}
})
}

/// `Popup` component.
///
/// # Styling
/// Inherits the [`PopupTheme`](freya_hooks::PopupTheme) theme.
/// ```rust, no_run
/// # use freya::prelude::*;
/// fn app() -> Element {
/// let mut show_popup = use_signal(|| false);
///
/// rsx!(
/// if *show_popup.read() {
/// Popup {
/// oncloserequest: move |_| {
/// show_popup.set(false)
/// },
/// PopupTitle {
/// label {
/// "Awesome Popup"
/// }
/// }
/// PopupContent {
/// label {
/// "Some content"
/// }
/// }
/// }
/// }
/// Button {
/// onclick: move |_| show_popup.set(true),
/// label {
/// "Open"
/// }
/// }
/// )
/// }
#[allow(non_snake_case)]
#[component]
pub fn Popup(
/// Theme override.
theme: Option<PopupThemeWith>,
/// Popup inner content.
children: Element,
/// Optional close request handler.
oncloserequest: Option<EventHandler>,
/// Whether to show or no the cross button in the top right corner.
#[props(default = true)]
show_close_button: bool,
) -> Element {
let PopupTheme {
background,
color,
cross_fill,
width,
height,
} = use_applied_theme!(&theme, popup);
rsx!(
PopupBackground {
rect {
padding: "14",
corner_radius: "8",
background: "{background}",
color: "{color}",
shadow: "0 4 5 0 rgb(0, 0, 0, 30)",
width: "{width}",
height: "{height}",
if show_close_button {
rect {
height: "0",
width: "fill",
cross_align: "end",
Button {
theme: theme_with!(ButtonTheme {
padding: "6".into(),
margin: "0".into(),
width: "30".into(),
height: "30".into(),
corner_radius: "999".into(),
shadow: "none".into()
}),
onclick: move |_| if let Some(oncloserequest) = &oncloserequest {
oncloserequest.call(());
},
CrossIcon {
fill: cross_fill
}
}
}
}
{children}
}
}
)
}

#[allow(non_snake_case)]
#[component]
pub fn PopupTitle(children: Element) -> Element {
rsx!(
rect {
font_size: "18",
margin: "4 2 8 2",
font_weight: "bold",
{children}
}
)
}

#[allow(non_snake_case)]
#[component]
pub fn PopupContent(children: Element) -> Element {
rsx!(
rect {
font_size: "15",
margin: "6 2",
{children}
}
)
}

#[cfg(test)]
mod test {
use dioxus::prelude::use_signal;
use freya::prelude::*;
use freya_testing::*;

#[tokio::test]
pub async fn popup() {
fn popup_app() -> Element {
let mut show_popup = use_signal(|| false);

rsx!(
if *show_popup.read() {
Popup {
oncloserequest: move |_| {
show_popup.set(false)
},
label {
"Hello, World!"
}
}
}
Button {
onclick: move |_| show_popup.set(true),
label {
"Open"
}
}
)
}

let mut utils = launch_test(popup_app);
utils.wait_for_update().await;

// Check the popup is closed
assert_eq!(utils.sdom().get().layout().size(), 3);

// Open the popup
utils.push_event(PlatformEvent::Mouse {
name: EventName::Click,
cursor: (5.0, 5.0).into(),
button: Some(MouseButton::Left),
});
utils.wait_for_update().await;

// Check the popup is opened
assert_eq!(utils.sdom().get().layout().size(), 9);

utils.push_event(PlatformEvent::Mouse {
name: EventName::Click,
cursor: (395.0, 180.0).into(),
button: Some(MouseButton::Left),
});
utils.wait_for_update().await;

// Check the popup is closed
assert_eq!(utils.sdom().get().layout().size(), 3);
}
}
5 changes: 5 additions & 0 deletions crates/core/src/events/event_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ impl EventName {
)
}

// Only let events that do not move the mouse, go through solid nodes
pub fn does_go_through_solid(&self) -> bool {
matches!(self, Self::KeyDown)
}

// Check if this event can change the hover state of a Node.
pub fn can_change_hover_state(&self) -> bool {
matches!(
Expand Down
3 changes: 2 additions & 1 deletion crates/core/src/events/events_measurer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ fn measure_dom_events(

let Style { background, .. } = &*node.get::<Style>().unwrap();

if background != &Fill::Color(Color::TRANSPARENT) && event.get_name().does_bubble()
if background != &Fill::Color(Color::TRANSPARENT)
&& !event.get_name().does_go_through_solid()
{
// If the background isn't transparent,
// we must make sure that next nodes are parent of it
Expand Down
18 changes: 13 additions & 5 deletions crates/hooks/src/theming/dark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub const DARK_THEME: Theme = Theme {
},
border_fill: cow_borrowed!("rgb(80, 80, 80)"),
focus_border_fill: cow_borrowed!("rgb(110, 110, 110)"),
shadow: cow_borrowed!("0 4 5 0 rgb(0, 0, 0, 0.1)"),
padding: LIGHT_THEME.button.padding,
margin: LIGHT_THEME.button.margin,
corner_radius: LIGHT_THEME.button.corner_radius,
Expand Down Expand Up @@ -71,7 +72,7 @@ pub const DARK_THEME: Theme = Theme {
color: cow_borrowed!("white"),
},
border_fill: cow_borrowed!("rgb(80, 80, 80)"),
arrow_fill: cow_borrowed!("rgb(40, 40, 40)"),
arrow_fill: cow_borrowed!("rgb(150, 150, 150)"),
},
dropdown_item: DropdownItemTheme {
background: cow_borrowed!("rgb(35, 35, 35)"),
Expand Down Expand Up @@ -126,10 +127,10 @@ pub const DARK_THEME: Theme = Theme {
width: LIGHT_THEME.network_image.width,
height: LIGHT_THEME.network_image.height,
},
arrow_icon: ArrowIconTheme {
width: LIGHT_THEME.arrow_icon.width,
height: LIGHT_THEME.arrow_icon.height,
margin: LIGHT_THEME.arrow_icon.margin,
icon: IconTheme {
width: LIGHT_THEME.icon.width,
height: LIGHT_THEME.icon.height,
margin: LIGHT_THEME.icon.margin,
},
sidebar: SidebarTheme {
background: cow_borrowed!("rgb(20, 20, 20)"),
Expand All @@ -145,4 +146,11 @@ pub const DARK_THEME: Theme = Theme {
color: cow_borrowed!("white"),
},
},
popup: PopupTheme {
background: cow_borrowed!("rgb(25, 25, 25)"),
color: cow_borrowed!("white"),
cross_fill: cow_borrowed!("rgb(150, 150, 150)"),
width: LIGHT_THEME.popup.width,
height: LIGHT_THEME.popup.height,
},
};
Loading
Loading