diff --git a/common/src/state/ui.rs b/common/src/state/ui.rs index 94e0223c44c..e141bec142b 100644 --- a/common/src/state/ui.rs +++ b/common/src/state/ui.rs @@ -204,7 +204,9 @@ pub struct UI { pub metadata: WindowMeta, #[serde(default = "default_emojis")] pub emojis: EmojiCounter, + #[serde(skip)] pub emoji_destination: Option, + #[serde(skip)] pub emoji_picker_visible: bool, #[serde(default = "bool_true")] transform_markdown_text: bool, diff --git a/kit/src/components/invisible_closer/mod.rs b/kit/src/components/invisible_closer/mod.rs index d8f7c0c7d9d..7d83c30a6d5 100644 --- a/kit/src/components/invisible_closer/mod.rs +++ b/kit/src/components/invisible_closer/mod.rs @@ -2,15 +2,21 @@ use dioxus::prelude::*; #[derive(Props)] pub struct Props<'a> { + classes: Option, onclose: EventHandler<'a, ()>, + children: Option>, } #[allow(non_snake_case)] pub fn InvisibleCloser<'a>(cx: Scope<'a, Props<'a>>) -> Element<'a> { cx.render(rsx!(div { - class: "close-handler-behind", + class: format_args!( + "close-handler-behind {}", + cx.props.classes.clone().unwrap_or_default() + ), onclick: move |_| { cx.props.onclose.call(()); - } + }, + cx.props.children.as_ref() })) } diff --git a/kit/src/components/invisible_closer/style.scss b/kit/src/components/invisible_closer/style.scss index 761c11e53da..ece2f3978db 100644 --- a/kit/src/components/invisible_closer/style.scss +++ b/kit/src/components/invisible_closer/style.scss @@ -1,9 +1,10 @@ .close-handler-behind { position: fixed; - top: 0; + top: var(--titlebar-height); left: 0; right: 0; bottom: 0; z-index: 1; + cursor: default; } \ No newline at end of file diff --git a/kit/src/elements/select/mod.rs b/kit/src/elements/select/mod.rs index 5ccd3092abd..38a6555c9f1 100644 --- a/kit/src/elements/select/mod.rs +++ b/kit/src/elements/select/mod.rs @@ -3,6 +3,8 @@ use std::collections::HashSet; use dioxus::prelude::*; use dioxus_elements::GlobalAttributes; +use crate::components::invisible_closer::InvisibleCloser; + #[derive(Props)] pub struct Props<'a> { #[props(optional)] @@ -126,9 +128,8 @@ pub fn FancySelect<'a>(cx: Scope<'a, FancySelectProps<'a>>) -> Element<'a> { }) ) }, - div { - class: "select-outside", - onclick: |_| { + InvisibleCloser { + onclose: |_| { visible.set(false); } } diff --git a/kit/src/elements/select/style.scss b/kit/src/elements/select/style.scss index 9be083a2cea..c9c9e261653 100644 --- a/kit/src/elements/select/style.scss +++ b/kit/src/elements/select/style.scss @@ -54,14 +54,4 @@ &:hover { background-color: var(--secondary-light); } -} - -.select-outside { - z-index: 1; - position: fixed; - left: 0; - top: 0; - right: 0; - bottom: 0; - cursor: default; } \ No newline at end of file diff --git a/native_extensions/emoji_selector/src/lib.rs b/native_extensions/emoji_selector/src/lib.rs index 417e91de2c7..65df64eb50f 100644 --- a/native_extensions/emoji_selector/src/lib.rs +++ b/native_extensions/emoji_selector/src/lib.rs @@ -8,6 +8,7 @@ use dioxus::prelude::*; use emojis::{Group, UnicodeVersion}; use extensions::{export_extension, Details, Extension, Location, Meta, Type}; use futures::StreamExt; +use kit::components::invisible_closer::InvisibleCloser; use kit::elements::textarea; use kit::{ components::nav::{Nav, Route}, @@ -190,111 +191,112 @@ fn render_selector<'a>( }); cx.render(rsx! ( + InvisibleCloser { + onclose: |_|{ + state.write().mutate(Action::SetEmojiDestination( + Some(common::state::ui::EmojiDestination::Chatbar), + )); + if !*mouse_over_emoji_button.read() && !*mouse_over_emoji_selector.read() { + state.write().mutate(Action::SetEmojiPickerVisible(false)); + } + } + } + div { + onmouseenter: |_| { + *mouse_over_emoji_selector.write_silent() = true; + }, + onmouseleave: |_| { + *mouse_over_emoji_selector.write_silent() = false; + let _ = eval(focus_script); + }, + id: "emoji_selector", + aria_label: "emoji-selector", + tabindex: "0", div { - onmouseenter: |_| { - *mouse_over_emoji_selector.write_silent() = true; - }, - onmouseleave: |_| { - *mouse_over_emoji_selector.write_silent() = false; - let _ = eval(focus_script); - }, - id: "emoji_selector", - aria_label: "emoji-selector", - tabindex: "0", - onblur: |_| { - // When leaving default to the chatbar - state.write().mutate(Action::SetEmojiDestination( - Some(common::state::ui::EmojiDestination::Chatbar), - )); - if !*mouse_over_emoji_button.read() && !*mouse_over_emoji_selector.read() { - state.write().mutate(Action::SetEmojiPickerVisible(false)); - } - }, - div { - class: "search-input disable-select", - textarea::Input { - placeholder: get_local_text("uplink.search-placeholder"), - key: "emoji-search-input", - id: String::from("emoji-search-input"), - loading: false, - ignore_focus: false, - show_char_counter: false, - aria_label: "emoji-search-input".into(), - value: String::new(), - onreturn: |_| {}, - onchange: |_| {}, - onkeyup: |_| {}, - prevent_up_down_arrows: !emoji_suggestions.is_empty(), - oncursor_update: move |(v, p): (String, i64)| { - let mut sub: String = v.chars().take(p as usize).collect(); - sub = if !sub.starts_with(':') { - format!(":{}", sub) - } else { - sub - }; - let capture = EMOJI_REGEX.captures(&sub); - match capture { - Some(emoji) => { - let emoji = &emoji[0]; - if emoji.contains(char::is_whitespace) { - emoji_suggestions.set(vec![]); - return; - } - let alias = emoji.replace(':', ""); - emoji_suggestions - .set(state.read().ui.emojis.get_matching_emoji(&alias, false)); + class: "search-input disable-select", + textarea::Input { + placeholder: get_local_text("uplink.search-placeholder"), + key: "emoji-search-input", + id: String::from("emoji-search-input"), + loading: false, + ignore_focus: false, + show_char_counter: false, + aria_label: "emoji-search-input".into(), + value: String::new(), + onreturn: |_| {}, + onchange: |_| {}, + onkeyup: |_| {}, + prevent_up_down_arrows: !emoji_suggestions.is_empty(), + oncursor_update: move |(v, p): (String, i64)| { + let mut sub: String = v.chars().take(p as usize).collect(); + sub = if !sub.starts_with(':') { + format!(":{}", sub) + } else { + sub + }; + let capture = EMOJI_REGEX.captures(&sub); + match capture { + Some(emoji) => { + let emoji = &emoji[0]; + if emoji.contains(char::is_whitespace) { + emoji_suggestions.set(vec![]); + return; } - None => emoji_suggestions.set(vec![]), + let alias = emoji.replace(':', ""); + emoji_suggestions + .set(state.read().ui.emojis.get_matching_emoji(&alias, false)); } - }, + None => emoji_suggestions.set(vec![]), } }, - div { - id: "scrolling", - padding_top: if !emoji_suggestions.is_empty() {"4px"} else {""}, - if !emoji_suggestions.is_empty() { - rsx!(emoji_suggestions.iter().map(|(emoji, _)| { - rsx!( - div { - aria_label: emoji.as_str(), - class: "emoji", - onclick: move |_| select_emoji_to_send(cx.scope, state, emoji.to_string(), ch), - emoji.as_str() - } - ) - })) - } else { - rsx! (emojis::Group::iter().map(|group| { - let name: String = group_to_str(group); - rsx!( - div { - id: "{group_to_str(group)}", - Label { - text: name - }, - } - div { - class: "emojis-container", - aria_label: "emojis-container", - group.emojis().filter(|emoji|is_supported(emoji.unicode_version())).map(|emoji| { - rsx!( - div { - aria_label: emoji.as_str(), - class: "emoji", - onclick: move |_| select_emoji_to_send(cx.scope, state, emoji.to_string(), ch), - emoji.as_str() - } - ) - }) - } - ) - })) } + }, + div { + id: "scrolling", + padding_top: if !emoji_suggestions.is_empty() {"4px"} else {""}, + if !emoji_suggestions.is_empty() { + rsx!(emoji_suggestions.iter().map(|(emoji, _)| { + rsx!( + div { + aria_label: emoji.as_str(), + class: "emoji", + onclick: move |_| select_emoji_to_send(cx.scope, state, emoji.to_string(), ch), + emoji.as_str() + } + ) + })) + } else { + rsx! (emojis::Group::iter().map(|group| { + let name: String = group_to_str(group); + rsx!( + div { + id: "{group_to_str(group)}", + Label { + text: name + }, + } + div { + class: "emojis-container", + aria_label: "emojis-container", + group.emojis().filter(|emoji|is_supported(emoji.unicode_version())).map(|emoji| { + rsx!( + div { + aria_label: emoji.as_str(), + class: "emoji", + onclick: move |_| select_emoji_to_send(cx.scope, state, emoji.to_string(), ch), + emoji.as_str() + } + ) + }) + } + ) + })) } - nav - }, - script { focus_script }, - )) + } + nav + }, + script { focus_script }, + )) } // this avoid a BorrowMut error. needs an argument to make the curly braces syntax work diff --git a/ui/src/layouts/chats/presentation/chat/controls.rs b/ui/src/layouts/chats/presentation/chat/controls.rs index bf0dafa71e9..3d06911f42a 100644 --- a/ui/src/layouts/chats/presentation/chat/controls.rs +++ b/ui/src/layouts/chats/presentation/chat/controls.rs @@ -1,6 +1,7 @@ use dioxus::prelude::*; use futures::{channel::oneshot, StreamExt}; use kit::{ + components::invisible_closer::InvisibleCloser, elements::{ button::Button, tooltip::{ArrowPosition, Tooltip}, @@ -264,9 +265,9 @@ pub fn get_controls(cx: Scope) -> Element { } }, show_more.then(|| { - rsx!(div { - class: "minimal-chat-button-group-out", - onclick: move |_|{ + rsx!(InvisibleCloser { + classes: "minimal-chat-button-group-out".into(), + onclose: move |_|{ show_more.set(false); }, } diff --git a/ui/src/layouts/chats/presentation/style.scss b/ui/src/layouts/chats/presentation/style.scss index 38e81aa7354..12d15b5b091 100644 --- a/ui/src/layouts/chats/presentation/style.scss +++ b/ui/src/layouts/chats/presentation/style.scss @@ -75,11 +75,6 @@ } .minimal-chat-button-group-out { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; z-index: 98, }