main
js 96 lines 2.74 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 import {canUseDOM} from 'shared/ExecutionEnvironment';
9
10 /**
11 * Generate a mapping of standard vendor prefixes using the defined style property and event name.
12 *
13 * @param {string} styleProp
14 * @param {string} eventName
15 * @returns {object}
16 */
17 function makePrefixMap(styleProp, eventName) {
18 const prefixes = {};
19
20 prefixes[styleProp.toLowerCase()] = eventName.toLowerCase();
21 prefixes['Webkit' + styleProp] = 'webkit' + eventName;
22 prefixes['Moz' + styleProp] = 'moz' + eventName;
23
24 return prefixes;
25 }
26
27 /**
28 * A list of event names to a configurable list of vendor prefixes.
29 */
30 const vendorPrefixes = {
31 animationend: makePrefixMap('Animation', 'AnimationEnd'),
32 animationiteration: makePrefixMap('Animation', 'AnimationIteration'),
33 animationstart: makePrefixMap('Animation', 'AnimationStart'),
34 transitionrun: makePrefixMap('Transition', 'TransitionRun'),
35 transitionstart: makePrefixMap('Transition', 'TransitionStart'),
36 transitioncancel: makePrefixMap('Transition', 'TransitionCancel'),
37 transitionend: makePrefixMap('Transition', 'TransitionEnd'),
38 };
39
40 /**
41 * Event names that have already been detected and prefixed (if applicable).
42 */
43 const prefixedEventNames = {};
44
45 /**
46 * Element to check for prefixes on.
47 */
48 let style = {};
49
50 /**
51 * Bootstrap if a DOM exists.
52 */
53 if (canUseDOM) {
54 style = document.createElement('div').style;
55
56 // On some platforms, in particular some releases of Android 4.x,
57 // the un-prefixed "animation" and "transition" properties are defined on the
58 // style object but the events that fire will still be prefixed, so we need
59 // to check if the un-prefixed events are usable, and if not remove them from the map.
60 if (!('AnimationEvent' in window)) {
61 delete vendorPrefixes.animationend.animation;
62 delete vendorPrefixes.animationiteration.animation;
63 delete vendorPrefixes.animationstart.animation;
64 }
65
66 // Same as above
67 if (!('TransitionEvent' in window)) {
68 delete vendorPrefixes.transitionend.transition;
69 }
70 }
71
72 /**
73 * Attempts to determine the correct vendor prefixed event name.
74 *
75 * @param {string} eventName
76 * @returns {string}
77 */
78 function getVendorPrefixedEventName(eventName) {
79 if (prefixedEventNames[eventName]) {
80 return prefixedEventNames[eventName];
81 } else if (!vendorPrefixes[eventName]) {
82 return eventName;
83 }
84
85 const prefixMap = vendorPrefixes[eventName];
86
87 for (const styleProp in prefixMap) {
88 if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) {
89 return (prefixedEventNames[eventName] = prefixMap[styleProp]);
90 }
91 }
92
93 return eventName;
94 }
95
96 export default getVendorPrefixedEventName;