UNPKG

8.35 kBJavaScriptView Raw
1import { Observable } from '../../data/observable';
2import { Screen } from '../../platform';
3import { isNumber, CORE_ANIMATION_DEFAULTS } from '../../utils';
4import { querySelectorAll } from '../core/view-base';
5// always increment when adding new transitions to be able to track their state
6export var SharedTransitionAnimationType;
7(function (SharedTransitionAnimationType) {
8 SharedTransitionAnimationType[SharedTransitionAnimationType["present"] = 0] = "present";
9 SharedTransitionAnimationType[SharedTransitionAnimationType["dismiss"] = 1] = "dismiss";
10})(SharedTransitionAnimationType || (SharedTransitionAnimationType = {}));
11class SharedTransitionObservable extends Observable {
12 // @ts-ignore
13 on(eventNames, callback, thisArg) {
14 super.on(eventNames, callback, thisArg);
15 }
16}
17let sharedTransitionEvents;
18let currentStack;
19/**
20 * Shared Element Transitions (preview)
21 * Allows you to auto animate between shared elements on two different screesn to create smooth navigational experiences.
22 * View components can define sharedTransitionTag="name" alone with a transition through this API.
23 */
24export class SharedTransition {
25 /**
26 * Configure a custom transition with presentation/dismissal options.
27 * @param transition The custom Transition instance.
28 * @param options
29 * @returns a configured SharedTransition instance for use with navigational APIs.
30 */
31 static custom(transition, options) {
32 SharedTransition.updateState(transition.id, {
33 ...(options || {}),
34 instance: transition,
35 activeType: SharedTransitionAnimationType.present,
36 });
37 const pageEnd = options?.pageEnd;
38 if (isNumber(pageEnd?.duration)) {
39 // Android uses milliseconds/iOS uses seconds
40 // users pass in milliseconds
41 transition.setDuration(__APPLE__ ? pageEnd?.duration / 1000 : pageEnd?.duration);
42 }
43 return { instance: transition };
44 }
45 /**
46 * Listen to various shared element transition events.
47 * @returns Observable
48 */
49 static events() {
50 if (!sharedTransitionEvents) {
51 sharedTransitionEvents = new SharedTransitionObservable();
52 }
53 return sharedTransitionEvents;
54 }
55 /**
56 * Notify a Shared Transition event.
57 * @param id transition instance id
58 * @param eventName Shared Transition event name
59 * @param type TransitionNavigationType
60 * @param action SharedTransitionEventAction
61 */
62 static notifyEvent(eventName, data) {
63 switch (eventName) {
64 case SharedTransition.startedEvent:
65 case SharedTransition.interactiveUpdateEvent:
66 SharedTransition.inProgress = true;
67 break;
68 default:
69 SharedTransition.inProgress = false;
70 break;
71 }
72 SharedTransition.events().notify({
73 eventName,
74 data,
75 });
76 }
77 /**
78 * Update transition state.
79 * @param id Transition instance id
80 * @param state SharedTransitionState
81 */
82 static updateState(id, state) {
83 if (!currentStack) {
84 currentStack = [];
85 }
86 const existingTransition = SharedTransition.getState(id);
87 if (existingTransition) {
88 // updating existing
89 for (const key in state) {
90 existingTransition[key] = state[key];
91 // console.log(' ... updating state: ', key, state[key])
92 }
93 }
94 else {
95 currentStack.push(state);
96 }
97 }
98 /**
99 * Get current state for any transition.
100 * @param id Transition instance id
101 */
102 static getState(id) {
103 return currentStack?.find((t) => t.instance?.id === id);
104 }
105 /**
106 * Finish transition state.
107 * @param id Transition instance id
108 */
109 static finishState(id) {
110 const index = currentStack?.findIndex((t) => t.instance?.id === id);
111 if (index > -1) {
112 currentStack.splice(index, 1);
113 }
114 }
115 /**
116 * Gather view collections based on sharedTransitionTag details.
117 * @param fromPage Page moving away from
118 * @param toPage Page moving to
119 * @returns Collections of views pertaining to shared elements or particular pages
120 */
121 static getSharedElements(fromPage, toPage) {
122 // 1. Presented view: gather all sharedTransitionTag views
123 const presentedSharedElements = querySelectorAll(toPage, 'sharedTransitionTag').filter((v) => !v.sharedTransitionIgnore && typeof v.sharedTransitionTag === 'string');
124 // console.log('presented sharedTransitionTag total:', presentedSharedElements.length);
125 // 2. Presenting view: gather all sharedTransitionTag views
126 const presentingSharedElements = querySelectorAll(fromPage, 'sharedTransitionTag').filter((v) => !v.sharedTransitionIgnore && typeof v.sharedTransitionTag === 'string');
127 // console.log(
128 // 'presenting sharedTransitionTags:',
129 // presentingSharedElements.map((v) => v.sharedTransitionTag)
130 // );
131 // 3. only handle sharedTransitionTag on presenting which match presented
132 const presentedTags = presentedSharedElements.map((v) => v.sharedTransitionTag);
133 return {
134 sharedElements: presentingSharedElements.filter((v) => presentedTags.includes(v.sharedTransitionTag)),
135 presented: presentedSharedElements,
136 presenting: presentingSharedElements,
137 };
138 }
139}
140/**
141 * When the transition starts.
142 */
143SharedTransition.startedEvent = 'SharedTransitionStartedEvent';
144/**
145 * When the transition finishes.
146 */
147SharedTransition.finishedEvent = 'SharedTransitionFinishedEvent';
148/**
149 * When the interactive transition cancels.
150 */
151SharedTransition.interactiveCancelledEvent = 'SharedTransitionInteractiveCancelledEvent';
152/**
153 * When the interactive transition updates with the percent value.
154 */
155SharedTransition.interactiveUpdateEvent = 'SharedTransitionInteractiveUpdateEvent';
156/**
157 * Enable to see various console logging output of Shared Element Transition behavior.
158 */
159SharedTransition.DEBUG = false;
160/**
161 * Get dimensional rectangle (x,y,width,height) from properties with fallbacks for any undefined values.
162 * @param props combination of properties conformed to SharedTransitionPageProperties
163 * @param defaults fallback properties when props doesn't contain a value for it
164 * @returns { x,y,width,height }
165 */
166export function getRectFromProps(props, defaults) {
167 defaults = {
168 x: 0,
169 y: 0,
170 width: getPlatformWidth(),
171 height: getPlatformHeight(),
172 ...(defaults || {}),
173 };
174 return {
175 x: isNumber(props?.x) ? props?.x : defaults.x,
176 y: isNumber(props?.y) ? props?.y : defaults.y,
177 width: isNumber(props?.width) ? props?.width : defaults.width,
178 height: isNumber(props?.height) ? props?.height : defaults.height,
179 };
180}
181/**
182 * Get spring properties with default fallbacks for any undefined values.
183 * @param props various spring related properties conforming to SharedSpringProperties
184 * @returns
185 */
186export function getSpringFromProps(props) {
187 return {
188 tension: isNumber(props?.tension) ? props?.tension : CORE_ANIMATION_DEFAULTS.spring.tension,
189 friction: isNumber(props?.friction) ? props?.friction : CORE_ANIMATION_DEFAULTS.spring.friction,
190 mass: isNumber(props?.mass) ? props?.mass : CORE_ANIMATION_DEFAULTS.spring.mass,
191 velocity: isNumber(props?.velocity) ? props?.velocity : CORE_ANIMATION_DEFAULTS.spring.velocity,
192 delay: isNumber(props?.delay) ? props?.delay : 0,
193 };
194}
195/**
196 * Page starting defaults for provided type.
197 * @param type TransitionNavigationType
198 * @returns { x,y,width,height }
199 */
200export function getPageStartDefaultsForType(type) {
201 return {
202 x: type === 'page' ? getPlatformWidth() : 0,
203 y: type === 'page' ? 0 : getPlatformHeight(),
204 width: getPlatformWidth(),
205 height: getPlatformHeight(),
206 };
207}
208function getPlatformWidth() {
209 return __ANDROID__ ? Screen.mainScreen.widthPixels : Screen.mainScreen.widthDIPs;
210}
211function getPlatformHeight() {
212 return __ANDROID__ ? Screen.mainScreen.heightPixels : Screen.mainScreen.heightDIPs;
213}
214//# sourceMappingURL=shared-transition.js.map
\No newline at end of file