@spothero/ui 14.3.4-beta.1 → 14.3.5-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -10
- package/CHANGELOG.tmp +5 -6
- package/package.json +1 -1
- package/styles/v2/components/index.js +0 -1
- package/v2/index-bundled.cjs.js +4 -3
- package/v2/index-bundled.cjs.js.map +1 -1
- package/v2/index-bundled.esm.js +4 -3
- package/v2/index-bundled.esm.js.map +1 -1
- package/v2/index-unbundled.cjs.js +706 -3440
- package/v2/index-unbundled.cjs.js.map +1 -1
- package/v2/index-unbundled.esm.js +696 -3429
- package/v2/index-unbundled.esm.js.map +1 -1
- package/styles/v2/components/ImageCarousel/ImageCarousel.jsx +0 -178
- package/styles/v2/components/ImageCarousel/ImageCarousel.spec.js +0 -53
- package/styles/v2/components/ImageCarousel/ImageCarousel.stories.js +0 -71
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import React, {useState, useEffect, useCallback} from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import {Box} from '@chakra-ui/react';
|
|
4
|
-
import useEmblaCarousel from 'embla-carousel-react';
|
|
5
|
-
import IconChevronLeft from '@spothero/icons/chevron-left';
|
|
6
|
-
import IconChevronRight from '@spothero/icons/chevron-right';
|
|
7
|
-
import V2Button from 'v2/components/Button/Button';
|
|
8
|
-
|
|
9
|
-
const ImageCarousel = ({images, width, height, ...props}) => {
|
|
10
|
-
const imgWidth = width ? `${width}rem` : '100%';
|
|
11
|
-
const imgHeight = `${height}rem`;
|
|
12
|
-
const Button = props.Button || V2Button;
|
|
13
|
-
|
|
14
|
-
const [viewportRef, embla] = useEmblaCarousel({
|
|
15
|
-
skipSnaps: false,
|
|
16
|
-
loop: true,
|
|
17
|
-
});
|
|
18
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
19
|
-
const scrollPrev = useCallback(() => embla && embla.scrollPrev(), [embla]);
|
|
20
|
-
const scrollNext = useCallback(() => embla && embla.scrollNext(), [embla]);
|
|
21
|
-
|
|
22
|
-
const onSelect = useCallback(() => {
|
|
23
|
-
if (!embla) return;
|
|
24
|
-
setSelectedIndex(embla.selectedScrollSnap());
|
|
25
|
-
}, [embla, setSelectedIndex]);
|
|
26
|
-
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
if (!embla) return;
|
|
29
|
-
onSelect();
|
|
30
|
-
embla.on('select', onSelect);
|
|
31
|
-
}, [embla, onSelect]);
|
|
32
|
-
|
|
33
|
-
if (images.length === 1) {
|
|
34
|
-
const image = images[0];
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<Box width={imgWidth} height={imgHeight} {...props}>
|
|
38
|
-
<img
|
|
39
|
-
style={{
|
|
40
|
-
width: '100%',
|
|
41
|
-
height: '100%',
|
|
42
|
-
objectFit: 'cover',
|
|
43
|
-
}}
|
|
44
|
-
src={image.src}
|
|
45
|
-
alt={image.alt}
|
|
46
|
-
/>
|
|
47
|
-
</Box>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<Box
|
|
53
|
-
as="section"
|
|
54
|
-
position="relative"
|
|
55
|
-
overflow="hidden"
|
|
56
|
-
width={imgWidth}
|
|
57
|
-
{...props}
|
|
58
|
-
>
|
|
59
|
-
<Box ref={viewportRef}>
|
|
60
|
-
<Box display="flex" role="group">
|
|
61
|
-
{images.map((image, index) => {
|
|
62
|
-
return (
|
|
63
|
-
<Box
|
|
64
|
-
position="relative"
|
|
65
|
-
flex="0 0 100%"
|
|
66
|
-
key={index}
|
|
67
|
-
aria-label={`Slide ${index + 1} of ${
|
|
68
|
-
images.length
|
|
69
|
-
}`}
|
|
70
|
-
>
|
|
71
|
-
<Box position="relative" height={imgHeight}>
|
|
72
|
-
<img
|
|
73
|
-
style={{
|
|
74
|
-
width: '100%',
|
|
75
|
-
height: '100%',
|
|
76
|
-
objectFit: 'cover',
|
|
77
|
-
}}
|
|
78
|
-
src={image.src}
|
|
79
|
-
alt={image.alt}
|
|
80
|
-
/>
|
|
81
|
-
</Box>
|
|
82
|
-
</Box>
|
|
83
|
-
);
|
|
84
|
-
})}
|
|
85
|
-
</Box>
|
|
86
|
-
</Box>
|
|
87
|
-
<Button
|
|
88
|
-
onClick={scrollPrev}
|
|
89
|
-
width="16"
|
|
90
|
-
height="100%"
|
|
91
|
-
position="absolute"
|
|
92
|
-
left="0"
|
|
93
|
-
top="0"
|
|
94
|
-
bg="none"
|
|
95
|
-
borderRadius="0"
|
|
96
|
-
border="0"
|
|
97
|
-
_hover={{
|
|
98
|
-
bg: 'none',
|
|
99
|
-
border: 0,
|
|
100
|
-
}}
|
|
101
|
-
_focus={{
|
|
102
|
-
boxShadow: 'none',
|
|
103
|
-
}}
|
|
104
|
-
padding="3"
|
|
105
|
-
>
|
|
106
|
-
<Box
|
|
107
|
-
width="100%"
|
|
108
|
-
padding="3"
|
|
109
|
-
borderRadius="50%"
|
|
110
|
-
bgColor="black"
|
|
111
|
-
opacity="0.6"
|
|
112
|
-
>
|
|
113
|
-
<IconChevronLeft />
|
|
114
|
-
</Box>
|
|
115
|
-
</Button>
|
|
116
|
-
<Button
|
|
117
|
-
onClick={scrollNext}
|
|
118
|
-
width="16"
|
|
119
|
-
height="100%"
|
|
120
|
-
position="absolute"
|
|
121
|
-
right="0"
|
|
122
|
-
top="0"
|
|
123
|
-
bg="none"
|
|
124
|
-
borderRadius="0"
|
|
125
|
-
border="0"
|
|
126
|
-
_hover={{
|
|
127
|
-
bg: 'none',
|
|
128
|
-
border: 0,
|
|
129
|
-
}}
|
|
130
|
-
_focus={{
|
|
131
|
-
boxShadow: 'none',
|
|
132
|
-
}}
|
|
133
|
-
padding="3"
|
|
134
|
-
>
|
|
135
|
-
<Box
|
|
136
|
-
width="100%"
|
|
137
|
-
padding="3"
|
|
138
|
-
borderRadius="50%"
|
|
139
|
-
bgColor="black"
|
|
140
|
-
opacity="0.6"
|
|
141
|
-
>
|
|
142
|
-
<IconChevronRight />
|
|
143
|
-
</Box>
|
|
144
|
-
</Button>
|
|
145
|
-
<Box
|
|
146
|
-
color="white"
|
|
147
|
-
borderRadius="1rem"
|
|
148
|
-
bgColor="black"
|
|
149
|
-
opacity="0.6"
|
|
150
|
-
paddingX={3}
|
|
151
|
-
paddingY={1}
|
|
152
|
-
fontSize="xs"
|
|
153
|
-
position="absolute"
|
|
154
|
-
bottom={3}
|
|
155
|
-
left="50%"
|
|
156
|
-
transform="translateX(-50%)"
|
|
157
|
-
>
|
|
158
|
-
{selectedIndex + 1}/{images.length}
|
|
159
|
-
</Box>
|
|
160
|
-
</Box>
|
|
161
|
-
);
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
ImageCarousel.propTypes = {
|
|
165
|
-
/** Array of images with src and alt */
|
|
166
|
-
images: PropTypes.arrayOf(
|
|
167
|
-
PropTypes.shape({
|
|
168
|
-
src: PropTypes.string.isRequired,
|
|
169
|
-
alt: PropTypes.string.isRequired,
|
|
170
|
-
})
|
|
171
|
-
).isRequired,
|
|
172
|
-
/** Height of the carousel in rem */
|
|
173
|
-
height: PropTypes.number.isRequired,
|
|
174
|
-
/** Width of the carousel in rem */
|
|
175
|
-
width: PropTypes.number,
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
export default ImageCarousel;
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import {render, screen} from '@testing-library/react';
|
|
3
|
-
|
|
4
|
-
import ImageCarousel from './ImageCarousel';
|
|
5
|
-
|
|
6
|
-
describe('ImageCarousel', () => {
|
|
7
|
-
it('displays an image without carousel buttons if only one image is present', () => {
|
|
8
|
-
render(
|
|
9
|
-
<ImageCarousel
|
|
10
|
-
width={40}
|
|
11
|
-
height={22.5}
|
|
12
|
-
images={[
|
|
13
|
-
{
|
|
14
|
-
src: 'https://via.placeholder.com/640x360',
|
|
15
|
-
alt: 'A single image',
|
|
16
|
-
},
|
|
17
|
-
]}
|
|
18
|
-
/>
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
expect(screen.getByRole('img')).toHaveAttribute(
|
|
22
|
-
'src',
|
|
23
|
-
'https://via.placeholder.com/640x360'
|
|
24
|
-
);
|
|
25
|
-
expect(screen.queryByRole('button')).toBeNull();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('displays a carousel of images with next and previous buttons if multiple images are present', () => {
|
|
29
|
-
render(
|
|
30
|
-
<ImageCarousel
|
|
31
|
-
width={50}
|
|
32
|
-
height={30}
|
|
33
|
-
images={[
|
|
34
|
-
{
|
|
35
|
-
src: 'https://via.placeholder.com/640x360',
|
|
36
|
-
alt: 'A very neat slide 1',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
src: 'https://via.placeholder.com/450x450',
|
|
40
|
-
alt: 'A very neat slide 2',
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
src: 'https://via.placeholder.com/290x780',
|
|
44
|
-
alt: 'A very neat slide 3',
|
|
45
|
-
},
|
|
46
|
-
]}
|
|
47
|
-
/>
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
expect(screen.queryAllByRole('img')).toHaveLength(3);
|
|
51
|
-
expect(screen.queryAllByRole('button')).toHaveLength(2);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import ImageCarousel from './ImageCarousel';
|
|
3
|
-
import {Box} from '@chakra-ui/react';
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
title: 'v2/ImageCarousel',
|
|
7
|
-
component: ImageCarousel,
|
|
8
|
-
parameters: {
|
|
9
|
-
removeBaseHtmlClass: true,
|
|
10
|
-
importBy: 'ImageCarousel',
|
|
11
|
-
},
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const Template = props => <ImageCarousel {...props} />;
|
|
15
|
-
|
|
16
|
-
const ParentTemplate = props => (
|
|
17
|
-
<Box borderWidth="1px" borderColor="gray.300" padding={4} width="100%">
|
|
18
|
-
<ImageCarousel {...props} />
|
|
19
|
-
</Box>
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
export const SingleImage = Template.bind({});
|
|
23
|
-
SingleImage.args = {
|
|
24
|
-
width: 40,
|
|
25
|
-
height: 22.5,
|
|
26
|
-
images: [
|
|
27
|
-
{
|
|
28
|
-
src: 'https://via.placeholder.com/640x360',
|
|
29
|
-
alt: 'A very neat single slide',
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export const MultipleImages = Template.bind({});
|
|
35
|
-
MultipleImages.args = {
|
|
36
|
-
width: 40,
|
|
37
|
-
height: 22.5,
|
|
38
|
-
images: [
|
|
39
|
-
{
|
|
40
|
-
src: 'https://via.placeholder.com/640x360',
|
|
41
|
-
alt: 'A very neat slide 1',
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
src: 'https://via.placeholder.com/450x450',
|
|
45
|
-
alt: 'A very neat slide 2',
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
src: 'https://via.placeholder.com/290x780',
|
|
49
|
-
alt: 'A very neat slide 3',
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export const ParentWidth = ParentTemplate.bind({});
|
|
55
|
-
ParentWidth.args = {
|
|
56
|
-
height: 20,
|
|
57
|
-
images: [
|
|
58
|
-
{
|
|
59
|
-
src: 'https://via.placeholder.com/640x360',
|
|
60
|
-
alt: 'A very neat slide 1',
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
src: 'https://via.placeholder.com/450x450',
|
|
64
|
-
alt: 'A very neat slide 2',
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
src: 'https://via.placeholder.com/290x780',
|
|
68
|
-
alt: 'A very neat slide 3',
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
};
|