PluginProbe
Block Animations, Motion & Scroll Effects – Ghost Kit / 3.7.2
Block Animations, Motion & Scroll Effects – Ghost Kit v3.7.2
3.7.2 3.7.1 3.7.0 3.6.1 trunk 1.6.3 2.25.0 3.3.0 3.3.1 3.3.2 3.3.3 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.5.0 3.5.1 3.6.0
ghostkit / gutenberg / extend / effects / frontend.js

frontend.js in Block Animations, Motion & Scroll Effects – Ghost Kit 3.7.2, at gutenberg/extend/effects/frontend.js

246 lines 5.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import round from '../../utils/round';
2 import DEFAULTS from './reveal/defaults';
3
4 const {
5 GHOSTKIT: { events, instance },
6 Motion: { animate, spring, inView },
7 } = window;
8
9 const isReducedMotion = window.matchMedia(
10 '(prefers-reduced-motion: reduce)'
11 ).matches;
12
13 /**
14 * Effects Reveal.
15 */
16 events.on(document, 'init.blocks.gkt', () => {
17 document.querySelectorAll('[data-gkt-effects]').forEach(($element) => {
18 if (isReducedMotion) {
19 $element.removeAttribute('data-gkt-effects');
20 return;
21 }
22
23 const dataString = $element.getAttribute('data-gkt-effects');
24 let data;
25
26 try {
27 data = JSON.parse(dataString);
28 } catch (_e) {
29 data = false;
30 }
31
32 $element.removeAttribute('data-gkt-effects');
33
34 if (!data) {
35 return;
36 }
37
38 events.trigger($element, 'prepare.effects.gkt', { data });
39
40 instance.set($element, 'effects', data);
41
42 if (!data?.reveal) {
43 return;
44 }
45
46 const config = {
47 ...DEFAULTS,
48 ...data.reveal,
49 };
50
51 events.trigger($element, 'prepare.effects.reveal.gkt', { config });
52
53 const stopInView = inView($element, () => {
54 $element.classList.remove('ghostkit-effects-reveal');
55
56 const options = {};
57
58 // Easing with Cubic Bezier.
59 if (config?.transition?.type === 'easing') {
60 options.type = 'tween';
61 options.duration = config.transition.duration;
62 options.delay = config.transition.delay;
63 options.ease = config.transition.easing;
64
65 // Easing with Spring.
66 } else if (config?.transition?.type === 'spring') {
67 options.type = spring;
68 options.delay = config.transition.delay;
69 options.stiffness = config.transition.stiffness;
70 options.damping = config.transition.damping;
71 options.mass = config.transition.mass;
72 }
73
74 const keyframes = {};
75
76 if (config.opacity !== 1) {
77 keyframes.opacity = [config.opacity, 1];
78 }
79 if (config.x !== 0) {
80 keyframes.x = [config.x, 0];
81 }
82 if (config.y !== 0) {
83 keyframes.y = [config.y, 0];
84 }
85 if (config.scale !== 1) {
86 keyframes.scale = [config.scale, 1];
87 }
88 if (config.rotate !== 0) {
89 keyframes.rotate = [config.rotate, 0];
90 }
91
92 const eventData = {
93 config,
94 keyframes,
95 options,
96 stopInView,
97 leaveCallback: () => {},
98 };
99
100 events.trigger($element, 'show.effects.reveal.gkt', eventData);
101
102 // Stop inView listener.
103 eventData.stopInView();
104
105 const animation = animate($element, keyframes, options);
106
107 animation.then(() => {
108 events.trigger(
109 $element,
110 'showed.effects.reveal.gkt',
111 eventData
112 );
113 });
114
115 // This will fire when the element leaves the viewport
116 return eventData.leaveCallback;
117 });
118
119 events.trigger($element, 'prepared.effects.reveal.gkt', { config });
120 });
121 });
122
123 /**
124 * Counters (Number Box, Progress Bar).
125 */
126 events.on(document, 'init.blocks.gkt', () => {
127 document
128 .querySelectorAll('.ghostkit-count-up:not(.ghostkit-count-up-ready)')
129 .forEach(($counter) => {
130 $counter.classList.add('ghostkit-count-up-ready');
131
132 if (isReducedMotion) {
133 return;
134 }
135
136 const isProgress = $counter.classList.contains(
137 'ghostkit-progress-bar'
138 );
139 const $progressRoot = isProgress
140 ? $counter.closest('.ghostkit-progress')
141 : null;
142 const from =
143 parseFloat($counter.getAttribute('data-count-from')) || 0;
144 const to =
145 parseFloat(
146 isProgress
147 ? $counter.getAttribute('aria-valuenow')
148 : $counter.textContent
149 ) || 0;
150 let $progressCountBadgeWrap;
151 let $progressCountBadge;
152 let digits = 0;
153
154 // biome-ignore-start lint/suspicious/noTemplateCurlyInString: `${val}` is a literal placeholder token inside the counter mask, not a template literal.
155 // prepare mask.
156 let mask = '';
157 if (!isProgress) {
158 mask = $counter.textContent.replace(to, '${val}');
159 }
160 if (!/\${val}/.test(mask)) {
161 mask = '${val}';
162 }
163
164 if (isProgress) {
165 $progressCountBadgeWrap = $progressRoot?.querySelector(
166 '.ghostkit-progress-bar-count'
167 );
168
169 if ($progressCountBadgeWrap) {
170 $progressCountBadge = $progressCountBadgeWrap.querySelector(
171 ':scope > div > span:nth-child(2)'
172 );
173
174 $progressCountBadgeWrap.style.width = '0%';
175 $progressCountBadge.textContent = '0';
176 }
177
178 $counter.style.width = '0%';
179 } else {
180 $counter.textContent = mask.replace('${val}', from);
181
182 // Calculate digits after the decimal point.
183 digits = Math.max(
184 (`${from}`.split('.')?.[1] || '').length,
185 (`${to}`.split('.')?.[1] || '').length
186 );
187 }
188
189 const config = {
190 from,
191 to,
192 duration: 1,
193 easing: [0.6, 0, 0.3, 1],
194 cb(progress) {
195 const position = (to - from) * progress + from;
196
197 if (isProgress) {
198 $counter.style.width = `${position}%`;
199
200 if ($progressCountBadgeWrap) {
201 $progressCountBadgeWrap.style.width = `${position}%`;
202 }
203
204 if ($progressCountBadge) {
205 $progressCountBadge.textContent =
206 Math.ceil(position);
207 }
208 } else {
209 $counter.textContent = mask.replace(
210 '${val}',
211 round(position, digits)
212 );
213 }
214 },
215 };
216 // biome-ignore-end lint/suspicious/noTemplateCurlyInString: `${val}` is a literal placeholder token inside the counter mask, not a template literal.
217
218 events.trigger($counter, 'prepare.counter.gkt', { config });
219
220 const inViewTarget = $progressRoot || $counter;
221
222 // Animate counter.
223 const stopInView = inView(
224 inViewTarget,
225 () => {
226 stopInView();
227
228 events.trigger($counter, 'count.counter.gkt', { config });
229
230 animate(0, 1, {
231 duration: config.duration,
232 ease: config.easing,
233 onUpdate: (progress) => {
234 config.cb(progress);
235 },
236 }).then(() => {
237 events.trigger($counter, 'counted.counter.gkt', {
238 config,
239 });
240 });
241 },
242 { margin: '-50px' }
243 );
244 });
245 });
246