react-native-reanimated
Version:
More powerful alternative to Animated library for React Native.
166 lines (157 loc) • 6.41 kB
JavaScript
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
import { runOnUIImmediately } from '../../threads';
import { registerEventHandler, unregisterEventHandler } from '../../core';
import { Platform } from 'react-native';
export class ProgressTransitionManager {
constructor() {
_defineProperty(this, "_sharedElementCount", 0);
_defineProperty(this, "_eventHandler", {
isRegistered: false,
onTransitionProgress: -1,
onAppear: -1,
onDisappear: -1,
onSwipeDismiss: -1
});
}
addProgressAnimation(viewTag, progressAnimation) {
runOnUIImmediately(() => {
'worklet';
global.ProgressTransitionRegister.addProgressAnimation(viewTag, progressAnimation);
})();
this.registerEventHandlers();
}
removeProgressAnimation(viewTag) {
this.unregisterEventHandlers();
runOnUIImmediately(() => {
'worklet';
global.ProgressTransitionRegister.removeProgressAnimation(viewTag);
})();
}
registerEventHandlers() {
this._sharedElementCount++;
const eventHandler = this._eventHandler;
if (!eventHandler.isRegistered) {
eventHandler.isRegistered = true;
const eventPrefix = Platform.OS === 'android' ? 'on' : 'top';
let lastProgressValue = -1;
eventHandler.onTransitionProgress = registerEventHandler(eventPrefix + 'TransitionProgress', event => {
'worklet';
const progress = event.progress;
if (progress === lastProgressValue) {
// During screen transition, handler receives two events with the same progress
// value for both screens, but for modals, there is only one event. To optimize
// performance and avoid unnecessary worklet calls, let's skip the second event.
return;
}
lastProgressValue = progress;
global.ProgressTransitionRegister.frame(progress);
});
eventHandler.onAppear = registerEventHandler(eventPrefix + 'Appear', () => {
'worklet';
global.ProgressTransitionRegister.onTransitionEnd();
});
if (Platform.OS === 'android') {
// onFinishTransitioning event is available only on Android and
// is used to handle closing modals
eventHandler.onDisappear = registerEventHandler('onFinishTransitioning', () => {
'worklet';
global.ProgressTransitionRegister.onAndroidFinishTransitioning();
});
} else if (Platform.OS === 'ios') {
// topDisappear event is required to handle closing modals on iOS
eventHandler.onDisappear = registerEventHandler('topDisappear', () => {
'worklet';
global.ProgressTransitionRegister.onTransitionEnd(true);
});
eventHandler.onSwipeDismiss = registerEventHandler('topGestureCancel', () => {
'worklet';
global.ProgressTransitionRegister.onTransitionEnd();
});
}
}
}
unregisterEventHandlers() {
this._sharedElementCount--;
if (this._sharedElementCount === 0) {
const eventHandler = this._eventHandler;
eventHandler.isRegistered = false;
if (eventHandler.onTransitionProgress !== -1) {
unregisterEventHandler(eventHandler.onTransitionProgress);
eventHandler.onTransitionProgress = -1;
}
if (eventHandler.onAppear !== -1) {
unregisterEventHandler(eventHandler.onAppear);
eventHandler.onAppear = -1;
}
if (eventHandler.onDisappear !== -1) {
unregisterEventHandler(eventHandler.onDisappear);
eventHandler.onDisappear = -1;
}
if (eventHandler.onSwipeDismiss !== -1) {
unregisterEventHandler(eventHandler.onSwipeDismiss);
eventHandler.onSwipeDismiss = -1;
}
}
}
}
function createProgressTransitionRegister() {
'worklet';
const progressAnimations = new Map();
const snapshots = new Map();
const currentTransitions = new Set();
const toRemove = new Set();
const progressTransitionManager = {
addProgressAnimation: (viewTag, progressAnimation) => {
progressAnimations.set(viewTag, progressAnimation);
},
removeProgressAnimation: viewTag => {
if (progressAnimations.size > 1) {
// Remove the animation config after the transition is finished
toRemove.add(viewTag);
} else {
progressAnimations.delete(viewTag);
}
},
onTransitionStart: (viewTag, snapshot) => {
snapshots.set(viewTag, snapshot);
currentTransitions.add(viewTag);
// set initial style for re-parented components
progressTransitionManager.frame(0);
},
frame: progress => {
for (const viewTag of currentTransitions) {
const progressAnimation = progressAnimations.get(viewTag);
const snapshot = snapshots.get(viewTag);
progressAnimation(viewTag, snapshot, progress);
}
},
onAndroidFinishTransitioning: () => {
if (toRemove.size > 0) {
// it should be ran only on modal closing
progressTransitionManager.onTransitionEnd();
}
},
onTransitionEnd: function () {
let removeViews = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
for (const viewTag of currentTransitions) {
_notifyAboutEnd(viewTag, removeViews);
}
currentTransitions.clear();
snapshots.clear();
if (toRemove.size > 0) {
for (const viewTag of toRemove) {
progressAnimations.delete(viewTag);
}
toRemove.clear();
}
}
};
return progressTransitionManager;
}
runOnUIImmediately(() => {
'worklet';
global.ProgressTransitionRegister = createProgressTransitionRegister();
})();
//# sourceMappingURL=ProgressTransitionManager.js.map