PluginProbe
Block Animations, Motion & Scroll Effects – Ghost Kit / 3.3.2
Block Animations, Motion & Scroll Effects – Ghost Kit v3.3.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 / blocks / accordion / frontend.js

frontend.js in Block Animations, Motion & Scroll Effects – Ghost Kit 3.3.2, at gutenberg/blocks/accordion/frontend.js

260 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { maybeDecode } from '../../utils/encode-decode';
2 import getSiblings from '../../utils/get-siblings';
3
4 /**
5 * Block Accordion
6 */
7 const {
8 location,
9 GHOSTKIT,
10 Motion: { animate },
11 requestAnimationFrame,
12 } = window;
13
14 const { events } = GHOSTKIT;
15
16 let pageHash = location.hash;
17
18 const ANIMATION_SPEED = 300;
19
20 function show($item, animationSpeed, cb) {
21 const $button = $item.querySelector(
22 '.ghostkit-accordion-item-heading > button'
23 );
24 const $content = $item.querySelector('.ghostkit-accordion-item-content');
25
26 $item.classList.add('ghostkit-accordion-item-active');
27
28 if ($button) {
29 $button.setAttribute('aria-expanded', 'true');
30 }
31
32 const contentStyles = window.getComputedStyle($content);
33
34 const endHeight = contentStyles.height;
35 const endPaddingTop = contentStyles.paddingTop;
36 const endPaddingBottom = contentStyles.paddingBottom;
37
38 $content.style.display = 'block';
39 $content.style.overflow = 'hidden';
40
41 const animation = animate(
42 $content,
43 {
44 height: ['0px', endHeight],
45 paddingTop: ['0px', endPaddingTop],
46 paddingBottom: ['0px', endPaddingBottom],
47 },
48 {
49 duration: animationSpeed / 1000,
50 easing: 'ease-out',
51 }
52 );
53
54 animation.finished.then(() => {
55 // Reset styles.
56 $content.style.display = '';
57 $content.style.overflow = '';
58 $content.style.height = '';
59 $content.style.paddingTop = '';
60 $content.style.paddingBottom = '';
61 $item.gktAccordion.animation = null;
62
63 cb();
64 });
65
66 $item.gktAccordion.animation = animation;
67 }
68
69 function hide($item, animationSpeed, cb) {
70 const $button = $item.querySelector(
71 '.ghostkit-accordion-item-heading > button'
72 );
73 const $content = $item.querySelector('.ghostkit-accordion-item-content');
74
75 const contentStyles = window.getComputedStyle($content);
76
77 const startPaddingTop = contentStyles.paddingTop;
78 const startPaddingBottom = contentStyles.paddingBottom;
79 const startHeight = contentStyles.height;
80
81 $content.style.display = 'block';
82 $content.style.overflow = 'hidden';
83
84 const animation = animate(
85 $content,
86 {
87 height: [startHeight, '0px'],
88 paddingTop: [startPaddingTop, '0px'],
89 paddingBottom: [startPaddingBottom, '0px'],
90 },
91 {
92 duration: animationSpeed / 1000,
93 easing: 'ease-out',
94 }
95 );
96
97 animation.finished.then(() => {
98 // Reset styles.
99 $content.style.display = '';
100 $content.style.overflow = '';
101 $content.style.height = '';
102 $content.style.paddingTop = '';
103 $content.style.paddingBottom = '';
104 $item.gktAccordion.animation = null;
105
106 cb();
107 });
108
109 $item.gktAccordion.animation = animation;
110
111 $item.classList.remove('ghostkit-accordion-item-active');
112
113 if ($button) {
114 $button.setAttribute('aria-expanded', 'false');
115 }
116 }
117
118 /**
119 * Toggle accordion item
120 *
121 * @param {Element} $heading - heading element
122 * @param {Int} animationSpeed - animation speed
123 * @param {boolean} skipCollapse - skip collapse other items
124 */
125 function toggleAccordionItem(
126 $heading,
127 animationSpeed = ANIMATION_SPEED,
128 skipCollapse = false
129 ) {
130 const $accordion = $heading.closest('.ghostkit-accordion');
131 const $item = $heading.closest('.ghostkit-accordion-item');
132 const isActive = $item.classList.contains('ghostkit-accordion-item-active');
133 const collapseOne =
134 !skipCollapse &&
135 $accordion.classList.contains('ghostkit-accordion-collapse-one');
136
137 if (!$item?.gktAccordion) {
138 $item.gktAccordion = {
139 animation: null,
140 };
141 }
142
143 if ($item.gktAccordion.animation) {
144 $item.gktAccordion.animation.stop();
145 }
146
147 // Wait for the next frame to call this code after animation stopped.
148 requestAnimationFrame(() => {
149 if (isActive) {
150 events.trigger($accordion, 'hide.accordion.gkt', {
151 relatedTarget: $item,
152 });
153
154 hide($item, animationSpeed, () => {
155 events.trigger($accordion, 'hidden.accordion.gkt', {
156 relatedTarget: $item,
157 });
158 });
159 } else {
160 events.trigger($accordion, 'show.accordion.gkt', {
161 relatedTarget: $item,
162 });
163
164 show($item, animationSpeed, () => {
165 events.trigger($accordion, 'shown.accordion.gkt', {
166 relatedTarget: $item,
167 });
168 });
169 }
170
171 // Hide all other elements
172 if (collapseOne && !isActive) {
173 getSiblings($item).forEach(($this) => {
174 if (
175 $this.classList.contains('ghostkit-accordion-item-active')
176 ) {
177 toggleAccordionItem($this, animationSpeed, true);
178 }
179 });
180 }
181 });
182 }
183
184 /**
185 * Prepare Accordions.
186 */
187 events.on(document, 'init.blocks.gkt', () => {
188 document
189 .querySelectorAll('.ghostkit-accordion:not(.ghostkit-accordion-ready)')
190 .forEach(($this) => {
191 $this.classList.add('ghostkit-accordion-ready');
192
193 events.trigger($this, 'prepare.accordion.gkt');
194
195 // activate by page hash
196 if (pageHash) {
197 const pageHashEncoded = maybeDecode(pageHash);
198
199 let $activeAccordion = $this.querySelector(
200 `:scope > [data-accordion="${pageHashEncoded.replace('#', '')}"]:not(.ghostkit-accordion-item-active) > .ghostkit-accordion-item-heading > button`
201 );
202
203 // Legacy.
204 if (!$activeAccordion) {
205 $activeAccordion = $this.querySelector(
206 `:scope > :not(.ghostkit-accordion-item-active) > .ghostkit-accordion-item-heading > [href="${pageHashEncoded}"]`
207 );
208 }
209
210 if ($activeAccordion) {
211 toggleAccordionItem($activeAccordion, 0);
212 }
213 }
214
215 events.trigger($this, 'prepared.accordion.gkt');
216 });
217 });
218
219 /**
220 * Click Accordions.
221 */
222 events.on(
223 document,
224 'click',
225 '.ghostkit-accordion-item .ghostkit-accordion-item-heading',
226 (e) => {
227 e.preventDefault();
228 toggleAccordionItem(e.delegateTarget, ANIMATION_SPEED);
229 }
230 );
231
232 /*
233 * Activate item on hash change.
234 */
235 const handlerActivateItem = () => {
236 if (window.location.hash === pageHash) {
237 return;
238 }
239
240 pageHash = window.location.hash;
241
242 if (!pageHash) {
243 return;
244 }
245
246 const pageHashEncoded = maybeDecode(pageHash);
247
248 // Activate accordion item.
249 document
250 .querySelectorAll(
251 `.ghostkit-accordion-ready > [data-accordion="${pageHashEncoded.replace('#', '')}"]:not(.ghostkit-accordion-item-active) > .ghostkit-accordion-item-heading > button,
252 .ghostkit-accordion-ready > :not(.ghostkit-accordion-item-active) > .ghostkit-accordion-item-heading > [href="${pageHashEncoded}"]`
253 )
254 .forEach(($this) => {
255 toggleAccordionItem($this, ANIMATION_SPEED);
256 });
257 };
258
259 events.on(window, 'hashchange', handlerActivateItem);
260