@treely/strapi-slices 7.1.0 → 7.1.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treely/strapi-slices",
3
- "version": "7.1.0",
3
+ "version": "7.1.2",
4
4
  "license": "MIT",
5
5
  "author": "Tree.ly FlexCo",
6
6
  "description": "@treely/strapi-slices is a open source library maintained by Tree.ly.",
@@ -22,43 +22,28 @@ Default.args = {
22
22
  logos: [
23
23
  {
24
24
  id: 1,
25
- img: {
26
- id: 1,
27
- alt: 'Alt text 1',
28
- img: { data: storybookStrapiAvatarMock },
29
- },
25
+ alt: 'Alt text 1',
26
+ img: { data: storybookStrapiAvatarMock },
30
27
  },
31
28
  {
32
29
  id: 2,
33
- img: {
34
- id: 2,
35
- alt: 'Alt text 1',
36
- img: { data: storybookStrapiAvatarMock },
37
- },
30
+ alt: 'Alt text 2',
31
+ img: { data: storybookStrapiAvatarMock },
38
32
  },
39
33
  {
40
34
  id: 3,
41
- img: {
42
- id: 3,
43
- alt: 'Alt text 1',
44
- img: { data: storybookStrapiAvatarMock },
45
- },
35
+ alt: 'Alt text 3',
36
+ img: { data: storybookStrapiAvatarMock },
46
37
  },
47
38
  {
48
39
  id: 4,
49
- img: {
50
- id: 4,
51
- alt: 'Alt text 1',
52
- img: { data: storybookStrapiTreeIconMock },
53
- },
40
+ alt: 'Alt text 4',
41
+ img: { data: storybookStrapiTreeIconMock },
54
42
  },
55
43
  {
56
44
  id: 5,
57
- img: {
58
- id: 5,
59
- alt: 'Alt text 1',
60
- img: { data: storybookStrapiCoverMock },
61
- },
45
+ alt: 'Partner Logo 5',
46
+ img: { data: storybookStrapiAvatarMock },
62
47
  },
63
48
  ],
64
49
  },
@@ -71,43 +56,28 @@ WithTitle.args = {
71
56
  logos: [
72
57
  {
73
58
  id: 1,
74
- img: {
75
- id: 1,
76
- alt: 'Partner Logo 1',
77
- img: { data: storybookStrapiAvatarMock },
78
- },
59
+ alt: 'Partner Logo 1',
60
+ img: { data: storybookStrapiAvatarMock },
79
61
  },
80
62
  {
81
63
  id: 2,
82
- img: {
83
- id: 2,
84
- alt: 'Partner Logo 2',
85
- img: { data: storybookStrapiAvatarMock },
86
- },
64
+ alt: 'Partner Logo 2',
65
+ img: { data: storybookStrapiAvatarMock },
87
66
  },
88
67
  {
89
68
  id: 3,
90
- img: {
91
- id: 3,
92
- alt: 'Partner Logo 3',
93
- img: { data: storybookStrapiAvatarMock },
94
- },
69
+ alt: 'Partner Logo 3',
70
+ img: { data: storybookStrapiAvatarMock },
95
71
  },
96
72
  {
97
73
  id: 4,
98
- img: {
99
- id: 4,
100
- alt: 'Partner Logo 4',
101
- img: { data: storybookStrapiTreeIconMock },
102
- },
74
+ alt: 'Partner Logo 4',
75
+ img: { data: storybookStrapiTreeIconMock },
103
76
  },
104
77
  {
105
78
  id: 5,
106
- img: {
107
- id: 5,
108
- alt: 'Partner Logo 5',
109
- img: { data: storybookStrapiCoverMock },
110
- },
79
+ alt: 'Partner Logo 5',
80
+ img: { data: storybookStrapiCoverMock },
111
81
  },
112
82
  ],
113
83
  },
@@ -31,39 +31,33 @@ const defaultProps: CarouselMarqueeBannerProps = {
31
31
  logos: [
32
32
  {
33
33
  id: 1,
34
+ alt: 'Logo 1',
34
35
  img: {
35
- id: 1,
36
- alt: 'Logo 1',
37
- img: {
38
- data: {
39
- ...strapiMediaMock,
40
- attributes: {
41
- ...strapiMediaMock.attributes,
42
- width: 1000,
43
- height: 600,
44
- },
36
+ data: {
37
+ ...strapiMediaMock,
38
+ attributes: {
39
+ ...strapiMediaMock.attributes,
40
+ width: 1000,
41
+ height: 600,
45
42
  },
46
43
  },
47
- objectFit: 'contain',
48
44
  },
45
+ objectFit: 'contain',
49
46
  },
50
47
  {
51
48
  id: 2,
49
+ alt: 'Logo 2',
52
50
  img: {
53
- id: 2,
54
- alt: 'Logo 2',
55
- img: {
56
- data: {
57
- ...strapiMediaMock,
58
- attributes: {
59
- ...strapiMediaMock.attributes,
60
- width: 800,
61
- height: 500,
62
- },
51
+ data: {
52
+ ...strapiMediaMock,
53
+ attributes: {
54
+ ...strapiMediaMock.attributes,
55
+ width: 800,
56
+ height: 500,
63
57
  },
64
58
  },
65
- objectFit: 'cover',
66
59
  },
60
+ objectFit: 'cover',
67
61
  },
68
62
  ],
69
63
  },
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import {
3
3
  DefaultSectionContainer,
4
4
  Flex,
@@ -6,6 +6,7 @@ import {
6
6
  Spacer,
7
7
  Box,
8
8
  useMediaQuery,
9
+ useToken,
9
10
  } from 'boemly';
10
11
  import Image from 'next/image';
11
12
  import useEmblaCarousel from 'embla-carousel-react';
@@ -21,37 +22,36 @@ import { CarouselInnerContainer, LogoGrid } from './styles';
21
22
  export interface CarouselMarqueeBannerProps {
22
23
  slice: {
23
24
  title?: string;
24
- logos: {
25
- id: number;
26
- img: StrapiImage;
27
- }[];
25
+ logos: StrapiImage[];
28
26
  };
29
27
  }
30
28
 
31
- export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
29
+ // Separate component containing the actual logic
30
+ const CarouselMarqueeBannerContent: React.FC<CarouselMarqueeBannerProps> = ({
32
31
  slice,
33
- }: CarouselMarqueeBannerProps) => {
32
+ }) => {
33
+ const [primary50] = useToken('colors', ['primary.50']);
34
34
  const { width: windowWidth } = useWindowSize();
35
- const shouldDuplicateLogos = slice.logos.length < 5;
35
+ const hasEnoughLogosForLoop = slice.logos.length >= 5;
36
36
  const LOOP_ARRAY_LENGTH = windowWidth > 2000 ? 5 : 4;
37
37
 
38
38
  // Duplicate Logos to create a full loop
39
- const logosToRender = shouldDuplicateLogos
40
- ? slice.logos
41
- : Array.from({ length: LOOP_ARRAY_LENGTH }, () => slice.logos).flat();
39
+ const logosToRender = hasEnoughLogosForLoop
40
+ ? Array.from({ length: LOOP_ARRAY_LENGTH }, () => slice.logos).flat()
41
+ : slice.logos;
42
42
 
43
43
  const [isMobile] = useMediaQuery(BREAKPOINT_MD_QUERY);
44
44
 
45
+ // Carousel setup
45
46
  const [emblaRef] = useEmblaCarousel(
46
47
  {
47
- loop: shouldDuplicateLogos ? false : true,
48
+ loop: hasEnoughLogosForLoop,
48
49
  align: 'start',
49
50
  containScroll: 'trimSnaps',
50
51
  dragFree: true,
51
52
  },
52
- shouldDuplicateLogos
53
- ? []
54
- : [
53
+ hasEnoughLogosForLoop
54
+ ? [
55
55
  AutoScroll({
56
56
  playOnInit: true,
57
57
  speed: isMobile ? 0.5 : 1,
@@ -60,10 +60,11 @@ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
60
60
  stopOnFocusIn: false,
61
61
  }),
62
62
  ]
63
+ : []
63
64
  );
64
65
 
65
- const renderLogos = () => {
66
- if (slice.logos.length < 5) {
66
+ const renderLogos = (): React.ReactNode => {
67
+ if (!hasEnoughLogosForLoop) {
67
68
  return (
68
69
  <LogoGrid>
69
70
  {slice.logos.map((logo, index) => (
@@ -87,18 +88,18 @@ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
87
88
  ? 'var(--boemly-sizes-16)'
88
89
  : 'var(--boemly-sizes-36)'
89
90
  } / ${getClosestRatio(
90
- logo.img.img.data.attributes.width,
91
- logo.img.img.data.attributes.height
91
+ logo.img.data.attributes.width,
92
+ logo.img.data.attributes.height
92
93
  )})`}
93
94
  width={isMobile ? '16' : '36'}
94
95
  borderRadius="xl"
95
96
  >
96
97
  <Image
97
- src={strapiMediaUrl(logo.img.img, 'large')}
98
- alt={logo.img.alt}
98
+ src={strapiMediaUrl(logo.img, 'large')}
99
+ alt={logo.alt}
99
100
  fill
100
101
  style={{
101
- objectFit: logo.img.objectFit || 'contain',
102
+ objectFit: logo.objectFit || 'contain',
102
103
  borderRadius: 'var(--boemly-radii-xl)',
103
104
  }}
104
105
  />
@@ -134,18 +135,18 @@ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
134
135
  ? 'var(--boemly-sizes-16)'
135
136
  : 'var(--boemly-sizes-36)'
136
137
  } / ${getClosestRatio(
137
- logo.img.img.data.attributes.width,
138
- logo.img.img.data.attributes.height
138
+ logo.img.data.attributes.width,
139
+ logo.img.data.attributes.height
139
140
  )})`}
140
141
  width={isMobile ? '16' : '36'}
141
142
  borderRadius="xl"
142
143
  >
143
144
  <Image
144
- src={strapiMediaUrl(logo.img.img, 'large')}
145
- alt={logo.img.alt}
145
+ src={strapiMediaUrl(logo.img, 'large')}
146
+ alt={logo.alt}
146
147
  fill
147
148
  style={{
148
- objectFit: logo.img.objectFit || 'contain',
149
+ objectFit: logo.objectFit || 'contain',
149
150
  borderRadius: 'var(--boemly-radii-xl)',
150
151
  }}
151
152
  />
@@ -159,18 +160,8 @@ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
159
160
  };
160
161
 
161
162
  return (
162
- <DefaultSectionContainer>
163
- <Box
164
- maxWidth="full"
165
- margin="auto"
166
- display="flex"
167
- flexDirection="column"
168
- justifyContent="center"
169
- alignItems="center"
170
- height="2xs"
171
- backgroundColor="gray.50"
172
- padding="42px 0 56px"
173
- >
163
+ <DefaultSectionContainer backgroundColor={primary50}>
164
+ <>
174
165
  {slice.title ? (
175
166
  <>
176
167
  <Flex alignItems="center" flexDirection="column">
@@ -178,14 +169,31 @@ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
178
169
  {slice.title}
179
170
  </Heading>
180
171
  </Flex>
181
- <Spacer height="12" />
172
+ <Spacer height="12" minHeight="12" />
182
173
  </>
183
174
  ) : null}
184
175
 
185
176
  {renderLogos()}
186
- </Box>
177
+ </>
187
178
  </DefaultSectionContainer>
188
179
  );
189
180
  };
190
181
 
182
+ // Lazy-rendering the child component after client-side hydration
183
+ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
184
+ slice,
185
+ }: CarouselMarqueeBannerProps) => {
186
+ const [showChild, setShowChild] = useState(false);
187
+
188
+ useEffect(() => {
189
+ setShowChild(true); // Hydrate the component after the client-side is ready
190
+ }, []);
191
+
192
+ if (!showChild) {
193
+ return <div />;
194
+ }
195
+
196
+ return <CarouselMarqueeBannerContent slice={slice} />;
197
+ };
198
+
191
199
  export default CarouselMarqueeBanner;