| 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; |