UNPKG

@nativescript/core

Version:

A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.

214 lines • 8.35 kB
import { Observable } from '../../data/observable'; import { Screen } from '../../platform'; import { isNumber, CORE_ANIMATION_DEFAULTS } from '../../utils'; import { querySelectorAll } from '../core/view-base'; // always increment when adding new transitions to be able to track their state export var SharedTransitionAnimationType; (function (SharedTransitionAnimationType) { SharedTransitionAnimationType[SharedTransitionAnimationType["present"] = 0] = "present"; SharedTransitionAnimationType[SharedTransitionAnimationType["dismiss"] = 1] = "dismiss"; })(SharedTransitionAnimationType || (SharedTransitionAnimationType = {})); class SharedTransitionObservable extends Observable { // @ts-ignore on(eventNames, callback, thisArg) { super.on(eventNames, callback, thisArg); } } let sharedTransitionEvents; let currentStack; /** * Shared Element Transitions (preview) * Allows you to auto animate between shared elements on two different screesn to create smooth navigational experiences. * View components can define sharedTransitionTag="name" alone with a transition through this API. */ export class SharedTransition { /** * Configure a custom transition with presentation/dismissal options. * @param transition The custom Transition instance. * @param options * @returns a configured SharedTransition instance for use with navigational APIs. */ static custom(transition, options) { SharedTransition.updateState(transition.id, { ...(options || {}), instance: transition, activeType: SharedTransitionAnimationType.present, }); const pageEnd = options?.pageEnd; if (isNumber(pageEnd?.duration)) { // Android uses milliseconds/iOS uses seconds // users pass in milliseconds transition.setDuration(__APPLE__ ? pageEnd?.duration / 1000 : pageEnd?.duration); } return { instance: transition }; } /** * Listen to various shared element transition events. * @returns Observable */ static events() { if (!sharedTransitionEvents) { sharedTransitionEvents = new SharedTransitionObservable(); } return sharedTransitionEvents; } /** * Notify a Shared Transition event. * @param id transition instance id * @param eventName Shared Transition event name * @param type TransitionNavigationType * @param action SharedTransitionEventAction */ static notifyEvent(eventName, data) { switch (eventName) { case SharedTransition.startedEvent: case SharedTransition.interactiveUpdateEvent: SharedTransition.inProgress = true; break; default: SharedTransition.inProgress = false; break; } SharedTransition.events().notify({ eventName, data, }); } /** * Update transition state. * @param id Transition instance id * @param state SharedTransitionState */ static updateState(id, state) { if (!currentStack) { currentStack = []; } const existingTransition = SharedTransition.getState(id); if (existingTransition) { // updating existing for (const key in state) { existingTransition[key] = state[key]; // console.log(' ... updating state: ', key, state[key]) } } else { currentStack.push(state); } } /** * Get current state for any transition. * @param id Transition instance id */ static getState(id) { return currentStack?.find((t) => t.instance?.id === id); } /** * Finish transition state. * @param id Transition instance id */ static finishState(id) { const index = currentStack?.findIndex((t) => t.instance?.id === id); if (index > -1) { currentStack.splice(index, 1); } } /** * Gather view collections based on sharedTransitionTag details. * @param fromPage Page moving away from * @param toPage Page moving to * @returns Collections of views pertaining to shared elements or particular pages */ static getSharedElements(fromPage, toPage) { // 1. Presented view: gather all sharedTransitionTag views const presentedSharedElements = querySelectorAll(toPage, 'sharedTransitionTag').filter((v) => !v.sharedTransitionIgnore && typeof v.sharedTransitionTag === 'string'); // console.log('presented sharedTransitionTag total:', presentedSharedElements.length); // 2. Presenting view: gather all sharedTransitionTag views const presentingSharedElements = querySelectorAll(fromPage, 'sharedTransitionTag').filter((v) => !v.sharedTransitionIgnore && typeof v.sharedTransitionTag === 'string'); // console.log( // 'presenting sharedTransitionTags:', // presentingSharedElements.map((v) => v.sharedTransitionTag) // ); // 3. only handle sharedTransitionTag on presenting which match presented const presentedTags = presentedSharedElements.map((v) => v.sharedTransitionTag); return { sharedElements: presentingSharedElements.filter((v) => presentedTags.includes(v.sharedTransitionTag)), presented: presentedSharedElements, presenting: presentingSharedElements, }; } } /** * When the transition starts. */ SharedTransition.startedEvent = 'SharedTransitionStartedEvent'; /** * When the transition finishes. */ SharedTransition.finishedEvent = 'SharedTransitionFinishedEvent'; /** * When the interactive transition cancels. */ SharedTransition.interactiveCancelledEvent = 'SharedTransitionInteractiveCancelledEvent'; /** * When the interactive transition updates with the percent value. */ SharedTransition.interactiveUpdateEvent = 'SharedTransitionInteractiveUpdateEvent'; /** * Enable to see various console logging output of Shared Element Transition behavior. */ SharedTransition.DEBUG = false; /** * Get dimensional rectangle (x,y,width,height) from properties with fallbacks for any undefined values. * @param props combination of properties conformed to SharedTransitionPageProperties * @param defaults fallback properties when props doesn't contain a value for it * @returns { x,y,width,height } */ export function getRectFromProps(props, defaults) { defaults = { x: 0, y: 0, width: getPlatformWidth(), height: getPlatformHeight(), ...(defaults || {}), }; return { x: isNumber(props?.x) ? props?.x : defaults.x, y: isNumber(props?.y) ? props?.y : defaults.y, width: isNumber(props?.width) ? props?.width : defaults.width, height: isNumber(props?.height) ? props?.height : defaults.height, }; } /** * Get spring properties with default fallbacks for any undefined values. * @param props various spring related properties conforming to SharedSpringProperties * @returns */ export function getSpringFromProps(props) { return { tension: isNumber(props?.tension) ? props?.tension : CORE_ANIMATION_DEFAULTS.spring.tension, friction: isNumber(props?.friction) ? props?.friction : CORE_ANIMATION_DEFAULTS.spring.friction, mass: isNumber(props?.mass) ? props?.mass : CORE_ANIMATION_DEFAULTS.spring.mass, velocity: isNumber(props?.velocity) ? props?.velocity : CORE_ANIMATION_DEFAULTS.spring.velocity, delay: isNumber(props?.delay) ? props?.delay : 0, }; } /** * Page starting defaults for provided type. * @param type TransitionNavigationType * @returns { x,y,width,height } */ export function getPageStartDefaultsForType(type) { return { x: type === 'page' ? getPlatformWidth() : 0, y: type === 'page' ? 0 : getPlatformHeight(), width: getPlatformWidth(), height: getPlatformHeight(), }; } function getPlatformWidth() { return __ANDROID__ ? Screen.mainScreen.widthPixels : Screen.mainScreen.widthDIPs; } function getPlatformHeight() { return __ANDROID__ ? Screen.mainScreen.heightPixels : Screen.mainScreen.heightDIPs; } //# sourceMappingURL=shared-transition.js.map