@constructor-io/constructorio-ui-plp 1.4.6 → 1.5.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/Filters/FilterOptionsList.js +1 -1
- package/lib/cjs/components/Filters/Filters.js +2 -1
- package/lib/cjs/components/ProductCard/ProductCard.css +14 -1
- package/lib/cjs/components/ProductCard/ProductCard.js +35 -5
- package/lib/cjs/constants.js +4 -1
- package/lib/cjs/hooks/useFilter.js +5 -2
- 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/Filters/FilterOptionsList.js +1 -1
- package/lib/mjs/components/Filters/Filters.js +2 -1
- package/lib/mjs/components/ProductCard/ProductCard.css +14 -1
- package/lib/mjs/components/ProductCard/ProductCard.js +34 -5
- package/lib/mjs/constants.js +3 -0
- package/lib/mjs/hooks/useFilter.js +5 -2
- 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 +14 -0
- package/lib/types/constants.d.ts +3 -0
- package/lib/types/hooks/useFilter.d.ts +1 -0
- package/lib/types/types.d.ts +6 -1
- package/lib/types/utils/itemFieldGetters.d.ts +2 -1
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@ function FilterOptionsList(props) {
|
|
|
14
14
|
'cio-collapsible-is-open': !isCollapsed,
|
|
15
15
|
}) },
|
|
16
16
|
react_1.default.createElement("ul", { className: 'cio-filter-multiple-options-list cio-collapsible-inner' },
|
|
17
|
-
optionsToRender.map((option) => (react_1.default.createElement(FilterOptionListRow_1.default, { id: `${facet.name}-${option.value}`, optionValue: option.value, displayValue: option.displayName, displayCountValue: option.count.toString(), isChecked: selectedOptionMap[option.value] || false, onChange: onOptionSelect }))),
|
|
17
|
+
optionsToRender.map((option) => (react_1.default.createElement(FilterOptionListRow_1.default, { id: `${facet.name}-${option.value}`, key: option.value, optionValue: option.value, displayValue: option.displayName, displayCountValue: option.count.toString(), isChecked: selectedOptionMap[option.value] || false, onChange: onOptionSelect }))),
|
|
18
18
|
initialNumOptions < facet.options.length && (react_1.default.createElement("button", { type: 'button', className: 'cio-see-all', onClick: () => setIsShowAll(!isShowAll) }, isShowAll ? 'Show Less' : 'Show All')))));
|
|
19
19
|
}
|
|
20
20
|
exports.default = FilterOptionsList;
|
|
@@ -7,12 +7,13 @@ const FilterGroup_1 = tslib_1.__importDefault(require("./FilterGroup"));
|
|
|
7
7
|
const useFilter_1 = tslib_1.__importDefault(require("../../hooks/useFilter"));
|
|
8
8
|
function Filters(props) {
|
|
9
9
|
const { children, initialNumOptions } = props, useFiltersProps = tslib_1.__rest(props, ["children", "initialNumOptions"]);
|
|
10
|
-
const { facets, setFilter, sliderStep, facetSliderSteps } = (0, useFilter_1.default)(useFiltersProps);
|
|
10
|
+
const { facets, setFilter, sliderStep, facetSliderSteps, clearFilters } = (0, useFilter_1.default)(useFiltersProps);
|
|
11
11
|
return (react_1.default.createElement(react_1.default.Fragment, null, typeof children === 'function' ? (children({
|
|
12
12
|
facets,
|
|
13
13
|
setFilter,
|
|
14
14
|
sliderStep,
|
|
15
15
|
facetSliderSteps,
|
|
16
|
+
clearFilters,
|
|
16
17
|
})) : (react_1.default.createElement("div", { className: 'cio-filters' }, facets.map((facet) => (react_1.default.createElement(FilterGroup_1.default, { facet: facet, initialNumOptions: initialNumOptions, setFilter: setFilter, sliderStep: sliderStep, facetSliderSteps: facetSliderSteps, key: facet.name })))))));
|
|
17
18
|
}
|
|
18
19
|
exports.default = Filters;
|
|
@@ -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,23 @@
|
|
|
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 constants_1 = require("../../constants");
|
|
10
11
|
/**
|
|
11
12
|
* ProductCard component that has Constructor tracking built-in.
|
|
12
13
|
*/
|
|
13
14
|
function ProductCard(props) {
|
|
15
|
+
const [isRolloverImageShown, setIsRolloverImageShown] = (0, react_1.useState)(false);
|
|
16
|
+
const cardRef = (0, react_1.useRef)(null);
|
|
14
17
|
const { item, children } = props;
|
|
15
18
|
const state = (0, useCioPlpContext_1.useCioPlpContext)();
|
|
16
19
|
const productInfo = (0, useProduct_1.default)({ item });
|
|
17
|
-
const { productSwatch, itemName, itemPrice, itemImageUrl, itemUrl, salePrice, hasSalePrice } = productInfo;
|
|
20
|
+
const { productSwatch, itemName, itemPrice, itemImageUrl, itemUrl, salePrice, hasSalePrice, rolloverImage, } = productInfo;
|
|
18
21
|
if (!state) {
|
|
19
22
|
throw new Error('This component is meant to be used within the CioPlp provider.');
|
|
20
23
|
}
|
|
@@ -26,16 +29,43 @@ function ProductCard(props) {
|
|
|
26
29
|
const { formatPrice } = state.formatters;
|
|
27
30
|
const onClick = (0, callbacks_1.useOnProductCardClick)(client, state.callbacks.onProductCardClick);
|
|
28
31
|
const cnstrcData = (0, utils_1.getProductCardCnstrcDataAttributes)(productInfo);
|
|
32
|
+
const handleRolloverImageState = (isShown) => {
|
|
33
|
+
var _a;
|
|
34
|
+
setIsRolloverImageShown(isShown);
|
|
35
|
+
if (isShown && rolloverImage) {
|
|
36
|
+
const event = new CustomEvent(constants_1.EMITTED_EVENTS.PRODUCT_CARD_IMAGE_ROLLOVER, {
|
|
37
|
+
detail: { item },
|
|
38
|
+
bubbles: true,
|
|
39
|
+
});
|
|
40
|
+
(_a = cardRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const onMouseEnter = (event) => {
|
|
44
|
+
if (state.callbacks.onProductCardMouseEnter) {
|
|
45
|
+
state.callbacks.onProductCardMouseEnter(event, item);
|
|
46
|
+
}
|
|
47
|
+
handleRolloverImageState(true);
|
|
48
|
+
};
|
|
49
|
+
const onMouseLeave = (event) => {
|
|
50
|
+
if (state.callbacks.onProductCardMouseLeave) {
|
|
51
|
+
state.callbacks.onProductCardMouseLeave(event, item);
|
|
52
|
+
}
|
|
53
|
+
handleRolloverImageState(false);
|
|
54
|
+
};
|
|
29
55
|
return (react_1.default.createElement(react_1.default.Fragment, null, typeof children === 'function' ? (children({
|
|
30
56
|
item,
|
|
31
57
|
productInfo,
|
|
32
58
|
formatPrice,
|
|
33
59
|
onAddToCart,
|
|
34
60
|
onClick,
|
|
61
|
+
onMouseEnter,
|
|
62
|
+
onMouseLeave,
|
|
63
|
+
isRolloverImageShown,
|
|
35
64
|
productCardCnstrcDataAttributes: cnstrcData,
|
|
36
|
-
})) : (react_1.default.createElement("a", Object.assign({}, cnstrcData, { className: 'cio-product-card', href: itemUrl, 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); } }),
|
|
37
|
-
react_1.default.createElement("div", { className: 'cio-image-container' },
|
|
38
|
-
react_1.default.createElement("img", { alt: itemName, src: itemImageUrl, className: 'cio-image' })
|
|
65
|
+
})) : (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); } }),
|
|
66
|
+
react_1.default.createElement("div", { className: 'cio-image-container', onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave },
|
|
67
|
+
react_1.default.createElement("img", { alt: itemName, src: itemImageUrl, className: 'cio-image' }),
|
|
68
|
+
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') }))),
|
|
39
69
|
react_1.default.createElement("div", { className: 'cio-content' },
|
|
40
70
|
react_1.default.createElement("div", { className: 'cio-item-prices-container' },
|
|
41
71
|
hasSalePrice && (react_1.default.createElement("div", { className: 'cio-item-price', id: 'cio-sale-price' }, formatPrice(salePrice))),
|
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
|
+
};
|
|
@@ -10,9 +10,8 @@ function useFilter(props) {
|
|
|
10
10
|
throw new Error('useFilter must be used within a component that is a child of <CioPlp />');
|
|
11
11
|
}
|
|
12
12
|
const { getRequestConfigs, setRequestConfigs } = (0, useRequestConfigs_1.default)();
|
|
13
|
-
const { filters: requestFilters } = getRequestConfigs();
|
|
14
13
|
const setFilter = (filterName, filterValue) => {
|
|
15
|
-
const newFilters =
|
|
14
|
+
const newFilters = getRequestConfigs().filters || {};
|
|
16
15
|
newFilters[filterName] = filterValue;
|
|
17
16
|
// Remove filter entirely
|
|
18
17
|
if (filterValue === null) {
|
|
@@ -20,11 +19,15 @@ function useFilter(props) {
|
|
|
20
19
|
}
|
|
21
20
|
setRequestConfigs({ filters: newFilters, page: 1 });
|
|
22
21
|
};
|
|
22
|
+
const clearFilters = () => {
|
|
23
|
+
setRequestConfigs({ filters: {}, page: 1 });
|
|
24
|
+
};
|
|
23
25
|
return {
|
|
24
26
|
facets,
|
|
25
27
|
setFilter,
|
|
26
28
|
sliderStep,
|
|
27
29
|
facetSliderSteps,
|
|
30
|
+
clearFilters,
|
|
28
31
|
};
|
|
29
32
|
}
|
|
30
33
|
exports.default = useFilter;
|
|
@@ -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
|
@@ -11,6 +11,6 @@ export default function FilterOptionsList(props) {
|
|
|
11
11
|
'cio-collapsible-is-open': !isCollapsed,
|
|
12
12
|
}) },
|
|
13
13
|
React.createElement("ul", { className: 'cio-filter-multiple-options-list cio-collapsible-inner' },
|
|
14
|
-
optionsToRender.map((option) => (React.createElement(FilterOptionListRow, { id: `${facet.name}-${option.value}`, optionValue: option.value, displayValue: option.displayName, displayCountValue: option.count.toString(), isChecked: selectedOptionMap[option.value] || false, onChange: onOptionSelect }))),
|
|
14
|
+
optionsToRender.map((option) => (React.createElement(FilterOptionListRow, { id: `${facet.name}-${option.value}`, key: option.value, optionValue: option.value, displayValue: option.displayName, displayCountValue: option.count.toString(), isChecked: selectedOptionMap[option.value] || false, onChange: onOptionSelect }))),
|
|
15
15
|
initialNumOptions < facet.options.length && (React.createElement("button", { type: 'button', className: 'cio-see-all', onClick: () => setIsShowAll(!isShowAll) }, isShowAll ? 'Show Less' : 'Show All')))));
|
|
16
16
|
}
|
|
@@ -4,11 +4,12 @@ import FilterGroup from './FilterGroup';
|
|
|
4
4
|
import useFilter from '../../hooks/useFilter';
|
|
5
5
|
export default function Filters(props) {
|
|
6
6
|
const { children, initialNumOptions, ...useFiltersProps } = props;
|
|
7
|
-
const { facets, setFilter, sliderStep, facetSliderSteps } = useFilter(useFiltersProps);
|
|
7
|
+
const { facets, setFilter, sliderStep, facetSliderSteps, clearFilters } = useFilter(useFiltersProps);
|
|
8
8
|
return (React.createElement(React.Fragment, null, typeof children === 'function' ? (children({
|
|
9
9
|
facets,
|
|
10
10
|
setFilter,
|
|
11
11
|
sliderStep,
|
|
12
12
|
facetSliderSteps,
|
|
13
|
+
clearFilters,
|
|
13
14
|
})) : (React.createElement("div", { className: 'cio-filters' }, facets.map((facet) => (React.createElement(FilterGroup, { facet: facet, initialNumOptions: initialNumOptions, setFilter: setFilter, sliderStep: sliderStep, facetSliderSteps: facetSliderSteps, key: facet.name })))))));
|
|
14
15
|
}
|
|
@@ -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,20 @@
|
|
|
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 { EMITTED_EVENTS } from '../../constants';
|
|
7
8
|
/**
|
|
8
9
|
* ProductCard component that has Constructor tracking built-in.
|
|
9
10
|
*/
|
|
10
11
|
export default function ProductCard(props) {
|
|
12
|
+
const [isRolloverImageShown, setIsRolloverImageShown] = useState(false);
|
|
13
|
+
const cardRef = useRef(null);
|
|
11
14
|
const { item, children } = props;
|
|
12
15
|
const state = useCioPlpContext();
|
|
13
16
|
const productInfo = useProductInfo({ item });
|
|
14
|
-
const { productSwatch, itemName, itemPrice, itemImageUrl, itemUrl, salePrice, hasSalePrice } = productInfo;
|
|
17
|
+
const { productSwatch, itemName, itemPrice, itemImageUrl, itemUrl, salePrice, hasSalePrice, rolloverImage, } = productInfo;
|
|
15
18
|
if (!state) {
|
|
16
19
|
throw new Error('This component is meant to be used within the CioPlp provider.');
|
|
17
20
|
}
|
|
@@ -23,16 +26,42 @@ export default function ProductCard(props) {
|
|
|
23
26
|
const { formatPrice } = state.formatters;
|
|
24
27
|
const onClick = useOnProductCardClick(client, state.callbacks.onProductCardClick);
|
|
25
28
|
const cnstrcData = getProductCardCnstrcDataAttributes(productInfo);
|
|
29
|
+
const handleRolloverImageState = (isShown) => {
|
|
30
|
+
setIsRolloverImageShown(isShown);
|
|
31
|
+
if (isShown && rolloverImage) {
|
|
32
|
+
const event = new CustomEvent(EMITTED_EVENTS.PRODUCT_CARD_IMAGE_ROLLOVER, {
|
|
33
|
+
detail: { item },
|
|
34
|
+
bubbles: true,
|
|
35
|
+
});
|
|
36
|
+
cardRef.current?.dispatchEvent(event);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const onMouseEnter = (event) => {
|
|
40
|
+
if (state.callbacks.onProductCardMouseEnter) {
|
|
41
|
+
state.callbacks.onProductCardMouseEnter(event, item);
|
|
42
|
+
}
|
|
43
|
+
handleRolloverImageState(true);
|
|
44
|
+
};
|
|
45
|
+
const onMouseLeave = (event) => {
|
|
46
|
+
if (state.callbacks.onProductCardMouseLeave) {
|
|
47
|
+
state.callbacks.onProductCardMouseLeave(event, item);
|
|
48
|
+
}
|
|
49
|
+
handleRolloverImageState(false);
|
|
50
|
+
};
|
|
26
51
|
return (React.createElement(React.Fragment, null, typeof children === 'function' ? (children({
|
|
27
52
|
item,
|
|
28
53
|
productInfo,
|
|
29
54
|
formatPrice,
|
|
30
55
|
onAddToCart,
|
|
31
56
|
onClick,
|
|
57
|
+
onMouseEnter,
|
|
58
|
+
onMouseLeave,
|
|
59
|
+
isRolloverImageShown,
|
|
32
60
|
productCardCnstrcDataAttributes: cnstrcData,
|
|
33
|
-
})) : (React.createElement("a", { ...cnstrcData, className: 'cio-product-card', href: itemUrl, onClick: (e) => onClick(e, item, productSwatch?.selectedVariation?.variationId) },
|
|
34
|
-
React.createElement("div", { className: 'cio-image-container' },
|
|
35
|
-
React.createElement("img", { alt: itemName, src: itemImageUrl, className: 'cio-image' })
|
|
61
|
+
})) : (React.createElement("a", { ...cnstrcData, className: 'cio-product-card', href: itemUrl, ref: cardRef, onClick: (e) => onClick(e, item, productSwatch?.selectedVariation?.variationId) },
|
|
62
|
+
React.createElement("div", { className: 'cio-image-container', onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave },
|
|
63
|
+
React.createElement("img", { alt: itemName, src: itemImageUrl, className: 'cio-image' }),
|
|
64
|
+
rolloverImage && (React.createElement("img", { alt: `${itemName} rollover`, src: rolloverImage, loading: 'lazy', className: concatStyles('cio-image cio-rollover-image', isRolloverImageShown && 'is-active') }))),
|
|
36
65
|
React.createElement("div", { className: 'cio-content' },
|
|
37
66
|
React.createElement("div", { className: 'cio-item-prices-container' },
|
|
38
67
|
hasSalePrice && (React.createElement("div", { className: 'cio-item-price', id: 'cio-sale-price' }, formatPrice(salePrice))),
|
package/lib/mjs/constants.js
CHANGED
|
@@ -7,9 +7,8 @@ export default function useFilter(props) {
|
|
|
7
7
|
throw new Error('useFilter must be used within a component that is a child of <CioPlp />');
|
|
8
8
|
}
|
|
9
9
|
const { getRequestConfigs, setRequestConfigs } = useRequestConfigs();
|
|
10
|
-
const { filters: requestFilters } = getRequestConfigs();
|
|
11
10
|
const setFilter = (filterName, filterValue) => {
|
|
12
|
-
const newFilters =
|
|
11
|
+
const newFilters = getRequestConfigs().filters || {};
|
|
13
12
|
newFilters[filterName] = filterValue;
|
|
14
13
|
// Remove filter entirely
|
|
15
14
|
if (filterValue === null) {
|
|
@@ -17,10 +16,14 @@ export default function useFilter(props) {
|
|
|
17
16
|
}
|
|
18
17
|
setRequestConfigs({ filters: newFilters, page: 1 });
|
|
19
18
|
};
|
|
19
|
+
const clearFilters = () => {
|
|
20
|
+
setRequestConfigs({ filters: {}, page: 1 });
|
|
21
|
+
};
|
|
20
22
|
return {
|
|
21
23
|
facets,
|
|
22
24
|
setFilter,
|
|
23
25
|
sliderStep,
|
|
24
26
|
facetSliderSteps,
|
|
27
|
+
clearFilters,
|
|
25
28
|
};
|
|
26
29
|
}
|
|
@@ -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.5.0';
|
|
@@ -29,6 +29,20 @@ export interface ProductCardRenderProps extends ProductCardProps {
|
|
|
29
29
|
* Set globally at the CioPlp provider level.
|
|
30
30
|
*/
|
|
31
31
|
onClick: (event: React.MouseEvent, item: Item) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Callback to run on Product Card Mouse Enter.
|
|
34
|
+
* Set globally at the CioPlp provider level.
|
|
35
|
+
*/
|
|
36
|
+
onMouseEnter: (event: React.MouseEvent, item: Item) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Callback to run on Product Card Mouse Leave.
|
|
39
|
+
* Set globally at the CioPlp provider level.
|
|
40
|
+
*/
|
|
41
|
+
onMouseLeave: (event: React.MouseEvent, item: Item) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Boolean to show/hide the rollover image.
|
|
44
|
+
*/
|
|
45
|
+
isRolloverImageShown: boolean;
|
|
32
46
|
/**
|
|
33
47
|
* Data Attributes to surface on parent div of product card.
|
|
34
48
|
*/
|
package/lib/types/constants.d.ts
CHANGED
package/lib/types/types.d.ts
CHANGED
|
@@ -13,8 +13,9 @@ export type CioClientOptions = Omit<ConstructorClientOptions, 'apiKey' | 'sendTr
|
|
|
13
13
|
export interface ItemFieldGetters {
|
|
14
14
|
getPrice: (item: Item | Variation) => number;
|
|
15
15
|
getSalePrice: (item: Item | Variation) => number | undefined;
|
|
16
|
+
getRolloverImage: (item: Item | Variation) => string | undefined;
|
|
16
17
|
getSwatchPreview: (variation: Variation) => string;
|
|
17
|
-
getSwatches: (item: Item, retrievePrice: ItemFieldGetters['getPrice'], retrieveSwatchPreview: ItemFieldGetters['getSwatchPreview'], retrieveSalePrice: ItemFieldGetters['getSalePrice']) => SwatchItem[] | undefined;
|
|
18
|
+
getSwatches: (item: Item, retrievePrice: ItemFieldGetters['getPrice'], retrieveSwatchPreview: ItemFieldGetters['getSwatchPreview'], retrieveSalePrice: ItemFieldGetters['getSalePrice'], retrieveRolloverImage: ItemFieldGetters['getRolloverImage']) => SwatchItem[] | undefined;
|
|
18
19
|
}
|
|
19
20
|
export interface Formatters {
|
|
20
21
|
formatPrice: (price?: number) => string;
|
|
@@ -22,6 +23,8 @@ export interface Formatters {
|
|
|
22
23
|
export interface Callbacks {
|
|
23
24
|
onAddToCart?: (event: React.MouseEvent, item: Item, selectedVariation?: Variation) => void;
|
|
24
25
|
onProductCardClick?: (event: React.MouseEvent, item: Item) => void;
|
|
26
|
+
onProductCardMouseEnter?: (event: React.MouseEvent, item: Item) => void;
|
|
27
|
+
onProductCardMouseLeave?: (event: React.MouseEvent, item: Item) => void;
|
|
25
28
|
onSwatchClick?: (event: React.MouseEvent, swatch: SwatchItem) => void;
|
|
26
29
|
onRedirect?: (url: string) => void;
|
|
27
30
|
}
|
|
@@ -134,6 +137,7 @@ export interface SwatchItem {
|
|
|
134
137
|
salePrice?: number;
|
|
135
138
|
swatchPreview: string;
|
|
136
139
|
variationId?: string;
|
|
140
|
+
rolloverImage?: string;
|
|
137
141
|
}
|
|
138
142
|
export interface PlpBrowseData {
|
|
139
143
|
resultId: string;
|
|
@@ -178,6 +182,7 @@ export interface ProductInfoObject {
|
|
|
178
182
|
itemUrl?: string;
|
|
179
183
|
itemImageUrl?: string;
|
|
180
184
|
variationId?: string;
|
|
185
|
+
rolloverImage?: string;
|
|
181
186
|
hasSalePrice?: boolean;
|
|
182
187
|
}
|
|
183
188
|
export type UseProductInfoProps = {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ItemFieldGetters, Item, SwatchItem, Variation } from '../types';
|
|
2
2
|
export declare function getPrice(item: Item | Variation): number;
|
|
3
3
|
export declare function getSalePrice(item: Item | Variation): number | undefined;
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function getRolloverImage(item: Item | Variation): string | undefined;
|
|
5
|
+
export declare function getSwatches(item: Item, retrievePrice: ItemFieldGetters['getPrice'], retrieveSwatchPreview: ItemFieldGetters['getSwatchPreview'], retrieveSalePrice: ItemFieldGetters['getSalePrice'], retrieveRolloverImage: ItemFieldGetters['getRolloverImage']): SwatchItem[] | undefined;
|
|
5
6
|
export declare function getSwatchPreview(variation: Variation): string;
|
package/lib/types/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "1.
|
|
1
|
+
declare const _default: "1.5.0";
|
|
2
2
|
export default _default;
|