UNPKG

react-native-reanimated

Version:

More powerful alternative to Animated library for React Native.

166 lines (157 loc) • 6.41 kB
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