@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
301 lines • 10.4 kB
JavaScript
import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty";
import _pushInstanceProperty from "core-js-pure/stable/instance/push.js";
export default class HeightAnimation {
constructor(opts = {}) {
_defineProperty(this, "onStartStack", []);
_defineProperty(this, "onEndStack", []);
_defineProperty(this, "events", []);
_defineProperty(this, "opts", {
animate: true
});
_defineProperty(this, "timeouts", []);
_defineProperty(this, "firstTime", 0);
_defineProperty(this, "startTime", 0);
_defineProperty(this, "duration", 0);
_defineProperty(this, "firstPaintStyle", {
visibility: 'hidden',
opacity: '0',
height: 'auto'
});
this.isInBrowser = typeof window !== 'undefined';
this.setState('init');
this.setOptions(opts);
}
callAnimationStart() {
this.startTime = Date.now();
if (!this.firstTime) {
this.firstTime = this.startTime;
}
if (this.onStartStack) {
this.onStartStack.forEach(fn => {
if (typeof fn === 'function') {
fn(this.state);
}
});
}
}
callAnimationEnd() {
this.isAnimating = false;
if (this.state !== 'opened') {
delete this.__currentHeight;
}
this.removeEndEvents();
if (this.onEndStack) {
this.onEndStack.forEach(fn => {
if (typeof fn === 'function') {
fn(this.state);
}
});
}
}
addEndEvent(listener) {
var _context2, _this$elem, _this$elem$addEventLi;
this.removeEndEvents();
const handleTransitionEnd = e => {
if (this.canFinish()) {
listener(e);
} else {
const delay = this.duration - (Date.now() - this.startTime);
if (delay === -1) {
listener(e);
} else {
var _context;
_pushInstanceProperty(_context = this.timeouts).call(_context, setTimeout(() => listener(e), delay));
}
}
};
_pushInstanceProperty(_context2 = this.events).call(_context2, handleTransitionEnd);
(_this$elem = this.elem) === null || _this$elem === void 0 || (_this$elem$addEventLi = _this$elem.addEventListener) === null || _this$elem$addEventLi === void 0 || _this$elem$addEventLi.call(_this$elem, 'transitionend', handleTransitionEnd);
}
removeEndEvents() {
this.events.forEach(listener => {
var _this$elem2, _this$elem2$removeEve;
(_this$elem2 = this.elem) === null || _this$elem2 === void 0 || (_this$elem2$removeEve = _this$elem2.removeEventListener) === null || _this$elem2$removeEve === void 0 || _this$elem2$removeEve.call(_this$elem2, 'transitionend', listener);
});
this.events = [];
}
setElement(elem) {
var _this$elem3, _globalThis$animation;
this.elem = elem || typeof document !== 'undefined' && document.createElement('div');
if (String((_this$elem3 = this.elem) === null || _this$elem3 === void 0 ? void 0 : _this$elem3.nodeName).toLowerCase() === 'td') {
this.elem = this.elem.parentElement;
}
this.duration = (_globalThis$animation = globalThis.animationDuration) !== null && _globalThis$animation !== void 0 ? _globalThis$animation : parseFloat(window.getComputedStyle(this.elem).transitionDuration) * 1000 || 400;
}
setState(state) {
this.state = Object.freeze(state);
}
setOptions(opts) {
this.opts = Object.freeze({
...this.opts,
...opts
});
}
getOptions() {
return this.opts;
}
remove() {
this.stop();
this.removeEndEvents();
this.setState('init');
this.isAnimating = false;
this.onEndStack = [];
this.onStartStack = [];
this.__currentHeight = undefined;
this.elem = undefined;
}
setAsOpen() {
if (this.state === 'opened') {
return;
}
this.setState('opening');
this.callAnimationStart();
this.setState('opened');
this.callAnimationEnd();
}
setAsClosed() {
if (this.state === 'closed') {
return;
}
this.setState('closing');
this.callAnimationStart();
this.setState('closed');
this.callAnimationEnd();
}
getHeight() {
var _this$withFallback;
return (_this$withFallback = this.withFallback(this.elem, 'clientHeight')) !== null && _this$withFallback !== void 0 ? _this$withFallback : null;
}
getUnknownHeight() {
var _this$elem$parentNode, _this$withFallback2, _this$withFallback3, _clonedElem$parentNod;
if (!this.elem) {
return null;
}
if (this.isAnimating && typeof this.__currentHeight !== 'undefined') {
return this.__currentHeight;
}
const clonedElem = this.elem.cloneNode(true);
const inputs = clonedElem.querySelectorAll('input');
inputs.forEach(input => {
input.removeAttribute('name');
input.removeAttribute('id');
});
for (const key in this.firstPaintStyle) {
clonedElem.style[key] = this.firstPaintStyle[key];
}
clonedElem.style.position = 'absolute';
(_this$elem$parentNode = this.elem.parentNode) === null || _this$elem$parentNode === void 0 || _this$elem$parentNode.insertBefore(clonedElem, this.elem.nextSibling);
const elemWidth = this.elem.clientWidth;
const clonedWidth = (_this$withFallback2 = this.withFallback(clonedElem, 'clientWidth', 'data-width')) !== null && _this$withFallback2 !== void 0 ? _this$withFallback2 : 0;
if (clonedWidth > elemWidth) {
clonedElem.style.width = `${elemWidth}px`;
}
const height = (_this$withFallback3 = this.withFallback(this.elem, 'clientHeight', 'data-height')) !== null && _this$withFallback3 !== void 0 ? _this$withFallback3 : null;
(_clonedElem$parentNod = clonedElem.parentNode) === null || _clonedElem$parentNod === void 0 || _clonedElem$parentNod.removeChild(clonedElem);
if (height) {
this.__currentHeight = height;
}
return height;
}
withFallback(elem, key, fallback) {
const val = fallback && elem.hasAttribute(fallback) ? parseFloat(elem.getAttribute(fallback)) : elem === null || elem === void 0 ? void 0 : elem[key];
if (isNaN(val)) {
return null;
}
return val;
}
onStart(fn) {
var _context3;
_pushInstanceProperty(_context3 = this.onStartStack).call(_context3, fn);
}
onEnd(fn) {
var _context4;
_pushInstanceProperty(_context4 = this.onEndStack).call(_context4, fn);
}
start(fromHeight, toHeight) {
if (!this.elem || !(this.isInBrowser && typeof window.requestAnimationFrame === 'function')) {
return;
}
const opts = this.getOptions();
if (opts.animate === false) {
return;
}
this.stop();
this.isAnimating = true;
this.reqId1 = window.requestAnimationFrame(() => {
if (!this.elem || toHeight !== 0 && this.elem.classList.contains('dnb-height-animation--stop')) {
return;
}
this.elem.style.height = `${fromHeight}px`;
this.reqId2 = window.requestAnimationFrame(() => {
if (!this.elem) {
return;
}
this.elem.style.height = `${toHeight}px`;
});
});
}
stop() {
this.timeouts.forEach(id => clearTimeout(id));
this.timeouts = [];
if (this.isInBrowser && typeof window.requestAnimationFrame === 'function') {
window.cancelAnimationFrame(this.reqId1);
window.cancelAnimationFrame(this.reqId2);
}
}
open() {
if (this.state === 'opened' || this.state === 'opening' || this.shouldBypassAnimation()) {
this.setAsOpen();
return;
}
this.setState('opening');
this.callAnimationStart();
const toHeight = this.getUnknownHeight();
this.addEndEvent(e => {
if (this.state === 'opening' && e.target === e.currentTarget || !e.currentTarget) {
if (this.elem) {
this.elem.style.overflowY = '';
}
this.setState('opened');
this.readjust();
}
});
this.start(0, toHeight);
}
close() {
if (this.state === 'closed' || this.state === 'closing' || this.shouldBypassAnimation()) {
this.setAsClosed();
return;
}
this.setState('closing');
this.callAnimationStart();
const fromHeight = this.getHeight();
this.addEndEvent(e => {
if (this.state === 'closing' && e.target === e.currentTarget || !e.currentTarget) {
if (this.elem) {
this.elem.style.visibility = 'hidden';
this.elem.style.overflowY = 'clip';
}
this.setState('closed');
this.callAnimationEnd();
}
});
this.start(fromHeight, 0);
}
adjustTo(fromHeight = null, toHeight = null) {
const opts = this.getOptions();
if (!this.elem || opts.animate === false || this.state === 'opening' || this.state === 'closing') {
return;
}
if (fromHeight === null) {
fromHeight = this.getHeight();
}
if (toHeight === null) {
toHeight = this.getUnknownHeight();
}
if (fromHeight === toHeight) {
return;
}
this.setState('adjusting');
this.callAnimationStart();
this.addEndEvent(e => {
if (this.state === 'adjusting' && (e.target === e.currentTarget || !e.currentTarget)) {
if (this.elem) {
this.elem.style.height = 'auto';
}
this.setState('adjusted');
}
this.callAnimationEnd();
});
this.start(fromHeight, toHeight);
}
readjust() {
const endHeight = this.getHeight();
if (this.elem) {
this.elem.style.height = 'auto';
}
this.__currentHeight = undefined;
const newHeight = this.getUnknownHeight();
if (endHeight !== newHeight) {
this.adjustTo(endHeight, newHeight);
} else {
this.callAnimationEnd();
}
}
canFinish() {
var _globalThis$animation2;
return Boolean(this.startTime && Date.now() - this.startTime > ((_globalThis$animation2 = globalThis.animationDuration) !== null && _globalThis$animation2 !== void 0 ? _globalThis$animation2 : this.duration));
}
shouldBypassAnimation() {
var _globalThis$bypassTim;
const opts = this.getOptions();
if (!this.elem || opts.animate === false) {
return true;
}
if (this.isInBrowser && (globalThis.IS_TEST || globalThis.bypassTime === -1)) {
return false;
}
return Boolean(this.firstTime && Date.now() - this.firstTime < ((_globalThis$bypassTim = globalThis.bypassTime) !== null && _globalThis$bypassTim !== void 0 ? _globalThis$bypassTim : 100));
}
}
//# sourceMappingURL=HeightAnimationInstance.js.map