@akinon/next 2.0.0-beta.2 → 2.0.0-beta.20

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.
Files changed (189) hide show
  1. package/.eslintrc.js +12 -0
  2. package/CHANGELOG.md +377 -7
  3. package/__tests__/next-config.test.ts +83 -0
  4. package/__tests__/tsconfig.json +23 -0
  5. package/api/auth.ts +133 -44
  6. package/api/barcode-search.ts +59 -0
  7. package/api/cache.ts +41 -5
  8. package/api/client.ts +21 -4
  9. package/api/form.ts +85 -0
  10. package/api/image-proxy.ts +75 -0
  11. package/api/product-categories.ts +53 -0
  12. package/api/similar-product-list.ts +63 -0
  13. package/api/similar-products.ts +111 -0
  14. package/api/virtual-try-on.ts +382 -0
  15. package/assets/styles/index.scss +84 -0
  16. package/babel.config.js +6 -0
  17. package/bin/pz-generate-routes.js +115 -0
  18. package/bin/pz-prebuild.js +1 -0
  19. package/bin/pz-predev.js +1 -0
  20. package/bin/pz-run-tests.js +99 -0
  21. package/bin/run-prebuild-tests.js +46 -0
  22. package/components/accordion.tsx +20 -5
  23. package/components/button.tsx +51 -36
  24. package/components/client-root.tsx +138 -2
  25. package/components/file-input.tsx +65 -3
  26. package/components/index.ts +1 -0
  27. package/components/input.tsx +1 -1
  28. package/components/link.tsx +46 -16
  29. package/components/logger-popup.tsx +213 -0
  30. package/components/modal.tsx +32 -16
  31. package/components/plugin-module.tsx +62 -3
  32. package/components/price.tsx +2 -2
  33. package/components/select.tsx +1 -1
  34. package/components/selected-payment-option-view.tsx +21 -0
  35. package/components/theme-editor/blocks/accordion-block.tsx +136 -0
  36. package/components/theme-editor/blocks/block-renderer-registry.tsx +77 -0
  37. package/components/theme-editor/blocks/button-block.tsx +593 -0
  38. package/components/theme-editor/blocks/counter-block.tsx +348 -0
  39. package/components/theme-editor/blocks/divider-block.tsx +20 -0
  40. package/components/theme-editor/blocks/embed-block.tsx +208 -0
  41. package/components/theme-editor/blocks/group-block.tsx +116 -0
  42. package/components/theme-editor/blocks/hotspot-block.tsx +147 -0
  43. package/components/theme-editor/blocks/icon-block.tsx +230 -0
  44. package/components/theme-editor/blocks/image-block.tsx +137 -0
  45. package/components/theme-editor/blocks/image-gallery-block.tsx +269 -0
  46. package/components/theme-editor/blocks/input-block.tsx +123 -0
  47. package/components/theme-editor/blocks/link-block.tsx +216 -0
  48. package/components/theme-editor/blocks/lottie-block.tsx +325 -0
  49. package/components/theme-editor/blocks/map-block.tsx +89 -0
  50. package/components/theme-editor/blocks/slider-block.tsx +595 -0
  51. package/components/theme-editor/blocks/tab-block.tsx +10 -0
  52. package/components/theme-editor/blocks/text-block.tsx +52 -0
  53. package/components/theme-editor/blocks/video-block.tsx +122 -0
  54. package/components/theme-editor/components/action-toolbar.tsx +305 -0
  55. package/components/theme-editor/components/designer-overlay.tsx +74 -0
  56. package/components/theme-editor/components/with-designer-features.tsx +142 -0
  57. package/components/theme-editor/dynamic-font-loader.tsx +79 -0
  58. package/components/theme-editor/hooks/use-designer-features.tsx +100 -0
  59. package/components/theme-editor/hooks/use-external-designer.tsx +95 -0
  60. package/components/theme-editor/hooks/use-native-widget-data.ts +188 -0
  61. package/components/theme-editor/hooks/use-visibility-context.ts +27 -0
  62. package/components/theme-editor/placeholder-registry.ts +31 -0
  63. package/components/theme-editor/sections/before-after-section.tsx +245 -0
  64. package/components/theme-editor/sections/contact-form-section.tsx +563 -0
  65. package/components/theme-editor/sections/countdown-campaign-banner-section.tsx +433 -0
  66. package/components/theme-editor/sections/coupon-banner-section.tsx +710 -0
  67. package/components/theme-editor/sections/divider-section.tsx +62 -0
  68. package/components/theme-editor/sections/featured-product-spotlight-section.tsx +507 -0
  69. package/components/theme-editor/sections/find-in-store-section.tsx +1995 -0
  70. package/components/theme-editor/sections/hover-showcase-section.tsx +326 -0
  71. package/components/theme-editor/sections/image-hotspot-section.tsx +142 -0
  72. package/components/theme-editor/sections/installment-options-section.tsx +1065 -0
  73. package/components/theme-editor/sections/notification-banner-section.tsx +173 -0
  74. package/components/theme-editor/sections/order-tracking-lookup-section.tsx +1379 -0
  75. package/components/theme-editor/sections/posts-slider-section.tsx +472 -0
  76. package/components/theme-editor/sections/pre-order-launch-banner-section.tsx +663 -0
  77. package/components/theme-editor/sections/section-renderer-registry.tsx +89 -0
  78. package/components/theme-editor/sections/section-wrapper.tsx +135 -0
  79. package/components/theme-editor/sections/shipping-threshold-progress-section.tsx +586 -0
  80. package/components/theme-editor/sections/stats-counter-section.tsx +486 -0
  81. package/components/theme-editor/sections/tabs-section.tsx +578 -0
  82. package/components/theme-editor/theme-block.tsx +102 -0
  83. package/components/theme-editor/theme-placeholder-client.tsx +218 -0
  84. package/components/theme-editor/theme-placeholder-wrapper.tsx +732 -0
  85. package/components/theme-editor/theme-placeholder.tsx +288 -0
  86. package/components/theme-editor/theme-section.tsx +1224 -0
  87. package/components/theme-editor/theme-settings-context.tsx +13 -0
  88. package/components/theme-editor/utils/index.ts +792 -0
  89. package/components/theme-editor/utils/iterator-utils.ts +234 -0
  90. package/components/theme-editor/utils/publish-window.ts +86 -0
  91. package/components/theme-editor/utils/visibility-rules.ts +188 -0
  92. package/data/client/account.ts +17 -2
  93. package/data/client/api.ts +2 -0
  94. package/data/client/basket.ts +66 -5
  95. package/data/client/checkout.ts +391 -99
  96. package/data/client/misc.ts +38 -2
  97. package/data/client/product.ts +19 -2
  98. package/data/client/user.ts +16 -8
  99. package/data/server/category.ts +11 -9
  100. package/data/server/flatpage.ts +11 -4
  101. package/data/server/form.ts +15 -4
  102. package/data/server/landingpage.ts +11 -4
  103. package/data/server/list.ts +5 -4
  104. package/data/server/menu.ts +11 -3
  105. package/data/server/product.ts +111 -55
  106. package/data/server/seo.ts +14 -4
  107. package/data/server/special-page.ts +5 -4
  108. package/data/server/widget.ts +90 -5
  109. package/data/urls.ts +16 -5
  110. package/hocs/client/with-segment-defaults.tsx +2 -2
  111. package/hocs/server/with-segment-defaults.tsx +65 -20
  112. package/hooks/index.ts +4 -0
  113. package/hooks/use-localization.ts +24 -10
  114. package/hooks/use-logger-context.tsx +114 -0
  115. package/hooks/use-logger.ts +92 -0
  116. package/hooks/use-loyalty-availability.ts +21 -0
  117. package/hooks/use-payment-options.ts +2 -1
  118. package/hooks/use-pz-params.ts +37 -0
  119. package/hooks/use-router.ts +51 -14
  120. package/hooks/use-sentry-uncaught-errors.ts +24 -0
  121. package/instrumentation/index.ts +10 -1
  122. package/instrumentation/node.ts +2 -20
  123. package/jest.config.js +25 -0
  124. package/lib/cache-handler.mjs +534 -16
  125. package/lib/cache.ts +272 -37
  126. package/localization/index.ts +2 -1
  127. package/localization/provider.tsx +2 -5
  128. package/middlewares/bfcache-headers.ts +18 -0
  129. package/middlewares/checkout-provider.ts +1 -1
  130. package/middlewares/complete-gpay.ts +32 -26
  131. package/middlewares/complete-masterpass.ts +33 -26
  132. package/middlewares/complete-wallet.ts +182 -0
  133. package/middlewares/default.ts +360 -215
  134. package/middlewares/index.ts +10 -2
  135. package/middlewares/locale.ts +34 -11
  136. package/middlewares/masterpass-rest-callback.ts +230 -0
  137. package/middlewares/oauth-login.ts +200 -57
  138. package/middlewares/pretty-url.ts +21 -8
  139. package/middlewares/redirection-payment.ts +32 -26
  140. package/middlewares/saved-card-redirection.ts +33 -26
  141. package/middlewares/three-d-redirection.ts +32 -26
  142. package/middlewares/url-redirection.ts +11 -1
  143. package/middlewares/wallet-complete-redirection.ts +206 -0
  144. package/package.json +25 -10
  145. package/plugins.d.ts +19 -4
  146. package/plugins.js +10 -1
  147. package/redux/actions.ts +47 -0
  148. package/redux/middlewares/checkout.ts +63 -138
  149. package/redux/middlewares/index.ts +14 -10
  150. package/redux/middlewares/pre-order/address.ts +7 -2
  151. package/redux/middlewares/pre-order/attribute-based-shipping-option.ts +7 -1
  152. package/redux/middlewares/pre-order/data-source-shipping-option.ts +7 -1
  153. package/redux/middlewares/pre-order/delivery-option.ts +7 -1
  154. package/redux/middlewares/pre-order/index.ts +16 -10
  155. package/redux/middlewares/pre-order/installment-option.ts +8 -1
  156. package/redux/middlewares/pre-order/payment-option-reset.ts +37 -0
  157. package/redux/middlewares/pre-order/payment-option.ts +7 -1
  158. package/redux/middlewares/pre-order/pre-order-validation.ts +8 -3
  159. package/redux/middlewares/pre-order/redirection.ts +8 -2
  160. package/redux/middlewares/pre-order/set-pre-order.ts +6 -2
  161. package/redux/middlewares/pre-order/shipping-option.ts +7 -1
  162. package/redux/middlewares/pre-order/shipping-step.ts +5 -1
  163. package/redux/reducers/checkout.ts +23 -3
  164. package/redux/reducers/index.ts +11 -3
  165. package/redux/reducers/root.ts +7 -2
  166. package/redux/reducers/widget.ts +80 -0
  167. package/sentry/index.ts +69 -13
  168. package/tailwind/content.js +16 -0
  169. package/types/commerce/account.ts +5 -1
  170. package/types/commerce/checkout.ts +35 -1
  171. package/types/commerce/widget.ts +33 -0
  172. package/types/index.ts +101 -6
  173. package/types/next-auth.d.ts +2 -2
  174. package/types/widget.ts +80 -0
  175. package/utils/app-fetch.ts +7 -2
  176. package/utils/generate-commerce-search-params.ts +3 -2
  177. package/utils/get-checkout-path.ts +3 -0
  178. package/utils/get-root-hostname.ts +28 -0
  179. package/utils/index.ts +64 -10
  180. package/utils/localization.ts +4 -0
  181. package/utils/mobile-3d-iframe.ts +8 -2
  182. package/utils/override-middleware.ts +7 -12
  183. package/utils/pz-segments.ts +92 -0
  184. package/utils/redirect-ignore.ts +35 -0
  185. package/utils/redirect.ts +9 -3
  186. package/utils/redirection-iframe.ts +8 -2
  187. package/utils/widget-styles.ts +107 -0
  188. package/views/error-page.tsx +93 -0
  189. package/with-pz-config.js +13 -6
@@ -0,0 +1,472 @@
1
+ import React from 'react';
2
+ import Carousel from 'react-multi-carousel';
3
+ import 'react-multi-carousel/lib/styles.css';
4
+ import clsx from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+
7
+ import ThemeBlock from '../theme-block';
8
+ import { useThemeSettingsContext } from '../theme-settings-context';
9
+ import { getCSSStyles, getResponsiveValue } from '../utils';
10
+
11
+ interface PostsSliderSectionProps {
12
+ section: any;
13
+ currentBreakpoint?: string;
14
+ placeholderId?: string;
15
+ isDesigner?: boolean;
16
+ selectedBlockId?: string | null;
17
+ }
18
+
19
+ const parseNumber = (value: unknown, fallback: number) => {
20
+ if (value === undefined || value === null || value === '') return fallback;
21
+ const parsed = typeof value === 'string' ? Number(value) : Number(value);
22
+ return Number.isFinite(parsed) ? parsed : fallback;
23
+ };
24
+
25
+ const clampNumber = (value: number, min: number, max: number) =>
26
+ Math.min(Math.max(value, min), max);
27
+
28
+ const getNestedValue = (source: unknown, path: string): unknown => {
29
+ if (!path) return source;
30
+ const parts = path.split('.');
31
+ let current: unknown = source;
32
+
33
+ for (const part of parts) {
34
+ const arrayMatch = part.match(/^(.+)\[(\d+)\]$/);
35
+ if (arrayMatch) {
36
+ const [, arrayName, indexStr] = arrayMatch;
37
+ const arrayValue = (current as Record<string, unknown>)?.[arrayName];
38
+ if (!Array.isArray(arrayValue)) return undefined;
39
+ current = arrayValue[parseInt(indexStr, 10)];
40
+ continue;
41
+ }
42
+
43
+ current = (current as Record<string, unknown>)?.[part];
44
+ if (current === undefined) return undefined;
45
+ }
46
+
47
+ return current;
48
+ };
49
+
50
+ const cloneBlock = (block: any): any => ({
51
+ ...block,
52
+ properties: block.properties ? { ...block.properties } : block.properties,
53
+ styles: block.styles
54
+ ? JSON.parse(JSON.stringify(block.styles))
55
+ : block.styles,
56
+ blocks: block.blocks
57
+ ? block.blocks.map((child: any) => cloneBlock(child))
58
+ : undefined
59
+ });
60
+
61
+ const replaceBlockValues = (
62
+ blockToReplace: any,
63
+ productData: Record<string, unknown>,
64
+ productIndex: number
65
+ ) => {
66
+ const newBlock = cloneBlock(blockToReplace);
67
+ const isPlaceholderMode =
68
+ !productData || Object.keys(productData).length === 0;
69
+
70
+ if (newBlock.properties?.dataBinding && !isPlaceholderMode) {
71
+ const bindingPath = String(newBlock.properties.dataBinding).replace(
72
+ 'item.',
73
+ ''
74
+ );
75
+ const resolvedValue = getNestedValue(productData, bindingPath);
76
+
77
+ if (resolvedValue !== undefined) {
78
+ if (newBlock.properties?.tag === 'a') {
79
+ newBlock.properties = {
80
+ ...newBlock.properties,
81
+ href: String(resolvedValue)
82
+ };
83
+ } else {
84
+ newBlock.value =
85
+ typeof resolvedValue === 'string' || typeof resolvedValue === 'number'
86
+ ? String(resolvedValue)
87
+ : resolvedValue;
88
+ }
89
+ }
90
+ } else if (isPlaceholderMode && newBlock.type === 'image') {
91
+ const placeholderImages = [
92
+ '/assets/images/product-placeholder-1.jpg',
93
+ '/assets/images/product-placeholder-2.jpg',
94
+ '/assets/images/product-placeholder-3.jpg',
95
+ '/assets/images/product-placeholder-4.jpg'
96
+ ];
97
+ const placeholderIndex = productIndex % placeholderImages.length;
98
+
99
+ if (
100
+ newBlock.value &&
101
+ typeof newBlock.value === 'string' &&
102
+ newBlock.value.includes('product-placeholder')
103
+ ) {
104
+ newBlock.value = placeholderImages[placeholderIndex];
105
+ }
106
+ }
107
+
108
+ if (newBlock.blocks && newBlock.blocks.length > 0) {
109
+ newBlock.blocks = newBlock.blocks.map((childBlock: any) =>
110
+ replaceBlockValues(childBlock, productData, productIndex)
111
+ );
112
+ }
113
+
114
+ return newBlock;
115
+ };
116
+
117
+ const getIteratorProducts = (
118
+ section: any,
119
+ iteratorBlock: any,
120
+ isDesigner: boolean
121
+ ): Record<string, unknown>[] => {
122
+ if (!section?.dataSource?.details) return [];
123
+
124
+ const dataPath =
125
+ iteratorBlock.iteratorDataPath ||
126
+ iteratorBlock.properties?.iteratorDataPath;
127
+
128
+ const details = section.dataSource.details;
129
+ const inEditor =
130
+ isDesigner && typeof window !== 'undefined' && window.parent !== window;
131
+
132
+ const candidates: unknown[] = inEditor
133
+ ? [
134
+ details.collection?.products,
135
+ details.static?.data,
136
+ details.collection?.data,
137
+ details
138
+ ]
139
+ : [
140
+ details.collection?.data?.products,
141
+ details.collection?.data,
142
+ details.collection?.products,
143
+ details.static?.data,
144
+ details
145
+ ];
146
+
147
+ for (const candidate of candidates) {
148
+ if (Array.isArray(candidate)) {
149
+ return candidate as Record<string, unknown>[];
150
+ }
151
+ if (candidate && dataPath) {
152
+ const pathValue = getNestedValue(candidate, dataPath);
153
+ if (Array.isArray(pathValue)) {
154
+ return pathValue as Record<string, unknown>[];
155
+ }
156
+ }
157
+ }
158
+
159
+ return [];
160
+ };
161
+
162
+ const PostsSliderSection: React.FC<PostsSliderSectionProps> = ({
163
+ section,
164
+ currentBreakpoint = 'desktop',
165
+ placeholderId = '',
166
+ isDesigner = false,
167
+ selectedBlockId = null
168
+ }) => {
169
+ const themeSettings = useThemeSettingsContext();
170
+
171
+ const getConfigEntry = (key: string) =>
172
+ section.properties?.[key] ?? section.styles?.[key];
173
+
174
+ const normalizeResponsiveNumber = (
175
+ value: unknown,
176
+ fallback: { desktop: number; tablet: number; mobile: number }
177
+ ) => {
178
+ if (value === undefined || value === null || value === '') {
179
+ return { ...fallback };
180
+ }
181
+
182
+ if (typeof value === 'number' || typeof value === 'string') {
183
+ const parsed = parseNumber(value, fallback.desktop);
184
+ return { desktop: parsed, tablet: parsed, mobile: parsed };
185
+ }
186
+
187
+ if (typeof value === 'object') {
188
+ const responsiveValue = value as Record<string, unknown>;
189
+ const candidate =
190
+ typeof responsiveValue.desktop === 'object' &&
191
+ responsiveValue.desktop !== null
192
+ ? (responsiveValue.desktop as Record<string, unknown>)
193
+ : responsiveValue;
194
+
195
+ return {
196
+ desktop: parseNumber(candidate.desktop, fallback.desktop),
197
+ tablet: parseNumber(candidate.tablet, fallback.tablet),
198
+ mobile: parseNumber(candidate.mobile, fallback.mobile)
199
+ };
200
+ }
201
+
202
+ return { ...fallback };
203
+ };
204
+
205
+ const itemsConfig = normalizeResponsiveNumber(
206
+ getConfigEntry('items-per-slide'),
207
+ { desktop: 4, tablet: 3, mobile: 1 }
208
+ );
209
+ const slidesConfig = normalizeResponsiveNumber(
210
+ getConfigEntry('slides-to-slide'),
211
+ { desktop: 1, tablet: 1, mobile: 1 }
212
+ );
213
+
214
+ const sortedBlocks = [...(section.blocks || [])]
215
+ .sort((a, b) => (a.order || 0) - (b.order || 0))
216
+ .filter((block) => (isDesigner ? true : !block.hidden));
217
+
218
+ const expandedBlocks = sortedBlocks.flatMap((block) => {
219
+ if (!block.isIterator || !block.blocks || block.blocks.length === 0) {
220
+ return [block];
221
+ }
222
+
223
+ const template = block.blocks[0];
224
+ const products = getIteratorProducts(section, block, isDesigner);
225
+ const fallbackCount = clampNumber(
226
+ parseNumber(block.properties?.iteratorCount, 1),
227
+ 1,
228
+ 50
229
+ );
230
+ const actualCount = products.length > 0 ? products.length : fallbackCount;
231
+
232
+ return Array.from({ length: actualCount }, (_, index) => {
233
+ const product = products[index] || {};
234
+ const cloned = replaceBlockValues(template, product, index);
235
+
236
+ return {
237
+ ...cloned,
238
+ id: `${template.id || block.id}-iter-${index}`,
239
+ __iteratorParentId: block.id,
240
+ __fromIterator: true
241
+ };
242
+ });
243
+ });
244
+
245
+ const visibleCount = expandedBlocks.length;
246
+
247
+ const desktopItems = clampNumber(itemsConfig.desktop, 1, 8);
248
+ const tabletItems = clampNumber(itemsConfig.tablet, 1, 6);
249
+ const mobileItems = clampNumber(itemsConfig.mobile, 1, 4);
250
+ const desktopSlides = clampNumber(
251
+ slidesConfig.desktop,
252
+ 1,
253
+ Math.max(1, visibleCount)
254
+ );
255
+ const tabletSlides = clampNumber(
256
+ slidesConfig.tablet,
257
+ 1,
258
+ Math.max(1, visibleCount)
259
+ );
260
+ const mobileSlides = clampNumber(
261
+ slidesConfig.mobile,
262
+ 1,
263
+ Math.max(1, visibleCount)
264
+ );
265
+
266
+ const itemsPerView =
267
+ currentBreakpoint === 'mobile'
268
+ ? mobileItems
269
+ : currentBreakpoint === 'tablet'
270
+ ? tabletItems
271
+ : desktopItems;
272
+
273
+ const responsive = {
274
+ desktop: {
275
+ breakpoint: { max: 3000, min: 1024 },
276
+ items: desktopItems,
277
+ slidesToSlide: desktopSlides
278
+ },
279
+ tablet: {
280
+ breakpoint: { max: 1023, min: 768 },
281
+ items: tabletItems,
282
+ slidesToSlide: tabletSlides
283
+ },
284
+ mobile: {
285
+ breakpoint: { max: 767, min: 0 },
286
+ items: mobileItems,
287
+ slidesToSlide: mobileSlides
288
+ }
289
+ };
290
+
291
+ const currentSlidesToSlide =
292
+ currentBreakpoint === 'mobile'
293
+ ? mobileSlides
294
+ : currentBreakpoint === 'tablet'
295
+ ? tabletSlides
296
+ : desktopSlides;
297
+
298
+ const carouselResponsive = isDesigner
299
+ ? {
300
+ desktop: {
301
+ breakpoint: { max: 3000, min: 0 },
302
+ items: itemsPerView,
303
+ slidesToSlide: currentSlidesToSlide
304
+ }
305
+ }
306
+ : responsive;
307
+
308
+ const maxWidth = getResponsiveValue(
309
+ section.styles?.['max-width'],
310
+ currentBreakpoint,
311
+ 'normal'
312
+ );
313
+ const maxWidthClass =
314
+ maxWidth === 'narrow'
315
+ ? 'max-w-4xl'
316
+ : maxWidth === 'normal'
317
+ ? 'max-w-7xl'
318
+ : '';
319
+ const hasMaxWidth = maxWidth !== 'none' && maxWidth !== 'full';
320
+
321
+ const styleEntries = section.styles || {};
322
+ const filteredStyles = Object.fromEntries(
323
+ Object.entries(styleEntries).filter(
324
+ ([key]) =>
325
+ ![
326
+ 'items-per-slide',
327
+ 'slides-to-slide',
328
+ 'show-arrows',
329
+ 'show-dots',
330
+ 'max-width'
331
+ ].includes(key)
332
+ )
333
+ );
334
+
335
+ const sectionStyles = getCSSStyles(
336
+ filteredStyles,
337
+ themeSettings,
338
+ currentBreakpoint
339
+ );
340
+
341
+ const gapValue = getResponsiveValue(
342
+ section.styles?.gap,
343
+ currentBreakpoint,
344
+ 16
345
+ );
346
+ const gap = parseNumber(gapValue, 16);
347
+ const slidePadding = gap > 0 ? gap / 2 : 0;
348
+
349
+ const showArrows =
350
+ getResponsiveValue(
351
+ getConfigEntry('show-arrows'),
352
+ currentBreakpoint,
353
+ true
354
+ ) === true && visibleCount > itemsPerView;
355
+ const showDots =
356
+ getResponsiveValue(
357
+ getConfigEntry('show-dots'),
358
+ currentBreakpoint,
359
+ false
360
+ ) === true && visibleCount > itemsPerView;
361
+ const autoPlay =
362
+ getResponsiveValue(getConfigEntry('autoplay'), currentBreakpoint, false) ===
363
+ true;
364
+ const autoPlaySpeed = clampNumber(
365
+ parseNumber(getConfigEntry('autoplay-speed'), 3000),
366
+ 1000,
367
+ 10000
368
+ );
369
+ const infinite =
370
+ getResponsiveValue(getConfigEntry('infinite'), currentBreakpoint, false) ===
371
+ true;
372
+ const hasMultipleSlides = visibleCount > itemsPerView;
373
+ const useInfinite = infinite && hasMultipleSlides;
374
+ const useAutoPlay = autoPlay && hasMultipleSlides;
375
+
376
+ const postBlockAction = (type: string, blockId: string, label?: string) => {
377
+ if (!window.parent) return;
378
+ window.parent.postMessage(
379
+ {
380
+ type,
381
+ data: {
382
+ placeholderId,
383
+ sectionId: section.id,
384
+ blockId,
385
+ ...(label ? { label } : {})
386
+ }
387
+ },
388
+ '*'
389
+ );
390
+ };
391
+
392
+ if (expandedBlocks.length === 0) {
393
+ return (
394
+ <div
395
+ className="p-4 text-gray-400 border border-dashed border-gray-300 rounded"
396
+ style={sectionStyles}
397
+ >
398
+ No posts available
399
+ </div>
400
+ );
401
+ }
402
+
403
+ return (
404
+ <div
405
+ className={twMerge(
406
+ clsx('relative z-10 w-full', hasMaxWidth && 'mx-auto', maxWidthClass)
407
+ )}
408
+ style={sectionStyles}
409
+ >
410
+ <Carousel
411
+ key={`${desktopItems}-${tabletItems}-${mobileItems}-${desktopSlides}-${tabletSlides}-${mobileSlides}-${visibleCount}-${currentBreakpoint}-${useInfinite}-${useAutoPlay}-${autoPlaySpeed}`}
412
+ responsive={carouselResponsive}
413
+ {...(isDesigner ? { slidesToSlide: currentSlidesToSlide } : {})}
414
+ swipeable={true}
415
+ draggable={true}
416
+ arrows={showArrows}
417
+ showDots={showDots}
418
+ renderDotsOutside={showDots}
419
+ infinite={useInfinite}
420
+ rewind={useInfinite}
421
+ rewindWithAnimation={useInfinite}
422
+ autoPlay={useAutoPlay}
423
+ autoPlaySpeed={autoPlaySpeed}
424
+ containerClass="posts-slider-carousel"
425
+ dotListClass="posts-slider-dots"
426
+ >
427
+ {expandedBlocks.map((block) => {
428
+ const controlBlockId = block.__iteratorParentId || block.id;
429
+ const isIteratorClone = Boolean(block.__fromIterator);
430
+
431
+ return (
432
+ <div
433
+ key={block.id}
434
+ style={{
435
+ paddingLeft: slidePadding,
436
+ paddingRight: slidePadding
437
+ }}
438
+ >
439
+ <ThemeBlock
440
+ block={block}
441
+ placeholderId={placeholderId}
442
+ sectionId={section.id}
443
+ isDesigner={isDesigner && !isIteratorClone}
444
+ isSelected={selectedBlockId === controlBlockId}
445
+ selectedBlockId={selectedBlockId}
446
+ currentBreakpoint={currentBreakpoint}
447
+ onMoveUp={() =>
448
+ postBlockAction('MOVE_BLOCK_UP', controlBlockId)
449
+ }
450
+ onMoveDown={() =>
451
+ postBlockAction('MOVE_BLOCK_DOWN', controlBlockId)
452
+ }
453
+ onDuplicate={() =>
454
+ postBlockAction('DUPLICATE_BLOCK', controlBlockId)
455
+ }
456
+ onToggleVisibility={() =>
457
+ postBlockAction('TOGGLE_BLOCK_VISIBILITY', controlBlockId)
458
+ }
459
+ onDelete={() => postBlockAction('DELETE_BLOCK', controlBlockId)}
460
+ onRename={(newLabel) =>
461
+ postBlockAction('RENAME_BLOCK', controlBlockId, newLabel)
462
+ }
463
+ />
464
+ </div>
465
+ );
466
+ })}
467
+ </Carousel>
468
+ </div>
469
+ );
470
+ };
471
+
472
+ export default PostsSliderSection;