Skip to content

Commit cc0f587

Browse files
committed
refactor: (WIP) create classes to handle different animation types
1 parent 445012a commit cc0f587

File tree

6 files changed

+1080
-74
lines changed

6 files changed

+1080
-74
lines changed

js-css-animations/AnimationHandler.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
export default class AnimationHandler {
2+
constructor(element, action, animationId) {
3+
this.element = element;
4+
this.action = action;
5+
this.animationId = animationId;
6+
}
7+
8+
static modules = {};
9+
10+
static async getModule(modulePath) {
11+
if (!(modulePath in this.modules)) {
12+
const module = await import(modulePath);
13+
this.modules[modulePath] = module;
14+
}
15+
16+
return this.modules[modulePath];
17+
}
18+
19+
begin() {
20+
throw new TypeError("Method 'begin' is not implemented.");
21+
}
22+
23+
middle() {
24+
throw new TypeError("Method 'middle' is not implemented.");
25+
}
26+
27+
end() {
28+
throw new Error("Method 'end' is not implemented.");
29+
}
30+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { MOTION_ANIMS_ID, PROPERTY_NAMES, CLASS_NAMES } from './globals.js';
2+
import AnimationHandler from './AnimationHandler.js';
3+
4+
export default class MotionAnimationHandler extends AnimationHandler {
5+
constructor(element, action, animationId) {
6+
super(element, action, animationId);
7+
this.currentTransition = null;
8+
}
9+
10+
static #transitionsModule = null;
11+
12+
static #removeMotionCssClass(element) {
13+
const className = [...element.classList].find(cl =>
14+
cl.match(/js\-anim\-\-(rotate|scale)/)
15+
);
16+
17+
if (className) element.classList.remove(className);
18+
if (className === CLASS_NAMES.move[MOTION_ANIMS_ID.rotate]) {
19+
element.style.removeProperty(PROPERTY_NAMES.angle);
20+
}
21+
}
22+
23+
static async #initTransitionsModule() {
24+
if (!this.#transitionsModule) {
25+
this.#transitionsModule = await AnimationHandler.getModule(
26+
'./transitions.js'
27+
);
28+
}
29+
}
30+
31+
async begin() {
32+
await MotionAnimationHandler.#initTransitionsModule();
33+
this.currentTransition =
34+
MotionAnimationHandler.#transitionsModule.getCurrentTransition(
35+
this.element
36+
);
37+
MotionAnimationHandler.#removeMotionCssClass(this.element);
38+
}
39+
40+
async middle() {
41+
await MotionAnimationHandler.#initTransitionsModule();
42+
if (this.currentTransition) {
43+
MotionAnimationHandler.#transitionsModule.appendTransition(
44+
this.element,
45+
CLASS_NAMES[this.action][this.animationId],
46+
this.currentTransition
47+
);
48+
}
49+
if (this.action === 'move') this.element.classList.add(CLASS_NAMES.moved);
50+
}
51+
52+
end() {
53+
if (this.action === 'moveBack')
54+
this.element.classList.remove(CLASS_NAMES.moved);
55+
}
56+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { CLASS_NAMES, PROPERTY_NAMES } from './globals.js';
2+
import AnimationHandler from './AnimationHandler.js';
3+
4+
export default class VisibilityAnimationHandler extends AnimationHandler {
5+
constructor(element, action, animationId) {
6+
super(element, action, animationId);
7+
this.overflowHidden = null;
8+
this.maintainSpace = null;
9+
}
10+
11+
setOverflowHidden(overflowHidden) {
12+
this.overflowHidden = overflowHidden;
13+
}
14+
15+
setMaintainSpace(maintainSpace) {
16+
this.maintainSpace = maintainSpace;
17+
}
18+
19+
static #applyOverflowHidden(element) {
20+
element.classList.add(CLASS_NAMES.overflowHidden);
21+
}
22+
23+
static #removeOverflowHidden(element) {
24+
element.classList.remove(CLASS_NAMES.overflowHidden);
25+
}
26+
27+
static #hasIterationProp(element) {
28+
const iterationProperty = element.style.getPropertyValue(
29+
PROPERTY_NAMES.iteration
30+
);
31+
32+
return (
33+
iterationProperty != '1' &&
34+
iterationProperty.match(/^(infinite|\d+)$/) !== null
35+
);
36+
}
37+
38+
begin() {
39+
if (this.overflowHidden && this.element.parentElement)
40+
VisibilityAnimationHandler.#applyOverflowHidden(
41+
this.element.parentElement
42+
);
43+
}
44+
45+
middle() {
46+
setTimeout(() => {
47+
if (this.action === 'show') {
48+
this.element.classList.remove(
49+
CLASS_NAMES.hidden,
50+
CLASS_NAMES.collapsed
51+
);
52+
}
53+
}, 0);
54+
}
55+
56+
end() {
57+
if (this.action === 'hide') {
58+
this.maintainSpace
59+
? this.element.classList.add(CLASS_NAMES.hidden)
60+
: this.element.classList.add(CLASS_NAMES.collapsed);
61+
}
62+
63+
if (this.overflowHidden && this.element.parentElement)
64+
VisibilityAnimationHandler.#removeOverflowHidden(
65+
this.element.parentElement
66+
);
67+
68+
if (!VisibilityAnimationHandler.#hasIterationProp(this.element))
69+
this.element.classList.remove(CLASS_NAMES[this.action][this.animationId]);
70+
}
71+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import VisibilityAnimationHandler from './VisibilityAnimationHandler.js';
2+
3+
export default class VisibilityAnimationWithParentResizeHandler extends VisibilityAnimationHandler {
4+
constructor(element, action, animationId) {
5+
super(element, action, animationId);
6+
this.heightTransition = null;
7+
this.widthTransition = null;
8+
this.dimension = null;
9+
this.parentMeasures = null;
10+
}
11+
12+
setDimensionsTransition(heightTransition, widthTransition) {
13+
this.heightTransition = heightTransition;
14+
this.widthTransition = widthTransition;
15+
}
16+
17+
static #resizeParentModule = null;
18+
static #measurementsModule = null;
19+
20+
static async #initResizeParentModule() {
21+
if (!VisibilityAnimationWithParentResizeHandler.#resizeParentModule) {
22+
VisibilityAnimationWithParentResizeHandler.#resizeParentModule =
23+
await this.getModule('./resize-parent.js');
24+
}
25+
}
26+
27+
static async #initMeasurementsModule() {
28+
if (!VisibilityAnimationWithParentResizeHandler.#measurementsModule) {
29+
VisibilityAnimationWithParentResizeHandler.#measurementsModule =
30+
await this.getModule('./measurements.js');
31+
}
32+
}
33+
34+
async begin() {
35+
await VisibilityAnimationWithParentResizeHandler.#initResizeParentModule();
36+
super.begin();
37+
38+
if (this.widthTransition || this.heightTransition) {
39+
const parentData =
40+
VisibilityAnimationWithParentResizeHandler.#resizeParentModule.initParentResize(
41+
{
42+
element: this.element,
43+
action: this.action,
44+
widthTransition: this.widthTransition,
45+
heightTransition: this.heightTransition,
46+
}
47+
);
48+
49+
this.parentMeasures = parentData.parentMeasures;
50+
this.dimension = parentData.dimension;
51+
}
52+
}
53+
54+
async middle() {
55+
await VisibilityAnimationWithParentResizeHandler.#initMeasurementsModule();
56+
super.middle();
57+
58+
setTimeout(() => {
59+
if (this.dimension)
60+
VisibilityAnimationWithParentResizeHandler.#measurementsModule.setParentMaxMeasures(
61+
{
62+
parentState: 'final',
63+
element: this.element,
64+
parentMeasures: this.parentMeasures,
65+
action: this.action,
66+
dimension: this.dimension,
67+
}
68+
);
69+
}, 0);
70+
}
71+
72+
async end() {
73+
await VisibilityAnimationWithParentResizeHandler.#initResizeParentModule();
74+
super.end();
75+
76+
const { widthTransition, heightTransition } = this;
77+
if (widthTransition || heightTransition) {
78+
VisibilityAnimationWithParentResizeHandler.#resizeParentModule.endParentResize(
79+
this.element,
80+
{ widthTransition, heightTransition }
81+
);
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)