|
1 | | -/** @jsx h */ |
2 | | -/* eslint-disable react/prop-types */ |
3 | | -import { h } from "preact"; |
4 | | -//import { useEffect, useState } from "preact/compat"; |
| 1 | +// @ts-check |
| 2 | +import { BaseCarousel } from "../../core/components/BaseCarousel"; |
5 | 3 |
|
6 | | -import Glide from "@glidejs/glide"; |
| 4 | +const AsuCarousel = BaseCarousel; |
7 | 5 |
|
8 | | -// Include required and custom styles for @glidejs/glide |
9 | | -import "./styles.scss"; |
10 | | - |
11 | | -// Requirement: We import bs4-theme css from QA site in preview-head.html. |
12 | | - |
13 | | -// Initially based on this approach: |
14 | | -// https://stackoverflow.com/questions/61596516/glide-js-with-react |
15 | | - |
16 | | -const AsuCarousel = props => { |
17 | | - //console.log("props", props); |
18 | | - |
19 | | - // Only prop for the slider configs we expose is perView. Everything else is |
20 | | - // considered locked down for Web Standards 2. |
21 | | - // We implement "slider" approach per Web Standards 2: |
22 | | - // - Dead-end advance when end is reached. No wrap around. |
23 | | - // - First card is focused. |
24 | | - // - No advance allowed to create whitespace at the end of slide. Stops with |
25 | | - // all visible. |
26 | | - // - Shadow (at either left or right) should disappear when there is no next |
27 | | - // or previous. |
28 | | - // - Instead of tying the bullets to the number of cards, we do a calculation |
29 | | - // tying the bullets to the number of "views" or "panels" so the last bullet |
30 | | - // displays the max number of cards with no overhanging card or extra |
31 | | - // whitespace. TODO Negative impact on a11y from this? |
32 | | - |
33 | | - // Get glide instance class name. |
34 | | - // Defaults to glide. If implementing multiple instnaces, you MUST provide |
35 | | - // an unique instance name for all but one instance. |
36 | | - let instanceName = `glide-${Math.ceil(Math.random() * 10000)}`; |
37 | | - |
38 | | - // Calculate number of buttons to show so we don't advance past perView. |
39 | | - // TODO Limtation: this does not recalc if the screen is resized and the |
40 | | - // perView adapts. In that case Prev/next buttons or swipe may need to be |
41 | | - // used to see all slides. Leverage GlideJS resize event? |
42 | | - // See docs: https://glidejs.com/docs/events/ |
43 | | - // The resize event is implemented further down and commented out until a |
44 | | - // solid strategy for updating the buttons is in place. |
45 | | - let itemCount = props.carouselItems.length; |
46 | | - let buttonCount; |
47 | | - |
48 | | - // Get Original viewport width so we can set buttonCount. |
49 | | - // Note: buttonCount is not adaptive at this time, per comment above. |
50 | | - let vw = Math.max( |
51 | | - document.documentElement.clientWidth || 0, |
52 | | - window.innerWidth || 0 |
53 | | - ); |
54 | | - //console.log("VW", vw); |
55 | | - buttonCount = itemCount; |
56 | | - if (vw < 768) { |
57 | | - // Value for sm breakpoint |
58 | | - //console.log("VW sm", vw); |
59 | | - // No adjusting buttonCount. Always max, one at a time for sm. |
60 | | - } else if (vw < 992) { |
61 | | - // Value for md breakpoint |
62 | | - //console.log("VW md", vw); |
63 | | - if (props.perView >= 2) { |
64 | | - buttonCount = itemCount - 1; |
65 | | - } |
66 | | - } else { |
67 | | - // Value for lg breakpoint |
68 | | - //console.log("VW lg", vw); |
69 | | - if (props.perView >= 2) { |
70 | | - buttonCount = itemCount - 1; |
71 | | - } |
72 | | - if (props.perView >= 3) { |
73 | | - buttonCount = itemCount - 2; |
74 | | - } |
75 | | - } |
76 | | - |
77 | | - // Build out bullets markup based on buttonCount. |
78 | | - let buttonElements = []; |
79 | | - for (var i = 0; i < buttonCount; i++) { |
80 | | - buttonElements.push( |
81 | | - <button |
82 | | - className="glide__bullet" |
83 | | - data-glide-dir={"=" + i} |
84 | | - aria-label={"Slide view " + (i + 1)} |
85 | | - ></button> |
86 | | - ); |
87 | | - } |
88 | | - |
89 | | - // Set a perView value for each breakpoint so we adapt down appropriately. |
90 | | - let perViewSm, perViewMd, perViewLg; |
91 | | - switch (props.perView ? props.perView : "1") { |
92 | | - case "3": |
93 | | - // Values used in config call. |
94 | | - perViewSm = 1; |
95 | | - perViewMd = 2; |
96 | | - perViewLg = 3; |
97 | | - break; |
98 | | - case "2": |
99 | | - // Values used in config call. |
100 | | - perViewSm = 1; |
101 | | - perViewMd = 2; |
102 | | - perViewLg = 2; |
103 | | - break; |
104 | | - case "1": |
105 | | - default: |
106 | | - // Values used in config call. |
107 | | - perViewSm = 1; |
108 | | - perViewMd = 1; |
109 | | - perViewLg = 1; |
110 | | - } |
111 | | - |
112 | | - // Set GlideJS config options, per https://glidejs.com/docs/options/ |
113 | | - const sliderConfig = { |
114 | | - type: "slider", // No wrap-around. |
115 | | - focusAt: 0, |
116 | | - bound: true, // Only if type slider with focusAt 0 |
117 | | - rewind: false, // Only if type slider |
118 | | - gap: 24, // Space between slides... may be impacted by viewport size. |
119 | | - keyboard: true, // Left/Right arrow key support for slides - true is default. Accessible? |
120 | | - startAt: 0, |
121 | | - swipeThreshold: 80, // Distance required for swipe to change slide. |
122 | | - dragThreshold: 120, // Distance for mouse drag to change slide. |
123 | | - perTouch: 1, // Number of slides that can be moved per each swipe/drag. |
124 | | - breakpoints: { |
125 | | - 576: { |
126 | | - // BS4 sm |
127 | | - perView: perViewSm, |
128 | | - peek: { before: 0, after: 62 }, |
129 | | - }, |
130 | | - 768: { |
131 | | - // BS4 md |
132 | | - //perView: props.perView > 1 ? 2 : 1, |
133 | | - perView: perViewSm, |
134 | | - peek: { before: 124, after: 124 }, |
135 | | - }, |
136 | | - 992: { |
137 | | - // BS4 lg |
138 | | - //perView: props.perView > 1 ? props.perView : 1, |
139 | | - perView: perViewMd, |
140 | | - peek: { before: 124, after: 124 }, |
141 | | - }, |
142 | | - 1260: { |
143 | | - // BS4 xl |
144 | | - //perView: props.perView > 1 ? props.perView : 1, |
145 | | - perView: perViewLg, |
146 | | - peek: { before: 124, after: 124 }, |
147 | | - }, |
148 | | - 1400: { |
149 | | - //perView: props.perView > 1 ? props.perView : 1, |
150 | | - perView: perViewLg, |
151 | | - peek: { before: 124, after: 124 }, |
152 | | - }, |
153 | | - 1920: { |
154 | | - //perView: props.perView > 1 ? props.perView : 1, |
155 | | - perView: perViewLg, |
156 | | - peek: { before: 124, after: 124 }, |
157 | | - }, |
158 | | - }, |
159 | | - }; |
160 | | - |
161 | | - // Following wasn't triggered with useEffect approach... so we just ensure |
162 | | - // the DOM is loaded. |
163 | | - |
164 | | - // Works on first load with current code but doesn't refresh successfully in |
165 | | - // Storybook when code is updated - have to reload page. |
166 | | - // Better approach using window ? Learn about that. |
167 | | - // Or https://www.npmjs.com/package/preact-hot-loader ? |
168 | | - document.addEventListener("DOMContentLoaded", function () { |
169 | | - // Load up a new glideJS slider, but don't mount until we have event |
170 | | - // listener (https://glidejs.com/docs/events/) handlers defined and configs |
171 | | - // all mustered. |
172 | | - const slider = new Glide(`#${instanceName}`, sliderConfig); |
173 | | - //const slider = new Glide(".glide", sliderConfig); |
174 | | - |
175 | | - // Implement glidejs event listeners. |
176 | | - |
177 | | - // We use event listeners to clear and set class names to show/hide |
178 | | - // gradients when at the start, middle or end of a slider. |
179 | | - |
180 | | - // On build.before event... |
181 | | - slider.on("build.before", function () { |
182 | | - // Set .slider-start for starting gradient styles. |
183 | | - let gliderElement = document.getElementById(`${instanceName}`); |
184 | | - gliderElement.classList.add("slider-start"); |
185 | | - }); |
186 | | - |
187 | | - // On Move event... |
188 | | - slider.on("move", function (e) { |
189 | | - // Get glider top level element. |
190 | | - let gliderElement = document.getElementById(`${instanceName}`); |
191 | | - |
192 | | - // Gradient-triggering classes. |
193 | | - var gradientClasses = ["slider-start", "slider-mid", "slider-end"]; |
194 | | - |
195 | | - // Set/clear classes for gradients. |
196 | | - if (slider.index == 0) { |
197 | | - // START SLIDE. |
198 | | - // Gradient for start. |
199 | | - gliderElement.classList.remove(...gradientClasses); |
200 | | - gliderElement.classList.add("slider-start"); |
201 | | - // Enable/disable prev/next styles. Glide takes care of actual disable. |
202 | | - document |
203 | | - .querySelector(`#${instanceName} .glide__arrow--prev`) |
204 | | - .classList.add("glide__arrow--disabled"); |
205 | | - document |
206 | | - .querySelector(`#${instanceName} .glide__arrow--next`) |
207 | | - .classList.remove("glide__arrow--disabled"); |
208 | | - } else if (slider.index >= buttonCount - 1) { |
209 | | - // MIDDLE SLIDES. |
210 | | - // Gradient for end. |
211 | | - gliderElement.classList.remove(...gradientClasses); |
212 | | - gliderElement.classList.add("slider-end"); |
213 | | - // Enable/disable prev/next styles. Glide takes care of actual disable. |
214 | | - document |
215 | | - .querySelector(`#${instanceName} .glide__arrow--prev`) |
216 | | - .classList.remove("glide__arrow--disabled"); |
217 | | - document |
218 | | - .querySelector(`#${instanceName} .glide__arrow--next`) |
219 | | - .classList.add("glide__arrow--disabled"); |
220 | | - } else { |
221 | | - // LAST SLIDE. |
222 | | - // Gradient for middle. |
223 | | - gliderElement.classList.remove(...gradientClasses); |
224 | | - gliderElement.classList.add("slider-mid"); |
225 | | - // Enable/disable prev/next styles. Glide takes care of actual disable. |
226 | | - document |
227 | | - .querySelector(`#${instanceName} .glide__arrow--prev`) |
228 | | - .classList.remove("glide__arrow--disabled"); |
229 | | - document |
230 | | - .querySelector(`#${instanceName} .glide__arrow--next`) |
231 | | - .classList.remove("glide__arrow--disabled"); |
232 | | - } |
233 | | - }); |
234 | | - |
235 | | - // On Resize event... |
236 | | - /* TODO Leverage this event to recalculate and updating number of bullets. |
237 | | - * See notes about this above. |
238 | | - slider.on("resize", function () { |
239 | | - // Get Original viewport width |
240 | | - let vw = Math.max( |
241 | | - document.documentElement.clientWidth || 0, |
242 | | - window.innerWidth || 0 |
243 | | - ); |
244 | | - console.log("VW on resize", vw); |
245 | | - if (vw < 768) { |
246 | | - // Value for sm breakpoint |
247 | | - console.log("VW sm", vw); |
248 | | - } else if (vw < 992) { |
249 | | - // Value for md breakpoint |
250 | | - console.log("VW md", vw); |
251 | | - } else { |
252 | | - // Value for lg breakpoint |
253 | | - console.log("VW lg", vw); |
254 | | - } |
255 | | - }); |
256 | | - */ |
257 | | - |
258 | | - slider.mount(); |
259 | | - //console.log(slider); |
260 | | - }); |
261 | | - |
262 | | - // Imported from preact/hooks |
263 | | - /* |
264 | | - useEffect(() => { |
265 | | - console.log("hit AsuCarousel useEffect"); |
266 | | - return () => { |
267 | | - console.log("sliiiiiider"); |
268 | | - const slider = new Glide(".glide", sliderConfiguration); |
269 | | - slider.mount(); |
270 | | - console.log(slider); |
271 | | - }; |
272 | | - }, []); |
273 | | - //}, [slider]); |
274 | | - */ |
275 | | - |
276 | | - // Setup carousel items from the carouselItems prop. |
277 | | - const listItems = props.carouselItems.map(sliderItem => ( |
278 | | - <li key={sliderItem.id.toString()} className="glide__slide slider"> |
279 | | - {sliderItem.item} |
280 | | - </li> |
281 | | - )); |
282 | | - |
283 | | - // For prev and next button icons we use the Creative Commons licensed |
284 | | - // FontAweseome chevron-left and chevron-right SVG without alterations. |
285 | | - // This serves as the required link to the license as per attribution |
286 | | - // guidelines provided at time of use: https://fontawesome.com/license |
287 | | - |
288 | | - return ( |
289 | | - <div className="glide" id={instanceName}> |
290 | | - <div className="glide__track" data-glide-el="track"> |
291 | | - <ul className="glide__slides">{listItems}</ul> |
292 | | - </div> |
293 | | - <div className="glide__bullets" data-glide-el="controls[nav]"> |
294 | | - {buttonElements} |
295 | | - </div> |
296 | | - <div className="glide__arrows" data-glide-el="controls"> |
297 | | - <button |
298 | | - className="glide__arrow glide__arrow--prev" |
299 | | - data-glide-dir="<" |
300 | | - aria-label="Previous slide" |
301 | | - > |
302 | | - <svg |
303 | | - aria-hidden="true" |
304 | | - focusable="false" |
305 | | - data-prefix="fas" |
306 | | - data-icon="chevron-left" |
307 | | - className="svg-inline--fa fa-chevron-left fa-w-10" |
308 | | - role="img" |
309 | | - xmlns="http://www.w3.org/2000/svg" |
310 | | - viewBox="0 0 320 512" |
311 | | - > |
312 | | - <path |
313 | | - fill="currentColor" |
314 | | - d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z" |
315 | | - ></path> |
316 | | - </svg> |
317 | | - </button> |
318 | | - <button |
319 | | - className="glide__arrow glide__arrow--next" |
320 | | - data-glide-dir=">" |
321 | | - aria-label="Next slide" |
322 | | - > |
323 | | - <svg |
324 | | - aria-hidden="true" |
325 | | - focusable="false" |
326 | | - data-prefix="fas" |
327 | | - data-icon="chevron-right" |
328 | | - className="svg-inline--fa fa-chevron-right fa-w-10" |
329 | | - role="img" |
330 | | - xmlns="http://www.w3.org/2000/svg" |
331 | | - viewBox="0 0 320 512" |
332 | | - > |
333 | | - <path |
334 | | - fill="currentColor" |
335 | | - d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z" |
336 | | - ></path> |
337 | | - </svg> |
338 | | - </button> |
339 | | - </div> |
340 | | - </div> |
341 | | - ); |
342 | | -}; |
343 | | - |
344 | | -//export default AsuCarousel; |
345 | 6 | export { AsuCarousel }; |
0 commit comments