-
Notifications
You must be signed in to change notification settings - Fork 683
/
carousel.js
180 lines (167 loc) · 5.51 KB
/
carousel.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import React, { useMemo } from 'react';
import { arrayOf, bool, number, shape, string } from 'prop-types';
import { useIntl } from 'react-intl';
import {
ChevronLeft as ChevronLeftIcon,
ChevronRight as ChevronRightIcon
} from 'react-feather';
import { transparentPlaceholder } from '@magento/peregrine/lib/util/images';
import { useProductImageCarousel } from '@magento/peregrine/lib/talons/ProductImageCarousel/useProductImageCarousel';
import { useStyle } from '../../classify';
import AriaButton from '../AriaButton';
import Icon from '../Icon';
import Image from '../Image';
import defaultClasses from './carousel.module.css';
import Thumbnail from './thumbnail';
const IMAGE_WIDTH = 640;
/**
* Carousel component for product images
* Carousel - Component that holds number of images
* where typically one image visible, and other
* images can be navigated through previous and next buttons
*
* @typedef ProductImageCarousel
* @kind functional component
*
* @param {props} props
*
* @returns {React.Element} React carousel component that displays a product image
*/
const ProductImageCarousel = props => {
const { images } = props;
const { formatMessage } = useIntl();
const talonProps = useProductImageCarousel({
images,
imageWidth: IMAGE_WIDTH
});
const {
currentImage,
activeItemIndex,
altText,
handleNext,
handlePrevious,
handleThumbnailClick,
sortedImages
} = talonProps;
// create thumbnail image component for every images in sorted order
const thumbnails = useMemo(
() =>
sortedImages.map((item, index) => (
<Thumbnail
key={item.uid}
item={item}
itemIndex={index}
isActive={activeItemIndex === index}
onClickHandler={handleThumbnailClick}
/>
)),
[activeItemIndex, handleThumbnailClick, sortedImages]
);
const classes = useStyle(defaultClasses, props.classes);
let image;
if (currentImage.file) {
image = (
<Image
alt={altText}
classes={{
image: classes.currentImage,
root: classes.imageContainer
}}
resource={currentImage.file}
width={IMAGE_WIDTH}
/>
);
} else {
image = (
<Image
alt={altText}
classes={{
image: classes.currentImage_placeholder,
root: classes.imageContainer
}}
src={transparentPlaceholder}
/>
);
}
const previousButton = formatMessage({
id: 'productImageCarousel.previousButtonAriaLabel',
defaultMessage: 'Previous Image'
});
const nextButton = formatMessage({
id: 'productImageCarousel.nextButtonAriaLabel',
defaultMessage: 'Next Image'
});
const chevronClasses = { root: classes.chevron };
return (
<div className={classes.root}>
<div className={classes.carouselContainer}>
<AriaButton
className={classes.previousButton}
onPress={handlePrevious}
aria-label={previousButton}
type="button"
>
<Icon
classes={chevronClasses}
src={ChevronLeftIcon}
size={40}
/>
</AriaButton>
{image}
<AriaButton
className={classes.nextButton}
onPress={handleNext}
aria-label={nextButton}
type="button"
>
<Icon
classes={chevronClasses}
src={ChevronRightIcon}
size={40}
/>
</AriaButton>
</div>
<div className={classes.thumbnailList}>{thumbnails}</div>
</div>
);
};
/**
* Props for {@link ProductImageCarousel}
*
* @typedef props
*
* @property {Object} classes An object containing the class names for the
* ProductImageCarousel component
* @property {string} classes.currentImage classes for visible image
* @property {string} classes.imageContainer classes for image container
* @property {string} classes.nextButton classes for next button
* @property {string} classes.previousButton classes for previous button
* @property {string} classes.root classes for root container
* @property {Object[]} images Product images input for Carousel
* @property {bool} images[].disabled Is image disabled
* @property {string} images[].file filePath of image
* @property {string} images[].uid the id of the image
* @property {string} images[].label label for image
* @property {string} images[].position Position of image in Carousel
*/
ProductImageCarousel.propTypes = {
classes: shape({
carouselContainer: string,
currentImage: string,
currentImage_placeholder: string,
imageContainer: string,
nextButton: string,
previousButton: string,
root: string
}),
images: arrayOf(
shape({
label: string,
position: number,
disabled: bool,
file: string.isRequired,
uid: string.isRequired
})
).isRequired
};
export default ProductImageCarousel;