Skip to content

Commit 1dec2ef

Browse files
committed
fix: hover box doesn't get dismissed when cursor leaves the preview slowly
1 parent 515b4a0 commit 1dec2ef

3 files changed

Lines changed: 41 additions & 12 deletions

File tree

src/LiveDevelopment/BrowserScripts/RemoteFunctions.js

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -595,14 +595,13 @@ function RemoteFunctions(config = {}) {
595595
}
596596

597597
const element = event.target;
598-
if(!LivePreviewView.isElementInspectable(element) || element.nodeType !== Node.ELEMENT_NODE) {
599-
return;
600-
}
601598

602-
// Same element as last hover — nothing changed, skip entirely
603599
if (element === _lastHoverTarget) {
604600
return;
605601
}
602+
if(!LivePreviewView.isElementInspectable(element) || element.nodeType !== Node.ELEMENT_NODE) {
603+
return;
604+
}
606605
_lastHoverTarget = element;
607606

608607
// if _hoverHighlight is uninitialized, initialize it
@@ -615,21 +614,30 @@ function RemoteFunctions(config = {}) {
615614
}
616615
}
617616

618-
function onElementHoverOut(event) {
619-
// don't want highlighting and stuff when auto scrolling
620-
if (SHARED_STATE.isAutoScrolling) { return; }
617+
function _clearHoverState() {
618+
if (SHARED_STATE.isAutoScrolling) {
619+
return;
620+
}
621+
if (_hoverHighlight && shouldShowHighlightOnHover()) {
622+
_lastHoverTarget = null;
623+
_scheduleHoverUpdate();
624+
}
625+
}
621626

627+
function onElementHoverOut(event) {
622628
const element = event.target;
623629
// Use isElementInspectable (not isElementEditable) so that JS-rendered
624630
// elements also get their hover highlight and hover box properly dismissed.
625631
if(LivePreviewView.isElementInspectable(element) && element.nodeType === Node.ELEMENT_NODE) {
626-
if (_hoverHighlight && shouldShowHighlightOnHover()) {
627-
_lastHoverTarget = null;
628-
_scheduleHoverUpdate();
629-
}
632+
_clearHoverState();
630633
}
631634
}
632635

636+
// for popped out window: the in-panel iframe case is forwarded parent-side via _LD.clearHoverState().
637+
function onDocumentMouseLeave() {
638+
_clearHoverState();
639+
}
640+
633641
function scrollElementToViewPort(element) {
634642
if (!element) {
635643
return;
@@ -711,7 +719,9 @@ function RemoteFunctions(config = {}) {
711719

712720
function disableHoverListeners() {
713721
window.document.removeEventListener("mouseover", onElementHover);
722+
window.document.removeEventListener("mousemove", onElementHover);
714723
window.document.removeEventListener("mouseout", onElementHoverOut);
724+
window.document.documentElement.removeEventListener("mouseleave", onDocumentMouseLeave);
715725
// Cancel any pending rAF hover update so stale callbacks don't fire
716726
if (_pendingHoverRAF) {
717727
cancelAnimationFrame(_pendingHoverRAF);
@@ -732,7 +742,9 @@ function RemoteFunctions(config = {}) {
732742
if (config.mode === 'edit' && shouldShowHighlightOnHover()) {
733743
disableHoverListeners();
734744
window.document.addEventListener("mouseover", onElementHover);
745+
window.document.addEventListener("mousemove", onElementHover);
735746
window.document.addEventListener("mouseout", onElementHoverOut);
747+
window.document.documentElement.addEventListener("mouseleave", onDocumentMouseLeave);
736748
}
737749
}
738750

@@ -1714,7 +1726,8 @@ function RemoteFunctions(config = {}) {
17141726
"getHighlightCount": getHighlightCount,
17151727
"getHighlightTrackingElement": getHighlightTrackingElement,
17161728
"getHighlightStyle": getHighlightStyle,
1717-
"setHotCornerHidden": setHotCornerHidden
1729+
"setHotCornerHidden": setHotCornerHidden,
1730+
"clearHoverState": _clearHoverState
17181731
};
17191732

17201733
// the below code comment is replaced by added scripts for extensibility

src/LiveDevelopment/LiveDevMultiBrowser.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,16 @@ define(function (require, exports, module) {
733733
}
734734
}
735735

736+
/**
737+
* Clear hover highlight and hover box in the preview. Forwarded from the parent because the
738+
* previewed iframe does not reliably receive mouseout/mouseleave on a slow pointer exit.
739+
*/
740+
function clearHoverState() {
741+
if (_protocol) {
742+
_protocol.evaluate("_LD.clearHoverState && _LD.clearHoverState()");
743+
}
744+
}
745+
736746
/**
737747
* Update configuration in the remote browser
738748
*/
@@ -860,6 +870,7 @@ define(function (require, exports, module) {
860870
exports.showHighlight = showHighlight;
861871
exports.hideHighlight = hideHighlight;
862872
exports.redrawHighlight = redrawHighlight;
873+
exports.clearHoverState = clearHoverState;
863874
exports.getConfig = getConfig;
864875
exports.updateConfig = updateConfig;
865876
exports.refreshConfig = refreshConfig;

src/extensionsIntegrated/Phoenix-live-preview/main.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,11 @@ define(function (require, exports, module) {
828828
$panel.find(".custom-server-banner-close-icon").on("click", ()=>{
829829
$panel.find(".live-preview-custom-banner").addClass("forced-hidden");
830830
});
831+
// The previewed iframe does not reliably fire mouseout/mouseleave on a slow pointer exit,
832+
// leaving the hover highlight/box stuck. Detect the leave parent-side and forward a clear.
833+
$panel.on("mouseleave", "#panel-live-preview-frame", function () {
834+
MultiBrowserLiveDev.clearHoverState();
835+
});
831836
$iframe[0].onload = function () {
832837
$iframe.attr('srcdoc', null);
833838
};

0 commit comments

Comments
 (0)