@constructor-io/constructorio-ui-plp 1.4.7 → 1.6.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/README.md +1 -1
- package/dist/constructorio-ui-plp-bundled.js +14 -14
- package/lib/cjs/components/ProductCard/ProductCard.css +14 -1
- package/lib/cjs/components/ProductCard/ProductCard.js +52 -19
- package/lib/cjs/components/ProductCard/index.js +0 -1
- package/lib/cjs/components/RenderPropsWrapper/CustomHtmlRender.js +24 -0
- package/lib/cjs/components/RenderPropsWrapper/RenderPropsWrapper.js +15 -0
- package/lib/cjs/constants.js +4 -1
- package/lib/cjs/hooks/useCioPlpProvider.js +3 -1
- package/lib/cjs/hooks/useProduct.js +14 -7
- package/lib/cjs/hooks/useProductSwatch.js +4 -3
- package/lib/cjs/utils/itemFieldGetters.js +8 -2
- package/lib/cjs/version.js +1 -1
- package/lib/mjs/components/ProductCard/ProductCard.css +14 -1
- package/lib/mjs/components/ProductCard/ProductCard.js +50 -19
- package/lib/mjs/components/ProductCard/index.js +0 -1
- package/lib/mjs/components/RenderPropsWrapper/CustomHtmlRender.js +20 -0
- package/lib/mjs/components/RenderPropsWrapper/RenderPropsWrapper.js +11 -0
- package/lib/mjs/constants.js +3 -0
- package/lib/mjs/hooks/useCioPlpProvider.js +3 -1
- package/lib/mjs/hooks/useProduct.js +8 -1
- package/lib/mjs/hooks/useProductSwatch.js +4 -3
- package/lib/mjs/utils/itemFieldGetters.js +6 -1
- package/lib/mjs/version.js +1 -1
- package/lib/types/components/ProductCard/ProductCard.d.ts +1 -37
- package/lib/types/components/ProductCard/index.d.ts +0 -1
- package/lib/types/components/RenderPropsWrapper/CustomHtmlRender.d.ts +7 -0
- package/lib/types/components/RenderPropsWrapper/RenderPropsWrapper.d.ts +25 -0
- package/lib/types/constants.d.ts +3 -0
- package/lib/types/index.d.ts +0 -1
- package/lib/types/types.d.ts +63 -1
- package/lib/types/utils/itemFieldGetters.d.ts +2 -1
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
.cio-image-container {
|
|
9
9
|
width: 100%;
|
|
10
10
|
height: auto;
|
|
11
|
+
position: relative;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
.cio-image {
|
|
@@ -16,6 +17,18 @@
|
|
|
16
17
|
object-fit: cover;
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
.cio-rollover-image {
|
|
21
|
+
position: absolute;
|
|
22
|
+
left: 0;
|
|
23
|
+
top: 0;
|
|
24
|
+
transition: opacity 0.3s ease-in-out;
|
|
25
|
+
opacity: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.cio-rollover-image.is-active {
|
|
29
|
+
opacity: 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
.cio-content {
|
|
20
33
|
width: 100%;
|
|
21
34
|
}
|
|
@@ -56,4 +69,4 @@
|
|
|
56
69
|
height: 40px;
|
|
57
70
|
font-size: 16px;
|
|
58
71
|
cursor: pointer;
|
|
59
|
-
}
|
|
72
|
+
}
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
-
const react_1 = tslib_1.
|
|
4
|
+
const react_1 = tslib_1.__importStar(require("react"));
|
|
5
5
|
const useCioPlpContext_1 = require("../../hooks/useCioPlpContext");
|
|
6
6
|
const callbacks_1 = require("../../hooks/callbacks");
|
|
7
7
|
const ProductSwatch_1 = tslib_1.__importDefault(require("../ProductSwatch"));
|
|
8
8
|
const useProduct_1 = tslib_1.__importDefault(require("../../hooks/useProduct"));
|
|
9
9
|
const utils_1 = require("../../utils");
|
|
10
|
+
const RenderPropsWrapper_1 = tslib_1.__importDefault(require("../RenderPropsWrapper/RenderPropsWrapper"));
|
|
11
|
+
const constants_1 = require("../../constants");
|
|
10
12
|
/**
|
|
11
13
|
* ProductCard component that has Constructor tracking built-in.
|
|
12
14
|
*/
|
|
13
15
|
function ProductCard(props) {
|
|
16
|
+
var _a;
|
|
17
|
+
const [isRolloverImageShown, setIsRolloverImageShown] = (0, react_1.useState)(false);
|
|
18
|
+
const cardRef = (0, react_1.useRef)(null);
|
|
14
19
|
const { item, children } = props;
|
|
15
20
|
const state = (0, useCioPlpContext_1.useCioPlpContext)();
|
|
16
21
|
const productInfo = (0, useProduct_1.default)({ item });
|
|
17
|
-
const { productSwatch, itemName, itemPrice, itemImageUrl, itemUrl, salePrice, hasSalePrice } = productInfo;
|
|
22
|
+
const { productSwatch, itemName, itemPrice, itemImageUrl, itemUrl, salePrice, hasSalePrice, rolloverImage, } = productInfo;
|
|
18
23
|
if (!state) {
|
|
19
24
|
throw new Error('This component is meant to be used within the CioPlp provider.');
|
|
20
25
|
}
|
|
@@ -26,22 +31,50 @@ function ProductCard(props) {
|
|
|
26
31
|
const { formatPrice } = state.formatters;
|
|
27
32
|
const onClick = (0, callbacks_1.useOnProductCardClick)(client, state.callbacks.onProductCardClick);
|
|
28
33
|
const cnstrcData = (0, utils_1.getProductCardCnstrcDataAttributes)(productInfo);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
const handleRolloverImageState = (isShown) => {
|
|
35
|
+
var _a;
|
|
36
|
+
setIsRolloverImageShown(isShown);
|
|
37
|
+
if (isShown && rolloverImage) {
|
|
38
|
+
const event = new CustomEvent(constants_1.EMITTED_EVENTS.PRODUCT_CARD_IMAGE_ROLLOVER, {
|
|
39
|
+
detail: { item },
|
|
40
|
+
bubbles: true,
|
|
41
|
+
});
|
|
42
|
+
(_a = cardRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const onMouseEnter = (event) => {
|
|
46
|
+
if (state.callbacks.onProductCardMouseEnter) {
|
|
47
|
+
state.callbacks.onProductCardMouseEnter(event, item);
|
|
48
|
+
}
|
|
49
|
+
handleRolloverImageState(true);
|
|
50
|
+
};
|
|
51
|
+
const onMouseLeave = (event) => {
|
|
52
|
+
if (state.callbacks.onProductCardMouseLeave) {
|
|
53
|
+
state.callbacks.onProductCardMouseLeave(event, item);
|
|
54
|
+
}
|
|
55
|
+
handleRolloverImageState(false);
|
|
56
|
+
};
|
|
57
|
+
return (react_1.default.createElement(RenderPropsWrapper_1.default, { props: {
|
|
58
|
+
item,
|
|
59
|
+
productInfo,
|
|
60
|
+
formatPrice,
|
|
61
|
+
onAddToCart,
|
|
62
|
+
onClick,
|
|
63
|
+
onMouseEnter,
|
|
64
|
+
onMouseLeave,
|
|
65
|
+
isRolloverImageShown,
|
|
66
|
+
productCardCnstrcDataAttributes: cnstrcData,
|
|
67
|
+
}, override: children, htmlOverride: (_a = state.renderOverrides.productCard) === null || _a === void 0 ? void 0 : _a.renderHtml, topLevelAttributes: Object.assign(Object.assign({}, cnstrcData), { className: 'cio-product-card' }) },
|
|
68
|
+
react_1.default.createElement("a", Object.assign({}, cnstrcData, { className: 'cio-product-card', href: itemUrl, ref: cardRef, onClick: (e) => { var _a; return onClick(e, item, (_a = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _a === void 0 ? void 0 : _a.variationId); } }),
|
|
69
|
+
react_1.default.createElement("div", { className: 'cio-image-container', onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave },
|
|
70
|
+
react_1.default.createElement("img", { alt: itemName, src: itemImageUrl, className: 'cio-image' }),
|
|
71
|
+
rolloverImage && (react_1.default.createElement("img", { alt: `${itemName} rollover`, src: rolloverImage, loading: 'lazy', className: (0, utils_1.concatStyles)('cio-image cio-rollover-image', isRolloverImageShown && 'is-active') }))),
|
|
72
|
+
react_1.default.createElement("div", { className: 'cio-content' },
|
|
73
|
+
react_1.default.createElement("div", { className: 'cio-item-prices-container' },
|
|
74
|
+
hasSalePrice && (react_1.default.createElement("div", { className: 'cio-item-price', id: 'cio-sale-price' }, formatPrice(salePrice))),
|
|
75
|
+
Number(itemPrice) >= 0 && (react_1.default.createElement("div", { className: (0, utils_1.concatStyles)('cio-item-price', hasSalePrice && 'cio-item-price-strikethrough') }, formatPrice(itemPrice)))),
|
|
76
|
+
react_1.default.createElement("div", { className: 'cio-item-name' }, itemName),
|
|
77
|
+
productSwatch && react_1.default.createElement(ProductSwatch_1.default, { swatchObject: productSwatch })),
|
|
78
|
+
react_1.default.createElement("button", { className: 'cio-add-to-cart-button', type: 'button', onClick: (e) => { var _a; return onAddToCart(e, item, itemPrice, (_a = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _a === void 0 ? void 0 : _a.variationId); } }, "Add to Cart"))));
|
|
46
79
|
}
|
|
47
80
|
exports.default = ProductCard;
|
|
@@ -2,5 +2,4 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const ProductCard_1 = tslib_1.__importDefault(require("./ProductCard"));
|
|
5
|
-
tslib_1.__exportStar(require("./ProductCard"), exports);
|
|
6
5
|
exports.default = ProductCard_1.default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const react_1 = tslib_1.__importStar(require("react"));
|
|
5
|
+
function CustomHtmlRender(props) {
|
|
6
|
+
const { renderHtml, topLevelAttributes = {} } = props, otherProps = tslib_1.__rest(props, ["renderHtml", "topLevelAttributes"]);
|
|
7
|
+
const ref = (0, react_1.useRef)(null);
|
|
8
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
9
|
+
const customElement = renderHtml(otherProps);
|
|
10
|
+
const isDomElement = customElement instanceof HTMLElement;
|
|
11
|
+
const isReactNode = (0, react_1.isValidElement)(customElement);
|
|
12
|
+
if (isDomElement && ref.current) {
|
|
13
|
+
ref.current.innerHTML = ''; // Clear previous content
|
|
14
|
+
ref.current.appendChild(customElement);
|
|
15
|
+
}
|
|
16
|
+
if (isReactNode) {
|
|
17
|
+
return customElement;
|
|
18
|
+
}
|
|
19
|
+
if (isDomElement) {
|
|
20
|
+
return react_1.default.createElement("div", Object.assign({}, topLevelAttributes, { ref: ref }));
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
exports.default = CustomHtmlRender;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
/* eslint-disable no-nested-ternary */
|
|
5
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
6
|
+
const CustomHtmlRender_1 = tslib_1.__importDefault(require("./CustomHtmlRender"));
|
|
7
|
+
function RenderPropsWrapper({ props, children, override, htmlOverride, topLevelAttributes, }) {
|
|
8
|
+
const isRenderProps = typeof override === 'function';
|
|
9
|
+
const isJSX = typeof override === 'object';
|
|
10
|
+
const isHtmlOverride = typeof htmlOverride === 'function';
|
|
11
|
+
return (react_1.default.createElement(react_1.default.Fragment, null, isRenderProps ? (override(props)) : isJSX ? (override) : isHtmlOverride ? (react_1.default.createElement(CustomHtmlRender_1.default, Object.assign({}, props, { renderHtml: htmlOverride, topLevelAttributes: topLevelAttributes }))) : (
|
|
12
|
+
// Default implementation
|
|
13
|
+
children)));
|
|
14
|
+
}
|
|
15
|
+
exports.default = RenderPropsWrapper;
|
package/lib/cjs/constants.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEMO_API_KEY = void 0;
|
|
3
|
+
exports.EMITTED_EVENTS = exports.DEMO_API_KEY = void 0;
|
|
4
4
|
// eslint-disable-next-line import/prefer-default-export
|
|
5
5
|
exports.DEMO_API_KEY = 'key_M57QS8SMPdLdLx4x';
|
|
6
|
+
exports.EMITTED_EVENTS = {
|
|
7
|
+
PRODUCT_CARD_IMAGE_ROLLOVER: 'cio.ui-plp.productCardImageRollover',
|
|
8
|
+
};
|
|
@@ -7,7 +7,7 @@ const defaultGetters = tslib_1.__importStar(require("../utils/itemFieldGetters")
|
|
|
7
7
|
const defaultFormatters = tslib_1.__importStar(require("../utils/formatters"));
|
|
8
8
|
const defaultUrlHelpers = tslib_1.__importStar(require("../utils/urlHelpers"));
|
|
9
9
|
function useCioPlpProvider(props) {
|
|
10
|
-
const { apiKey, formatters, callbacks, itemFieldGetters, urlHelpers, staticRequestConfigs = {}, cioClient: customCioClient, cioClientOptions: customCioClientOptions = {}, } = props;
|
|
10
|
+
const { apiKey, formatters, callbacks, itemFieldGetters, urlHelpers, staticRequestConfigs = {}, renderOverrides = {}, cioClient: customCioClient, cioClientOptions: customCioClientOptions = {}, } = props;
|
|
11
11
|
const [cioClientOptions, setCioClientOptions] = (0, react_1.useState)(customCioClientOptions);
|
|
12
12
|
const cioClient = (0, useCioClient_1.default)({ apiKey, cioClient: customCioClient, options: cioClientOptions });
|
|
13
13
|
const contextValue = (0, react_1.useMemo)(() => ({
|
|
@@ -19,6 +19,7 @@ function useCioPlpProvider(props) {
|
|
|
19
19
|
formatters: Object.assign(Object.assign({}, defaultFormatters), formatters),
|
|
20
20
|
callbacks: Object.assign({}, callbacks),
|
|
21
21
|
urlHelpers: Object.assign(Object.assign({}, defaultUrlHelpers), urlHelpers),
|
|
22
|
+
renderOverrides: Object.assign({}, renderOverrides),
|
|
22
23
|
}), [
|
|
23
24
|
cioClient,
|
|
24
25
|
cioClientOptions,
|
|
@@ -26,6 +27,7 @@ function useCioPlpProvider(props) {
|
|
|
26
27
|
formatters,
|
|
27
28
|
callbacks,
|
|
28
29
|
urlHelpers,
|
|
30
|
+
renderOverrides,
|
|
29
31
|
staticRequestConfigs,
|
|
30
32
|
]);
|
|
31
33
|
return contextValue;
|
|
@@ -6,7 +6,7 @@ const useCioPlpContext_1 = require("./useCioPlpContext");
|
|
|
6
6
|
const utils_1 = require("../utils");
|
|
7
7
|
const itemFieldGetters_1 = require("../utils/itemFieldGetters");
|
|
8
8
|
const useProductInfo = ({ item }) => {
|
|
9
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
9
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
10
10
|
const state = (0, useCioPlpContext_1.useCioPlpContext)();
|
|
11
11
|
const productSwatch = (0, useProductSwatch_1.default)({ item });
|
|
12
12
|
if (!item.data || !item.itemId || !item.itemName) {
|
|
@@ -14,13 +14,19 @@ const useProductInfo = ({ item }) => {
|
|
|
14
14
|
}
|
|
15
15
|
const getPrice = (0, utils_1.tryCatchify)(((_a = state === null || state === void 0 ? void 0 : state.itemFieldGetters) === null || _a === void 0 ? void 0 : _a.getPrice) || itemFieldGetters_1.getPrice);
|
|
16
16
|
const getSalePrice = (0, utils_1.tryCatchify)(((_b = state === null || state === void 0 ? void 0 : state.itemFieldGetters) === null || _b === void 0 ? void 0 : _b.getSalePrice) || itemFieldGetters_1.getSalePrice);
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
17
|
+
const getRolloverImage = (0, utils_1.tryCatchify)(((_c = state === null || state === void 0 ? void 0 : state.itemFieldGetters) === null || _c === void 0 ? void 0 : _c.getRolloverImage) || itemFieldGetters_1.getRolloverImage);
|
|
18
|
+
const itemName = ((_d = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _d === void 0 ? void 0 : _d.itemName) || item.itemName;
|
|
19
|
+
const itemPrice = ((_e = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _e === void 0 ? void 0 : _e.price) || getPrice(item);
|
|
20
|
+
const itemImageUrl = ((_f = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _f === void 0 ? void 0 : _f.imageUrl) || item.imageUrl;
|
|
21
|
+
const itemUrl = ((_g = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _g === void 0 ? void 0 : _g.url) || item.url;
|
|
22
|
+
const variationId = (_h = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _h === void 0 ? void 0 : _h.variationId;
|
|
23
|
+
let rolloverImage = (_j = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _j === void 0 ? void 0 : _j.rolloverImage;
|
|
24
|
+
// Fallback to item's rollover image if all variations don't have a rollover image
|
|
25
|
+
if (!rolloverImage && ((_k = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.swatchList) === null || _k === void 0 ? void 0 : _k.every((swatch) => !swatch.rolloverImage))) {
|
|
26
|
+
rolloverImage = getRolloverImage(item);
|
|
27
|
+
}
|
|
22
28
|
const { itemId } = item;
|
|
23
|
-
let salePrice = ((
|
|
29
|
+
let salePrice = ((_l = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _l === void 0 ? void 0 : _l.salePrice) || getSalePrice(item);
|
|
24
30
|
let hasSalePrice = true;
|
|
25
31
|
if (!(0, utils_1.isValidSalePrice)(salePrice, itemPrice)) {
|
|
26
32
|
salePrice = undefined;
|
|
@@ -35,6 +41,7 @@ const useProductInfo = ({ item }) => {
|
|
|
35
41
|
variationId,
|
|
36
42
|
itemId,
|
|
37
43
|
salePrice,
|
|
44
|
+
rolloverImage,
|
|
38
45
|
hasSalePrice,
|
|
39
46
|
};
|
|
40
47
|
};
|
|
@@ -4,7 +4,7 @@ const react_1 = require("react");
|
|
|
4
4
|
const useCioPlpContext_1 = require("./useCioPlpContext");
|
|
5
5
|
const itemFieldGetters_1 = require("../utils/itemFieldGetters");
|
|
6
6
|
const useProductSwatch = ({ item }) => {
|
|
7
|
-
var _a, _b, _c, _d;
|
|
7
|
+
var _a, _b, _c, _d, _e;
|
|
8
8
|
const [selectedVariation, setSelectedVariation] = (0, react_1.useState)();
|
|
9
9
|
const [swatchList, setSwatchList] = (0, react_1.useState)([]);
|
|
10
10
|
const state = (0, useCioPlpContext_1.useCioPlpContext)();
|
|
@@ -12,16 +12,17 @@ const useProductSwatch = ({ item }) => {
|
|
|
12
12
|
const getPrice = ((_b = state === null || state === void 0 ? void 0 : state.itemFieldGetters) === null || _b === void 0 ? void 0 : _b.getPrice) || itemFieldGetters_1.getPrice;
|
|
13
13
|
const getSalePrice = ((_c = state === null || state === void 0 ? void 0 : state.itemFieldGetters) === null || _c === void 0 ? void 0 : _c.getSalePrice) || itemFieldGetters_1.getSalePrice;
|
|
14
14
|
const getSwatchPreview = ((_d = state === null || state === void 0 ? void 0 : state.itemFieldGetters) === null || _d === void 0 ? void 0 : _d.getSwatchPreview) || itemFieldGetters_1.getSwatchPreview;
|
|
15
|
+
const getRolloverImage = ((_e = state === null || state === void 0 ? void 0 : state.itemFieldGetters) === null || _e === void 0 ? void 0 : _e.getRolloverImage) || itemFieldGetters_1.getRolloverImage;
|
|
15
16
|
(0, react_1.useEffect)(() => {
|
|
16
17
|
if (item === null || item === void 0 ? void 0 : item.variations) {
|
|
17
18
|
try {
|
|
18
|
-
setSwatchList(getSwatches(item, getPrice, getSwatchPreview, getSalePrice) || []);
|
|
19
|
+
setSwatchList(getSwatches(item, getPrice, getSwatchPreview, getSalePrice, getRolloverImage) || []);
|
|
19
20
|
}
|
|
20
21
|
catch (e) {
|
|
21
22
|
// do nothing
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
|
-
}, [item, getSwatches, getPrice, getSwatchPreview, getSalePrice]);
|
|
25
|
+
}, [item, getSwatches, getPrice, getSwatchPreview, getSalePrice, getRolloverImage]);
|
|
25
26
|
(0, react_1.useEffect)(() => {
|
|
26
27
|
if (item === null || item === void 0 ? void 0 : item.variations) {
|
|
27
28
|
const initialSwatch = swatchList === null || swatchList === void 0 ? void 0 : swatchList.find((swatch) => (swatch === null || swatch === void 0 ? void 0 : swatch.variationId) === (item === null || item === void 0 ? void 0 : item.variationId));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getSwatchPreview = exports.getSwatches = exports.getSalePrice = exports.getPrice = void 0;
|
|
3
|
+
exports.getSwatchPreview = exports.getSwatches = exports.getRolloverImage = exports.getSalePrice = exports.getPrice = void 0;
|
|
4
4
|
// eslint-disable-next-line import/prefer-default-export
|
|
5
5
|
function getPrice(item) {
|
|
6
6
|
return item.data.price;
|
|
@@ -10,7 +10,12 @@ function getSalePrice(item) {
|
|
|
10
10
|
return item.data.sale_price;
|
|
11
11
|
}
|
|
12
12
|
exports.getSalePrice = getSalePrice;
|
|
13
|
-
function
|
|
13
|
+
function getRolloverImage(item) {
|
|
14
|
+
return item.data.rolloverImage;
|
|
15
|
+
}
|
|
16
|
+
exports.getRolloverImage = getRolloverImage;
|
|
17
|
+
/* eslint-disable-next-line max-params */
|
|
18
|
+
function getSwatches(item, retrievePrice, retrieveSwatchPreview, retrieveSalePrice, retrieveRolloverImage) {
|
|
14
19
|
var _a;
|
|
15
20
|
const swatchList = [];
|
|
16
21
|
(_a = item === null || item === void 0 ? void 0 : item.variations) === null || _a === void 0 ? void 0 : _a.forEach((variation) => {
|
|
@@ -23,6 +28,7 @@ function getSwatches(item, retrievePrice, retrieveSwatchPreview, retrieveSalePri
|
|
|
23
28
|
price: retrievePrice(variation),
|
|
24
29
|
salePrice: retrieveSalePrice(variation),
|
|
25
30
|
swatchPreview: retrieveSwatchPreview(variation),
|
|
31
|
+
rolloverImage: retrieveRolloverImage(variation),
|
|
26
32
|
});
|
|
27
33
|
}
|
|
28
34
|
});
|
package/lib/cjs/version.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
.cio-image-container {
|
|
9
9
|
width: 100%;
|
|
10
10
|
height: auto;
|
|
11
|
+
position: relative;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
.cio-image {
|
|
@@ -16,6 +17,18 @@
|
|
|
16
17
|
object-fit: cover;
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
.cio-rollover-image {
|
|
21
|
+
position: absolute;
|
|
22
|
+
left: 0;
|
|
23
|
+
top: 0;
|
|
24
|
+
transition: opacity 0.3s ease-in-out;
|
|
25
|
+
opacity: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.cio-rollover-image.is-active {
|
|
29
|
+
opacity: 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
.cio-content {
|
|
20
33
|
width: 100%;
|
|
21
34
|
}
|
|
@@ -56,4 +69,4 @@
|
|
|
56
69
|
height: 40px;
|
|
57
70
|
font-size: 16px;
|
|
58
71
|
cursor: pointer;
|
|
59
|
-
}
|
|
72
|
+
}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState, useRef } from 'react';
|
|
2
2
|
import { useCioPlpContext } from '../../hooks/useCioPlpContext';
|
|
3
3
|
import { useOnAddToCart, useOnProductCardClick } from '../../hooks/callbacks';
|
|
4
4
|
import ProductSwatch from '../ProductSwatch';
|
|
5
5
|
import useProductInfo from '../../hooks/useProduct';
|
|
6
6
|
import { concatStyles, getProductCardCnstrcDataAttributes } from '../../utils';
|
|
7
|
+
import RenderPropsWrapper from '../RenderPropsWrapper/RenderPropsWrapper';
|
|
8
|
+
import { EMITTED_EVENTS } from '../../constants';
|
|
7
9
|
/**
|
|
8
10
|
* ProductCard component that has Constructor tracking built-in.
|
|
9
11
|
*/
|
|
10
12
|
export default function ProductCard(props) {
|
|
13
|
+
const [isRolloverImageShown, setIsRolloverImageShown] = useState(false);
|
|
14
|
+
const cardRef = useRef(null);
|
|
11
15
|
const { item, children } = props;
|
|
12
16
|
const state = useCioPlpContext();
|
|
13
17
|
const productInfo = useProductInfo({ item });
|
|
14
|
-
const { productSwatch, itemName, itemPrice, itemImageUrl, itemUrl, salePrice, hasSalePrice } = productInfo;
|
|
18
|
+
const { productSwatch, itemName, itemPrice, itemImageUrl, itemUrl, salePrice, hasSalePrice, rolloverImage, } = productInfo;
|
|
15
19
|
if (!state) {
|
|
16
20
|
throw new Error('This component is meant to be used within the CioPlp provider.');
|
|
17
21
|
}
|
|
@@ -23,21 +27,48 @@ export default function ProductCard(props) {
|
|
|
23
27
|
const { formatPrice } = state.formatters;
|
|
24
28
|
const onClick = useOnProductCardClick(client, state.callbacks.onProductCardClick);
|
|
25
29
|
const cnstrcData = getProductCardCnstrcDataAttributes(productInfo);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
30
|
+
const handleRolloverImageState = (isShown) => {
|
|
31
|
+
setIsRolloverImageShown(isShown);
|
|
32
|
+
if (isShown && rolloverImage) {
|
|
33
|
+
const event = new CustomEvent(EMITTED_EVENTS.PRODUCT_CARD_IMAGE_ROLLOVER, {
|
|
34
|
+
detail: { item },
|
|
35
|
+
bubbles: true,
|
|
36
|
+
});
|
|
37
|
+
cardRef.current?.dispatchEvent(event);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const onMouseEnter = (event) => {
|
|
41
|
+
if (state.callbacks.onProductCardMouseEnter) {
|
|
42
|
+
state.callbacks.onProductCardMouseEnter(event, item);
|
|
43
|
+
}
|
|
44
|
+
handleRolloverImageState(true);
|
|
45
|
+
};
|
|
46
|
+
const onMouseLeave = (event) => {
|
|
47
|
+
if (state.callbacks.onProductCardMouseLeave) {
|
|
48
|
+
state.callbacks.onProductCardMouseLeave(event, item);
|
|
49
|
+
}
|
|
50
|
+
handleRolloverImageState(false);
|
|
51
|
+
};
|
|
52
|
+
return (React.createElement(RenderPropsWrapper, { props: {
|
|
53
|
+
item,
|
|
54
|
+
productInfo,
|
|
55
|
+
formatPrice,
|
|
56
|
+
onAddToCart,
|
|
57
|
+
onClick,
|
|
58
|
+
onMouseEnter,
|
|
59
|
+
onMouseLeave,
|
|
60
|
+
isRolloverImageShown,
|
|
61
|
+
productCardCnstrcDataAttributes: cnstrcData,
|
|
62
|
+
}, override: children, htmlOverride: state.renderOverrides.productCard?.renderHtml, topLevelAttributes: { ...cnstrcData, className: 'cio-product-card' } },
|
|
63
|
+
React.createElement("a", { ...cnstrcData, className: 'cio-product-card', href: itemUrl, ref: cardRef, onClick: (e) => onClick(e, item, productSwatch?.selectedVariation?.variationId) },
|
|
64
|
+
React.createElement("div", { className: 'cio-image-container', onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave },
|
|
65
|
+
React.createElement("img", { alt: itemName, src: itemImageUrl, className: 'cio-image' }),
|
|
66
|
+
rolloverImage && (React.createElement("img", { alt: `${itemName} rollover`, src: rolloverImage, loading: 'lazy', className: concatStyles('cio-image cio-rollover-image', isRolloverImageShown && 'is-active') }))),
|
|
67
|
+
React.createElement("div", { className: 'cio-content' },
|
|
68
|
+
React.createElement("div", { className: 'cio-item-prices-container' },
|
|
69
|
+
hasSalePrice && (React.createElement("div", { className: 'cio-item-price', id: 'cio-sale-price' }, formatPrice(salePrice))),
|
|
70
|
+
Number(itemPrice) >= 0 && (React.createElement("div", { className: concatStyles('cio-item-price', hasSalePrice && 'cio-item-price-strikethrough') }, formatPrice(itemPrice)))),
|
|
71
|
+
React.createElement("div", { className: 'cio-item-name' }, itemName),
|
|
72
|
+
productSwatch && React.createElement(ProductSwatch, { swatchObject: productSwatch })),
|
|
73
|
+
React.createElement("button", { className: 'cio-add-to-cart-button', type: 'button', onClick: (e) => onAddToCart(e, item, itemPrice, productSwatch?.selectedVariation?.variationId) }, "Add to Cart"))));
|
|
43
74
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React, { useRef, isValidElement } from 'react';
|
|
2
|
+
export default function CustomHtmlRender(props) {
|
|
3
|
+
const { renderHtml, topLevelAttributes = {}, ...otherProps } = props;
|
|
4
|
+
const ref = useRef(null);
|
|
5
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6
|
+
const customElement = renderHtml(otherProps);
|
|
7
|
+
const isDomElement = customElement instanceof HTMLElement;
|
|
8
|
+
const isReactNode = isValidElement(customElement);
|
|
9
|
+
if (isDomElement && ref.current) {
|
|
10
|
+
ref.current.innerHTML = ''; // Clear previous content
|
|
11
|
+
ref.current.appendChild(customElement);
|
|
12
|
+
}
|
|
13
|
+
if (isReactNode) {
|
|
14
|
+
return customElement;
|
|
15
|
+
}
|
|
16
|
+
if (isDomElement) {
|
|
17
|
+
return React.createElement("div", { ...topLevelAttributes, ref: ref });
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* eslint-disable no-nested-ternary */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import CustomHtmlRender from './CustomHtmlRender';
|
|
4
|
+
export default function RenderPropsWrapper({ props, children, override, htmlOverride, topLevelAttributes, }) {
|
|
5
|
+
const isRenderProps = typeof override === 'function';
|
|
6
|
+
const isJSX = typeof override === 'object';
|
|
7
|
+
const isHtmlOverride = typeof htmlOverride === 'function';
|
|
8
|
+
return (React.createElement(React.Fragment, null, isRenderProps ? (override(props)) : isJSX ? (override) : isHtmlOverride ? (React.createElement(CustomHtmlRender, { ...props, renderHtml: htmlOverride, topLevelAttributes: topLevelAttributes })) : (
|
|
9
|
+
// Default implementation
|
|
10
|
+
children)));
|
|
11
|
+
}
|
package/lib/mjs/constants.js
CHANGED
|
@@ -4,7 +4,7 @@ import * as defaultGetters from '../utils/itemFieldGetters';
|
|
|
4
4
|
import * as defaultFormatters from '../utils/formatters';
|
|
5
5
|
import * as defaultUrlHelpers from '../utils/urlHelpers';
|
|
6
6
|
export default function useCioPlpProvider(props) {
|
|
7
|
-
const { apiKey, formatters, callbacks, itemFieldGetters, urlHelpers, staticRequestConfigs = {}, cioClient: customCioClient, cioClientOptions: customCioClientOptions = {}, } = props;
|
|
7
|
+
const { apiKey, formatters, callbacks, itemFieldGetters, urlHelpers, staticRequestConfigs = {}, renderOverrides = {}, cioClient: customCioClient, cioClientOptions: customCioClientOptions = {}, } = props;
|
|
8
8
|
const [cioClientOptions, setCioClientOptions] = useState(customCioClientOptions);
|
|
9
9
|
const cioClient = useCioClient({ apiKey, cioClient: customCioClient, options: cioClientOptions });
|
|
10
10
|
const contextValue = useMemo(() => ({
|
|
@@ -16,6 +16,7 @@ export default function useCioPlpProvider(props) {
|
|
|
16
16
|
formatters: { ...defaultFormatters, ...formatters },
|
|
17
17
|
callbacks: { ...callbacks },
|
|
18
18
|
urlHelpers: { ...defaultUrlHelpers, ...urlHelpers },
|
|
19
|
+
renderOverrides: { ...renderOverrides },
|
|
19
20
|
}), [
|
|
20
21
|
cioClient,
|
|
21
22
|
cioClientOptions,
|
|
@@ -23,6 +24,7 @@ export default function useCioPlpProvider(props) {
|
|
|
23
24
|
formatters,
|
|
24
25
|
callbacks,
|
|
25
26
|
urlHelpers,
|
|
27
|
+
renderOverrides,
|
|
26
28
|
staticRequestConfigs,
|
|
27
29
|
]);
|
|
28
30
|
return contextValue;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import useProductSwatch from './useProductSwatch';
|
|
2
2
|
import { useCioPlpContext } from './useCioPlpContext';
|
|
3
3
|
import { tryCatchify, isValidSalePrice } from '../utils';
|
|
4
|
-
import { getPrice as defaultGetPrice, getSalePrice as defaultGetSalePrice, } from '../utils/itemFieldGetters';
|
|
4
|
+
import { getPrice as defaultGetPrice, getSalePrice as defaultGetSalePrice, getRolloverImage as defaultGetRolloverImage, } from '../utils/itemFieldGetters';
|
|
5
5
|
const useProductInfo = ({ item }) => {
|
|
6
6
|
const state = useCioPlpContext();
|
|
7
7
|
const productSwatch = useProductSwatch({ item });
|
|
@@ -10,11 +10,17 @@ const useProductInfo = ({ item }) => {
|
|
|
10
10
|
}
|
|
11
11
|
const getPrice = tryCatchify(state?.itemFieldGetters?.getPrice || defaultGetPrice);
|
|
12
12
|
const getSalePrice = tryCatchify(state?.itemFieldGetters?.getSalePrice || defaultGetSalePrice);
|
|
13
|
+
const getRolloverImage = tryCatchify(state?.itemFieldGetters?.getRolloverImage || defaultGetRolloverImage);
|
|
13
14
|
const itemName = productSwatch?.selectedVariation?.itemName || item.itemName;
|
|
14
15
|
const itemPrice = productSwatch?.selectedVariation?.price || getPrice(item);
|
|
15
16
|
const itemImageUrl = productSwatch?.selectedVariation?.imageUrl || item.imageUrl;
|
|
16
17
|
const itemUrl = productSwatch?.selectedVariation?.url || item.url;
|
|
17
18
|
const variationId = productSwatch?.selectedVariation?.variationId;
|
|
19
|
+
let rolloverImage = productSwatch?.selectedVariation?.rolloverImage;
|
|
20
|
+
// Fallback to item's rollover image if all variations don't have a rollover image
|
|
21
|
+
if (!rolloverImage && productSwatch?.swatchList?.every((swatch) => !swatch.rolloverImage)) {
|
|
22
|
+
rolloverImage = getRolloverImage(item);
|
|
23
|
+
}
|
|
18
24
|
const { itemId } = item;
|
|
19
25
|
let salePrice = productSwatch?.selectedVariation?.salePrice || getSalePrice(item);
|
|
20
26
|
let hasSalePrice = true;
|
|
@@ -31,6 +37,7 @@ const useProductInfo = ({ item }) => {
|
|
|
31
37
|
variationId,
|
|
32
38
|
itemId,
|
|
33
39
|
salePrice,
|
|
40
|
+
rolloverImage,
|
|
34
41
|
hasSalePrice,
|
|
35
42
|
};
|
|
36
43
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
import { useCioPlpContext } from './useCioPlpContext';
|
|
3
|
-
import { getSwatches as defaultGetSwatches, getPrice as defaultGetPrice, getSwatchPreview as defaultGetSwatchPreview, getSalePrice as defaultGetSalePrice, } from '../utils/itemFieldGetters';
|
|
3
|
+
import { getSwatches as defaultGetSwatches, getPrice as defaultGetPrice, getSwatchPreview as defaultGetSwatchPreview, getSalePrice as defaultGetSalePrice, getRolloverImage as defaultGetRolloverImage, } from '../utils/itemFieldGetters';
|
|
4
4
|
const useProductSwatch = ({ item }) => {
|
|
5
5
|
const [selectedVariation, setSelectedVariation] = useState();
|
|
6
6
|
const [swatchList, setSwatchList] = useState([]);
|
|
@@ -9,16 +9,17 @@ const useProductSwatch = ({ item }) => {
|
|
|
9
9
|
const getPrice = state?.itemFieldGetters?.getPrice || defaultGetPrice;
|
|
10
10
|
const getSalePrice = state?.itemFieldGetters?.getSalePrice || defaultGetSalePrice;
|
|
11
11
|
const getSwatchPreview = state?.itemFieldGetters?.getSwatchPreview || defaultGetSwatchPreview;
|
|
12
|
+
const getRolloverImage = state?.itemFieldGetters?.getRolloverImage || defaultGetRolloverImage;
|
|
12
13
|
useEffect(() => {
|
|
13
14
|
if (item?.variations) {
|
|
14
15
|
try {
|
|
15
|
-
setSwatchList(getSwatches(item, getPrice, getSwatchPreview, getSalePrice) || []);
|
|
16
|
+
setSwatchList(getSwatches(item, getPrice, getSwatchPreview, getSalePrice, getRolloverImage) || []);
|
|
16
17
|
}
|
|
17
18
|
catch (e) {
|
|
18
19
|
// do nothing
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
|
-
}, [item, getSwatches, getPrice, getSwatchPreview, getSalePrice]);
|
|
22
|
+
}, [item, getSwatches, getPrice, getSwatchPreview, getSalePrice, getRolloverImage]);
|
|
22
23
|
useEffect(() => {
|
|
23
24
|
if (item?.variations) {
|
|
24
25
|
const initialSwatch = swatchList?.find((swatch) => swatch?.variationId === item?.variationId);
|
|
@@ -5,7 +5,11 @@ export function getPrice(item) {
|
|
|
5
5
|
export function getSalePrice(item) {
|
|
6
6
|
return item.data.sale_price;
|
|
7
7
|
}
|
|
8
|
-
export function
|
|
8
|
+
export function getRolloverImage(item) {
|
|
9
|
+
return item.data.rolloverImage;
|
|
10
|
+
}
|
|
11
|
+
/* eslint-disable-next-line max-params */
|
|
12
|
+
export function getSwatches(item, retrievePrice, retrieveSwatchPreview, retrieveSalePrice, retrieveRolloverImage) {
|
|
9
13
|
const swatchList = [];
|
|
10
14
|
item?.variations?.forEach((variation) => {
|
|
11
15
|
if (retrieveSwatchPreview(variation)) {
|
|
@@ -17,6 +21,7 @@ export function getSwatches(item, retrievePrice, retrieveSwatchPreview, retrieve
|
|
|
17
21
|
price: retrievePrice(variation),
|
|
18
22
|
salePrice: retrieveSalePrice(variation),
|
|
19
23
|
swatchPreview: retrieveSwatchPreview(variation),
|
|
24
|
+
rolloverImage: retrieveRolloverImage(variation),
|
|
20
25
|
});
|
|
21
26
|
}
|
|
22
27
|
});
|
package/lib/mjs/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '1.
|
|
1
|
+
export default '1.6.0';
|