Skip to content

Commit 7c351a5

Browse files
authored
Merge pull request #175 from ASU/UDS-388-image-carousel
feat(component-carousel): uds-388 - refactor old card carouse; create new image carousel
2 parents 40a7788 + 9f37bfe commit 7c351a5

File tree

12 files changed

+573
-358
lines changed

12 files changed

+573
-358
lines changed
Lines changed: 3 additions & 342 deletions
Original file line numberDiff line numberDiff line change
@@ -1,345 +1,6 @@
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";
53

6-
import Glide from "@glidejs/glide";
4+
const AsuCarousel = BaseCarousel;
75

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;
3456
export { AsuCarousel };

packages/component-carousel/src/components/AsuCarousel/index.stories.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
// @ts-check
12
/** @jsx h */
23

34
import { h, Fragment } from "preact";
4-
55
import { AsuCarousel } from ".";
66

77
const myCarouselItems = [
@@ -144,7 +144,7 @@ const myCarouselItems = [
144144

145145
export default {
146146
component: AsuCarousel,
147-
title: "Carousel",
147+
title: "Asu Carousel",
148148
};
149149

150150
export const ThreeItemCarousel = () => (

0 commit comments

Comments
 (0)