fix(overlays): add transition hooks to overlays
This commit is contained in:
parent
cfa2daf674
commit
278798636c
6 changed files with 72 additions and 3 deletions
5
.changeset/little-jeans-yell.md
Normal file
5
.changeset/little-jeans-yell.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/overlays': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Adds `async transitionShow` and `async transitionHide` to OverlayController to enable basic support for transitions/animations
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
"build:docs": "wca analyze \"packages/tabs/**/*.js\"",
|
"build:docs": "wca analyze \"packages/tabs/**/*.js\"",
|
||||||
"build:types": "tsc -p tsconfig.build.types.json",
|
"build:types": "tsc -p tsconfig.build.types.json",
|
||||||
"bundlesize": "rollup -c bundlesize/rollup.config.js && bundlesize",
|
"bundlesize": "rollup -c bundlesize/rollup.config.js && bundlesize",
|
||||||
"debug": "web-test-runner \"packages/input-datepicker/test/**/*.test.js\" --watch",
|
"debug": "web-test-runner \"packages/overlays/test/**/*.test.js\" --watch",
|
||||||
"dev-server": "es-dev-server",
|
"dev-server": "es-dev-server",
|
||||||
"format": "npm run format:eslint && npm run format:prettier",
|
"format": "npm run format:eslint && npm run format:prettier",
|
||||||
"format:eslint": "eslint --ext .js,.html . --fix",
|
"format:eslint": "eslint --ext .js,.html . --fix",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { LionCalendar } from '@lion/calendar';
|
||||||
import { isSameDate } from '@lion/calendar/src/utils/isSameDate.js';
|
import { isSameDate } from '@lion/calendar/src/utils/isSameDate.js';
|
||||||
import { html, LitElement } from '@lion/core';
|
import { html, LitElement } from '@lion/core';
|
||||||
import { IsDateDisabled, MaxDate, MinDate, MinMaxDate } from '@lion/form-core';
|
import { IsDateDisabled, MaxDate, MinDate, MinMaxDate } from '@lion/form-core';
|
||||||
import { aTimeout, defineCE, expect, fixture } from '@open-wc/testing';
|
import { aTimeout, defineCE, expect, fixture, nextFrame } from '@open-wc/testing';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import '../lion-input-datepicker.js';
|
import '../lion-input-datepicker.js';
|
||||||
import { LionInputDatepicker } from '../src/LionInputDatepicker.js';
|
import { LionInputDatepicker } from '../src/LionInputDatepicker.js';
|
||||||
|
|
@ -73,6 +73,7 @@ describe('<lion-input-datepicker>', () => {
|
||||||
elObj.overlayController.contentNode.dispatchEvent(
|
elObj.overlayController.contentNode.dispatchEvent(
|
||||||
new KeyboardEvent('keyup', { key: 'Escape' }),
|
new KeyboardEvent('keyup', { key: 'Escape' }),
|
||||||
);
|
);
|
||||||
|
await nextFrame();
|
||||||
expect(elObj.overlayController.isShown).to.equal(false);
|
expect(elObj.overlayController.isShown).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -83,6 +84,7 @@ describe('<lion-input-datepicker>', () => {
|
||||||
expect(elObj.overlayController.isShown).to.equal(true);
|
expect(elObj.overlayController.isShown).to.equal(true);
|
||||||
|
|
||||||
elObj.overlayCloseButtonEl.click();
|
elObj.overlayCloseButtonEl.click();
|
||||||
|
await nextFrame();
|
||||||
expect(elObj.overlayController.isShown).to.equal(false);
|
expect(elObj.overlayController.isShown).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -678,6 +678,7 @@ export class OverlayController extends EventTargetShim {
|
||||||
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'));
|
||||||
|
await this.transitionShow({ backdropNode: this.backdropNode, contentNode: this.contentNode });
|
||||||
}
|
}
|
||||||
/** @type {function} */ (this._showResolve)();
|
/** @type {function} */ (this._showResolve)();
|
||||||
}
|
}
|
||||||
|
|
@ -782,7 +783,7 @@ export class OverlayController extends EventTargetShim {
|
||||||
const event = new CustomEvent('before-hide', { cancelable: true });
|
const event = new CustomEvent('before-hide', { cancelable: true });
|
||||||
this.dispatchEvent(event);
|
this.dispatchEvent(event);
|
||||||
if (!event.defaultPrevented) {
|
if (!event.defaultPrevented) {
|
||||||
// await this.transitionHide({ backdropNode: this.backdropNode, contentNode: this.contentNode });
|
await this.transitionHide({ backdropNode: this.backdropNode, contentNode: this.contentNode });
|
||||||
this.contentWrapperNode.style.display = 'none';
|
this.contentWrapperNode.style.display = 'none';
|
||||||
this._handleFeatures({ phase: 'hide' });
|
this._handleFeatures({ phase: 'hide' });
|
||||||
this._keepBodySize({ phase: 'hide' });
|
this._keepBodySize({ phase: 'hide' });
|
||||||
|
|
@ -798,6 +799,12 @@ export class OverlayController extends EventTargetShim {
|
||||||
// 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(config) {}
|
async transitionHide(config) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{backdropNode:HTMLElement, contentNode:HTMLElement}} config
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
|
||||||
|
async transitionShow(config) {}
|
||||||
|
|
||||||
_restoreFocus() {
|
_restoreFocus() {
|
||||||
// We only are allowed to move focus if we (still) 'own' it.
|
// We only are allowed to move focus if we (still) 'own' it.
|
||||||
// Otherwise we assume the 'outside world' has, purposefully, taken over
|
// Otherwise we assume the 'outside world' has, purposefully, taken over
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,7 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`));
|
`));
|
||||||
closeBtn.click();
|
closeBtn.click();
|
||||||
|
await nextFrame(); // hide takes at least a frame
|
||||||
expect(el.opened).to.be.false;
|
expect(el.opened).to.be.false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1100,6 +1100,60 @@ describe('OverlayController', () => {
|
||||||
await ctrl0.show();
|
await ctrl0.show();
|
||||||
expect(getTopEl()).to.equal(ctrl0.contentNode);
|
expect(getTopEl()).to.equal(ctrl0.contentNode);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('awaits a "transitionHide" hook before hiding for real', done => {
|
||||||
|
const ctrl = new OverlayController({
|
||||||
|
...withGlobalTestConfig(),
|
||||||
|
});
|
||||||
|
ctrl.show();
|
||||||
|
|
||||||
|
/** @type {{ (): void; (value?: void | PromiseLike<void> | undefined): void; }} */
|
||||||
|
let hideTransitionFinished;
|
||||||
|
ctrl.transitionHide = () =>
|
||||||
|
new Promise(resolve => {
|
||||||
|
hideTransitionFinished = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
ctrl.hide();
|
||||||
|
|
||||||
|
expect(getComputedStyle(ctrl.contentWrapperNode).display).to.equal('block');
|
||||||
|
setTimeout(() => {
|
||||||
|
hideTransitionFinished();
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(getComputedStyle(ctrl.contentWrapperNode).display).to.equal('none');
|
||||||
|
done();
|
||||||
|
}, 0);
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('awaits a "transitionShow" hook before finishing the show method', done => {
|
||||||
|
const ctrl = new OverlayController({
|
||||||
|
...withGlobalTestConfig(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @type {{ (): void; (value?: void | PromiseLike<void> | undefined): void; }} */
|
||||||
|
let showTransitionFinished;
|
||||||
|
ctrl.transitionShow = () =>
|
||||||
|
new Promise(resolve => {
|
||||||
|
showTransitionFinished = resolve;
|
||||||
|
});
|
||||||
|
ctrl.show();
|
||||||
|
|
||||||
|
let showIsDone = false;
|
||||||
|
|
||||||
|
/** @type {Promise<void>} */ (ctrl._showComplete).then(() => {
|
||||||
|
showIsDone = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(showIsDone).to.be.false;
|
||||||
|
setTimeout(() => {
|
||||||
|
showTransitionFinished();
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(showIsDone).to.be.true;
|
||||||
|
done();
|
||||||
|
}, 0);
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Update Configuration', () => {
|
describe('Update Configuration', () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue