@constructor-io/constructorio-ui-plp 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/constructorio-ui-plp-bundled.js +12 -12
  2. package/lib/cjs/components/CioPlp/CioPlp.js +2 -2
  3. package/lib/cjs/components/ProductCard/ProductCard.js +24 -21
  4. package/lib/cjs/components/ProductCard/index.js +0 -1
  5. package/lib/cjs/components/RenderPropsWrapper/CustomHtmlRender.js +24 -0
  6. package/lib/cjs/components/RenderPropsWrapper/RenderPropsWrapper.js +15 -0
  7. package/lib/cjs/hooks/useCioPlpProvider.js +3 -1
  8. package/lib/cjs/hooks/useGroups.js +7 -1
  9. package/lib/cjs/hooks/useOptionsList.js +7 -5
  10. package/lib/cjs/utils/itemFieldGetters.js +6 -1
  11. package/lib/cjs/version.js +1 -1
  12. package/lib/mjs/components/CioPlp/CioPlp.js +2 -2
  13. package/lib/mjs/components/ProductCard/ProductCard.js +23 -21
  14. package/lib/mjs/components/ProductCard/index.js +0 -1
  15. package/lib/mjs/components/RenderPropsWrapper/CustomHtmlRender.js +20 -0
  16. package/lib/mjs/components/RenderPropsWrapper/RenderPropsWrapper.js +11 -0
  17. package/lib/mjs/hooks/useCioPlpProvider.js +3 -1
  18. package/lib/mjs/hooks/useGroups.js +8 -2
  19. package/lib/mjs/hooks/useOptionsList.js +8 -6
  20. package/lib/mjs/utils/itemFieldGetters.js +3 -0
  21. package/lib/mjs/version.js +1 -1
  22. package/lib/types/components/ProductCard/ProductCard.d.ts +1 -51
  23. package/lib/types/components/ProductCard/index.d.ts +0 -1
  24. package/lib/types/components/RenderPropsWrapper/CustomHtmlRender.d.ts +7 -0
  25. package/lib/types/components/RenderPropsWrapper/RenderPropsWrapper.d.ts +25 -0
  26. package/lib/types/hooks/useGroups.d.ts +6 -1
  27. package/lib/types/hooks/useOptionsList.d.ts +5 -0
  28. package/lib/types/hooks/usePagination.d.ts +10 -0
  29. package/lib/types/index.d.ts +0 -1
  30. package/lib/types/types.d.ts +59 -1
  31. package/lib/types/utils/itemFieldGetters.d.ts +2 -1
  32. package/lib/types/version.d.ts +1 -1
  33. package/package.json +1 -1
@@ -6,8 +6,8 @@ const CioPlpProvider_1 = tslib_1.__importDefault(require("./CioPlpProvider"));
6
6
  const CioPlpGrid_1 = tslib_1.__importDefault(require("../CioPlpGrid"));
7
7
  // Wrapper component for CioPlpProvider with default Markup
8
8
  function CioPlp(props) {
9
- const { children, initialSearchResponse, initialBrowseResponse, sortConfigs, paginationConfigs, filterConfigs } = props, rest = tslib_1.__rest(props, ["children", "initialSearchResponse", "initialBrowseResponse", "sortConfigs", "paginationConfigs", "filterConfigs"]);
10
- const defaultMarkup = (react_1.default.createElement(CioPlpGrid_1.default, { initialSearchResponse: initialSearchResponse, initialBrowseResponse: initialBrowseResponse, sortConfigs: sortConfigs, paginationConfigs: paginationConfigs, filterConfigs: filterConfigs }));
9
+ const { children, initialSearchResponse, initialBrowseResponse, sortConfigs, paginationConfigs, filterConfigs, groupsConfigs } = props, rest = tslib_1.__rest(props, ["children", "initialSearchResponse", "initialBrowseResponse", "sortConfigs", "paginationConfigs", "filterConfigs", "groupsConfigs"]);
10
+ const defaultMarkup = (react_1.default.createElement(CioPlpGrid_1.default, { initialSearchResponse: initialSearchResponse, initialBrowseResponse: initialBrowseResponse, sortConfigs: sortConfigs, paginationConfigs: paginationConfigs, filterConfigs: filterConfigs, groupsConfigs: groupsConfigs }));
11
11
  return (react_1.default.createElement("div", { className: 'cio-plp' },
12
12
  react_1.default.createElement(CioPlpProvider_1.default, Object.assign({}, rest), children || defaultMarkup)));
13
13
  }
@@ -7,11 +7,13 @@ 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"));
10
11
  const constants_1 = require("../../constants");
11
12
  /**
12
13
  * ProductCard component that has Constructor tracking built-in.
13
14
  */
14
15
  function ProductCard(props) {
16
+ var _a;
15
17
  const [isRolloverImageShown, setIsRolloverImageShown] = (0, react_1.useState)(false);
16
18
  const cardRef = (0, react_1.useRef)(null);
17
19
  const { item, children } = props;
@@ -52,26 +54,27 @@ function ProductCard(props) {
52
54
  }
53
55
  handleRolloverImageState(false);
54
56
  };
55
- return (react_1.default.createElement(react_1.default.Fragment, null, typeof children === 'function' ? (children({
56
- item,
57
- productInfo,
58
- formatPrice,
59
- onAddToCart,
60
- onClick,
61
- onMouseEnter,
62
- onMouseLeave,
63
- isRolloverImageShown,
64
- productCardCnstrcDataAttributes: cnstrcData,
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') }))),
69
- react_1.default.createElement("div", { className: 'cio-content' },
70
- react_1.default.createElement("div", { className: 'cio-item-prices-container' },
71
- hasSalePrice && (react_1.default.createElement("div", { className: 'cio-item-price', id: 'cio-sale-price' }, formatPrice(salePrice))),
72
- Number(itemPrice) >= 0 && (react_1.default.createElement("div", { className: (0, utils_1.concatStyles)('cio-item-price', hasSalePrice && 'cio-item-price-strikethrough') }, formatPrice(itemPrice)))),
73
- react_1.default.createElement("div", { className: 'cio-item-name' }, itemName),
74
- productSwatch && react_1.default.createElement(ProductSwatch_1.default, { swatchObject: productSwatch })),
75
- 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")))));
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"))));
76
79
  }
77
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;
@@ -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;
@@ -9,11 +9,12 @@ const useOptionsList_1 = tslib_1.__importDefault(require("./useOptionsList"));
9
9
  const useCioBreadcrumb_1 = tslib_1.__importDefault(require("./useCioBreadcrumb"));
10
10
  function useGroups(props) {
11
11
  var _a, _b;
12
- const { groups, initialNumOptions: numOptionsProps } = props;
12
+ const { groups, initialNumOptions: numOptionsProps, isHiddenGroupFn } = props;
13
13
  const contextValue = (0, useCioPlpContext_1.useCioPlpContext)();
14
14
  if (!contextValue) {
15
15
  throw new Error('useGroups must be used within a component that is a child of <CioPlp />');
16
16
  }
17
+ const { getIsHiddenGroupField } = contextValue.itemFieldGetters;
17
18
  const { setFilter } = (0, useFilter_1.default)({ facets: [] });
18
19
  const { getRequestConfigs } = (0, useRequestConfigs_1.default)();
19
20
  const requestConfigs = getRequestConfigs();
@@ -26,10 +27,15 @@ function useGroups(props) {
26
27
  const setGroup = (groupId) => {
27
28
  setFilter('group_id', groupId);
28
29
  };
30
+ const isHiddenOptionFn = (0, react_1.useCallback)((group) => (typeof isHiddenGroupFn === 'function' && isHiddenGroupFn(group)) ||
31
+ (typeof getIsHiddenGroupField === 'function' && getIsHiddenGroupField(group)) ||
32
+ false, // Ensure that isHiddenOptionFn never returns undefined
33
+ [isHiddenGroupFn, getIsHiddenGroupField]);
29
34
  const { breadcrumbs, currentPage } = (0, useCioBreadcrumb_1.default)({ groups, filterValue: currentGroupId || 'all' }) || [];
30
35
  const { initialNumOptions, isShowAll, setIsShowAll, optionsToRender, setOptionsToRender } = (0, useOptionsList_1.default)({
31
36
  options: groupOptions,
32
37
  initialNumOptions: numOptionsProps,
38
+ isHiddenOptionFn,
33
39
  });
34
40
  const [selectedGroupId, setSelectedGroupId] = (0, react_1.useState)();
35
41
  const onOptionSelect = (groupId) => {
@@ -1,18 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const react_1 = require("react");
4
+ const defaultIsHiddenOptionFn = () => false;
4
5
  function useOptionsList(props) {
5
- const { options, initialNumOptions = 5 } = props;
6
+ const { options, initialNumOptions = 5, isHiddenOptionFn = defaultIsHiddenOptionFn } = props;
7
+ const filteredOptions = (0, react_1.useMemo)(() => options.filter((option) => !isHiddenOptionFn(option)), [isHiddenOptionFn, options]);
6
8
  const [isShowAll, setIsShowAll] = (0, react_1.useState)(false);
7
- const [optionsToRender, setOptionsToRender] = (0, react_1.useState)(options);
9
+ const [optionsToRender, setOptionsToRender] = (0, react_1.useState)(filteredOptions);
8
10
  (0, react_1.useEffect)(() => {
9
11
  if (isShowAll) {
10
- setOptionsToRender(options);
12
+ setOptionsToRender(filteredOptions);
11
13
  }
12
14
  else {
13
- setOptionsToRender(options.slice(0, initialNumOptions));
15
+ setOptionsToRender(filteredOptions.slice(0, initialNumOptions));
14
16
  }
15
- }, [isShowAll, options, initialNumOptions]);
17
+ }, [isShowAll, filteredOptions, initialNumOptions]);
16
18
  return {
17
19
  // props
18
20
  initialNumOptions,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSwatchPreview = exports.getSwatches = exports.getRolloverImage = exports.getSalePrice = exports.getPrice = void 0;
3
+ exports.getIsHiddenGroupField = 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;
@@ -40,3 +40,8 @@ function getSwatchPreview(variation) {
40
40
  return (_a = variation === null || variation === void 0 ? void 0 : variation.data) === null || _a === void 0 ? void 0 : _a.swatchPreview;
41
41
  }
42
42
  exports.getSwatchPreview = getSwatchPreview;
43
+ function getIsHiddenGroupField(group) {
44
+ var _a;
45
+ return (_a = group === null || group === void 0 ? void 0 : group.data) === null || _a === void 0 ? void 0 : _a.cio_plp_hidden;
46
+ }
47
+ exports.getIsHiddenGroupField = getIsHiddenGroupField;
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = '1.5.0';
3
+ exports.default = '1.6.1';
@@ -3,8 +3,8 @@ import CioPlpProvider from './CioPlpProvider';
3
3
  import CioPlpGrid from '../CioPlpGrid';
4
4
  // Wrapper component for CioPlpProvider with default Markup
5
5
  export default function CioPlp(props) {
6
- const { children, initialSearchResponse, initialBrowseResponse, sortConfigs, paginationConfigs, filterConfigs, ...rest } = props;
7
- const defaultMarkup = (React.createElement(CioPlpGrid, { initialSearchResponse: initialSearchResponse, initialBrowseResponse: initialBrowseResponse, sortConfigs: sortConfigs, paginationConfigs: paginationConfigs, filterConfigs: filterConfigs }));
6
+ const { children, initialSearchResponse, initialBrowseResponse, sortConfigs, paginationConfigs, filterConfigs, groupsConfigs, ...rest } = props;
7
+ const defaultMarkup = (React.createElement(CioPlpGrid, { initialSearchResponse: initialSearchResponse, initialBrowseResponse: initialBrowseResponse, sortConfigs: sortConfigs, paginationConfigs: paginationConfigs, filterConfigs: filterConfigs, groupsConfigs: groupsConfigs }));
8
8
  return (React.createElement("div", { className: 'cio-plp' },
9
9
  React.createElement(CioPlpProvider, { ...rest }, children || defaultMarkup)));
10
10
  }
@@ -4,6 +4,7 @@ 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';
7
8
  import { EMITTED_EVENTS } from '../../constants';
8
9
  /**
9
10
  * ProductCard component that has Constructor tracking built-in.
@@ -48,25 +49,26 @@ export default function ProductCard(props) {
48
49
  }
49
50
  handleRolloverImageState(false);
50
51
  };
51
- return (React.createElement(React.Fragment, null, typeof children === 'function' ? (children({
52
- item,
53
- productInfo,
54
- formatPrice,
55
- onAddToCart,
56
- onClick,
57
- onMouseEnter,
58
- onMouseLeave,
59
- isRolloverImageShown,
60
- productCardCnstrcDataAttributes: cnstrcData,
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') }))),
65
- React.createElement("div", { className: 'cio-content' },
66
- React.createElement("div", { className: 'cio-item-prices-container' },
67
- hasSalePrice && (React.createElement("div", { className: 'cio-item-price', id: 'cio-sale-price' }, formatPrice(salePrice))),
68
- Number(itemPrice) >= 0 && (React.createElement("div", { className: concatStyles('cio-item-price', hasSalePrice && 'cio-item-price-strikethrough') }, formatPrice(itemPrice)))),
69
- React.createElement("div", { className: 'cio-item-name' }, itemName),
70
- productSwatch && React.createElement(ProductSwatch, { swatchObject: productSwatch })),
71
- React.createElement("button", { className: 'cio-add-to-cart-button', type: 'button', onClick: (e) => onAddToCart(e, item, itemPrice, productSwatch?.selectedVariation?.variationId) }, "Add to Cart")))));
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"))));
72
74
  }
@@ -1,3 +1,2 @@
1
1
  import ProductCard from './ProductCard';
2
- export * from './ProductCard';
3
2
  export default ProductCard;
@@ -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
+ }
@@ -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,15 +1,16 @@
1
- import { useState } from 'react';
1
+ import { useCallback, useState } from 'react';
2
2
  import { useCioPlpContext } from './useCioPlpContext';
3
3
  import useFilter from './useFilter';
4
4
  import useRequestConfigs from './useRequestConfigs';
5
5
  import useOptionsList from './useOptionsList';
6
6
  import useCioBreadcrumb from './useCioBreadcrumb';
7
7
  export default function useGroups(props) {
8
- const { groups, initialNumOptions: numOptionsProps } = props;
8
+ const { groups, initialNumOptions: numOptionsProps, isHiddenGroupFn } = props;
9
9
  const contextValue = useCioPlpContext();
10
10
  if (!contextValue) {
11
11
  throw new Error('useGroups must be used within a component that is a child of <CioPlp />');
12
12
  }
13
+ const { getIsHiddenGroupField } = contextValue.itemFieldGetters;
13
14
  const { setFilter } = useFilter({ facets: [] });
14
15
  const { getRequestConfigs } = useRequestConfigs();
15
16
  const requestConfigs = getRequestConfigs();
@@ -22,10 +23,15 @@ export default function useGroups(props) {
22
23
  const setGroup = (groupId) => {
23
24
  setFilter('group_id', groupId);
24
25
  };
26
+ const isHiddenOptionFn = useCallback((group) => (typeof isHiddenGroupFn === 'function' && isHiddenGroupFn(group)) ||
27
+ (typeof getIsHiddenGroupField === 'function' && getIsHiddenGroupField(group)) ||
28
+ false, // Ensure that isHiddenOptionFn never returns undefined
29
+ [isHiddenGroupFn, getIsHiddenGroupField]);
25
30
  const { breadcrumbs, currentPage } = useCioBreadcrumb({ groups, filterValue: currentGroupId || 'all' }) || [];
26
31
  const { initialNumOptions, isShowAll, setIsShowAll, optionsToRender, setOptionsToRender } = useOptionsList({
27
32
  options: groupOptions,
28
33
  initialNumOptions: numOptionsProps,
34
+ isHiddenOptionFn,
29
35
  });
30
36
  const [selectedGroupId, setSelectedGroupId] = useState();
31
37
  const onOptionSelect = (groupId) => {
@@ -1,16 +1,18 @@
1
- import { useEffect, useState } from 'react';
1
+ import { useEffect, useMemo, useState } from 'react';
2
+ const defaultIsHiddenOptionFn = () => false;
2
3
  export default function useOptionsList(props) {
3
- const { options, initialNumOptions = 5 } = props;
4
+ const { options, initialNumOptions = 5, isHiddenOptionFn = defaultIsHiddenOptionFn } = props;
5
+ const filteredOptions = useMemo(() => options.filter((option) => !isHiddenOptionFn(option)), [isHiddenOptionFn, options]);
4
6
  const [isShowAll, setIsShowAll] = useState(false);
5
- const [optionsToRender, setOptionsToRender] = useState(options);
7
+ const [optionsToRender, setOptionsToRender] = useState(filteredOptions);
6
8
  useEffect(() => {
7
9
  if (isShowAll) {
8
- setOptionsToRender(options);
10
+ setOptionsToRender(filteredOptions);
9
11
  }
10
12
  else {
11
- setOptionsToRender(options.slice(0, initialNumOptions));
13
+ setOptionsToRender(filteredOptions.slice(0, initialNumOptions));
12
14
  }
13
- }, [isShowAll, options, initialNumOptions]);
15
+ }, [isShowAll, filteredOptions, initialNumOptions]);
14
16
  return {
15
17
  // props
16
18
  initialNumOptions,
@@ -30,3 +30,6 @@ export function getSwatches(item, retrievePrice, retrieveSwatchPreview, retrieve
30
30
  export function getSwatchPreview(variation) {
31
31
  return variation?.data?.swatchPreview;
32
32
  }
33
+ export function getIsHiddenGroupField(group) {
34
+ return group?.data?.cio_plp_hidden;
35
+ }
@@ -1 +1 @@
1
- export default '1.5.0';
1
+ export default '1.6.1';
@@ -1,56 +1,6 @@
1
1
  import React from 'react';
2
- import { CnstrcData, IncludeRenderProps, Item, ProductInfoObject } from '../../types';
3
- interface Props {
4
- /**
5
- * Constructor's Transformed API Item Object.
6
- */
7
- item: Item;
8
- }
9
- /**
10
- * Props that will be passed to the renderProps function
11
- */
12
- export interface ProductCardRenderProps extends ProductCardProps {
13
- /**
14
- * Function to format the price. Defaults to "$0.00".
15
- * Set globally at the CioPlp provider level.
16
- */
17
- formatPrice: (price: number) => string;
18
- /**
19
- * Object containing information about the current product, variation
20
- */
21
- productInfo: ProductInfoObject;
22
- /**
23
- * Callback to run on add-to-cart event.
24
- * Set globally at the CioPlp provider level.
25
- */
26
- onAddToCart: (event: React.MouseEvent, item: Item, revenue: number, selectedVariation: string) => void;
27
- /**
28
- * Callback to run on Product Card Click.
29
- * Set globally at the CioPlp provider level.
30
- */
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;
46
- /**
47
- * Data Attributes to surface on parent div of product card.
48
- */
49
- productCardCnstrcDataAttributes: CnstrcData;
50
- }
51
- export type ProductCardProps = IncludeRenderProps<Props, ProductCardRenderProps>;
2
+ import { ProductCardProps } from '../../types';
52
3
  /**
53
4
  * ProductCard component that has Constructor tracking built-in.
54
5
  */
55
6
  export default function ProductCard(props: ProductCardProps): React.JSX.Element;
56
- export {};
@@ -1,3 +1,2 @@
1
1
  import ProductCard from './ProductCard';
2
- export * from './ProductCard';
3
2
  export default ProductCard;
@@ -0,0 +1,7 @@
1
+ import React, { ReactNode } from 'react';
2
+ interface CustomHtmlRenderProps<T> {
3
+ renderHtml: (props: T) => HTMLElement | ReactNode;
4
+ topLevelAttributes?: object;
5
+ }
6
+ export default function CustomHtmlRender<T>(props: T & CustomHtmlRenderProps<T>): React.JSX.Element | null;
7
+ export {};
@@ -0,0 +1,25 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { RenderPropsChildren } from '../../types';
3
+ export interface ReactPropsWrapperProps<T> {
4
+ /**
5
+ * The props to be passed to the render props function provided
6
+ */
7
+ props: T;
8
+ /**
9
+ * The default implementation to be nested within the wrapper
10
+ */
11
+ children: ReactNode;
12
+ /**
13
+ * One of Function<T> | JSX. Overrides default implementation
14
+ */
15
+ override?: RenderPropsChildren<T>;
16
+ /**
17
+ * One of Function<T> -> HTMLElement. Overrides default implementation
18
+ */
19
+ htmlOverride?: (props: T) => HTMLElement | ReactNode;
20
+ /**
21
+ * Object containing the attributes to be spread on the top-level div. To be used with `htmlOverride`
22
+ */
23
+ topLevelAttributes?: object;
24
+ }
25
+ export default function RenderPropsWrapper<T>({ props, children, override, htmlOverride, topLevelAttributes, }: ReactPropsWrapperProps<T>): React.JSX.Element;
@@ -1,11 +1,16 @@
1
1
  import { PlpItemGroup } from '../types';
2
2
  import { UseOptionsListProps } from './useOptionsList';
3
3
  import { Breadcrumb } from './useCioBreadcrumb';
4
- export interface UseGroupProps extends Omit<UseOptionsListProps<PlpItemGroup>, 'options'> {
4
+ export interface UseGroupProps extends Omit<UseOptionsListProps<PlpItemGroup>, 'options' | 'isHiddenOptionFn'> {
5
5
  /**
6
6
  * Used to build and render the groups filter dynamically
7
7
  */
8
8
  groups: Array<PlpItemGroup>;
9
+ /**
10
+ * Function that takes in a PlpItemGroup and returns `true` if the group should be hidden from the final render
11
+ * @returns boolean
12
+ */
13
+ isHiddenGroupFn?: (group: PlpItemGroup) => boolean;
9
14
  }
10
15
  export default function useGroups(props: UseGroupProps): {
11
16
  groupOptions: PlpItemGroup[];
@@ -8,6 +8,11 @@ export interface UseOptionsListProps<T> {
8
8
  * The remaining options will be hidden under a "Show All" button
9
9
  */
10
10
  initialNumOptions?: number;
11
+ /**
12
+ * Function that takes in an option object T and returns `true` if it should NOT be rendered as an option
13
+ * @returns boolean
14
+ */
15
+ isHiddenOptionFn?: (option: T) => boolean;
11
16
  }
12
17
  export default function useOptionsList<T>(props: UseOptionsListProps<T>): {
13
18
  initialNumOptions: number;
@@ -1,9 +1,19 @@
1
1
  export interface UsePaginationProps {
2
2
  /**
3
+ * **⚠️ Deprecation Notice ⚠️**
4
+ *
5
+ * _This field will be deprecated in v2._
6
+ * _If you're looking to change the number of items requested please use `staticRequestConfigs` instead._
7
+ *
3
8
  * Total number of results returned by the API response
4
9
  */
5
10
  totalNumResults: number;
6
11
  /**
12
+ * **⚠️ Deprecation Notice ⚠️**
13
+ *
14
+ * _This field will be deprecated in v2._
15
+ * _If you're looking to change the number of items requested please use `staticRequestConfigs` instead._
16
+ *
7
17
  * Number of results returned per page
8
18
  */
9
19
  resultsPerPage?: number;
@@ -28,7 +28,6 @@ export type { FiltersProps, FiltersWithRenderProps } from './components/Filters'
28
28
  export type { GroupsProps, GroupsWithRenderProps } from './components/Groups';
29
29
  export type { MobileModalProps } from './components/MobileModal';
30
30
  export type { PaginationProps, PaginationWithRenderProps } from './components/Pagination';
31
- export type { ProductCardProps } from './components/ProductCard';
32
31
  export type { ProductSwatchProps } from './components/ProductSwatch';
33
32
  export type { SortProps, SortWithRenderProps } from './components/Sort';
34
33
  export type { UseOptionsListProps } from './hooks/useOptionsList';