1/* global gsap */ 2(function () { 3 const { 4 mergeObjects, 5 prefersReducedMotion 6 } = BreakdanceFrontend.utils; 7 8 class BreakdancePopupAnimation { 9 animatingClass = 'breakdance-popup-animating'; 10 completedClass = 'breakdance-popup-open'; 11 12 slideWidth = 200; 13 slideHeight = 200; 14 flipDistance = 100; 15 16 entranceAnimations = { 17 fade: [ 18 { alpha: 0 }, 19 { alpha: 1 } 20 ], 21 22 slideUp: [ 23 { y: this.slideHeight }, 24 { y: 0 } 25 ], 26 slideDown: [ 27 { y: -this.slideHeight }, 28 { y: 0 } 29 ], 30 slideRight: [ 31 { x: -this.slideWidth }, 32 { x: 0 } 33 ], 34 slideLeft: [ 35 { x: this.slideWidth }, 36 { x: 0 } 37 ], 38 39 flipUp: [ 40 { perspective: 2500, rotateX: -this.flipDistance }, 41 { rotateX: 0 } 42 ], 43 44 flipDown: [ 45 { perspective: 2500, rotateX: this.flipDistance }, 46 { rotateX: 0 } 47 ], 48 49 flipLeft: [ 50 { perspective: 2500, rotateY: -this.flipDistance }, 51 { rotateY: 0 } 52 ], 53 54 flipRight: [ 55 { perspective: 2500, rotateY: this.flipDistance }, 56 { rotateY: 0 } 57 ], 58 59 zoomIn: [ 60 { scale: 0.6 }, 61 { scale: 1 } 62 ], 63 zoomOut: [ 64 { scale: 1.2 }, 65 { scale: 1 } 66 ], 67 }; 68 69 70 exitAnimations = { 71 fade: [ 72 { alpha: 1 }, 73 { alpha: 0 } 74 ], 75 76 slideDown: [ 77 { y: 0 }, 78 { y: this.slideHeight }, 79 ], 80 slideUp: [ 81 { y: 0 }, 82 { y: -this.slideHeight }, 83 ], 84 slideRight: [ 85 { x: 0 }, 86 { x: this.slideWidth }, 87 ], 88 slideLeft: [ 89 { x: 0 }, 90 { x: -this.slideWidth }, 91 ], 92 93 flipUp: [ 94 { rotateX: 0 }, 95 { perspective: 2500, rotateX: this.flipDistance }, 96 ], 97 98 flipDown: [ 99 { rotateX: 0 }, 100 { perspective: 2500, rotateX: -this.flipDistance }, 101 ], 102 103 flipLeft: [ 104 { rotateY: 0 }, 105 { perspective: 2500, rotateY: this.flipDistance }, 106 ], 107 108 flipRight: [ 109 { rotateY: 0 }, 110 { perspective: 2500, rotateY: -this.flipDistance }, 111 ], 112 113 zoomOut: [ 114 { scale: 1 }, 115 { scale: 0.6 }, 116 ], 117 zoomIn: [ 118 { scale: 1 }, 119 { scale: 1.2 }, 120 ], 121 }; 122 123 defaultOptions = { 124 animation_type: null, 125 duration: { number: 500, unit: 'ms', style: '500ms' }, 126 delay: { number: 0, unit: 'ms', style: '0ms' }, 127 ease: 'power1.out', 128 }; 129 130 initialized = false; 131 132 constructor(element, wrapper, options, isExitAnimation = false) { 133 this.element = element; 134 this.wrapper = wrapper; 135 this.options = mergeObjects(this.defaultOptions, options); 136 this.isExitAnimation = isExitAnimation; 137 138 this.init(); 139 } 140 141 getDuration(value) { 142 if (!value) return value; 143 if (value.unit === 's') return value.number; 144 return value.number / 1000; // Convert MS to S 145 } 146 147 createTween() { 148 const type = this.options.animation_type; 149 const animations = this.isExitAnimation ? this.exitAnimations : this.entranceAnimations; 150 151 if (!animations[type]) { 152 console.log(`[POPUP] The selected ${type} animation is invalid.`); 153 return; 154 } 155 156 const [from, to] = animations[type]; 157 const ease = this.options.ease; 158 const duration = this.getDuration(this.options.duration);
159 const delay = this.getDuration(this.options.delay); 160 161 const anim = gsap.timeline({ 162 paused: true 163 }); 164 165 anim.fromTo(this.wrapper, { 166 alpha: this.isExitAnimation ? 1 : 0 167 }, { 168 alpha: this.isExitAnimation ? 0 : 1, 169 duration, 170 delay, 171 }, 0); 172 173 anim.fromTo(this.element, { 174 ...from, 175 autoAlpha: this.isExitAnimation ? 1 : 0 176 }, 177 { 178 ...to, 179 autoAlpha: this.isExitAnimation ? 0 : 1, 180 duration, 181 delay, 182 ease, 183 clearProps: 'all', 184 onStart: () => { 185 this.wrapper.classList.add(this.animatingClass); 186 }, 187 onComplete: () => { 188 this.wrapper.classList.remove(this.animatingClass); 189 if (this.isExitAnimation) { 190 this.wrapper.classList.remove(this.completedClass); 191 } else { 192 this.wrapper.classList.add(this.completedClass); 193 } 194 } 195 }, 0); 196 197 return anim; 198 } 199 200 play() { 201 if (!this.tween) return; 202 return this.tween.progress(0).play(); 203 } 204 205 initTween() { 206 if (this.initialized) return; 207 this.initialized = true; 208 209 this.element.classList.remove(this.completedClass); 210 this.tween = this.createTween(); 211 } 212 213 destroy() { 214 this.initialized = false; 215 216 if (!this.element) return; 217 218 this.element.classList.add(this.completedClass); 219 220 if (!this.tween) return; 221 222 this.tween.kill(); 223 this.tween = null; 224 225 // Remove all inline styles 226 gsap.set(this.element, { clearProps: 'all' }); 227 } 228 229 init() { 230 if (!this.options.animation_type) return; 231 232 if (prefersReducedMotion()) { 233 console.log('[POPUP] Not playing animations. "Prefers Reduced Motion" is enabled.') 234 this.wrapper.classList.add(this.completedClass); 235 return; 236 } 237 238 this.initTween(); 239 } 240 } 241 242 window.BreakdancePopupAnimation = BreakdancePopupAnimation; 243}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.