Merge pull request #436 from ing-bank/feat/closeEventOnOverlay
feat(overlay): close/hide events on dom (OverlayMixin) level
This commit is contained in:
commit
eefd2e61b4
11 changed files with 268 additions and 92 deletions
|
|
@ -2,11 +2,6 @@ import { withModalDialogConfig, OverlayMixin } from '@lion/overlays';
|
|||
import { LitElement, html } from '@lion/core';
|
||||
|
||||
export class LionDialog extends OverlayMixin(LitElement) {
|
||||
constructor() {
|
||||
super();
|
||||
this.closeEventName = 'dialog-close';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
_defineOverlayConfig() {
|
||||
return {
|
||||
|
|
@ -15,6 +10,7 @@ export class LionDialog extends OverlayMixin(LitElement) {
|
|||
}
|
||||
|
||||
_setupOpenCloseListeners() {
|
||||
super._setupOpenCloseListeners();
|
||||
this.__toggle = () => {
|
||||
this.opened = !this.opened;
|
||||
};
|
||||
|
|
@ -25,6 +21,7 @@ export class LionDialog extends OverlayMixin(LitElement) {
|
|||
}
|
||||
|
||||
_teardownOpenCloseListeners() {
|
||||
super._teardownOpenCloseListeners();
|
||||
if (this._overlayInvokerNode) {
|
||||
this._overlayInvokerNode.removeEventListener('click', this.__toggle);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ storiesOf('Overlays Specific WC | Dialog', module)
|
|||
Hello! You can close this notification here:
|
||||
<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>
|
||||
|
|
@ -97,7 +97,7 @@ storiesOf('Overlays Specific WC | Dialog', module)
|
|||
Hello! You can close this notification here:
|
||||
<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>
|
||||
|
|
@ -123,7 +123,7 @@ storiesOf('Overlays Specific WC | Dialog', module)
|
|||
Hello! You can close this notification here:
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -90,9 +90,8 @@ export class LionCalendarOverlayFrame extends LocalizeMixin(LitElement) {
|
|||
];
|
||||
}
|
||||
|
||||
__dispatchHideEvent() {
|
||||
// Designed to work in conjunction with ModalDialogController
|
||||
this.dispatchEvent(new CustomEvent('hide'), { bubbles: true });
|
||||
__dispatchCloseEvent() {
|
||||
this.dispatchEvent(new Event('close-overlay'), { bubbles: true });
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
@ -104,7 +103,7 @@ export class LionCalendarOverlayFrame extends LocalizeMixin(LitElement) {
|
|||
<slot name="heading"></slot>
|
||||
</h1>
|
||||
<button
|
||||
@click="${this.__dispatchHideEvent}"
|
||||
@click="${this.__dispatchCloseEvent}"
|
||||
id="close-button"
|
||||
title="${this.msgLit('lion-calendar-overlay-frame:close')}"
|
||||
aria-label="${this.msgLit('lion-calendar-overlay-frame:close')}"
|
||||
|
|
|
|||
|
|
@ -343,6 +343,10 @@ export class LionInputDatepicker extends OverlayMixin(LionInputDate) {
|
|||
* @override Configures OverlayMixin
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ html`
|
|||
<div slot="content">
|
||||
This is an overlay
|
||||
<button
|
||||
@click=${e => e.target.dispatchEvent(new Event('hide', { bubbles: true }))}
|
||||
@click=${e => e.target.dispatchEvent(new Event('overlay-close', { bubbles: true }))}
|
||||
>x</button>
|
||||
<div>
|
||||
<button slot="invoker">
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ export class OverlayController {
|
|||
trapsKeyboardFocus: false,
|
||||
hidesOnEsc: false,
|
||||
hidesOnOutsideClick: false,
|
||||
hidesOnHideEventInContentNode: true,
|
||||
isTooltip: false,
|
||||
handlesUserInteraction: false,
|
||||
handlesAccessibility: false,
|
||||
|
|
@ -244,12 +243,16 @@ export class OverlayController {
|
|||
if (this.isShown) {
|
||||
return;
|
||||
}
|
||||
this.dispatchEvent(new Event('before-show'));
|
||||
this._contentNodeWrapper.style.display = this.placementMode === 'local' ? 'inline-block' : '';
|
||||
await this._handleFeatures({ phase: 'show' });
|
||||
await this._handlePosition({ phase: 'show' });
|
||||
this.elementToFocusAfterHide = elementToFocusAfterHide;
|
||||
this.dispatchEvent(new Event('show'));
|
||||
|
||||
const event = new CustomEvent('before-show', { cancelable: true });
|
||||
this.dispatchEvent(event);
|
||||
if (!event.defaultPrevented) {
|
||||
this._contentNodeWrapper.style.display = this.placementMode === 'local' ? 'inline-block' : '';
|
||||
await this._handleFeatures({ phase: 'show' });
|
||||
await this._handlePosition({ phase: 'show' });
|
||||
this.elementToFocusAfterHide = elementToFocusAfterHide;
|
||||
this.dispatchEvent(new Event('show'));
|
||||
}
|
||||
}
|
||||
|
||||
async _handlePosition({ phase }) {
|
||||
|
|
@ -285,12 +288,15 @@ export class OverlayController {
|
|||
return;
|
||||
}
|
||||
|
||||
this.dispatchEvent(new Event('before-hide'));
|
||||
// await this.transitionHide({ backdropNode: this.backdropNode, conentNode: this.contentNode });
|
||||
this._contentNodeWrapper.style.display = 'none';
|
||||
this._handleFeatures({ phase: 'hide' });
|
||||
this.dispatchEvent(new Event('hide'));
|
||||
this._restoreFocus();
|
||||
const event = new CustomEvent('before-hide', { cancelable: true });
|
||||
this.dispatchEvent(event);
|
||||
if (!event.defaultPrevented) {
|
||||
// await this.transitionHide({ backdropNode: this.backdropNode, conentNode: this.contentNode });
|
||||
this._contentNodeWrapper.style.display = 'none';
|
||||
this._handleFeatures({ phase: 'hide' });
|
||||
this.dispatchEvent(new Event('hide'));
|
||||
this._restoreFocus();
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
|
||||
|
|
@ -337,9 +343,6 @@ export class OverlayController {
|
|||
if (this.hidesOnOutsideClick) {
|
||||
this._handleHidesOnOutsideClick({ phase });
|
||||
}
|
||||
if (this.hidesOnHideEventInContentNode) {
|
||||
this._handleHidesOnHideEventInContentNode({ phase });
|
||||
}
|
||||
if (this.handlesAccessibility) {
|
||||
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() {
|
||||
if (!this._referenceNode) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,13 @@ export const OverlayMixin = dedupeMixin(
|
|||
this.__config = value;
|
||||
}
|
||||
|
||||
_requestUpdate(name, oldValue) {
|
||||
super._requestUpdate(name, oldValue);
|
||||
if (name === 'opened') {
|
||||
this.dispatchEvent(new Event('opened-changed'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @overridable method `_defineOverlay`
|
||||
* @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
|
||||
*/
|
||||
// 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
|
||||
* @desc use this method to tear down your event listeners
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
_teardownOpenCloseListeners() {}
|
||||
_teardownOpenCloseListeners() {
|
||||
if (this._overlayContentNode) {
|
||||
this._overlayContentNode.removeEventListener(
|
||||
'close-overlay',
|
||||
this.__closeEventInContentNodeHandler,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
|
|
@ -110,7 +135,9 @@ export const OverlayMixin = dedupeMixin(
|
|||
}
|
||||
|
||||
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
|
||||
// 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',
|
||||
);
|
||||
if (shadowOutlet) {
|
||||
contentNode = Array.from(shadowOutlet.children).find(child => child.slot === 'content');
|
||||
this._cachedOverlayContentNode = Array.from(shadowOutlet.children).find(
|
||||
child => child.slot === 'content',
|
||||
);
|
||||
} else {
|
||||
contentNode = Array.from(this.children).find(child => child.slot === 'content');
|
||||
this._cachedOverlayContentNode = Array.from(this.children).find(
|
||||
child => child.slot === 'content',
|
||||
);
|
||||
}
|
||||
|
||||
if (contentNode) {
|
||||
this._cachedOverlayContentNode = contentNode;
|
||||
}
|
||||
return contentNode || this._cachedOverlayContentNode;
|
||||
return this._cachedOverlayContentNode;
|
||||
}
|
||||
|
||||
_setupOverlayCtrl() {
|
||||
|
|
@ -137,7 +164,6 @@ export const OverlayMixin = dedupeMixin(
|
|||
});
|
||||
this.__syncToOverlayController();
|
||||
this.__setupSyncFromOverlayController();
|
||||
|
||||
this._setupOpenCloseListeners();
|
||||
}
|
||||
|
||||
|
|
@ -151,22 +177,38 @@ export const OverlayMixin = dedupeMixin(
|
|||
this.__onOverlayCtrlShow = () => {
|
||||
this.opened = true;
|
||||
};
|
||||
|
||||
this.__onOverlayCtrlHide = () => {
|
||||
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('hide', this.__onOverlayCtrlHide);
|
||||
this._overlayCtrl.addEventListener('before-show', this.__onBeforeShow);
|
||||
this._overlayCtrl.addEventListener('before-hide', this.__onBeforeHide);
|
||||
}
|
||||
|
||||
__teardownSyncFromOverlayController() {
|
||||
this._overlayCtrl.removeEventListener('show', this.__onOverlayCtrlShow);
|
||||
this._overlayCtrl.removeEventListener('hide', this.__onOverlayCtrlHide);
|
||||
this._overlayCtrl.removeEventListener('before-show', this.__onBeforeShow);
|
||||
this._overlayCtrl.removeEventListener('before-hide', this.__onBeforeHide);
|
||||
}
|
||||
|
||||
__syncToOverlayController() {
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ customElements.define(
|
|||
}
|
||||
|
||||
_setupOpenCloseListeners() {
|
||||
super._setupOpenCloseListeners();
|
||||
this.__toggle = () => {
|
||||
this.opened = !this.opened;
|
||||
};
|
||||
|
|
@ -106,6 +107,7 @@ customElements.define(
|
|||
}
|
||||
|
||||
_teardownOpenCloseListeners() {
|
||||
super._teardownOpenCloseListeners();
|
||||
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:
|
||||
<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>
|
||||
|
|
@ -168,7 +170,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
|
|||
Hello! You can close this notification here:
|
||||
<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>
|
||||
|
|
@ -197,7 +199,9 @@ storiesOf('Overlay System | Overlay as a WC', module)
|
|||
<div slot="content" class="demo-overlay">
|
||||
<div>
|
||||
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
|
||||
</button>
|
||||
<lion-demo-overlay
|
||||
|
|
@ -208,7 +212,8 @@ storiesOf('Overlay System | Overlay as a WC', module)
|
|||
Hello! You can close this notification here:
|
||||
<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>
|
||||
|
|
@ -234,7 +239,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
|
|||
Hello! You can close this notification here:
|
||||
<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>
|
||||
|
|
@ -299,7 +304,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
|
|||
Hello! You can close this notification here:
|
||||
<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>
|
||||
|
|
@ -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>
|
||||
<lion-demo-overlay
|
||||
.config=${{ ...withBottomSheetConfig() }}
|
||||
@before-show=${e => {
|
||||
@before-opened=${e => {
|
||||
if (window.innerWidth >= 600) {
|
||||
e.target.config = { ...withModalDialogConfig() };
|
||||
} else {
|
||||
|
|
@ -368,7 +373,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
|
|||
Hello! You can close this notification here:
|
||||
<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>
|
||||
|
|
@ -450,6 +455,87 @@ storiesOf('Overlay System | Overlay as a WC', module)
|
|||
${popup}
|
||||
</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', () => {
|
||||
|
|
@ -467,7 +553,7 @@ storiesOf('Overlay System | Overlay as a WC', module)
|
|||
Hello! You can close this notification here:
|
||||
<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
|
||||
>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { expect, fixture, html, aTimeout } from '@open-wc/testing';
|
||||
import sinon from 'sinon';
|
||||
|
||||
export function runOverlayMixinSuite({ /* tagString, */ tag, suffix = '' }) {
|
||||
describe(`OverlayMixin${suffix}`, () => {
|
||||
|
|
@ -53,5 +54,87 @@ export function runOverlayMixinSuite({ /* tagString, */ tag, suffix = '' }) {
|
|||
itEl.config = { viewportConfig: { placement: '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;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
it('hides on outside click', async () => {
|
||||
const contentNode = await fixture('<div>Content</div>');
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { LitElement, html } from '@lion/core';
|
|||
export class LionTooltip extends OverlayMixin(LitElement) {
|
||||
constructor() {
|
||||
super();
|
||||
this.closeEventName = 'tooltip-close';
|
||||
this.mouseActive = false;
|
||||
this.keyActive = false;
|
||||
}
|
||||
|
|
@ -19,6 +18,7 @@ export class LionTooltip extends OverlayMixin(LitElement) {
|
|||
}
|
||||
|
||||
_setupOpenCloseListeners() {
|
||||
super._setupOpenCloseListeners();
|
||||
this.__resetActive = () => {
|
||||
this.mouseActive = false;
|
||||
this.keyActive = false;
|
||||
|
|
@ -58,6 +58,7 @@ export class LionTooltip extends OverlayMixin(LitElement) {
|
|||
}
|
||||
|
||||
_teardownOpenCloseListeners() {
|
||||
super._teardownOpenCloseListeners();
|
||||
this._overlayCtrl.removeEventListener('hide', this.__resetActive);
|
||||
this.removeEventListener('mouseenter', this.__showMouse);
|
||||
this.removeEventListener('mouseleave', this._hideMouse);
|
||||
|
|
|
|||
Loading…
Reference in a new issue