diff --git a/packages/unity-react-core/package.json b/packages/unity-react-core/package.json index c0364c0cd1..1ec177afbd 100644 --- a/packages/unity-react-core/package.json +++ b/packages/unity-react-core/package.json @@ -104,6 +104,7 @@ }, "dependencies": { "@glidejs/glide": "^3.6.0", + "embla-carousel-react": "^8.6.0", "react-share": "^5.3" }, "peerDependencies": { diff --git a/packages/unity-react-core/src/components/ComponentCarousel/components/ImageGalleryCarousel/EmblaImageGalleryPrototype.jsx b/packages/unity-react-core/src/components/ComponentCarousel/components/ImageGalleryCarousel/EmblaImageGalleryPrototype.jsx new file mode 100644 index 0000000000..110319ec5f --- /dev/null +++ b/packages/unity-react-core/src/components/ComponentCarousel/components/ImageGalleryCarousel/EmblaImageGalleryPrototype.jsx @@ -0,0 +1,134 @@ +//@ts-check +import React, { useState, useEffect, useCallback } from "react"; +import useEmblaCarousel from "embla-carousel-react"; +import PropTypes from "prop-types"; + +const EmblaImageGalleryPrototype = ({ + imageItems = [], + hasContent = false, + maxWidth = "996px" +}) => { + //Initializing Embla + const [emblaRef, emblaApi] = useEmblaCarousel({ loop: false, align: "start" }); + + //React state to track the active slide + const [selectedIndex, setSelectedIndex] = useState(0); + + //Navigation controls + const scrollPrev = useCallback(() => emblaApi && emblaApi.scrollPrev(), [emblaApi]); + const scrollNext = useCallback(() => emblaApi && emblaApi.scrollNext(), [emblaApi]); + const scrollTo = useCallback((index) => emblaApi && emblaApi.scrollTo(index), [emblaApi]); + + const onSelect = useCallback(() => { + if (!emblaApi) return; + setSelectedIndex(emblaApi.selectedScrollSnap()); //save number to react state + }, [emblaApi]); + + //Use direct react callback to update uI + useEffect(() => { + if (!emblaApi) return; + emblaApi.on("select", onSelect); + emblaApi.on("reInit", onSelect); + onSelect(); //Set initial state on load + }, [emblaApi, onSelect]); + + if (!imageItems || imageItems.length === 0) return null; //prevent website from crashing if empty data + + const currentItem = imageItems[selectedIndex]; + + return ( + //600px so it matches storybook wrapper limit (temperory) +
+ +
{/* force images to shrink and fit */} + +
+ {imageItems.map((item) => ( //iterate and render every image inside contatiner +
+ {item.imageAltText +
+ ))} +
+
+ + {/* prevent nav bar from getting reduced in size */} +
+ + {/* Arrows */} +
+ + + + {/* thumbnails in nav bar */} +
{/* allow scrolling images if too many */} + {/* clickable thumbnail images */} + {imageItems.map((item, index) => ( + + ))} +
+ + +
+ + {/* Captions */} + {hasContent && (currentItem.title || currentItem.content) && ( //hide if no text caption +
+
+ {currentItem.title &&

{currentItem.title}

} +
+
+
+ )} +
+
+ ); +}; + +EmblaImageGalleryPrototype.propTypes = { + imageItems: PropTypes.array.isRequired, + hasContent: PropTypes.bool, + maxWidth: PropTypes.string, +}; + +export { EmblaImageGalleryPrototype }; + diff --git a/packages/unity-react-core/src/components/ComponentCarousel/components/ImageGalleryCarousel/ImageGalleryCarousel.stories.jsx b/packages/unity-react-core/src/components/ComponentCarousel/components/ImageGalleryCarousel/ImageGalleryCarousel.stories.jsx index b6122c462e..113df4ea12 100644 --- a/packages/unity-react-core/src/components/ComponentCarousel/components/ImageGalleryCarousel/ImageGalleryCarousel.stories.jsx +++ b/packages/unity-react-core/src/components/ComponentCarousel/components/ImageGalleryCarousel/ImageGalleryCarousel.stories.jsx @@ -121,3 +121,15 @@ export const ImageCarouselWithMoreContent = () => ( /> ); + +import { EmblaImageGalleryPrototype } from "./EmblaImageGalleryPrototype"; + +export const EmblaPrototype = () => ( + + + +); diff --git a/yarn.lock b/yarn.lock index a270a21578..35100528e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -517,6 +517,7 @@ __metadata: chromium-bidi: "npm:^3.0.0" classnames: "npm:^2.2.6" css-loader: "npm:^5.2.0" + embla-carousel-react: "npm:^8.6.0" file-loader: "npm:^6.2.0" glob: "npm:^7.1.6" html-entities: "npm:^2.3.1" @@ -14359,6 +14360,34 @@ __metadata: languageName: node linkType: hard +"embla-carousel-react@npm:^8.6.0": + version: 8.6.0 + resolution: "embla-carousel-react@npm:8.6.0" + dependencies: + embla-carousel: "npm:8.6.0" + embla-carousel-reactive-utils: "npm:8.6.0" + peerDependencies: + react: ^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + checksum: 10c0/461b0c427a6fca62e730c7b39d08e9c55b01a2138c173d5b9ebf77ec92092a900b45ac384731c77382b48d5d65946994d3abba6e9899a66d6e16f8ddf191ed1c + languageName: node + linkType: hard + +"embla-carousel-reactive-utils@npm:8.6.0": + version: 8.6.0 + resolution: "embla-carousel-reactive-utils@npm:8.6.0" + peerDependencies: + embla-carousel: 8.6.0 + checksum: 10c0/33d07e6df4d8dec9b4fc95858838ea2d5e5df078039c05b2a342c05ba4979d8d18564a1c607da445fed744daf969a0b5a90124ce487a854e86ced6f0458b51e9 + languageName: node + linkType: hard + +"embla-carousel@npm:8.6.0": + version: 8.6.0 + resolution: "embla-carousel@npm:8.6.0" + checksum: 10c0/f4c598e7be28b70340d31ffd2bebb2472db370b0c81d9b089bf9555cf618695f35dc4a0694565c994c9ab972731123063f945aa09ff485df0df761d79c6a08ef + languageName: node + linkType: hard + "emittery@npm:^0.13.1": version: 0.13.1 resolution: "emittery@npm:0.13.1"