diff --git a/packages/react-juce/package-lock.json b/packages/react-juce/package-lock.json index 0102e68b..386b0c3a 100644 --- a/packages/react-juce/package-lock.json +++ b/packages/react-juce/package-lock.json @@ -1,6 +1,6 @@ { "name": "react-juce", - "version": "0.2.13", + "version": "0.2.11", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2140,16 +2140,8 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "color-string": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.4.tgz", - "integrity": "sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "colorette": { "version": "1.2.1", @@ -3292,11 +3284,6 @@ } } }, - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", @@ -4546,14 +4533,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "requires": { - "is-arrayish": "^0.3.1" - } - }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", diff --git a/packages/react-juce/src/lib/Backend.ts b/packages/react-juce/src/lib/Backend.ts index 307054cf..7835418d 100644 --- a/packages/react-juce/src/lib/Backend.ts +++ b/packages/react-juce/src/lib/Backend.ts @@ -276,6 +276,12 @@ NativeMethods.dispatchViewEvent = function dispatchEvent( return; } + // mouseEnter and mouseLeave events do not bubble + // https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseenter_event + if ((eventType === "onMouseEnter") || (eventType === "onMouseLeave")) { + event.stopPropagation(); + } + __bubbleEvent(instance, eventType, event); } }; diff --git a/react_juce/core/ReactApplicationRoot.h b/react_juce/core/ReactApplicationRoot.h index ae039cf2..5eb24c59 100644 --- a/react_juce/core/ReactApplicationRoot.h +++ b/react_juce/core/ReactApplicationRoot.h @@ -63,6 +63,29 @@ namespace reactjuce bool keyPressed(const juce::KeyPress& key) override; #endif + juce::Component* componentUnderMouse; + + void mouseDrag(const juce::MouseEvent &e) override { + auto* newComponentUnderMouse = getComponentAt(e.x, e.y); + + if (componentUnderMouse != newComponentUnderMouse){ + // The old target may need a mouseLeave event now + if (componentUnderMouse != nullptr) { + if (auto v = dynamic_cast(componentUnderMouse)){ + v->checkMouseEnter(e.getEventRelativeTo(v)); + } + } + + // The new target may need a mouseEnter event now + if (auto v = dynamic_cast(newComponentUnderMouse)){ + v->checkMouseEnter(e.getEventRelativeTo(v)); + } + + } + + componentUnderMouse = newComponentUnderMouse; + } + //============================================================================== /** Evaluates a javascript bundle file in the EcmascriptEngine. * diff --git a/react_juce/core/View.cpp b/react_juce/core/View.cpp index 9ec07350..dc74dc21 100644 --- a/react_juce/core/View.cpp +++ b/react_juce/core/View.cpp @@ -248,18 +248,52 @@ namespace reactjuce void View::mouseEnter (const juce::MouseEvent& e) { - dispatchViewEvent("onMouseEnter", detail::makeViewEventObject(e, *this)); + if (!wasMouseOver) + { + dispatchViewEvent("onMouseEnter", detail::makeViewEventObject(e, *this)); + } + + wasMouseOver = true; } void View::mouseExit (const juce::MouseEvent& e) { - dispatchViewEvent("onMouseLeave", detail::makeViewEventObject(e, *this)); + if (!reallyContains(e.getPosition(), true)) + { + if (wasMouseOver) + { + dispatchViewEvent("onMouseLeave", detail::makeViewEventObject(e, *this)); + } + + wasMouseOver = false; + } else { + wasMouseOver = true; + } + } + + void View::checkMouseEnter(const juce::MouseEvent& e) + { + bool isMouseOverNow = reallyContains(e.getPosition(), true); + + if (!wasMouseOver && isMouseOverNow){ + mouseEnter(e); + } else if (wasMouseOver && !isMouseOverNow) { + mouseExit(e); + } } void View::mouseDrag (const juce::MouseEvent& e) { // TODO: mouseDrag isn't a dom event... is it? dispatchViewEvent("onMouseDrag", detail::makeViewEventObject(e, *this)); + + // mouseDrags are always dispatched to the component originaly clicked + // so send this up to the ReactApplicationRoot to check for necessary + // enter and leave events. Maybe this should ReactApplicationRoot should just + // be a mouseListener for all its children instead? + if (auto* parent = findParentComponentOfClass()) + parent->mouseDrag(e.getEventRelativeTo(parent)); + } void View::mouseDoubleClick (const juce::MouseEvent& e) diff --git a/react_juce/core/View.h b/react_juce/core/View.h index 827c1b10..bcba623d 100644 --- a/react_juce/core/View.h +++ b/react_juce/core/View.h @@ -103,6 +103,7 @@ namespace reactjuce /** Invokes an "exported" native method on the View instance */ juce::var invokeMethod(const juce::String &method, const juce::var::NativeFunctionArgs &args); + void checkMouseEnter(const juce::MouseEvent& e); protected: //============================================================================== /** Exports/Registers a method on this View instance so it may be called @@ -114,11 +115,12 @@ namespace reactjuce //============================================================================== juce::NamedValueSet props; juce::Rectangle cachedFloatBounds; - private: //============================================================================== juce::Uuid _viewId; juce::Identifier _refId; + bool wasMouseOver = false; + std::unordered_map nativeMethods;