pub fn dragleave_helper(callback: impl Fn() + 'static, drag_ref: NodeRef) -> Callback<DragEvent> {
    Callback::from({
        clone!(drag_ref);
        move |event: DragEvent| {
            js_log_maybe!({
                event.stop_propagation();
                event.prevent_default();

                let mut related_target = event
                    .related_target()
                    .or_else(|| Some(JsValue::UNDEFINED.unchecked_into::<EventTarget>()))
                    .and_then(|x| x.dyn_into::<Element>().ok());

                // This is a wild chrome bug. `dragleave` can fire with the `relatedTarget`
                // property set to an element inside the closed `ShadowRoot` hosted by a
                // browser-native `<select>` tag, which fails the `.contains()` check
                // below.  This mystery `ShadowRoot` has a structure that looks like this
                // (tested in Chrome 92), which we try to detect as best we can below.
                //
                // ```html
                // <div aria-hidden="true">Selected Text Here</siv>
                // <slot name="user-agent-custom-assign-slot"></slot>
                // ```
                //
                // This is pretty course though, since there is no guarantee this structure
                // will be maintained in future Chrome versions; the `.expect()` in this
                // method chain should at least warn us if this regresses.
                //
                // Wait - you don't believe me?  Throw a debugger statement inside this
                // conditional and drag a column over a pivot-mode active columns list.
                if related_target
                    .as_ref()
                    .map(|x| x.has_attribute("aria-hidden"))
                    .unwrap_or_default()
                {
                    related_target = Some(
                        related_target
                            .into_jserror()?
                            .parent_node()
                            .into_jserror()?
                            .dyn_ref::<ShadowRoot>()
                            .ok_or_else(|| JsValue::from("Chrome drag/drop bug detection failed"))?
                            .host()
                            .unchecked_into::<Element>(),
                    )
                }

                let current_target = drag_ref.cast::<HtmlElement>().into_jserror()?;
                match related_target {
                    Some(ref related) => {
                        if !current_target.contains(Some(related)) {
                            callback();
                        }
                    }
                    None => {
                        // Safari (OSX and iOS) don't set `relatedTarget`, so we need to
                        // read a memoized value from the `"dragenter"` event.
                        let dataset = current_target.dataset();
                        if dataset.get("safaridragleave").is_some() {
                            dataset.delete("safaridragleave");
                        } else {
                            callback();
                        }
                    }
                };
            })
        }
    })
}
/// HTML drag/drop will fire a bubbling `dragleave` event over all children of a
/// `dragleave`-listened-to element, so we need to filter out the events from
/// the children elements with this esoteric DOM arcana.
HTML drag/drop will fire a bubbling `dragleave` event over all children of a
`dragleave`-listened-to element, so we need to filter out the events from
the children elements with this esoteric DOM arcana.
HTML drag / drop will fire a bubbling ` dragleave ` event over all children of a ` dragleave ` - listened - to element so we need to filter out the events from the children elements with this esoteric DOM arcana .
pub fn dragleave_helper(callback: impl Fn() + 'static, drag_ref: NodeRef) -> Callback<DragEvent> {
    Callback::from({
        clone!(drag_ref);
        move |event: DragEvent| {
            js_log_maybe!({
                event.stop_propagation();
                event.prevent_default();
                let mut related_target = event
                    .related_target()
                    .or_else(|| Some(JsValue::UNDEFINED.unchecked_into::<EventTarget>()))
                    .and_then(|x| x.dyn_into::<Element>().ok());
                // This is a wild chrome bug. `dragleave` can fire with the `relatedTarget`
                // property set to an element inside the closed `ShadowRoot` hosted by a
                // browser-native `<select>` tag, which fails the `.contains()` check
                // below.  This mystery `ShadowRoot` has a structure that looks like this
                // (tested in Chrome 92), which we try to detect as best we can below.
                //
                // ```html
                // <div aria-hidden="true">Selected Text Here</siv>
                // <slot name="user-agent-custom-assign-slot"></slot>
                // ```
                //
                // This is pretty course though, since there is no guarantee this structure
                // will be maintained in future Chrome versions; the `.expect()` in this
                // method chain should at least warn us if this regresses.
                //
                // Wait - you don't believe me?  Throw a debugger statement inside this
                // conditional and drag a column over a pivot-mode active columns list.
                if related_target
                    .as_ref()
                    .map(|x| x.has_attribute("aria-hidden"))
                    .unwrap_or_default()
                {
                    related_target = Some(
                        related_target
                            .into_jserror()?
                            .parent_node()
                            .into_jserror()?
                            .dyn_ref::<ShadowRoot>()
                            .ok_or_else(|| JsValue::from("Chrome drag/drop bug detection failed"))?
                            .host()
                            .unchecked_into::<Element>(),
                    )
                }
                let current_target = drag_ref.cast::<HtmlElement>().into_jserror()?;
                match related_target {
                    Some(ref related) => {
                        if !current_target.contains(Some(related)) {
                            callback();
                        }
                    }
                    None => {
                        // Safari (OSX and iOS) don't set `relatedTarget`, so we need to
                        // read a memoized value from the `"dragenter"` event.
                        let dataset = current_target.dataset();
                        if dataset.get("safaridragleave").is_some() {
                            dataset.delete("safaridragleave");
                        } else {
                            callback();
                        }
                    }
                };
            })
        }
    })
}
pub fn dragleave_helper ( callback : impl Fn ( ) + ' static , drag_ref : NodeRef ) -> Callback < DragEvent > { Callback :: from ( { clone ! ( drag_ref ) ; move | event : DragEvent | { js_log_maybe ! ( { event stop_propagation ( ) event prevent_default ( ) let mut related_target event related_target ( ) or_else ( Some ( JsValue UNDEFINED unchecked_into EventTarget ( ) ) ) and_then ( x x dyn_into Element ( ) ok ( ) ) // This is a wild chrome bug. `dragleave` can fire with the `relatedTarget` // property set to an element inside the closed `ShadowRoot` hosted by a // browser-native `<select>` tag, which fails the `.contains()` check // below.  This mystery `ShadowRoot` has a structure that looks like this // (tested in Chrome 92), which we try to detect as best we can below. // ```html // <div aria-hidden="true">Selected Text Here</siv> // <slot name="user-agent-custom-assign-slot"></slot> // ``` // This is pretty course though, since there is no guarantee this structure // will be maintained in future Chrome versions; the `.expect()` in this // method chain should at least warn us if this regresses. // Wait - you don't believe me?  Throw a debugger statement inside this // conditional and drag a column over a pivot-mode active columns list. if related_target as_ref ( ) map ( x x has_attribute ( " " ) ) unwrap_or_default ( ) { related_target Some ( related_target into_jserror ( ) parent_node ( ) into_jserror ( ) dyn_ref ShadowRoot ( ) ok_or_else ( JsValue from ( " " ) ) host ( ) unchecked_into Element ( ) ) } let current_target drag_ref cast HtmlElement ( ) into_jserror ( ) match related_target { Some ( ref related ) { if current_target contains ( Some ( related ) ) { callback ( ) } } None { // Safari (OSX and iOS) don't set `relatedTarget`, so we need to // read a memoized value from the `"dragenter"` event. let dataset current_target dataset ( ) if dataset get ( " " ) is_some ( ) { dataset delete ( " " ) } else { callback ( ) } } } } ) } } ) }
HTML drag/drop will fire a bubbling `dragleave` event over all children of a
`dragleave`-listened-to element, so we need to filter out the events from
the children elements with this esoteric DOM arcana.
HTML drag / drop will fire a bubbling ` dragleave ` event over all children of a ` dragleave ` - listened - to element so we need to filter out the events from the children elements with this esoteric DOM arcana .
callback
impl Fn() + 'static
drag_ref
NodeRef
callback
impl Fn() + 'static
drag_ref
NodeRef