Skip to content

Commit 18af91c

Browse files
committed
refactor(materialbox): remove animejs
1 parent 4a18fbc commit 18af91c

File tree

2 files changed

+156
-138
lines changed

2 files changed

+156
-138
lines changed

sass/components/_materialbox.scss

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@
2222
right: 0;
2323
bottom: 0;
2424
left: 0;
25-
background-color: #292929;
25+
background-color: var(--md-sys-color-background);
2626
z-index: 1000;
2727
will-change: opacity;
2828
}
2929

3030
.materialbox-caption {
3131
position: fixed;
3232
display: none;
33-
color: #fff;
33+
color: var(--font-color-main);
3434
line-height: 50px;
3535
bottom: 0;
3636
left: 0;

src/materialbox.ts

+154-136
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import anim from "animejs";
2-
31
import { Utils } from "./utils";
42
import { BaseOptions, Component, InitElements, MElement } from "./component";
53

@@ -129,35 +127,35 @@ export class Materialbox extends Component<MaterialboxOptions> {
129127
this.el.removeAttribute('style');
130128
}
131129

132-
_setupEventHandlers() {
130+
private _setupEventHandlers() {
133131
this.el.addEventListener('click', this._handleMaterialboxClick);
134132
}
135133

136-
_removeEventHandlers() {
134+
private _removeEventHandlers() {
137135
this.el.removeEventListener('click', this._handleMaterialboxClick);
138136
}
139137

140-
_handleMaterialboxClick = () => {
138+
private _handleMaterialboxClick = () => {
141139
// If already modal, return to original
142140
if (this.doneAnimating === false || (this.overlayActive && this.doneAnimating))
143141
this.close();
144142
else
145143
this.open();
146144
}
147145

148-
_handleWindowScroll = () => {
146+
private _handleWindowScroll = () => {
149147
if (this.overlayActive) this.close();
150148
}
151149

152-
_handleWindowResize = () => {
150+
private _handleWindowResize = () => {
153151
if (this.overlayActive) this.close();
154152
}
155153

156-
_handleWindowEscape = (e: KeyboardEvent) => {
154+
private _handleWindowEscape = (e: KeyboardEvent) => {
157155
if (Utils.keys.ESC.includes(e.key) && this.doneAnimating && this.overlayActive) this.close();
158156
}
159157

160-
_makeAncestorsOverflowVisible() {
158+
private _makeAncestorsOverflowVisible() {
161159
this._changedAncestorList = [];
162160
let ancestor = this.placeholder.parentNode;
163161
while (ancestor !== null && ancestor !== document) {
@@ -178,12 +176,49 @@ export class Materialbox extends Component<MaterialboxOptions> {
178176
left: box.left + window.pageXOffset - docElem.clientLeft
179177
};
180178
}
179+
private _updateVars(): void {
180+
this.windowWidth = window.innerWidth;
181+
this.windowHeight = window.innerHeight;
182+
this.caption = this.el.getAttribute('data-caption') || '';
183+
}
184+
185+
// Image
186+
private _animateImageIn(): void {
187+
this.el.style.maxHeight = this.newHeight.toString() + 'px';
188+
this.el.style.maxWidth = this.newWidth.toString() + 'px';
189+
const duration = this.options.inDuration;
190+
// from
191+
this.el.style.transition = 'none';
192+
this.el.style.height = this.originalHeight + 'px';
193+
this.el.style.width = this.originalWidth + 'px';
194+
setTimeout(() => {
195+
// easeOutQuad
196+
this.el.style.transition = `height ${duration}ms ease,
197+
width ${duration}ms ease,
198+
left ${duration}ms ease,
199+
top ${duration}ms ease
200+
`;
201+
// to
202+
this.el.style.height = this.newHeight + 'px';
203+
this.el.style.width = this.newWidth + 'px';
204+
this.el.style.left = (Utils.getDocumentScrollLeft() +
205+
this.windowWidth / 2 -
206+
this._offset(this.placeholder).left -
207+
this.newWidth / 2) + 'px';
181208

182-
_animateImageIn() {
183-
this.el.style.maxHeight = this.newHeight.toString()+'px';
184-
this.el.style.maxWidth = this.newWidth.toString()+'px';
209+
this.el.style.top = (Utils.getDocumentScrollTop() +
210+
this.windowHeight / 2 -
211+
this._offset(this.placeholder).top -
212+
this.newHeight / 2) + 'px';
213+
}, 1);
185214

186-
const animOptions = {
215+
setTimeout(() => {
216+
this.doneAnimating = true;
217+
if (typeof this.options.onOpenEnd === 'function') this.options.onOpenEnd.call(this, this.el);
218+
}, duration);
219+
220+
/*
221+
anim({
187222
targets: this.el, // image
188223
height: [this.originalHeight, this.newHeight],
189224
width: [this.originalWidth, this.newWidth],
@@ -197,65 +232,110 @@ export class Materialbox extends Component<MaterialboxOptions> {
197232
this.windowHeight / 2 -
198233
this._offset(this.placeholder).top -
199234
this.newHeight / 2,
235+
200236
duration: this.options.inDuration,
201237
easing: 'easeOutQuad',
202238
complete: () => {
203239
this.doneAnimating = true;
204-
// onOpenEnd callback
205-
if (typeof this.options.onOpenEnd === 'function') {
206-
this.options.onOpenEnd.call(this, this.el);
207-
}
240+
if (typeof this.options.onOpenEnd === 'function') this.options.onOpenEnd.call(this, this.el);
208241
}
209-
};
210-
// Override max-width or max-height if needed
211-
//const elStyle = this.el.style;
212-
//console.log('mh', elStyle.maxHeight, '->', this.newHeight);
213-
//console.log('mw', elStyle.maxWidth, '->', this.newWidth);
214-
//if (elStyle.maxWidth !== 'none') animOptions.maxWidth = this.newWidth;
215-
//if (elStyle.maxHeight !== 'none') animOptions.maxHeight = this.newHeight;
216-
//console.log('>>> animate');
217-
//console.log(JSON.stringify(animOptions));
218-
anim(animOptions);
242+
});
243+
*/
244+
}
245+
private _animateImageOut(): void {
246+
const duration = this.options.outDuration;
247+
// easeOutQuad
248+
this.el.style.transition = `height ${duration}ms ease,
249+
width ${duration}ms ease,
250+
left ${duration}ms ease,
251+
top ${duration}ms ease
252+
`;
253+
// to
254+
this.el.style.height = this.originalWidth + 'px';
255+
this.el.style.width = this.originalWidth + 'px';
256+
this.el.style.left = '0';
257+
this.el.style.top = '0';
258+
setTimeout(() => {
259+
this.placeholder.style.height = '';
260+
this.placeholder.style.width = '';
261+
this.placeholder.style.position = '';
262+
this.placeholder.style.top = '';
263+
this.placeholder.style.left = '';
264+
// Revert to width or height attribute
265+
if (this.attrWidth) this.el.setAttribute('width', this.attrWidth.toString());
266+
if (this.attrHeight) this.el.setAttribute('height', this.attrHeight.toString());
267+
this.el.removeAttribute('style');
268+
this.originInlineStyles && this.el.setAttribute('style', this.originInlineStyles);
269+
// Remove class
270+
this.el.classList.remove('active');
271+
this.doneAnimating = true;
272+
// Remove overflow overrides on ancestors
273+
this._changedAncestorList.forEach(anchestor => anchestor.style.overflow = '');
274+
// onCloseEnd callback
275+
if (typeof this.options.onCloseEnd === 'function') this.options.onCloseEnd.call(this, this.el);
276+
}, duration);
219277
}
220278

221-
_animateImageOut() {
222-
const animOptions = {
223-
targets: this.el,
224-
width: this.originalWidth,
225-
height: this.originalHeight,
226-
left: 0,
227-
top: 0,
228-
duration: this.options.outDuration,
229-
easing: 'easeOutQuad',
230-
complete: () => {
231-
this.placeholder.style.height = '';
232-
this.placeholder.style.width = '';
233-
this.placeholder.style.position = '';
234-
this.placeholder.style.top = '';
235-
this.placeholder.style.left = '';
236-
// Revert to width or height attribute
237-
if (this.attrWidth) this.el.setAttribute('width', this.attrWidth.toString());
238-
if (this.attrHeight) this.el.setAttribute('height', this.attrHeight.toString());
239-
this.el.removeAttribute('style');
240-
this.originInlineStyles && this.el.setAttribute('style', this.originInlineStyles);
241-
// Remove class
242-
this.el.classList.remove('active');
243-
this.doneAnimating = true;
244-
// Remove overflow overrides on ancestors
245-
this._changedAncestorList.forEach(anchestor => anchestor.style.overflow = '');
246-
// onCloseEnd callback
247-
if (typeof this.options.onCloseEnd === 'function') {
248-
this.options.onCloseEnd.call(this, this.el);
249-
}
250-
}
251-
};
252-
anim(animOptions);
279+
// Caption
280+
private _addCaption(): void {
281+
this._photoCaption = document.createElement('div');
282+
this._photoCaption.classList.add('materialbox-caption');
283+
this._photoCaption.innerText = this.caption;
284+
document.body.append(this._photoCaption);
285+
this._photoCaption.style.display = 'inline';
286+
// Animate
287+
this._photoCaption.style.transition = 'none';
288+
this._photoCaption.style.opacity = '0'
289+
const duration = this.options.inDuration;
290+
setTimeout(() => {
291+
this._photoCaption.style.transition = `opacity ${duration}ms ease`;
292+
this._photoCaption.style.opacity = '1';
293+
}, 1);
294+
}
295+
private _removeCaption(): void {
296+
const duration = this.options.outDuration;
297+
this._photoCaption.style.transition = `opacity ${duration}ms ease`;
298+
this._photoCaption.style.opacity = '0';
299+
setTimeout(() => {
300+
this._photoCaption.remove();
301+
}, duration);
253302
}
254303

255-
_updateVars() {
256-
this.windowWidth = window.innerWidth;
257-
this.windowHeight = window.innerHeight;
258-
this.caption = this.el.getAttribute('data-caption') || '';
304+
// Overlay
305+
private _addOverlay(): void {
306+
this._overlay = document.createElement('div');
307+
this._overlay.id = 'materialbox-overlay';
308+
this._overlay.addEventListener('click', e => {
309+
if (this.doneAnimating) this.close();
310+
}, {once: true});
311+
312+
// Put before in origin image to preserve z-index layering.
313+
this.el.before(this._overlay);
314+
315+
// Set dimensions if needed
316+
const overlayOffset = this._overlay.getBoundingClientRect();
317+
this._overlay.style.width = this.windowWidth + 'px';
318+
this._overlay.style.height = this.windowHeight + 'px';
319+
this._overlay.style.left = -1 * overlayOffset.left + 'px';
320+
this._overlay.style.top = -1 * overlayOffset.top + 'px';
321+
322+
// Animate
323+
this._overlay.style.transition = 'none';
324+
this._overlay.style.opacity = '0'
325+
const duration = this.options.inDuration;
326+
setTimeout(() => {
327+
this._overlay.style.transition = `opacity ${duration}ms ease`;
328+
this._overlay.style.opacity = '1';
329+
}, 1);
330+
}
331+
private _removeOverlay(): void {
332+
const duration = this.options.outDuration;
333+
this._overlay.style.transition = `opacity ${duration}ms ease`;
334+
this._overlay.style.opacity = '0';
335+
setTimeout(() => {
336+
this.overlayActive = false;
337+
this._overlay.remove();
338+
}, duration);
259339
}
260340

261341
/**
@@ -270,12 +350,10 @@ export class Materialbox extends Component<MaterialboxOptions> {
270350
this.el.classList.add('active');
271351
this.overlayActive = true;
272352
// onOpenStart callback
273-
if (typeof this.options.onOpenStart === 'function') {
274-
this.options.onOpenStart.call(this, this.el);
275-
}
353+
if (typeof this.options.onOpenStart === 'function') this.options.onOpenStart.call(this, this.el);
276354
// Set positioning for placeholder
277-
this.placeholder.style.width = this.placeholder.getBoundingClientRect().width+'px';
278-
this.placeholder.style.height = this.placeholder.getBoundingClientRect().height+'px';
355+
this.placeholder.style.width = this.placeholder.getBoundingClientRect().width + 'px';
356+
this.placeholder.style.height = this.placeholder.getBoundingClientRect().height + 'px';
279357
this.placeholder.style.position = 'relative';
280358
this.placeholder.style.top = '0';
281359
this.placeholder.style.left = '0';
@@ -295,46 +373,9 @@ export class Materialbox extends Component<MaterialboxOptions> {
295373
this.el.style.width = this.attrHeight+'px';
296374
this.el.removeAttribute('height');
297375
}
298-
// Add overlay
299-
this._overlay = document.createElement('div');
300-
this._overlay.id = 'materialbox-overlay';
301-
this._overlay.style.opacity = '0';
302-
this._overlay.addEventListener('click', e => {
303-
if (this.doneAnimating) this.close();
304-
}, {once: true});
305-
// Put before in origin image to preserve z-index layering.
306-
this.el.before(this._overlay);
307-
// Set dimensions if needed
308-
const overlayOffset = this._overlay.getBoundingClientRect();
309-
this._overlay.style.width = this.windowWidth+'px';
310-
this._overlay.style.height = this.windowHeight+'px';
311-
this._overlay.style.left = -1 * overlayOffset.left+'px';
312-
this._overlay.style.top = -1 * overlayOffset.top+'px';
313-
anim.remove(this.el);
314-
anim.remove(this._overlay);
315-
// Animate Overlay
316-
anim({
317-
targets: this._overlay,
318-
opacity: 1,
319-
duration: this.options.inDuration,
320-
easing: 'easeOutQuad'
321-
});
376+
this._addOverlay();
322377
// Add and animate caption if it exists
323-
if (this.caption !== '') {
324-
if (this._photoCaption) anim.remove(this._photoCaption);
325-
this._photoCaption = document.createElement('div');
326-
this._photoCaption.classList.add('materialbox-caption');
327-
this._photoCaption.innerText = this.caption;
328-
document.body.append(this._photoCaption);
329-
this._photoCaption.style.display = 'inline';
330-
anim({
331-
targets: this._photoCaption,
332-
opacity: 1,
333-
duration: this.options.inDuration,
334-
easing: 'easeOutQuad'
335-
});
336-
}
337-
378+
if (this.caption !== '') this._addCaption();
338379
// Resize Image
339380
const widthPercent = this.originalWidth / this.windowWidth;
340381
const heightPercent = this.originalHeight / this.windowHeight;
@@ -353,7 +394,6 @@ export class Materialbox extends Component<MaterialboxOptions> {
353394
this.newHeight = this.windowHeight * 0.9;
354395
}
355396
this._animateImageIn();
356-
357397
// Handle Exit triggers
358398
window.addEventListener('scroll', this._handleWindowScroll);
359399
window.addEventListener('resize', this._handleWindowResize);
@@ -367,38 +407,16 @@ export class Materialbox extends Component<MaterialboxOptions> {
367407
this._updateVars();
368408
this.doneAnimating = false;
369409
// onCloseStart callback
370-
if (typeof this.options.onCloseStart === 'function') {
371-
this.options.onCloseStart.call(this, this.el);
372-
}
373-
anim.remove(this.el);
374-
anim.remove(this._overlay);
375-
if (this.caption !== '') anim.remove(this._photoCaption);
410+
if (typeof this.options.onCloseStart === 'function') this.options.onCloseStart.call(this, this.el);
411+
//anim.remove(this.el);
412+
//anim.remove(this._overlay);
413+
//if (this.caption !== '') anim.remove(this._photoCaption);
376414
// disable exit handlers
377415
window.removeEventListener('scroll', this._handleWindowScroll);
378416
window.removeEventListener('resize', this._handleWindowResize);
379417
window.removeEventListener('keyup', this._handleWindowEscape);
380-
anim({
381-
targets: this._overlay,
382-
opacity: 0,
383-
duration: this.options.outDuration,
384-
easing: 'easeOutQuad',
385-
complete: () => {
386-
this.overlayActive = false;
387-
this._overlay.remove();
388-
}
389-
});
418+
this._removeOverlay();
390419
this._animateImageOut();
391-
// Remove Caption + reset css settings on image
392-
if (this.caption !== '') {
393-
anim({
394-
targets: this._photoCaption,
395-
opacity: 0,
396-
duration: this.options.outDuration,
397-
easing: 'easeOutQuad',
398-
complete: () => {
399-
this._photoCaption.remove();
400-
}
401-
});
402-
}
420+
if (this.caption !== '') this._removeCaption();
403421
}
404422
}

0 commit comments

Comments
 (0)