Skip to content

Commit

Permalink
🐛♻️ handling resize event
Browse files Browse the repository at this point in the history
  • Loading branch information
provok-me committed Aug 28, 2021
1 parent af9e784 commit 67fa5de
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 86 deletions.
6 changes: 5 additions & 1 deletion packages/alice/src/contracts/Tween.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface TweenCoordinates {
y: number;
}

export interface TweenState {
export interface TweenStateDefault {
itemId: string | null;
classes: string[];
boundings: Boundings | null;
Expand All @@ -21,6 +21,10 @@ export interface TweenState {
collantEvent: string;
}

export interface TweenState extends TweenStateDefault {
itemId: string;
}

export type TriggerOffsets = [number, number];

export interface TweenOptions {
Expand Down
2 changes: 1 addition & 1 deletion packages/alice/src/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export type AnyFunction = (...args: any[]) => typeof args;
export type AnyFunction = (...args: any[]) => typeof args | void;
10 changes: 8 additions & 2 deletions packages/alice/src/detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,16 +173,22 @@ export class Detect extends Tween {
return;
}

this._handleResize();
// Clear transforms before cleaning tweens
this._handleDetectResize();

// Handling all tweens global reset during resize (debounced by using static method).
Tween._handleResize();
},
outerHeight: (val: number) => {
if (!val) {
return;
}

this._handleResize();
// Clear transforms before cleaning tweens
this._handleDetectResize();

// Handling all tweens global reset during resize (debounced by using static method).
Tween._handleResize();
},
});
}
Expand Down
26 changes: 17 additions & 9 deletions packages/alice/src/speed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,15 @@ export class Speed extends Tween {
const { height: windowHeight } = Speed._eva.view.data;

// Computing in view detection for each tween.
tween.state.isInView = isInView(
Speed._reactor.data.scrollTop,
windowHeight,
triggerOffsets,
boundings,
coordinates
);
if (tween.options.addClass) {
tween.state.isInView = isInView(
Speed._reactor.data.scrollTop,
windowHeight,
triggerOffsets,
boundings,
coordinates
);
}

// Computing in view detection for speed computations.
tween.state.isInSpeedView = isInView(
Expand Down Expand Up @@ -283,16 +285,22 @@ export class Speed extends Tween {
return;
}

this._handleResize();
// Clear transforms before cleaning tweens
this._handleSpeedResize();

// Handling all tweens global reset during resize (debounced by using static method).
Tween._handleResize();
},
outerHeight: (val) => {
if (!val) {
return;
}

this._handleResize();
// Clear transforms before cleaning tweens
this._handleSpeedResize();

// Handling all tweens global reset during resize (debounced by using static method).
Tween._handleResize();
},
});
}
Expand Down
149 changes: 76 additions & 73 deletions packages/alice/src/tween.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import debounce from 'lodash/debounce';
import raf from 'raf';
import fastdomCore from 'fastdom';
import fastdomPromised from 'fastdom/extensions/fastdom-promised';
Expand All @@ -9,6 +10,7 @@ import {
TweenList,
TweenState,
InputTweenOptions,
TweenStateDefault,
} from './contracts/Tween';

// fastdom extension
Expand Down Expand Up @@ -97,11 +99,11 @@ export abstract class Tween {
/**
* @description Default tween state.
* @static
* @type {TweenState}
* @type {TweenStateDefault}
* @memberof Tween
*/

static _defaultState: TweenState = {
static _defaultState: TweenStateDefault = {
itemId: null,
classes: [],
boundings: null,
Expand All @@ -123,12 +125,64 @@ export abstract class Tween {
};

/**
* @description Boolean used to debounce the tweens reset during window resize.
* @private
* @description Number (ms) used to debounce the tweens reset during window resize.
* @static
* @memberof Tween
*/

private _resizingMainHandler = false;
static _resizeDelay = 300;

/**
* @description Handling tweens when window resizes.
* @author Alphability <[email protected]>
* @static
* @memberof Tween
*/
static _handleResize = debounce(() => {
if (!Tween._reactor) {
return;
}

// Read DOM
Object.values(Tween._list).forEach((item) => {
/**
* Resetting each prop that has something to do with the window (positions, scroll, etc.).
* ⚠️ In order to reset a Proxy prop
* you need to go to the furthest nested level.
* NOTE: Do not reset classes here. They're handled in the proxy itself.
*/

// Reset boundings since they're based on the window's layout
item.state.boundings = Tween._defaultState.boundings;
item.state.targetBoundings = Tween._defaultState.targetBoundings;

// Reset the transform coordinates since the transforms are cleared during the resize
item.state.coordinates.x = Tween._defaultState.coordinates.x;
item.state.coordinates.y = Tween._defaultState.coordinates.y;

// Reset lerp since the transforms have been cleared
item.state.lerpDone = Tween._defaultState.lerpDone;

// NOTE: In view are computed during the scroll. The resize handler force a scroll update at the end of the function. So, no need to reset inview values.

item.state.collant.parsedOffset =
Tween._defaultState.collant.parsedOffset;
item.state.collant.scrollOffset =
Tween._defaultState.collant.scrollOffset;
item.state.collantEvent = Tween._defaultState.collantEvent;
});

raf(() => {
/**
* ⚠️ Force update elements' scroll calculation
* on the frame following the coordinates resets.
*/

if (Tween._reactor.data.scrollTop) {
Tween._reactor.data.scrollTop -= 1;
}
});
}, Tween._resizeDelay);

/**
* @description Emitting a notification.
Expand Down Expand Up @@ -236,13 +290,21 @@ export abstract class Tween {
* @memberof Tween
*/

private _getProxyState(element: HTMLElement, itemIndex: number): TweenState {
private _getProxyState(
itemId: string,
element: HTMLElement,
itemIndex: number
): TweenState {
// ⚠️ The state needs to be declared here in order to give a fresh object to each proxy
const state = JSON.parse(JSON.stringify(Tween._defaultState));
const state: TweenState = {
...JSON.parse(JSON.stringify(Tween._defaultState)),
itemId,
};

return new Proxy(state, {
set: (target, prop, propValue, receiver) => {
const oldClasses = [...target.classes];

// isInView
if (prop === 'isInView' && target.isInView !== propValue) {
const eventName = propValue ? 'enter-view' : 'leave-view';
Expand Down Expand Up @@ -279,10 +341,14 @@ export abstract class Tween {
);

classesToRemove.forEach((className: string) => {
element.classList.remove(className);
fastdom.mutate(() => {
element.classList.remove(className);
});
});
classesToAdd.forEach((className: string) => {
element.classList.add(className);
fastdom.mutate(() => {
element.classList.add(className);
});
});
}

Expand Down Expand Up @@ -322,9 +388,8 @@ export abstract class Tween {
itemIndex,
inputOptions,
options: processedOptions,
state: this._getProxyState(element, itemIndex),
state: this._getProxyState(itemId, element, itemIndex),
};
Tween._list[itemId].state.itemId = itemId;

return itemId;
}
Expand All @@ -344,68 +409,6 @@ export abstract class Tween {
delete Tween._list[id];
}

/**
* @description Handling tweens when window resizes.
* @author Alphability <[email protected]>
* @protected
* @returns {void}
* @memberof Tween
*/

protected _handleResize(): void {
if (this._resizingMainHandler || !Tween._reactor) {
return;
}

this._resizingMainHandler = true;
const classes: string[][] = [];

// Read DOM
Object.values(Tween._list).forEach((item, index) => {
/**
* Resetting each prop.
* ⚠️ In order to reset a Proxy prop
* you need to go to the furthest nested level.
*/
classes[index] = [...item.state.classes];
item.state.classes = Tween._defaultState.classes;
item.state.boundings = Tween._defaultState.boundings;
item.state.targetBoundings = Tween._defaultState.targetBoundings;
item.state.coordinates.x = Tween._defaultState.coordinates.x;
item.state.coordinates.y = Tween._defaultState.coordinates.y;
item.state.lerpDone = Tween._defaultState.lerpDone;
item.state.collant.parsedOffset =
Tween._defaultState.collant.parsedOffset;
item.state.collant.scrollOffset =
Tween._defaultState.collant.scrollOffset;
item.state.isInView = Tween._defaultState.isInView;
item.state.isInSpeedView = Tween._defaultState.isInSpeedView;
item.state.collantEvent = Tween._defaultState.collantEvent;
});

// Write DOM
Object.values(Tween._list).forEach((item, index) => {
classes[index].forEach((className) => {
fastdom.mutate(() => {
item.element.classList.remove(className);
});
});
});

raf(() => {
/**
* ⚠️ Force update elements' scroll calculation
* on the frame following the DOM resets.
*/

if (Tween._reactor.data.scrollTop) {
Tween._reactor.data.scrollTop -= 1;
}

this._resizingMainHandler = false;
});
}

protected _destroy(): void {
const ids = Object.keys(Tween._list);
this._remove(ids);
Expand Down

0 comments on commit 67fa5de

Please sign in to comment.