From 27111a95831dc0dc846af8f889a9479294ab8515 Mon Sep 17 00:00:00 2001 From: Westbrook Johnson Date: Fri, 19 Mar 2021 11:25:17 -0400 Subject: [PATCH] fix(overlay): persist hover overlay when there is not click content --- packages/overlay/src/OverlayTrigger.ts | 10 ++- packages/overlay/src/overlay-stack.ts | 7 +- packages/overlay/stories/overlay.stories.ts | 1 + .../test/overlay-trigger-hover.test.ts | 78 ++++++++++++++++++- packages/overlay/test/overlay-trigger.test.ts | 1 + 5 files changed, 91 insertions(+), 6 deletions(-) diff --git a/packages/overlay/src/OverlayTrigger.ts b/packages/overlay/src/OverlayTrigger.ts index 273e36dc71..bfc996198f 100644 --- a/packages/overlay/src/OverlayTrigger.ts +++ b/packages/overlay/src/OverlayTrigger.ts @@ -24,6 +24,7 @@ import { Placement, TriggerInteractions, OverlayOptions, + OverlayOpenCloseDetail, } from './overlay-types'; import { openOverlay } from './loader.js'; import overlayTriggerStyles from './overlay-trigger.css.js'; @@ -75,8 +76,10 @@ export class OverlayTrigger extends LitElement { private hoverContent?: HTMLElement; private targetContent?: HTMLElement; - private handleClose(): void { - this.removeAttribute('open'); + private handleClose(event?: CustomEvent): void { + if (!event || this.open === event.detail.interaction) { + this.removeAttribute('open'); + } } protected render(): TemplateResult { @@ -145,6 +148,7 @@ export class OverlayTrigger extends LitElement { case 'longpress': if (!this.closeLongpressOverlay) { this.onTriggerLongpress(); + this.onTriggerMouseLeave(); } break; default: @@ -209,6 +213,8 @@ export class OverlayTrigger extends LitElement { case 'click': if (this.clickContent) { this.open = event.type; + } else if (this.closeHoverOverlay) { + event.preventDefault(); } return; case 'longpress': diff --git a/packages/overlay/src/overlay-stack.ts b/packages/overlay/src/overlay-stack.ts index 25d219a6a2..0bac5d442d 100644 --- a/packages/overlay/src/overlay-stack.ts +++ b/packages/overlay/src/overlay-stack.ts @@ -411,14 +411,15 @@ export class OverlayStack { private initialLongpressClick = false; - private handleMouse = (): void => { + private handleMouse = (event: Event): void => { if (this.initialLongpressClick) { this.initialLongpressClick = false; return; } - if (!this.preventMouseRootClose) { - this.closeTopOverlay(); + if (this.preventMouseRootClose || event.defaultPrevented) { + return; } + this.closeTopOverlay(); }; private handleKeyUp = (event: KeyboardEvent): void => { diff --git a/packages/overlay/stories/overlay.stories.ts b/packages/overlay/stories/overlay.stories.ts index 7c3a05d9c8..1fc4bb7425 100644 --- a/packages/overlay/stories/overlay.stories.ts +++ b/packages/overlay/stories/overlay.stories.ts @@ -483,6 +483,7 @@ export const longpress = (): TemplateResult => { + Search real hard... diff --git a/packages/overlay/test/overlay-trigger-hover.test.ts b/packages/overlay/test/overlay-trigger-hover.test.ts index 880791c0e8..5fbc66b27d 100644 --- a/packages/overlay/test/overlay-trigger-hover.test.ts +++ b/packages/overlay/test/overlay-trigger-hover.test.ts @@ -9,13 +9,20 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { fixture, elementUpdated, waitUntil, html } from '@open-wc/testing'; +import { + fixture, + elementUpdated, + waitUntil, + html, + expect, +} from '@open-wc/testing'; import '@spectrum-web-components/popover/sp-popover.js'; import '@spectrum-web-components/action-button/sp-action-button.js'; import '@spectrum-web-components/icons-workflow/icons/sp-icon-magnify.js'; import { OverlayTrigger } from '..'; import '@spectrum-web-components/overlay/overlay-trigger.js'; import { spy } from 'sinon'; +import { ActionButton } from '@spectrum-web-components/action-button'; describe('Overlay Trigger - Hover', () => { it('displays `hover` declaratively', async () => { @@ -50,4 +57,73 @@ describe('Overlay Trigger - Hover', () => { timeout: 2000, }); }); + it('persists hover content', async () => { + const el = await fixture( + (() => html` + + + + + + + `)() + ); + await elementUpdated(el); + + expect(el.open).to.be.undefined; + + const trigger = el.querySelector('[slot="trigger"]') as ActionButton; + trigger.dispatchEvent( + new Event('mouseenter', { + bubbles: true, + }) + ); + + await elementUpdated(el); + + expect(el.open).to.equal('hover'); + + trigger.click(); + + await elementUpdated(el); + + expect(el.open).to.equal('hover'); + }); + it('closes persistent hover content on `longpress`', async () => { + const el = await fixture( + (() => html` + + + + + + + + `)() + ); + await elementUpdated(el); + + expect(el.open).to.be.undefined; + + const trigger = el.querySelector('[slot="trigger"]') as ActionButton; + trigger.dispatchEvent( + new Event('mouseenter', { + bubbles: true, + }) + ); + + await elementUpdated(el); + + expect(el.open).to.equal('hover'); + + trigger.dispatchEvent( + new Event('longpress', { + bubbles: true, + }) + ); + + await elementUpdated(el); + + expect(el.open).to.equal('longpress'); + }); }); diff --git a/packages/overlay/test/overlay-trigger.test.ts b/packages/overlay/test/overlay-trigger.test.ts index c702fb8215..ee43195abc 100644 --- a/packages/overlay/test/overlay-trigger.test.ts +++ b/packages/overlay/test/overlay-trigger.test.ts @@ -840,6 +840,7 @@ describe('Overlay Trigger', () => { 'open' ); + await nextFrame(); document.body.click(); await elementUpdated(overlayTriggers[1]); await waitUntil(() => {