@spothero/ui 14.3.4 → 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.
@@ -1,177 +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 Button 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
-
13
- const [viewportRef, embla] = useEmblaCarousel({
14
- skipSnaps: false,
15
- loop: true,
16
- });
17
- const [selectedIndex, setSelectedIndex] = useState(0);
18
- const scrollPrev = useCallback(() => embla && embla.scrollPrev(), [embla]);
19
- const scrollNext = useCallback(() => embla && embla.scrollNext(), [embla]);
20
-
21
- const onSelect = useCallback(() => {
22
- if (!embla) return;
23
- setSelectedIndex(embla.selectedScrollSnap());
24
- }, [embla, setSelectedIndex]);
25
-
26
- useEffect(() => {
27
- if (!embla) return;
28
- onSelect();
29
- embla.on('select', onSelect);
30
- }, [embla, onSelect]);
31
-
32
- if (images.length === 1) {
33
- const image = images[0];
34
-
35
- return (
36
- <Box width={imgWidth} height={imgHeight} {...props}>
37
- <img
38
- style={{
39
- width: '100%',
40
- height: '100%',
41
- objectFit: 'cover',
42
- }}
43
- src={image.src}
44
- alt={image.alt}
45
- />
46
- </Box>
47
- );
48
- }
49
-
50
- return (
51
- <Box
52
- as="section"
53
- position="relative"
54
- overflow="hidden"
55
- width={imgWidth}
56
- {...props}
57
- >
58
- <Box ref={viewportRef}>
59
- <Box display="flex" role="group">
60
- {images.map((image, index) => {
61
- return (
62
- <Box
63
- position="relative"
64
- flex="0 0 100%"
65
- key={index}
66
- aria-label={`Slide ${index + 1} of ${
67
- images.length
68
- }`}
69
- >
70
- <Box position="relative" height={imgHeight}>
71
- <img
72
- style={{
73
- width: '100%',
74
- height: '100%',
75
- objectFit: 'cover',
76
- }}
77
- src={image.src}
78
- alt={image.alt}
79
- />
80
- </Box>
81
- </Box>
82
- );
83
- })}
84
- </Box>
85
- </Box>
86
- <Button
87
- onClick={scrollPrev}
88
- width="16"
89
- height="100%"
90
- position="absolute"
91
- left="0"
92
- top="0"
93
- bg="none"
94
- borderRadius="0"
95
- border="0"
96
- _hover={{
97
- bg: 'none',
98
- border: 0,
99
- }}
100
- _focus={{
101
- boxShadow: 'none',
102
- }}
103
- padding="3"
104
- >
105
- <Box
106
- width="100%"
107
- padding="3"
108
- borderRadius="50%"
109
- bgColor="black"
110
- opacity="0.6"
111
- >
112
- <IconChevronLeft />
113
- </Box>
114
- </Button>
115
- <Button
116
- onClick={scrollNext}
117
- width="16"
118
- height="100%"
119
- position="absolute"
120
- right="0"
121
- top="0"
122
- bg="none"
123
- borderRadius="0"
124
- border="0"
125
- _hover={{
126
- bg: 'none',
127
- border: 0,
128
- }}
129
- _focus={{
130
- boxShadow: 'none',
131
- }}
132
- padding="3"
133
- >
134
- <Box
135
- width="100%"
136
- padding="3"
137
- borderRadius="50%"
138
- bgColor="black"
139
- opacity="0.6"
140
- >
141
- <IconChevronRight />
142
- </Box>
143
- </Button>
144
- <Box
145
- color="white"
146
- borderRadius="1rem"
147
- bgColor="black"
148
- opacity="0.6"
149
- paddingX={3}
150
- paddingY={1}
151
- fontSize="xs"
152
- position="absolute"
153
- bottom={3}
154
- left="50%"
155
- transform="translateX(-50%)"
156
- >
157
- {selectedIndex + 1}/{images.length}
158
- </Box>
159
- </Box>
160
- );
161
- };
162
-
163
- ImageCarousel.propTypes = {
164
- /** Array of images with src and alt */
165
- images: PropTypes.arrayOf(
166
- PropTypes.shape({
167
- src: PropTypes.string.isRequired,
168
- alt: PropTypes.string.isRequired,
169
- })
170
- ).isRequired,
171
- /** Height of the carousel in rem */
172
- height: PropTypes.number.isRequired,
173
- /** Width of the carousel in rem */
174
- width: PropTypes.number,
175
- };
176
-
177
- 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
- };