Merge pull request #436 from ing-bank/feat/closeEventOnOverlay

feat(overlay): close/hide events on dom (OverlayMixin) level
This commit is contained in:
Thomas Allmer 2019-12-11 16:31:03 +01:00 committed by GitHub
commit eefd2e61b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 268 additions and 92 deletions

View file

@ -2,11 +2,6 @@ import { withModalDialogConfig, OverlayMixin } from '@lion/overlays';
import { LitElement, html } from '@lion/core'; import { LitElement, html } from '@lion/core';
export class LionDialog extends OverlayMixin(LitElement) { export class LionDialog extends OverlayMixin(LitElement) {
constructor() {
super();
this.closeEventName = 'dialog-close';
}
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
_defineOverlayConfig() { _defineOverlayConfig() {
return { return {
@ -15,6 +10,7 @@ export class LionDialog extends OverlayMixin(LitElement) {
} }
_setupOpenCloseListeners() { _setupOpenCloseListeners() {
super._setupOpenCloseListeners();
this.__toggle = () => { this.__toggle = () => {
this.opened = !this.opened; this.opened = !this.opened;
}; };
@ -25,6 +21,7 @@ export class LionDialog extends OverlayMixin(LitElement) {
} }
_teardownOpenCloseListeners() { _teardownOpenCloseListeners() {
super._teardownOpenCloseListeners();
if (this._overlayInvokerNode) { if (this._overlayInvokerNode) {
this._overlayInvokerNode.removeEventListener('click', this.__toggle); this._overlayInvokerNode.removeEventListener('click', this.__toggle);
} }

View file

@ -80,7 +80,7 @@ storiesOf('Overlays Specific WC | Dialog', module)
Hello! You can close this notification here: Hello! You can close this notification here:
<button <button
class="close-button" class="close-button"
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
> >
</button> </button>
@ -97,7 +97,7 @@ storiesOf('Overlays Specific WC | Dialog', module)
Hello! You can close this notification here: Hello! You can close this notification here:
<button <button
class="close-button" class="close-button"
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
> >
</button> </button>
@ -123,7 +123,7 @@ storiesOf('Overlays Specific WC | Dialog', module)
Hello! You can close this notification here: Hello! You can close this notification here:
<button <button
class="close-button" class="close-button"
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
> >
</button> </button>

View file

@ -90,9 +90,8 @@ export class LionCalendarOverlayFrame extends LocalizeMixin(LitElement) {
]; ];
} }
__dispatchHideEvent() { __dispatchCloseEvent() {
// Designed to work in conjunction with ModalDialogController this.dispatchEvent(new Event('close-overlay'), { bubbles: true });
this.dispatchEvent(new CustomEvent('hide'), { bubbles: true });
} }
render() { render() {
@ -104,7 +103,7 @@ export class LionCalendarOverlayFrame extends LocalizeMixin(LitElement) {
<slot name="heading"></slot> <slot name="heading"></slot>
</h1> </h1>
<button <button
@click="${this.__dispatchHideEvent}" @click="${this.__dispatchCloseEvent}"
id="close-button" id="close-button"
title="${this.msgLit('lion-calendar-overlay-frame:close')}" title="${this.msgLit('lion-calendar-overlay-frame:close')}"
aria-label="${this.msgLit('lion-calendar-overlay-frame:close')}" aria-label="${this.msgLit('lion-calendar-overlay-frame:close')}"

View file

@ -343,6 +343,10 @@ export class LionInputDatepicker extends OverlayMixin(LionInputDate) {
* @override Configures OverlayMixin * @override Configures OverlayMixin
*/ */
get _overlayContentNode() { get _overlayContentNode() {
return this.shadowRoot.querySelector('lion-calendar-overlay-frame'); if (this._cachedOverlayContentNode) {
return this._cachedOverlayContentNode;
}
this._cachedOverlayContentNode = this.shadowRoot.querySelector('lion-calendar-overlay-frame');
return this._cachedOverlayContentNode;
} }
} }

View file

@ -41,7 +41,7 @@ html`
<div slot="content"> <div slot="content">
This is an overlay This is an overlay
<button <button
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e => e.target.dispatchEvent(new Event('overlay-close', { bubbles: true }))}
>x</button> >x</button>
<div> <div>
<button slot="invoker"> <button slot="invoker">

View file

@ -33,7 +33,6 @@ export class OverlayController {
trapsKeyboardFocus: false, trapsKeyboardFocus: false,
hidesOnEsc: false, hidesOnEsc: false,
hidesOnOutsideClick: false, hidesOnOutsideClick: false,
hidesOnHideEventInContentNode: true,
isTooltip: false, isTooltip: false,
handlesUserInteraction: false, handlesUserInteraction: false,
handlesAccessibility: false, handlesAccessibility: false,
@ -244,13 +243,17 @@ export class OverlayController {
if (this.isShown) { if (this.isShown) {
return; return;
} }
this.dispatchEvent(new Event('before-show'));
const event = new CustomEvent('before-show', { cancelable: true });
this.dispatchEvent(event);
if (!event.defaultPrevented) {
this._contentNodeWrapper.style.display = this.placementMode === 'local' ? 'inline-block' : ''; this._contentNodeWrapper.style.display = this.placementMode === 'local' ? 'inline-block' : '';
await this._handleFeatures({ phase: 'show' }); await this._handleFeatures({ phase: 'show' });
await this._handlePosition({ phase: 'show' }); await this._handlePosition({ phase: 'show' });
this.elementToFocusAfterHide = elementToFocusAfterHide; this.elementToFocusAfterHide = elementToFocusAfterHide;
this.dispatchEvent(new Event('show')); this.dispatchEvent(new Event('show'));
} }
}
async _handlePosition({ phase }) { async _handlePosition({ phase }) {
if (this.placementMode === 'global') { if (this.placementMode === 'global') {
@ -285,13 +288,16 @@ export class OverlayController {
return; return;
} }
this.dispatchEvent(new Event('before-hide')); const event = new CustomEvent('before-hide', { cancelable: true });
this.dispatchEvent(event);
if (!event.defaultPrevented) {
// await this.transitionHide({ backdropNode: this.backdropNode, conentNode: this.contentNode }); // await this.transitionHide({ backdropNode: this.backdropNode, conentNode: this.contentNode });
this._contentNodeWrapper.style.display = 'none'; this._contentNodeWrapper.style.display = 'none';
this._handleFeatures({ phase: 'hide' }); this._handleFeatures({ phase: 'hide' });
this.dispatchEvent(new Event('hide')); this.dispatchEvent(new Event('hide'));
this._restoreFocus(); this._restoreFocus();
} }
}
// eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars // eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
async transitionHide({ backdropNode, contentNode }) {} async transitionHide({ backdropNode, contentNode }) {}
@ -337,9 +343,6 @@ export class OverlayController {
if (this.hidesOnOutsideClick) { if (this.hidesOnOutsideClick) {
this._handleHidesOnOutsideClick({ phase }); this._handleHidesOnOutsideClick({ phase });
} }
if (this.hidesOnHideEventInContentNode) {
this._handleHidesOnHideEventInContentNode({ phase });
}
if (this.handlesAccessibility) { if (this.handlesAccessibility) {
this._handleAccessibility({ phase }); this._handleAccessibility({ phase });
} }
@ -498,18 +501,6 @@ export class OverlayController {
} }
} }
_handleHidesOnHideEventInContentNode({ phase }) {
if (phase === 'show') {
this.__hideEventInContentNodeHandler = ev => {
ev.stopPropagation();
this.hide();
};
this.contentNode.addEventListener('hide', this.__hideEventInContentNodeHandler);
} else if (phase === 'hide') {
this.contentNode.removeEventListener('keyup', this.__hideEventInContentNodeHandler);
}
}
_handleInheritsReferenceWidth() { _handleInheritsReferenceWidth() {
if (!this._referenceNode) { if (!this._referenceNode) {
return; return;

View file

@ -36,6 +36,13 @@ export const OverlayMixin = dedupeMixin(
this.__config = value; this.__config = value;
} }
_requestUpdate(name, oldValue) {
super._requestUpdate(name, oldValue);
if (name === 'opened') {
this.dispatchEvent(new Event('opened-changed'));
}
}
/** /**
* @overridable method `_defineOverlay` * @overridable method `_defineOverlay`
* @desc returns an instance of a (dynamic) overlay controller * @desc returns an instance of a (dynamic) overlay controller
@ -81,14 +88,32 @@ export const OverlayMixin = dedupeMixin(
* For example, set a click event listener on _overlayInvokerNode to set opened to true * For example, set a click event listener on _overlayInvokerNode to set opened to true
*/ */
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
_setupOpenCloseListeners() {} _setupOpenCloseListeners() {
this.__closeEventInContentNodeHandler = ev => {
ev.stopPropagation();
this._overlayCtrl.hide();
};
if (this._overlayContentNode) {
this._overlayContentNode.addEventListener(
'close-overlay',
this.__closeEventInContentNodeHandler,
);
}
}
/** /**
* @overridable * @overridable
* @desc use this method to tear down your event listeners * @desc use this method to tear down your event listeners
*/ */
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
_teardownOpenCloseListeners() {} _teardownOpenCloseListeners() {
if (this._overlayContentNode) {
this._overlayContentNode.removeEventListener(
'close-overlay',
this.__closeEventInContentNodeHandler,
);
}
}
firstUpdated(changedProperties) { firstUpdated(changedProperties) {
super.firstUpdated(changedProperties); super.firstUpdated(changedProperties);
@ -110,7 +135,9 @@ export const OverlayMixin = dedupeMixin(
} }
get _overlayContentNode() { get _overlayContentNode() {
let contentNode; if (this._cachedOverlayContentNode) {
return this._cachedOverlayContentNode;
}
// FIXME: This should shadow outlet in between the host and the content slot, is a problem // FIXME: This should shadow outlet in between the host and the content slot, is a problem
// Should simply be Array.from(this.children).find(child => child.slot === 'content') // Should simply be Array.from(this.children).find(child => child.slot === 'content')
@ -119,15 +146,15 @@ export const OverlayMixin = dedupeMixin(
child => child.slot === '_overlay-shadow-outlet', child => child.slot === '_overlay-shadow-outlet',
); );
if (shadowOutlet) { if (shadowOutlet) {
contentNode = Array.from(shadowOutlet.children).find(child => child.slot === 'content'); this._cachedOverlayContentNode = Array.from(shadowOutlet.children).find(
child => child.slot === 'content',
);
} else { } else {
contentNode = Array.from(this.children).find(child => child.slot === 'content'); this._cachedOverlayContentNode = Array.from(this.children).find(
child => child.slot === 'content',
);
} }
return this._cachedOverlayContentNode;
if (contentNode) {
this._cachedOverlayContentNode = contentNode;
}
return contentNode || this._cachedOverlayContentNode;
} }
_setupOverlayCtrl() { _setupOverlayCtrl() {
@ -137,7 +164,6 @@ export const OverlayMixin = dedupeMixin(
}); });
this.__syncToOverlayController(); this.__syncToOverlayController();
this.__setupSyncFromOverlayController(); this.__setupSyncFromOverlayController();
this._setupOpenCloseListeners(); this._setupOpenCloseListeners();
} }
@ -151,22 +177,38 @@ export const OverlayMixin = dedupeMixin(
this.__onOverlayCtrlShow = () => { this.__onOverlayCtrlShow = () => {
this.opened = true; this.opened = true;
}; };
this.__onOverlayCtrlHide = () => { this.__onOverlayCtrlHide = () => {
this.opened = false; this.opened = false;
}; };
this.__onBeforeShow = () => {
this.dispatchEvent(new Event('before-show')); this.__onBeforeShow = beforeShowEvent => {
const event = new CustomEvent('before-opened', { cancelable: true });
this.dispatchEvent(event);
if (event.defaultPrevented) {
beforeShowEvent.preventDefault();
}
};
this.__onBeforeHide = beforeHideEvent => {
const event = new CustomEvent('before-closed', { cancelable: true });
this.dispatchEvent(event);
if (event.defaultPrevented) {
beforeHideEvent.preventDefault();
}
}; };
this._overlayCtrl.addEventListener('show', this.__onOverlayCtrlShow); this._overlayCtrl.addEventListener('show', this.__onOverlayCtrlShow);
this._overlayCtrl.addEventListener('hide', this.__onOverlayCtrlHide); this._overlayCtrl.addEventListener('hide', this.__onOverlayCtrlHide);
this._overlayCtrl.addEventListener('before-show', this.__onBeforeShow); this._overlayCtrl.addEventListener('before-show', this.__onBeforeShow);
this._overlayCtrl.addEventListener('before-hide', this.__onBeforeHide);
} }
__teardownSyncFromOverlayController() { __teardownSyncFromOverlayController() {
this._overlayCtrl.removeEventListener('show', this.__onOverlayCtrlShow); this._overlayCtrl.removeEventListener('show', this.__onOverlayCtrlShow);
this._overlayCtrl.removeEventListener('hide', this.__onOverlayCtrlHide); this._overlayCtrl.removeEventListener('hide', this.__onOverlayCtrlHide);
this._overlayCtrl.removeEventListener('before-show', this.__onBeforeShow); this._overlayCtrl.removeEventListener('before-show', this.__onBeforeShow);
this._overlayCtrl.removeEventListener('before-hide', this.__onBeforeHide);
} }
__syncToOverlayController() { __syncToOverlayController() {

View file

@ -99,6 +99,7 @@ customElements.define(
} }
_setupOpenCloseListeners() { _setupOpenCloseListeners() {
super._setupOpenCloseListeners();
this.__toggle = () => { this.__toggle = () => {
this.opened = !this.opened; this.opened = !this.opened;
}; };
@ -106,6 +107,7 @@ customElements.define(
} }
_teardownOpenCloseListeners() { _teardownOpenCloseListeners() {
super._teardownOpenCloseListeners();
this._overlayInvokerNode.removeEventListener('click', this.__toggle); this._overlayInvokerNode.removeEventListener('click', this.__toggle);
} }
@ -149,7 +151,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
Hello! You can close this notification here: Hello! You can close this notification here:
<button <button
class="close-button" class="close-button"
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
> >
</button> </button>
@ -168,7 +170,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
Hello! You can close this notification here: Hello! You can close this notification here:
<button <button
class="close-button" class="close-button"
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
> >
</button> </button>
@ -197,7 +199,9 @@ storiesOf('Overlay System | Overlay as a WC', module)
<div slot="content" class="demo-overlay"> <div slot="content" class="demo-overlay">
<div> <div>
Hello! This is a notification. Hello! This is a notification.
<button @click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))}> <button
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
>
Close Close
</button> </button>
<lion-demo-overlay <lion-demo-overlay
@ -208,7 +212,8 @@ storiesOf('Overlay System | Overlay as a WC', module)
Hello! You can close this notification here: Hello! You can close this notification here:
<button <button
class="close-button" class="close-button"
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e =>
e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
> >
</button> </button>
@ -234,7 +239,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
Hello! You can close this notification here: Hello! You can close this notification here:
<button <button
class="close-button" class="close-button"
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
> >
</button> </button>
@ -299,7 +304,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
Hello! You can close this notification here: Hello! You can close this notification here:
<button <button
class="close-button" class="close-button"
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
> >
</button> </button>
@ -355,7 +360,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
<p>Close and open it again on a small screen (< 600px) and it will be a bottom sheet</p> <p>Close and open it again on a small screen (< 600px) and it will be a bottom sheet</p>
<lion-demo-overlay <lion-demo-overlay
.config=${{ ...withBottomSheetConfig() }} .config=${{ ...withBottomSheetConfig() }}
@before-show=${e => { @before-opened=${e => {
if (window.innerWidth >= 600) { if (window.innerWidth >= 600) {
e.target.config = { ...withModalDialogConfig() }; e.target.config = { ...withModalDialogConfig() };
} else { } else {
@ -368,7 +373,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
Hello! You can close this notification here: Hello! You can close this notification here:
<button <button
class="close-button" class="close-button"
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
> >
</button> </button>
@ -450,6 +455,87 @@ storiesOf('Overlay System | Overlay as a WC', module)
${popup} ${popup}
</div> </div>
`; `;
})
.add('Sync application state', () => {
const appState = {
opened: true,
};
const openedStateNode = renderOffline(
html`
<span>${appState.opened}</span>
`,
);
function onOpenClosed(ev) {
appState.opened = ev.target.opened;
openedStateNode.innerText = appState.opened;
}
const popup = renderOffline(html`
<lion-demo-overlay .opened="${appState.opened}" @opened-changed=${onOpenClosed}>
<button slot="invoker">Overlay</button>
<div slot="content" class="demo-overlay">
Hello! You can close this notification here:
<button
class="close-button"
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
>
</button>
</div>
</lion-demo-overlay>
`);
return html`
<style>
${overlayDemoStyle}
</style>
appState.opened: ${openedStateNode}
<div class="demo-box_placements">
${popup}
</div>
`;
})
.add('Intercept open/close', () => {
let shouldIntercept = true;
let shouldInterceptButton;
function toggleIntercept() {
shouldIntercept = !shouldIntercept;
shouldInterceptButton.textContent = shouldIntercept;
}
function intercept(ev) {
if (shouldIntercept) {
ev.preventDefault();
}
}
shouldInterceptButton = renderOffline(
html`
<button @click="${toggleIntercept}">${shouldIntercept}</button>
`,
);
const popup = renderOffline(html`
<lion-demo-overlay @before-closed=${intercept} @before-opened=${intercept}>
<button slot="invoker">Overlay</button>
<div slot="content" class="demo-overlay">
Hello! You can close this notification here:
<button
class="close-button"
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
>
</button>
</div>
</lion-demo-overlay>
`);
return html`
<style>
${overlayDemoStyle}
</style>
toggle shouldIntercept:${shouldInterceptButton}
<div class="demo-box_placements">
${popup}
</div>
`;
}); });
/* .add('Toggle placement with knobs', () => { /* .add('Toggle placement with knobs', () => {
@ -467,7 +553,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
Hello! You can close this notification here: Hello! You can close this notification here:
<button <button
class="close-button" class="close-button"
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))} @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
></button ></button
> >
</div> </div>

View file

@ -1,4 +1,5 @@
import { expect, fixture, html, aTimeout } from '@open-wc/testing'; import { expect, fixture, html, aTimeout } from '@open-wc/testing';
import sinon from 'sinon';
export function runOverlayMixinSuite({ /* tagString, */ tag, suffix = '' }) { export function runOverlayMixinSuite({ /* tagString, */ tag, suffix = '' }) {
describe(`OverlayMixin${suffix}`, () => { describe(`OverlayMixin${suffix}`, () => {
@ -53,5 +54,87 @@ export function runOverlayMixinSuite({ /* tagString, */ tag, suffix = '' }) {
itEl.config = { viewportConfig: { placement: 'left' } }; itEl.config = { viewportConfig: { placement: 'left' } };
expect(itEl._overlayCtrl.viewportConfig.placement).to.equal('left'); expect(itEl._overlayCtrl.viewportConfig.placement).to.equal('left');
}); });
it('fires "opened-changed" event on hide', async () => {
const spy = sinon.spy();
el = await fixture(html`
<${tag} @opened-changed="${spy}">
<div slot="content">content of the overlay</div>
<button slot="invoker">invoker button</button>
</${tag}>
`);
expect(spy).not.to.have.been.called;
await el._overlayCtrl.show();
expect(spy.callCount).to.equal(1);
expect(el.opened).to.be.true;
await el._overlayCtrl.hide();
expect(spy.callCount).to.equal(2);
expect(el.opened).to.be.false;
});
it('fires "before-closed" event on hide', async () => {
const beforeSpy = sinon.spy();
el = await fixture(html`
<${tag} @before-closed="${beforeSpy}" .opened="${true}">
<div slot="content">content of the overlay</div>
<button slot="invoker">invoker button</button>
</${tag}>
`);
expect(beforeSpy).not.to.have.been.called;
await el._overlayCtrl.hide();
expect(beforeSpy).to.have.been.called;
expect(el.opened).to.be.false;
});
it('fires before-opened" event on show', async () => {
const beforeSpy = sinon.spy();
el = await fixture(html`
<${tag} @before-opened="${beforeSpy}">
<div slot="content">content of the overlay</div>
<button slot="invoker">invoker button</button>
</${tag}>
`);
expect(beforeSpy).not.to.have.been.called;
await el._overlayCtrl.show();
expect(beforeSpy).to.have.been.called;
expect(el.opened).to.be.true;
});
it('allows to call `preventDefault()` on "before-opened"/"before-closed" events', async () => {
function preventer(ev) {
ev.preventDefault();
}
el = await fixture(html`
<${tag} @before-opened="${preventer}" @before-closed="${preventer}">
<div slot="content">content of the overlay</div>
<button slot="invoker">invoker button</button>
</${tag}>
`);
await el._overlayCtrl.show();
expect(el.opened).to.be.false;
});
it('hides content on "close-overlay" event within the content ', async () => {
function sendCloseEvent(e) {
e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }));
}
const closeBtn = await fixture(html`
<button @click=${sendCloseEvent}>
close
</button>
`);
el = await fixture(html`
<${tag} opened>
<div slot="content">
content of the overlay
${closeBtn}
</div>
<button slot="invoker">invoker button</button>
</${tag}>
`);
closeBtn.click();
expect(el.opened).to.be.false;
});
}); });
} }

View file

@ -314,33 +314,6 @@ describe('OverlayController', () => {
}); });
}); });
describe('hidesOnHideEventInContentNode', () => {
it('hides content on hide event within the content ', async () => {
const ctrl = new OverlayController({
...withGlobalTestConfig(),
hidesOnHideEventInContentNode: true,
contentNode: fixtureSync(html`
<div>
my content
<button @click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))}>
x
</button>
</div>
`),
});
await ctrl.show();
const closeBtn = ctrl.contentNode.querySelector('button');
closeBtn.click();
expect(ctrl.isShown).to.be.false;
});
it('does stop propagation of the "hide" event to not pollute the event stack and to prevent side effects', () => {
// TODO: how to test this?
});
});
describe('hidesOnOutsideClick', () => { describe('hidesOnOutsideClick', () => {
it('hides on outside click', async () => { it('hides on outside click', async () => {
const contentNode = await fixture('<div>Content</div>'); const contentNode = await fixture('<div>Content</div>');

View file

@ -4,7 +4,6 @@ import { LitElement, html } from '@lion/core';
export class LionTooltip extends OverlayMixin(LitElement) { export class LionTooltip extends OverlayMixin(LitElement) {
constructor() { constructor() {
super(); super();
this.closeEventName = 'tooltip-close';
this.mouseActive = false; this.mouseActive = false;
this.keyActive = false; this.keyActive = false;
} }
@ -19,6 +18,7 @@ export class LionTooltip extends OverlayMixin(LitElement) {
} }
_setupOpenCloseListeners() { _setupOpenCloseListeners() {
super._setupOpenCloseListeners();
this.__resetActive = () => { this.__resetActive = () => {
this.mouseActive = false; this.mouseActive = false;
this.keyActive = false; this.keyActive = false;
@ -58,6 +58,7 @@ export class LionTooltip extends OverlayMixin(LitElement) {
} }
_teardownOpenCloseListeners() { _teardownOpenCloseListeners() {
super._teardownOpenCloseListeners();
this._overlayCtrl.removeEventListener('hide', this.__resetActive); this._overlayCtrl.removeEventListener('hide', this.__resetActive);
this.removeEventListener('mouseenter', this.__showMouse); this.removeEventListener('mouseenter', this.__showMouse);
this.removeEventListener('mouseleave', this._hideMouse); this.removeEventListener('mouseleave', this._hideMouse);