@@ -4,6 +4,7 @@ pub use types::*;
4
4
5
5
use crate :: ConfigInjection ;
6
6
use leptos:: {
7
+ either:: Either ,
7
8
ev:: { self , on} ,
8
9
html,
9
10
leptos_dom:: helpers:: TimeoutHandle ,
@@ -12,7 +13,7 @@ use leptos::{
12
13
} ;
13
14
use std:: time:: Duration ;
14
15
use thaw_components:: { Binder , CSSTransition , Follower } ;
15
- use thaw_utils:: { add_event_listener , class_list, mount_style, BoxCallback } ;
16
+ use thaw_utils:: { class_list, mount_style, on_click_outside , BoxCallback } ;
16
17
17
18
#[ component]
18
19
pub fn Popover < T > (
41
42
let config_provider = ConfigInjection :: expect_context ( ) ;
42
43
43
44
let popover_ref = NodeRef :: < html:: Div > :: new ( ) ;
44
- let target_ref = NodeRef :: < thaw_utils:: Element > :: new ( ) ;
45
45
let is_show_popover = RwSignal :: new ( false ) ;
46
46
let show_popover_handle = StoredValue :: new ( None :: < TimeoutHandle > ) ;
47
47
@@ -93,67 +93,55 @@ where
93
93
. ok ( ) ;
94
94
} ) ;
95
95
} ;
96
- #[ cfg( any( feature = "csr" , feature = "hydrate" ) ) ]
97
- {
98
- let handle = window_event_listener ( ev:: click, move |ev| {
99
- use leptos:: wasm_bindgen:: __rt:: IntoJsResult ;
100
- if trigger_type != PopoverTriggerType :: Click {
101
- return ;
102
- }
103
- if !is_show_popover. get_untracked ( ) {
104
- return ;
105
- }
106
- let el = ev. target ( ) ;
107
- let mut el: Option < web_sys:: Element > =
108
- el. into_js_result ( ) . map_or ( None , |el| Some ( el. into ( ) ) ) ;
109
- let body = document ( ) . body ( ) . unwrap ( ) ;
110
- while let Some ( current_el) = el {
111
- if current_el == * body {
112
- break ;
113
- } ;
114
- let Some ( popover_el) = popover_ref. get_untracked ( ) else {
115
- break ;
116
- } ;
117
- if current_el == * * popover_el {
118
- return ;
119
- }
120
- el = current_el. parent_element ( ) ;
121
- }
122
- is_show_popover. set ( false ) ;
123
- } ) ;
124
- on_cleanup ( move || handle. remove ( ) ) ;
125
- }
126
-
127
- Effect :: new ( move |_| {
128
- let Some ( target_el) = target_ref. get ( ) else {
129
- return ;
130
- } ;
131
- let handler = add_event_listener ( target_el, ev:: click, move |event| {
132
- if trigger_type != PopoverTriggerType :: Click {
133
- return ;
134
- }
135
- event. stop_propagation ( ) ;
136
- is_show_popover. update ( |show| * show = !* show) ;
137
- } ) ;
138
- on_cleanup ( move || handler. remove ( ) ) ;
139
- } ) ;
140
96
141
97
let PopoverTrigger {
142
98
children : trigger_children,
143
99
} = popover_trigger;
100
+ let trigger_children = trigger_children. into_inner ( ) ( )
101
+ . into_inner ( )
102
+ . add_any_attr ( tachys_class ( ( "thaw-popover-trigger" , true ) ) )
103
+ . add_any_attr ( tachys_class ( ( "thaw-popover-trigger--open" , move || {
104
+ is_show_popover. get ( )
105
+ } ) ) ) ;
106
+
107
+ let trigger_children = match trigger_type {
108
+ PopoverTriggerType :: Click => {
109
+ let trigger_ref = NodeRef :: < thaw_utils:: Element > :: new ( ) ;
110
+ on_click_outside (
111
+ move || {
112
+ if !is_show_popover. get_untracked ( ) {
113
+ return None ;
114
+ }
115
+ let Some ( trigger_el) = trigger_ref. get_untracked ( ) else {
116
+ return None ;
117
+ } ;
118
+ let Some ( popover_el) = popover_ref. get_untracked ( ) else {
119
+ return None ;
120
+ } ;
121
+ Some ( vec ! [ popover_el. into( ) , trigger_el] )
122
+ } ,
123
+ move || is_show_popover. set ( false ) ,
124
+ ) ;
125
+ Either :: Left (
126
+ trigger_children
127
+ . add_any_attr ( node_ref ( trigger_ref) )
128
+ . add_any_attr ( on ( ev:: click, move |_| {
129
+ is_show_popover. update ( |show| {
130
+ * show = !* show;
131
+ } ) ;
132
+ } ) ) ,
133
+ )
134
+ }
135
+ PopoverTriggerType :: Hover => Either :: Right (
136
+ trigger_children
137
+ . add_any_attr ( on ( ev:: mouseenter, on_mouse_enter) )
138
+ . add_any_attr ( on ( ev:: mouseleave, on_mouse_leave) ) ,
139
+ ) ,
140
+ } ;
144
141
145
142
view ! {
146
143
<Binder >
147
- { trigger_children
148
- . into_inner( ) ( )
149
- . into_inner( )
150
- . add_any_attr( tachys_class( ( "thaw-popover-trigger" , true ) ) )
151
- . add_any_attr(
152
- tachys_class( ( "thaw-popover-trigger--open" , move || is_show_popover. get( ) ) ) ,
153
- )
154
- . add_any_attr( node_ref( target_ref) )
155
- . add_any_attr( on( ev:: mouseenter, on_mouse_enter) )
156
- . add_any_attr( on( ev:: mouseleave, on_mouse_leave) ) }
144
+ { trigger_children}
157
145
<Follower slot show=is_show_popover placement=position>
158
146
<CSSTransition
159
147
name="popover-transition"
0 commit comments