@gem-sdk/components 2.1.43 → 2.2.0-staging.28
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/dist/cjs/article/components/ArticleImage.js +2 -1
- package/dist/cjs/banner/components/hero-banner/index.liquid.js +4 -7
- package/dist/cjs/builder.js +4 -0
- package/dist/cjs/button/components/Button.liquid.js +3 -3
- package/dist/cjs/carousel/components/Carousel.liquid.js +3 -2
- package/dist/cjs/carousel/components/plugins/AutoPlayPlugin.js +17 -58
- package/dist/cjs/common/const.js +1 -1
- package/dist/cjs/helpers.js +6 -1
- package/dist/cjs/image/components/AdaptiveImage.liquid.js +6 -5
- package/dist/cjs/image/components/Image.js +2 -1
- package/dist/cjs/image/components/Image.liquid.js +6 -4
- package/dist/cjs/image/components/NextImage.liquid.js +4 -3
- package/dist/cjs/image-comparison/components/CompareImage.liquid.js +7 -3
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/index.liquid.js +4 -0
- package/dist/cjs/marquee/components/Marquee.liquid.js +10 -13
- package/dist/cjs/post-purchase/product/components/variants/Dropdown.js +1 -1
- package/dist/cjs/product/components/ProductButton.js +1 -1
- package/dist/cjs/product/components/ProductButton.liquid.js +21 -3
- package/dist/cjs/product/components/ProductImagesV2/liquid/ProductFeaturedImageCarousel.liquid.js +6 -5
- package/dist/cjs/product/components/ProductImagesV2/liquid/ProductGalleryCarousel.liquid.js +2 -2
- package/dist/cjs/product/components/ProductImagesV2/liquid/ProductGalleryGrid.liquid.js +4 -4
- package/dist/cjs/product/components/ProductImagesV2/liquid/ProductImages.liquid.js +4 -4
- package/dist/cjs/product/components/ProductVariants/variants/combine/index.js +1 -1
- package/dist/cjs/product/setting/ProductList.js +1 -1
- package/dist/cjs/tab/hooks/useTabInteraction.js +13 -9
- package/dist/cjs/text/components/Text.js +0 -1
- package/dist/cjs/third-party/components/AppstleBundlesDiscounts.js +32 -0
- package/dist/cjs/third-party/components/AppstleBundlesDiscounts.liquid.js +12 -0
- package/dist/cjs/third-party/components/Bogos/BogosSampleContent.js +9 -10
- package/dist/cjs/third-party/components/EcomsendBackInStockAlert.js +32 -0
- package/dist/cjs/third-party/components/EcomsendBackInStockAlert.liquid.js +21 -0
- package/dist/cjs/third-party/components/RechargeSubscriptions.liquid.js +1 -1
- package/dist/cjs/third-party/components/Releasit.liquid.js +4 -2
- package/dist/cjs/third-party/configs/AppstleBundlesDiscounts.js +12 -0
- package/dist/cjs/third-party/configs/BoldProductOptions.js +2 -2
- package/dist/cjs/third-party/configs/EcoboostifyShoppableReelUgc.js +1 -1
- package/dist/cjs/third-party/configs/EcomsendBackInStockAlert.js +12 -0
- package/dist/cjs/third-party/next.js +10 -0
- package/dist/cjs/third-party/setting/AppstleBundlesDiscounts.js +146 -0
- package/dist/cjs/third-party/setting/EcoboostifyShoppableReelUgc.js +2 -2
- package/dist/cjs/third-party/setting/EcomsendBackInStockAlert.js +128 -0
- package/dist/cjs/third-party/setting/Releasit.js +59 -2
- package/dist/cjs/third-party/setting/index.js +5 -1
- package/dist/cjs/video/components/HTML5Embed.js +2 -2
- package/dist/cjs/video/components/HTML5Embed.liquid.js +6 -3
- package/dist/cjs/video/components/LiteYouTubeEmbed.liquid.js +5 -3
- package/dist/esm/article/components/ArticleImage.js +2 -1
- package/dist/esm/banner/components/hero-banner/index.liquid.js +4 -7
- package/dist/esm/builder.js +4 -0
- package/dist/esm/button/components/Button.liquid.js +3 -3
- package/dist/esm/carousel/components/Carousel.liquid.js +3 -2
- package/dist/esm/carousel/components/plugins/AutoPlayPlugin.js +17 -58
- package/dist/esm/common/const.js +1 -1
- package/dist/esm/helpers.js +6 -1
- package/dist/esm/image/components/AdaptiveImage.liquid.js +6 -5
- package/dist/esm/image/components/Image.js +3 -2
- package/dist/esm/image/components/Image.liquid.js +6 -4
- package/dist/esm/image/components/NextImage.liquid.js +4 -3
- package/dist/esm/image-comparison/components/CompareImage.liquid.js +7 -3
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.liquid.js +2 -0
- package/dist/esm/marquee/components/Marquee.liquid.js +10 -13
- package/dist/esm/post-purchase/product/components/variants/Dropdown.js +1 -1
- package/dist/esm/product/components/ProductButton.js +1 -1
- package/dist/esm/product/components/ProductButton.liquid.js +21 -3
- package/dist/esm/product/components/ProductImagesV2/liquid/ProductFeaturedImageCarousel.liquid.js +6 -5
- package/dist/esm/product/components/ProductImagesV2/liquid/ProductGalleryCarousel.liquid.js +2 -2
- package/dist/esm/product/components/ProductImagesV2/liquid/ProductGalleryGrid.liquid.js +4 -4
- package/dist/esm/product/components/ProductImagesV2/liquid/ProductImages.liquid.js +4 -4
- package/dist/esm/product/components/ProductVariants/variants/combine/index.js +1 -1
- package/dist/esm/product/setting/ProductList.js +1 -1
- package/dist/esm/tab/hooks/useTabInteraction.js +14 -10
- package/dist/esm/text/components/Text.js +0 -1
- package/dist/esm/third-party/components/AppstleBundlesDiscounts.js +28 -0
- package/dist/esm/third-party/components/AppstleBundlesDiscounts.liquid.js +8 -0
- package/dist/esm/third-party/components/Bogos/BogosSampleContent.js +10 -11
- package/dist/esm/third-party/components/EcomsendBackInStockAlert.js +28 -0
- package/dist/esm/third-party/components/EcomsendBackInStockAlert.liquid.js +17 -0
- package/dist/esm/third-party/components/RechargeSubscriptions.liquid.js +1 -1
- package/dist/esm/third-party/components/Releasit.liquid.js +4 -2
- package/dist/esm/third-party/configs/AppstleBundlesDiscounts.js +8 -0
- package/dist/esm/third-party/configs/BoldProductOptions.js +2 -2
- package/dist/esm/third-party/configs/EcoboostifyShoppableReelUgc.js +1 -1
- package/dist/esm/third-party/configs/EcomsendBackInStockAlert.js +8 -0
- package/dist/esm/third-party/next.js +10 -0
- package/dist/esm/third-party/setting/AppstleBundlesDiscounts.js +142 -0
- package/dist/esm/third-party/setting/EcoboostifyShoppableReelUgc.js +2 -2
- package/dist/esm/third-party/setting/EcomsendBackInStockAlert.js +124 -0
- package/dist/esm/third-party/setting/Releasit.js +59 -2
- package/dist/esm/third-party/setting/index.js +5 -1
- package/dist/esm/video/components/HTML5Embed.js +2 -2
- package/dist/esm/video/components/HTML5Embed.liquid.js +6 -3
- package/dist/esm/video/components/LiteYouTubeEmbed.liquid.js +5 -3
- package/dist/types/index.d.ts +54 -8
- package/package.json +3 -3
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var EcomsendBackInStockAlert = require('../configs/EcomsendBackInStockAlert.js');
|
|
6
|
+
|
|
7
|
+
const config = {
|
|
8
|
+
tag: EcomsendBackInStockAlert.default.tag,
|
|
9
|
+
label: EcomsendBackInStockAlert.default.label,
|
|
10
|
+
icon: '<img class="gp-w-[24px] gp-border gp-border-[#494949] gp-rounded-[3px]" src="https://cdn.shopify.com/app-store/listing_images/d4d2bcc6f71dda4f30b09bd429b37065/icon/CLeo2LeKhIsDEAE=.png">',
|
|
11
|
+
editorConfigs: {
|
|
12
|
+
placeholder: {
|
|
13
|
+
flowTag: [
|
|
14
|
+
'Product'
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
component: {
|
|
18
|
+
isThirdParty: true
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
presets: [
|
|
22
|
+
{
|
|
23
|
+
id: EcomsendBackInStockAlert.default.id,
|
|
24
|
+
name: {
|
|
25
|
+
en: EcomsendBackInStockAlert.default.label
|
|
26
|
+
},
|
|
27
|
+
hideTextContent: true,
|
|
28
|
+
icon: {
|
|
29
|
+
desktop: `<div class="w-full flex flex-col items-center">
|
|
30
|
+
<img class="w-24 border border-dark-200 rounded-medium" src="https://cdn.shopify.com/app-store/listing_images/d4d2bcc6f71dda4f30b09bd429b37065/icon/CLeo2LeKhIsDEAE=.png">
|
|
31
|
+
<span class="preset-item-title">EcomSend Back in Stock Alert</span>
|
|
32
|
+
</div>`
|
|
33
|
+
},
|
|
34
|
+
components: [
|
|
35
|
+
{
|
|
36
|
+
tag: EcomsendBackInStockAlert.default.tag
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
settings: [
|
|
42
|
+
{
|
|
43
|
+
id: 'setting',
|
|
44
|
+
controls: [
|
|
45
|
+
{
|
|
46
|
+
id: 'widgetType',
|
|
47
|
+
label: 'Choose widget',
|
|
48
|
+
type: 'select',
|
|
49
|
+
options: [
|
|
50
|
+
{
|
|
51
|
+
label: 'Product Restore Email',
|
|
52
|
+
value: 'product-restore-email'
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
default: 'product-restore-email'
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 'install',
|
|
59
|
+
type: 'open-link',
|
|
60
|
+
target: '_blank',
|
|
61
|
+
linkType: 'install',
|
|
62
|
+
href: 'https://apps.shopify.com/email-1?utm_source=gempages',
|
|
63
|
+
appName: EcomsendBackInStockAlert.default.label
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'openApp',
|
|
67
|
+
type: 'open-link',
|
|
68
|
+
target: '_blank',
|
|
69
|
+
linkType: 'openApp',
|
|
70
|
+
href: '',
|
|
71
|
+
appName: EcomsendBackInStockAlert.default.label
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'align',
|
|
75
|
+
label: 'Alignment',
|
|
76
|
+
type: 'segment',
|
|
77
|
+
options: [
|
|
78
|
+
{
|
|
79
|
+
label: 'Left',
|
|
80
|
+
value: 'left',
|
|
81
|
+
type: 'align'
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
label: 'Center',
|
|
85
|
+
value: 'center',
|
|
86
|
+
type: 'align'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
label: 'Right',
|
|
90
|
+
value: 'right',
|
|
91
|
+
type: 'align'
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
devices: {
|
|
95
|
+
desktop: {
|
|
96
|
+
default: 'left'
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
ui: [
|
|
104
|
+
{
|
|
105
|
+
type: 'control',
|
|
106
|
+
setting: {
|
|
107
|
+
id: 'install'
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
type: 'control',
|
|
112
|
+
setting: {
|
|
113
|
+
id: 'openApp'
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
type: 'control',
|
|
118
|
+
label: {
|
|
119
|
+
en: 'Align'
|
|
120
|
+
},
|
|
121
|
+
setting: {
|
|
122
|
+
id: 'align'
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
exports.default = config;
|
|
@@ -11,6 +11,11 @@ const config = {
|
|
|
11
11
|
editorConfigs: {
|
|
12
12
|
component: {
|
|
13
13
|
isThirdParty: true
|
|
14
|
+
},
|
|
15
|
+
placeholder: {
|
|
16
|
+
flowTag: [
|
|
17
|
+
'Product'
|
|
18
|
+
]
|
|
14
19
|
}
|
|
15
20
|
},
|
|
16
21
|
presets: [
|
|
@@ -39,6 +44,16 @@ const config = {
|
|
|
39
44
|
{
|
|
40
45
|
id: 'setting',
|
|
41
46
|
controls: [
|
|
47
|
+
{
|
|
48
|
+
id: 'appBlockId',
|
|
49
|
+
type: 'input',
|
|
50
|
+
default: ''
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'productHandle',
|
|
54
|
+
type: 'input',
|
|
55
|
+
default: ''
|
|
56
|
+
},
|
|
42
57
|
{
|
|
43
58
|
id: 'install',
|
|
44
59
|
type: 'open-link',
|
|
@@ -55,6 +70,38 @@ const config = {
|
|
|
55
70
|
href: 'https://admin.shopify.com/?redirect=/apps/releasit-cod-order-form',
|
|
56
71
|
appName: Releasit.default.label
|
|
57
72
|
},
|
|
73
|
+
{
|
|
74
|
+
id: 'version',
|
|
75
|
+
label: 'Choose version',
|
|
76
|
+
type: 'select',
|
|
77
|
+
default: 'v1',
|
|
78
|
+
options: [
|
|
79
|
+
{
|
|
80
|
+
label: 'V1',
|
|
81
|
+
value: 'v1'
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
label: 'V2',
|
|
85
|
+
value: 'v2'
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 'widgetTypeV2',
|
|
91
|
+
label: 'Choose widget',
|
|
92
|
+
type: 'select',
|
|
93
|
+
default: 'button-app-block',
|
|
94
|
+
options: [
|
|
95
|
+
{
|
|
96
|
+
label: 'Releasit button',
|
|
97
|
+
value: 'button-app-block'
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
label: 'Releasit embedded form',
|
|
101
|
+
value: 'form-app-block'
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
},
|
|
58
105
|
{
|
|
59
106
|
id: 'align',
|
|
60
107
|
label: 'Alignment',
|
|
@@ -95,12 +142,22 @@ const config = {
|
|
|
95
142
|
{
|
|
96
143
|
type: 'control',
|
|
97
144
|
label: {
|
|
98
|
-
en: 'Choose
|
|
145
|
+
en: 'Choose version'
|
|
99
146
|
},
|
|
100
147
|
setting: {
|
|
101
|
-
id: '
|
|
148
|
+
id: 'version'
|
|
102
149
|
}
|
|
103
150
|
},
|
|
151
|
+
{
|
|
152
|
+
type: 'control',
|
|
153
|
+
label: {
|
|
154
|
+
en: 'Choose widget'
|
|
155
|
+
},
|
|
156
|
+
setting: {
|
|
157
|
+
id: 'widgetTypeV2'
|
|
158
|
+
},
|
|
159
|
+
condition: 'version === "v2"'
|
|
160
|
+
},
|
|
104
161
|
{
|
|
105
162
|
type: 'control',
|
|
106
163
|
setting: {
|
|
@@ -116,6 +116,8 @@ var BfSizeChartSizeGuide = require('./BfSizeChartSizeGuide.js');
|
|
|
116
116
|
var AlsoBoughtCbb = require('./AlsoBoughtCbb.js');
|
|
117
117
|
var HextomFreeShippingBar = require('./HextomFreeShippingBar.js');
|
|
118
118
|
var EcoboostifyShoppableReelUgc = require('./EcoboostifyShoppableReelUgc.js');
|
|
119
|
+
var EcomsendBackInStockAlert = require('./EcomsendBackInStockAlert.js');
|
|
120
|
+
var AppstleBundlesDiscounts = require('./AppstleBundlesDiscounts.js');
|
|
119
121
|
|
|
120
122
|
var index = {
|
|
121
123
|
HextomCountdownTimerBar: HextomCountdownTimerBar.default,
|
|
@@ -231,7 +233,9 @@ var index = {
|
|
|
231
233
|
BfSizeChartSizeGuide: BfSizeChartSizeGuide.default,
|
|
232
234
|
AlsoBoughtCbb: AlsoBoughtCbb.default,
|
|
233
235
|
HextomFreeShippingBar: HextomFreeShippingBar.default,
|
|
234
|
-
EcoboostifyShoppableReelUgc: EcoboostifyShoppableReelUgc.default
|
|
236
|
+
EcoboostifyShoppableReelUgc: EcoboostifyShoppableReelUgc.default,
|
|
237
|
+
EcomsendBackInStockAlert: EcomsendBackInStockAlert.default,
|
|
238
|
+
AppstleBundlesDiscounts: AppstleBundlesDiscounts.default
|
|
235
239
|
};
|
|
236
240
|
|
|
237
241
|
exports.default = index;
|
|
@@ -51,14 +51,14 @@ const HTML5Embed = (props)=>{
|
|
|
51
51
|
}),
|
|
52
52
|
props.thumbnail && showThumbnail && /*#__PURE__*/ jsxRuntime.jsxs("div", {
|
|
53
53
|
role: "presentation",
|
|
54
|
-
className: "gp-absolute gp-top-0 gp-left-0 gp-w-full",
|
|
54
|
+
className: "gp-absolute gp-top-0 gp-left-0 gp-w-full gp-h-full",
|
|
55
55
|
onClick: playVideoAndTurnOffThumbnail,
|
|
56
56
|
style: props.style,
|
|
57
57
|
children: [
|
|
58
58
|
/*#__PURE__*/ jsxRuntime.jsx("img", {
|
|
59
59
|
id: "video-thumbnail",
|
|
60
60
|
src: props.thumbnail,
|
|
61
|
-
className: "gp-w-full gp-h-full gp-object-
|
|
61
|
+
className: "gp-w-full gp-h-full gp-object-contain gp-thumbnail-video",
|
|
62
62
|
alt: "Video Thumbnail"
|
|
63
63
|
}),
|
|
64
64
|
/*#__PURE__*/ jsxRuntime.jsx("button", {
|
|
@@ -7,6 +7,7 @@ var NextImage_liquid = require('../../image/components/NextImage.liquid.js');
|
|
|
7
7
|
var helpers = require('../../helpers.js');
|
|
8
8
|
|
|
9
9
|
const HTML5Embed = (props)=>{
|
|
10
|
+
const { enableLazyLoadImage, pageContext } = props;
|
|
10
11
|
const videoId = `gp-video-${props.uid}`;
|
|
11
12
|
const preloadThumbnail = props.autoplay && props.thumbnail;
|
|
12
13
|
const offLazyVideo = !props.lazy && props.isVideoComponent;
|
|
@@ -23,7 +24,9 @@ const HTML5Embed = (props)=>{
|
|
|
23
24
|
'--op': 0,
|
|
24
25
|
'--z': -1,
|
|
25
26
|
display: 'none'
|
|
26
|
-
}
|
|
27
|
+
},
|
|
28
|
+
enableLazyLoadImage,
|
|
29
|
+
pageContext
|
|
27
30
|
})}
|
|
28
31
|
${core.RenderIf(props.autoplay, `<script>
|
|
29
32
|
document.addEventListener("DOMContentLoaded", (event) => {
|
|
@@ -72,14 +75,14 @@ const HTML5Embed = (props)=>{
|
|
|
72
75
|
</video>
|
|
73
76
|
<div
|
|
74
77
|
style="${props.style}"
|
|
75
|
-
class="${core.cls('gp-absolute gp-top-0 gp-left-0 gp-w-full gp-thumbnail-video', {
|
|
78
|
+
class="${core.cls('gp-absolute gp-top-0 gp-left-0 gp-w-full gp-h-full gp-thumbnail-video', {
|
|
76
79
|
'gp-hidden': !props.thumbnail || props.autoplay
|
|
77
80
|
})}"
|
|
78
81
|
>
|
|
79
82
|
<img
|
|
80
83
|
id="video-thumbnail"
|
|
81
84
|
src="${props.thumbnail ?? ''}"
|
|
82
|
-
class="gp-w-full gp-h-full gp-object-
|
|
85
|
+
class="gp-w-full gp-h-full gp-object-contain"
|
|
83
86
|
alt="Video Thumbnail"
|
|
84
87
|
></img>
|
|
85
88
|
<button
|
|
@@ -7,7 +7,7 @@ var NextImage_liquid = require('../../image/components/NextImage.liquid.js');
|
|
|
7
7
|
var helpers = require('../../helpers.js');
|
|
8
8
|
|
|
9
9
|
const LiteYouTubeEmbed = (props)=>{
|
|
10
|
-
const { style, lazy, preload } = props;
|
|
10
|
+
const { style, lazy, preload, enableLazyLoadImage, pageContext } = props;
|
|
11
11
|
const videoUid = `gp-video-${props.uid}`;
|
|
12
12
|
const videoId = encodeURIComponent(props.id);
|
|
13
13
|
const videoTitle = props.title;
|
|
@@ -42,7 +42,7 @@ const LiteYouTubeEmbed = (props)=>{
|
|
|
42
42
|
data-title="${videoTitle}"
|
|
43
43
|
style="${{
|
|
44
44
|
...core.makeStyleResponsive('bgi', {
|
|
45
|
-
desktop: preload ? `url('${posterUrl}')` : `url('${imagePlaceholder}')`
|
|
45
|
+
desktop: preload || !enableLazyLoadImage ? `url('${posterUrl}')` : `url('${imagePlaceholder}')`
|
|
46
46
|
}),
|
|
47
47
|
...style
|
|
48
48
|
}}"
|
|
@@ -52,7 +52,9 @@ const LiteYouTubeEmbed = (props)=>{
|
|
|
52
52
|
src: posterUrl,
|
|
53
53
|
alt: 'Poster',
|
|
54
54
|
className: `gp-invisible gp-w-full gp-h-full gp_lazyforbg`,
|
|
55
|
-
isDisableAspectStyle: true
|
|
55
|
+
isDisableAspectStyle: true,
|
|
56
|
+
enableLazyLoadImage,
|
|
57
|
+
pageContext
|
|
56
58
|
})}
|
|
57
59
|
<button
|
|
58
60
|
type="button"
|
|
@@ -10,7 +10,7 @@ import NextImage from '../../../image/components/NextImage.liquid.js';
|
|
|
10
10
|
import { getImageSrc, DEVICES } from '../../../image/helpers/getSrcSet.js';
|
|
11
11
|
import { createBlurDataURL } from '../../../image/components/helpers.js';
|
|
12
12
|
|
|
13
|
-
const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, children, rawChildren, advanced,
|
|
13
|
+
const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, children, rawChildren, advanced, enableLazyLoadImage = true })=>{
|
|
14
14
|
const { link, layout, verticalAlign, order, alignBanner, alt, title } = setting ?? {};
|
|
15
15
|
const { background, overlayEnable, overlayColor, overlayOpacity, verticalGutter, contentWidth, hoverEffect, hoverEffectDuration, hoverEffectScale, cornerBg, borderBg, hasActiveShadow, shadowBg, sizeSetting, contentPadding } = styles ?? {};
|
|
16
16
|
const enableParallax = setting?.enableParallax || false;
|
|
@@ -39,9 +39,6 @@ const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, childr
|
|
|
39
39
|
} else if (data.videoType === 'html5') {
|
|
40
40
|
delete data.video;
|
|
41
41
|
}
|
|
42
|
-
if (data.type !== 'image') {
|
|
43
|
-
delete data.image;
|
|
44
|
-
}
|
|
45
42
|
}
|
|
46
43
|
return background;
|
|
47
44
|
};
|
|
@@ -130,7 +127,7 @@ const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, childr
|
|
|
130
127
|
tablet: createBlurDataURL(srcSet?.tablet?.width ?? srcSet?.desktop?.width ?? 0, srcSet?.tablet?.height ?? srcSet?.desktop?.width ?? 0),
|
|
131
128
|
mobile: createBlurDataURL(srcSet?.mobile?.width ?? srcSet?.tablet?.width ?? srcSet?.desktop?.width ?? 0, srcSet?.mobile?.height ?? srcSet?.tablet?.height ?? srcSet?.desktop?.width ?? 0)
|
|
132
129
|
};
|
|
133
|
-
const enableLazyLoad = !setting?.preload &&
|
|
130
|
+
const enableLazyLoad = !setting?.preload && enableLazyLoadImage;
|
|
134
131
|
const renderInnerHeroBanner = ()=>{
|
|
135
132
|
return template /* liquid */ `
|
|
136
133
|
<div
|
|
@@ -180,7 +177,7 @@ const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, childr
|
|
|
180
177
|
alt,
|
|
181
178
|
title,
|
|
182
179
|
imagePlaceholder,
|
|
183
|
-
|
|
180
|
+
enableLazyLoadImage
|
|
184
181
|
})}
|
|
185
182
|
<div class="${cls('gp-absolute gp-w-full gp-h-full')}">
|
|
186
183
|
<div
|
|
@@ -223,7 +220,7 @@ const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, childr
|
|
|
223
220
|
alt: `lazy image ${device}`,
|
|
224
221
|
className: `gp-absolute gp-top-0 gp-invisible gp-w-full gp_lazyload gp-h-full gp_lazyforbg ${device === 'tablet' ? 'gp_lazybg_tl' : ''} ${device === 'mobile' ? 'gp_lazybg_mb' : ''}`,
|
|
225
222
|
isDisableAspectStyle: true,
|
|
226
|
-
|
|
223
|
+
enableLazyLoadImage
|
|
227
224
|
}));
|
|
228
225
|
}).join('') : ''}
|
|
229
226
|
</div></div>
|
package/dist/esm/builder.js
CHANGED
|
@@ -120,6 +120,8 @@ import BfSizeChartSizeGuide from './third-party/components/BfSizeChartSizeGuide.
|
|
|
120
120
|
import AlsoBoughtCbb from './third-party/components/AlsoBoughtCbb.js';
|
|
121
121
|
import HextomFreeShippingBar from './third-party/components/HextomFreeShippingBar.js';
|
|
122
122
|
import EcoboostifyShoppableReelUgc from './third-party/components/EcoboostifyShoppableReelUgc.js';
|
|
123
|
+
import EcomsendBackInStockAlert from './third-party/components/EcomsendBackInStockAlert.js';
|
|
124
|
+
import AppstleBundlesDiscounts from './third-party/components/AppstleBundlesDiscounts.js';
|
|
123
125
|
import CartLineVariant from './cart/components/CartLineVariant.js';
|
|
124
126
|
import Cart from './cart/components/Cart.js';
|
|
125
127
|
import CartList from './cart/components/CartList.js';
|
|
@@ -254,6 +256,8 @@ import PostPurchaseCountdownTimer from './post-purchase/countdown-timer/componen
|
|
|
254
256
|
import Text$1 from './post-purchase/text/Text.js';
|
|
255
257
|
|
|
256
258
|
var builder = {
|
|
259
|
+
AppstleBundlesDiscounts,
|
|
260
|
+
EcomsendBackInStockAlert,
|
|
257
261
|
EstimatedDeliveryDatePlus,
|
|
258
262
|
OkendoReviewsLoyalty,
|
|
259
263
|
EssentialAnnouncementBar,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { splitStyle, makeStyleResponsive, makeGlobalSize, composeTypographyClassName, composeTypographyStyle, composeBorderCss, composeCornerCss, getSingleColorVariable, template, cls, getGlobalColorStateClass, getGlobalColorStateStyle, composeRadius, getStyleShadowState, composeSize, getGradientBgrStyleForButton, RenderIf } from '@gem-sdk/core';
|
|
2
2
|
import { getInsertLinkData, getDynamicSourceLocales } from '../../helpers.js';
|
|
3
3
|
|
|
4
|
-
const Button = ({ className, builderProps, customAttrs, pageContext, setting = {}, styles = {}, style, wrapClassName = '', advanced, nodePrice, dataId })=>{
|
|
4
|
+
const Button = ({ className, builderProps, customAttrs, pageContext, setting = {}, styles = {}, style, wrapClassName = '', advanced, nodePrice, dataId, isForceValue = false })=>{
|
|
5
5
|
const { align, size, backgroundColor, textColor, roundedBtn, iconSpacing, globalSize } = styles;
|
|
6
6
|
const { label, iconSvg, btnLink, htmlType, disabled, loading, iconAlign, iconVisible, translate, disabledLoading = true } = setting;
|
|
7
7
|
const [wrapStyle, restStyle] = splitStyle([
|
|
@@ -66,7 +66,7 @@ const Button = ({ className, builderProps, customAttrs, pageContext, setting = {
|
|
|
66
66
|
color: ${getSingleColorVariable(styles?.textColor?.hover)};
|
|
67
67
|
}
|
|
68
68
|
`;
|
|
69
|
-
const labelValDisplay = getDynamicSourceLocales({
|
|
69
|
+
const labelValDisplay = isForceValue ? label : getDynamicSourceLocales({
|
|
70
70
|
val: label,
|
|
71
71
|
uid: builderProps?.uidTranslate ?? builderProps?.uid,
|
|
72
72
|
settingId: translate ?? 'label',
|
|
@@ -157,7 +157,7 @@ const Button = ({ className, builderProps, customAttrs, pageContext, setting = {
|
|
|
157
157
|
>${iconSvg}</span>`)}
|
|
158
158
|
<span
|
|
159
159
|
data-gp-text
|
|
160
|
-
class="${`gp-button-text-only gp-break-words group-data-[state=loading]:gp-invisible [&_p]:gp-whitespace-pre-line gp-z-1 gp-h-full gp-flex gp-items-center gp-overflow-hidden ${nodePrice ? appendTypoClass : ''}
|
|
160
|
+
class="${`gp-content-product-button gp-button-text-only gp-break-words group-data-[state=loading]:gp-invisible [&_p]:gp-whitespace-pre-line gp-z-1 gp-h-full gp-flex gp-items-center gp-overflow-hidden ${nodePrice ? appendTypoClass : ''}
|
|
161
161
|
${styles?.typo?.attrs?.italic ? '[&:not(:has(p))]:gp-pr-[0.2em] [&_p]:[&:has(p)]:gp-pr-[0.2em]' : ''}`}"
|
|
162
162
|
style="${{
|
|
163
163
|
...nodePrice && appendTypoStyle,
|
|
@@ -9,7 +9,7 @@ const DEVICES = [
|
|
|
9
9
|
'tablet',
|
|
10
10
|
'desktop'
|
|
11
11
|
];
|
|
12
|
-
const Carousel = ({ builderAttrs, builderProps, style, styles, moveToIdx, rootId, rootAttr, rootClass, wrapperClass, rootStyles, children, rawChildren, isHiddenArrowWhenDisabled = true, advanced, disableMarginAuto, conditionAppendJs, ...props })=>{
|
|
12
|
+
const Carousel = ({ builderAttrs, builderProps, style, styles, moveToIdx, rootId, rootAttr, rootClass, wrapperClass, rootStyles, children, rawChildren, isHiddenArrowWhenDisabled = true, advanced, disableMarginAuto, conditionAppendJs, ftShapeProductImage, ...props })=>{
|
|
13
13
|
const setting = mappingNavigationCarousel(props.setting);
|
|
14
14
|
const styleHeight = makeStyleResponsive('h', getHeightByShapeGlobalSize(styles?.sizeSetting));
|
|
15
15
|
const styleWidth = makeStyleWithDefault('w', getWidthByShapeGlobalSize(styles?.sizeSetting, true), {
|
|
@@ -108,7 +108,8 @@ const Carousel = ({ builderAttrs, builderProps, style, styles, moveToIdx, rootId
|
|
|
108
108
|
setting,
|
|
109
109
|
styles,
|
|
110
110
|
moveToIdx,
|
|
111
|
-
isHiddenArrowWhenDisabled
|
|
111
|
+
isHiddenArrowWhenDisabled,
|
|
112
|
+
ftShapeProductImage
|
|
112
113
|
}).replaceAll("'", ''')}' style="${{
|
|
113
114
|
...makeStyleResponsive('jc', styles?.align),
|
|
114
115
|
...rootStyles
|
|
@@ -2,41 +2,15 @@ const AutoPlayPlugin = (slider)=>{
|
|
|
2
2
|
let autoplay = slider.options.autoplay ?? {};
|
|
3
3
|
let timeout;
|
|
4
4
|
let mouseOver = false;
|
|
5
|
-
let inViewport = false;
|
|
6
|
-
let observer = null;
|
|
7
|
-
// Thêm sự kiện cho dot nếu có
|
|
8
|
-
const $dots = slider?.container?.closest('[data-component-type="component"]')?.querySelector('.carousel-dots');
|
|
9
|
-
// Callback của IntersectionObserver
|
|
10
|
-
function handleIntersection(entries) {
|
|
11
|
-
entries.forEach((entry)=>{
|
|
12
|
-
// Với threshold 0, chỉ cần một phần bất kỳ hiển thị sẽ đánh dấu isIntersecting
|
|
13
|
-
inViewport = entry.isIntersecting;
|
|
14
|
-
if (inViewport) {
|
|
15
|
-
nextTimeout();
|
|
16
|
-
} else {
|
|
17
|
-
clearNextTimeout();
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
function initIntersectionObserver() {
|
|
22
|
-
// Nếu đã có observer hoặc không có container thì không khởi tạo lại
|
|
23
|
-
if (observer || !slider.container) return;
|
|
24
|
-
observer = new IntersectionObserver(handleIntersection, {
|
|
25
|
-
root: null,
|
|
26
|
-
threshold: 0
|
|
27
|
-
});
|
|
28
|
-
observer.observe(slider.container);
|
|
29
|
-
}
|
|
30
5
|
function clearNextTimeout() {
|
|
31
6
|
clearTimeout(timeout);
|
|
32
7
|
}
|
|
33
8
|
function nextTimeout() {
|
|
34
|
-
|
|
9
|
+
clearTimeout(timeout);
|
|
35
10
|
timeout = setTimeout(()=>{
|
|
36
|
-
|
|
37
|
-
if (mouseOver || !autoplay.enable || !inViewport) return;
|
|
11
|
+
if (mouseOver || !autoplay.enable) return;
|
|
38
12
|
slider.next();
|
|
39
|
-
}, autoplay
|
|
13
|
+
}, autoplay?.delay ?? 2000);
|
|
40
14
|
}
|
|
41
15
|
function onMouseOver() {
|
|
42
16
|
mouseOver = true;
|
|
@@ -47,15 +21,11 @@ const AutoPlayPlugin = (slider)=>{
|
|
|
47
21
|
nextTimeout();
|
|
48
22
|
}
|
|
49
23
|
slider.on('created', ()=>{
|
|
50
|
-
|
|
51
|
-
$dots?.addEventListener('mouseout', onMouseOut);
|
|
52
|
-
// Nếu tùy chọn pauseOnHover bật thì thêm sự kiện hover cho container slider
|
|
53
|
-
if (autoplay.pauseOnHover && slider.container) {
|
|
24
|
+
if (autoplay.pauseOnHover) {
|
|
54
25
|
slider.container.addEventListener('mouseover', onMouseOver);
|
|
55
26
|
slider.container.addEventListener('mouseout', onMouseOut);
|
|
56
27
|
}
|
|
57
|
-
if (autoplay
|
|
58
|
-
initIntersectionObserver();
|
|
28
|
+
if (slider.options.autoplay?.enable) {
|
|
59
29
|
nextTimeout();
|
|
60
30
|
}
|
|
61
31
|
});
|
|
@@ -63,40 +33,29 @@ const AutoPlayPlugin = (slider)=>{
|
|
|
63
33
|
slider.on('animationEnded', nextTimeout);
|
|
64
34
|
slider.on('updated', (newOptions)=>{
|
|
65
35
|
autoplay = newOptions.options?.autoplay ?? {};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
36
|
+
nextTimeout();
|
|
37
|
+
});
|
|
38
|
+
slider.on('destroyed', ()=>{
|
|
39
|
+
slider.container.removeEventListener('mouseover', onMouseOver);
|
|
40
|
+
slider.container.removeEventListener('mouseout', onMouseOut);
|
|
70
41
|
});
|
|
71
42
|
slider.on('optionsChanged', (newOptions)=>{
|
|
72
|
-
|
|
43
|
+
const $dots = slider?.container?.closest('[data-component-type="component"]')?.querySelector('.carousel-dots');
|
|
44
|
+
$dots?.addEventListener('mouseover', onMouseOver);
|
|
45
|
+
$dots?.addEventListener('mouseout', onMouseOut);
|
|
46
|
+
if (newOptions.options.autoplay?.pauseOnHover !== autoplay.pauseOnHover) {
|
|
73
47
|
if (newOptions.options.autoplay?.pauseOnHover) {
|
|
74
48
|
slider.container.addEventListener('mouseover', onMouseOver);
|
|
75
49
|
slider.container.addEventListener('mouseout', onMouseOut);
|
|
76
|
-
}
|
|
50
|
+
}
|
|
51
|
+
if (!newOptions.options.autoplay?.pauseOnHover) {
|
|
77
52
|
slider.container.removeEventListener('mouseover', onMouseOver);
|
|
78
53
|
slider.container.removeEventListener('mouseout', onMouseOut);
|
|
79
54
|
mouseOver = false;
|
|
80
55
|
}
|
|
81
56
|
}
|
|
57
|
+
nextTimeout();
|
|
82
58
|
autoplay = newOptions.options.autoplay ?? {};
|
|
83
|
-
if (autoplay.enable) {
|
|
84
|
-
initIntersectionObserver();
|
|
85
|
-
nextTimeout();
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
slider.on('destroyed', ()=>{
|
|
89
|
-
if (slider.container) {
|
|
90
|
-
slider.container.removeEventListener('mouseover', onMouseOver);
|
|
91
|
-
slider.container.removeEventListener('mouseout', onMouseOut);
|
|
92
|
-
}
|
|
93
|
-
$dots?.removeEventListener('mouseover', onMouseOver);
|
|
94
|
-
$dots?.removeEventListener('mouseout', onMouseOut);
|
|
95
|
-
clearNextTimeout();
|
|
96
|
-
if (observer) {
|
|
97
|
-
observer.disconnect();
|
|
98
|
-
observer = null;
|
|
99
|
-
}
|
|
100
59
|
});
|
|
101
60
|
};
|
|
102
61
|
|
package/dist/esm/common/const.js
CHANGED
package/dist/esm/helpers.js
CHANGED
|
@@ -56,6 +56,10 @@ const getStaticLocale = (tag, key)=>{
|
|
|
56
56
|
const getSettingPreloadData = (disabledValue, enabledValue)=>{
|
|
57
57
|
return `{% if section.settings.section_preload == "false" %}${disabledValue} ${enabledValue ? `{% else %}${enabledValue}` : ''}{% endif %}`;
|
|
58
58
|
};
|
|
59
|
+
const getHttpUrl = (link)=>{
|
|
60
|
+
if (!link) return '';
|
|
61
|
+
return link.match(/^https?:\/\//i) ? link : `http://${link}`;
|
|
62
|
+
};
|
|
59
63
|
const getInsertLinkData = (defaultWrap, setting, htmlType)=>{
|
|
60
64
|
const URL_START_WITH = [
|
|
61
65
|
'#',
|
|
@@ -68,7 +72,7 @@ const getInsertLinkData = (defaultWrap, setting, htmlType)=>{
|
|
|
68
72
|
const isHyperlink = setting?.link !== undefined && setting.link !== '';
|
|
69
73
|
let urlHref = setting?.link ?? '';
|
|
70
74
|
const isHomePageHref = urlHref === '/';
|
|
71
|
-
const regexHttp = new RegExp(/^https
|
|
75
|
+
const regexHttp = new RegExp(/^(?:https?:\/\/)?[\w.-]+\.[a-z]{2,}/i);
|
|
72
76
|
const regexPageType = new RegExp(/^\/?(?:collections|pages|products|blogs|checkout|cart)\/?/i);
|
|
73
77
|
const isShopifyDomain = isHyperlink && !regexHttp.test(urlHref) && regexPageType.test(urlHref);
|
|
74
78
|
const isDomain = isHyperlink && regexHttp.test(urlHref);
|
|
@@ -79,6 +83,7 @@ const getInsertLinkData = (defaultWrap, setting, htmlType)=>{
|
|
|
79
83
|
urlHref = "{{ request.origin }}{{ routes.root_url | split: '/' | join: '/' }}" + urlHref;
|
|
80
84
|
}
|
|
81
85
|
}
|
|
86
|
+
if (isDomain) urlHref = getHttpUrl(urlHref);
|
|
82
87
|
const isLink = ()=>{
|
|
83
88
|
if (URL_START_WITH.find((el)=>urlHref.startsWith(el))) return true;
|
|
84
89
|
if (URL_INCLUDES.find((el)=>urlHref.includes(el))) return true;
|
|
@@ -2,7 +2,7 @@ import { template, cls, RenderIf, makeStyleResponsive } from '@gem-sdk/core';
|
|
|
2
2
|
import { getImageSrc } from '../helpers/getSrcSet.js';
|
|
3
3
|
import { createBlurDataURL } from './helpers.js';
|
|
4
4
|
|
|
5
|
-
const AdaptiveImage = ({ srcSet, priority, alt, aspectRatio, layout, className, pictureClass, style, imagePlaceholder,
|
|
5
|
+
const AdaptiveImage = ({ srcSet, priority, alt, aspectRatio, layout, className, pictureClass, style, imagePlaceholder, enableLazyLoadImage = true, pageContext, ...props })=>{
|
|
6
6
|
const fallBackImage = 'https://cdn.shopify.com/s/assets/no-image-2048-5e88c1b20e087fb7bbe9a3771824e743c244f437e4f8ba93bbf7b11b53f7824c_large.gif';
|
|
7
7
|
const srcDesktop = getImageSrc(srcSet?.desktop, 'desktop') || fallBackImage;
|
|
8
8
|
const srcTablet = (getImageSrc(srcSet?.tablet, 'tablet') ?? getImageSrc(srcSet?.desktop, 'tablet')) || fallBackImage;
|
|
@@ -27,16 +27,17 @@ const AdaptiveImage = ({ srcSet, priority, alt, aspectRatio, layout, className,
|
|
|
27
27
|
}}"
|
|
28
28
|
/>
|
|
29
29
|
`, template`
|
|
30
|
-
${srcMobile ? `<source media="(max-width: 767px)" data-srcSet="${srcMobile}" srcset="${
|
|
31
|
-
${srcTablet ? `<source media="(max-width: 1024px)" data-srcSet="${srcTablet}" srcset="${
|
|
30
|
+
${srcMobile ? `<source media="(max-width: 767px)" data-srcSet="${srcMobile}" srcset="${enableLazyLoadImage ? imagePlaceholder?.['mobile'] ?? createBlurDataURL(srcSet?.mobile?.width ?? srcSet?.tablet?.width ?? srcSet?.desktop?.width ?? 0, srcSet?.mobile?.height ?? srcSet?.tablet?.height ?? srcSet?.desktop?.height ?? 0) : srcMobile}" />` : ''}
|
|
31
|
+
${srcTablet ? `<source media="(max-width: 1024px)" data-srcSet="${srcTablet}" srcset="${enableLazyLoadImage ? imagePlaceholder?.['tablet'] ?? createBlurDataURL(srcSet?.tablet?.width ?? srcSet?.desktop?.width ?? 0, srcSet?.tablet?.height ?? srcSet?.desktop?.height ?? 0) : srcTablet}" />` : ''}
|
|
32
32
|
<img
|
|
33
33
|
${{
|
|
34
34
|
...props
|
|
35
35
|
}}
|
|
36
36
|
class="${cls(className, {
|
|
37
|
-
gp_lazyload:
|
|
37
|
+
gp_lazyload: enableLazyLoadImage,
|
|
38
|
+
gp_force_load: pageContext?.isOptimizePlan
|
|
38
39
|
})}"
|
|
39
|
-
src="${
|
|
40
|
+
src="${enableLazyLoadImage ? imagePlaceholder?.['desktop'] ?? createBlurDataURL(srcSet?.desktop?.width ?? 0, srcSet?.desktop?.height ?? 0) : srcDesktop}"
|
|
40
41
|
data-src="${srcDesktop}"
|
|
41
42
|
width="100%"
|
|
42
43
|
alt="${alt}"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { makeStyleResponsive, getWidthByShapeGlobalSize, makeWidth, getHeightByShapeGlobalSize, cls, getStyleShadowState, handleConvertClassColor, getBorderStyle, getBorderRadiusStyle, getStyleShadow, getAspectRatioGlobalSize, getGlobalColorStateClass, getGlobalColorStateStyle, makeStyleState, getCornerCSSFromGlobal } from '@gem-sdk/core';
|
|
2
|
+
import { useCurrentDevice, makeStyleResponsive, getWidthByShapeGlobalSize, makeWidth, getHeightByShapeGlobalSize, cls, getStyleShadowState, handleConvertClassColor, getBorderStyle, getBorderRadiusStyle, getStyleShadow, getAspectRatioGlobalSize, getGlobalColorStateClass, getGlobalColorStateStyle, makeStyleState, getCornerCSSFromGlobal } from '@gem-sdk/core';
|
|
3
3
|
import Link from '../../link/components/Link.js';
|
|
4
4
|
import AdaptiveImage from './AdaptiveImage.js';
|
|
5
5
|
import NextImage from './NextImage.js';
|
|
@@ -8,6 +8,7 @@ import { composeAspectRatio } from './helpers.js';
|
|
|
8
8
|
const Image = ({ styles, className, setting, builderAttrs, builderProps, style, children, onClick, onLoad })=>{
|
|
9
9
|
const { image, imageLink, srcSet, isNotLazyload } = setting ?? {};
|
|
10
10
|
const { customAspectRadio } = styles ?? {};
|
|
11
|
+
useCurrentDevice();
|
|
11
12
|
const { shape } = styles ?? {};
|
|
12
13
|
const WrapLink = imageLink?.link ? Link : 'div';
|
|
13
14
|
const opacity = {
|
|
@@ -82,7 +83,7 @@ const Image = ({ styles, className, setting, builderAttrs, builderProps, style,
|
|
|
82
83
|
setting?.isAdaptive ? /*#__PURE__*/ jsx(AdaptiveImage, {
|
|
83
84
|
srcSet: setting.srcSet,
|
|
84
85
|
pictureClass: "gp-contents",
|
|
85
|
-
className: cls(className, 'gp-w-full gp-max-w-full', handleConvertClassColor(styles?.borderImg)),
|
|
86
|
+
className: cls(className, 'gp-inline-block gp-w-full gp-max-w-full', handleConvertClassColor(styles?.borderImg)),
|
|
86
87
|
alt: setting.alt,
|
|
87
88
|
style: {
|
|
88
89
|
...imageWidth,
|