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:types": "tsc -p tsconfig.build.types.json",
|
||||
"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",
|
||||
"format": "npm run format:eslint && npm run format:prettier",
|
||||
"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 { html, LitElement } from '@lion/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 '../lion-input-datepicker.js';
|
||||
import { LionInputDatepicker } from '../src/LionInputDatepicker.js';
|
||||
|
|
@ -73,6 +73,7 @@ describe('<lion-input-datepicker>', () => {
|
|||
elObj.overlayController.contentNode.dispatchEvent(
|
||||
new KeyboardEvent('keyup', { key: 'Escape' }),
|
||||
);
|
||||
await nextFrame();
|
||||
expect(elObj.overlayController.isShown).to.equal(false);
|
||||
});
|
||||
|
||||
|
|
@ -83,6 +84,7 @@ describe('<lion-input-datepicker>', () => {
|
|||
expect(elObj.overlayController.isShown).to.equal(true);
|
||||
|
||||
elObj.overlayCloseButtonEl.click();
|
||||
await nextFrame();
|
||||
expect(elObj.overlayController.isShown).to.equal(false);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -678,6 +678,7 @@ export class OverlayController extends EventTargetShim {
|
|||
await this._handlePosition({ phase: 'show' });
|
||||
this.__elementToFocusAfterHide = elementToFocusAfterHide;
|
||||
this.dispatchEvent(new Event('show'));
|
||||
await this.transitionShow({ backdropNode: this.backdropNode, contentNode: this.contentNode });
|
||||
}
|
||||
/** @type {function} */ (this._showResolve)();
|
||||
}
|
||||
|
|
@ -782,7 +783,7 @@ export class OverlayController extends EventTargetShim {
|
|||
const event = new CustomEvent('before-hide', { cancelable: true });
|
||||
this.dispatchEvent(event);
|
||||
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._handleFeatures({ 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
|
||||
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() {
|
||||
// We only are allowed to move focus if we (still) 'own' it.
|
||||
// Otherwise we assume the 'outside world' has, purposefully, taken over
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
|
|||
</${tag}>
|
||||
`));
|
||||
closeBtn.click();
|
||||
await nextFrame(); // hide takes at least a frame
|
||||
expect(el.opened).to.be.false;
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1100,6 +1100,60 @@ describe('OverlayController', () => {
|
|||
await ctrl0.show();
|
||||
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', () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue