@constructor-io/constructorio-ui-autocomplete 1.23.18 → 1.23.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/constructorio-ui-autocomplete-bundled.js +11 -11
  2. package/lib/cjs/hooks/useCioAutocomplete.js +9 -34
  3. package/lib/cjs/hooks/useDownShift.js +44 -45
  4. package/lib/cjs/hooks/useNormalizedProps.js +53 -0
  5. package/lib/cjs/hooks/useSections/index.js +38 -0
  6. package/lib/cjs/hooks/useSections/useActiveSections.js +25 -0
  7. package/lib/cjs/hooks/useSections/useActiveSectionsWithData.js +16 -0
  8. package/lib/cjs/hooks/useSections/useRemoveSections.js +24 -0
  9. package/lib/cjs/hooks/useSections/useSectionsResults.js +28 -0
  10. package/lib/cjs/utils.js +8 -4
  11. package/lib/cjs/version.js +1 -1
  12. package/lib/mjs/hooks/useCioAutocomplete.js +13 -35
  13. package/lib/mjs/hooks/useDownShift.js +2 -2
  14. package/lib/mjs/hooks/useNormalizedProps.js +50 -0
  15. package/lib/mjs/hooks/useSections/index.js +34 -0
  16. package/lib/mjs/hooks/useSections/useActiveSections.js +22 -0
  17. package/lib/mjs/hooks/useSections/useActiveSectionsWithData.js +13 -0
  18. package/lib/mjs/hooks/useSections/useRemoveSections.js +20 -0
  19. package/lib/mjs/hooks/useSections/useSectionsResults.js +24 -0
  20. package/lib/mjs/utils.js +8 -4
  21. package/lib/mjs/version.js +1 -1
  22. package/lib/types/hooks/useCioAutocomplete.d.ts +1 -2
  23. package/lib/types/hooks/useDownShift.d.ts +3 -5
  24. package/lib/types/hooks/useNormalizedProps.d.ts +9 -0
  25. package/lib/types/hooks/{useSections.d.ts → useSections/index.d.ts} +3 -3
  26. package/lib/types/hooks/useSections/useActiveSections.d.ts +6 -0
  27. package/lib/types/hooks/useSections/useActiveSectionsWithData.d.ts +3 -0
  28. package/lib/types/hooks/useSections/useRemoveSections.d.ts +2 -0
  29. package/lib/types/hooks/useSections/useSectionsResults.d.ts +15 -0
  30. package/lib/types/types.d.ts +6 -3
  31. package/lib/types/utils.d.ts +1 -1
  32. package/lib/types/version.d.ts +1 -1
  33. package/package.json +1 -1
  34. package/lib/cjs/hooks/useSections.js +0 -63
  35. package/lib/mjs/hooks/useSections.js +0 -58
@@ -12,6 +12,7 @@ const useConsoleErrors_1 = tslib_1.__importDefault(require("./useConsoleErrors")
12
12
  const useSections_1 = tslib_1.__importDefault(require("./useSections"));
13
13
  const useRecommendationsObserver_1 = tslib_1.__importDefault(require("./useRecommendationsObserver"));
14
14
  const typeGuards_1 = require("../typeGuards");
15
+ const useNormalizedProps_1 = tslib_1.__importDefault(require("./useNormalizedProps"));
15
16
  exports.defaultSections = [
16
17
  {
17
18
  indexSectionName: 'Search Suggestions',
@@ -22,39 +23,9 @@ exports.defaultSections = [
22
23
  type: 'autocomplete',
23
24
  },
24
25
  ];
25
- const convertLegacyParametersAndAddDefaults = (sections) => sections.map((config) => {
26
- if ((0, typeGuards_1.isRecommendationsSection)(config)) {
27
- if (config.identifier && !config.podId) {
28
- return Object.assign(Object.assign({}, config), { podId: config.identifier });
29
- }
30
- if (!config.indexSectionName) {
31
- return Object.assign(Object.assign({}, config), { indexSectionName: 'Products' });
32
- }
33
- }
34
- if ((0, typeGuards_1.isAutocompleteSection)(config)) {
35
- if (config.identifier && !config.indexSectionName) {
36
- return Object.assign(Object.assign({}, config), { indexSectionName: config.identifier });
37
- }
38
- }
39
- return config;
40
- });
41
26
  const useCioAutocomplete = (options) => {
42
- // eslint-disable-next-line react-hooks/exhaustive-deps
43
- const memoizedOptions = (0, react_1.useMemo)(() => options, [JSON.stringify(options)]);
44
- const { onSubmit, onChange, openOnFocus, apiKey, cioJsClient, cioJsClientOptions, placeholder = 'What can we help you find today?', autocompleteClassName = 'cio-autocomplete', advancedParameters, defaultInput, getSearchResultsUrl, onIsOpenChange, } = memoizedOptions;
45
- let { sections = exports.defaultSections, zeroStateSections } = memoizedOptions;
46
- sections = (0, react_1.useMemo)(() => {
47
- if (sections) {
48
- return convertLegacyParametersAndAddDefaults(sections);
49
- }
50
- return sections;
51
- }, [sections]);
52
- zeroStateSections = (0, react_1.useMemo)(() => {
53
- if (zeroStateSections) {
54
- return convertLegacyParametersAndAddDefaults(zeroStateSections);
55
- }
56
- return zeroStateSections;
57
- }, [zeroStateSections]);
27
+ const { sections, zeroStateSections, cioJsClientOptions, advancedParameters } = (0, useNormalizedProps_1.default)(options);
28
+ const { onSubmit, onChange, openOnFocus, apiKey, cioJsClient, placeholder = 'What can we help you find today?', autocompleteClassName = 'cio-autocomplete', defaultInput, getSearchResultsUrl } = options, rest = tslib_1.__rest(options, ["onSubmit", "onChange", "openOnFocus", "apiKey", "cioJsClient", "placeholder", "autocompleteClassName", "defaultInput", "getSearchResultsUrl"]);
58
29
  const [query, setQuery] = (0, react_1.useState)(defaultInput || '');
59
30
  const previousQuery = (0, usePrevious_1.default)(query);
60
31
  const cioClient = (0, useCioClient_1.default)({ apiKey, cioJsClient, cioJsClientOptions });
@@ -63,7 +34,11 @@ const useCioAutocomplete = (options) => {
63
34
  const features = (0, react_1.useMemo)(() => (0, utils_1.getFeatures)(request), [request]);
64
35
  // Get dropdown items array from active sections (autocomplete + recommendations + custom)
65
36
  const items = (0, react_1.useMemo)(() => (0, utils_1.getItemsForActiveSections)(activeSectionsWithData), [activeSectionsWithData]);
66
- const { isOpen, getMenuProps, getLabelProps, openMenu, closeMenu, highlightedIndex, getInputProps, getItemProps: getItemPropsDownShift, } = (0, useDownShift_1.default)({ setQuery, items, onSubmit, cioClient, previousQuery, onIsOpenChange });
37
+ const { isOpen, getMenuProps, getLabelProps, openMenu, closeMenu, highlightedIndex, getInputProps, getItemProps: getItemPropsDownShift, } = (0, useDownShift_1.default)(Object.assign({ setQuery,
38
+ items,
39
+ onSubmit,
40
+ cioClient,
41
+ previousQuery }, rest));
67
42
  // Log console errors
68
43
  (0, useConsoleErrors_1.default)(sections, activeSections);
69
44
  // Track recommendation view
@@ -108,7 +83,7 @@ const useCioAutocomplete = (options) => {
108
83
  openMenu();
109
84
  }
110
85
  try {
111
- if ((advancedParameters === null || advancedParameters === void 0 ? void 0 : advancedParameters.fetchZeroStateOnFocus) && (items === null || items === void 0 ? void 0 : items.length) === 0) {
86
+ if (advancedParameters === null || advancedParameters === void 0 ? void 0 : advancedParameters.fetchZeroStateOnFocus) {
112
87
  fetchRecommendationResults();
113
88
  }
114
89
  (_a = cioClient === null || cioClient === void 0 ? void 0 : cioClient.tracker) === null || _a === void 0 ? void 0 : _a.trackInputFocus();
@@ -1,55 +1,54 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
3
4
  const downshift_1 = require("downshift");
4
5
  const utils_1 = require("../utils");
5
6
  let idCounter = 0;
6
- const useDownShift = ({ setQuery, items, onSubmit, cioClient, previousQuery = '', onIsOpenChange, }) => (0, downshift_1.useCombobox)({
7
- id: `cio-autocomplete-${idCounter++}`,
8
- items,
9
- itemToString: (item) => (item === null || item === void 0 ? void 0 : item.value) || '',
10
- onSelectedItemChange({ selectedItem }) {
11
- var _a;
12
- if (selectedItem) {
13
- if (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.value) {
14
- if (onSubmit)
15
- onSubmit({ item: selectedItem, originalQuery: previousQuery });
16
- try {
17
- if ((selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.section) === 'Search Suggestions') {
18
- setQuery(selectedItem.value || '');
19
- (0, utils_1.trackSearchSubmit)(cioClient, selectedItem.value, {
20
- originalQuery: previousQuery,
21
- });
7
+ const useDownShift = (_a) => {
8
+ var { setQuery, items, onSubmit, cioClient, previousQuery = '' } = _a, rest = tslib_1.__rest(_a, ["setQuery", "items", "onSubmit", "cioClient", "previousQuery"]);
9
+ return (0, downshift_1.useCombobox)(Object.assign({ id: `cio-autocomplete-${idCounter++}`, // eslint-disable-line
10
+ items, itemToString: (item) => (item === null || item === void 0 ? void 0 : item.value) || '', onSelectedItemChange({ selectedItem }) {
11
+ var _a;
12
+ if (selectedItem) {
13
+ if (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.value) {
14
+ if (onSubmit)
15
+ onSubmit({ item: selectedItem, originalQuery: previousQuery });
16
+ try {
17
+ if ((selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.section) === 'Search Suggestions') {
18
+ setQuery(selectedItem.value || '');
19
+ (0, utils_1.trackSearchSubmit)(cioClient, selectedItem.value, {
20
+ originalQuery: previousQuery,
21
+ });
22
+ }
23
+ // Autocomplete Select tracking
24
+ // Recommendation Select tracking
25
+ if (selectedItem.podId && ((_a = selectedItem.data) === null || _a === void 0 ? void 0 : _a.id) && selectedItem.strategy) {
26
+ cioClient === null || cioClient === void 0 ? void 0 : cioClient.tracker.trackRecommendationClick({
27
+ itemName: selectedItem.value,
28
+ itemId: selectedItem.data.id,
29
+ variationId: selectedItem.data.variation_id,
30
+ podId: selectedItem.podId,
31
+ strategyId: selectedItem.strategy.id,
32
+ section: selectedItem.section,
33
+ resultId: selectedItem.result_id,
34
+ });
35
+ // Select tracking for all other Constructor sections:
36
+ // (ie: Search Suggestions, Products, Custom Cio sections, etc)
37
+ // This does not apply to custom user defined sections that aren't part of Constructor index
38
+ }
39
+ else if (selectedItem.result_id) {
40
+ cioClient === null || cioClient === void 0 ? void 0 : cioClient.tracker.trackAutocompleteSelect(selectedItem.value, {
41
+ originalQuery: previousQuery,
42
+ section: selectedItem.section,
43
+ });
44
+ }
22
45
  }
23
- // Autocomplete Select tracking
24
- // Recommendation Select tracking
25
- if (selectedItem.podId && ((_a = selectedItem.data) === null || _a === void 0 ? void 0 : _a.id) && selectedItem.strategy) {
26
- cioClient === null || cioClient === void 0 ? void 0 : cioClient.tracker.trackRecommendationClick({
27
- itemName: selectedItem.value,
28
- itemId: selectedItem.data.id,
29
- variationId: selectedItem.data.variation_id,
30
- podId: selectedItem.podId,
31
- strategyId: selectedItem.strategy.id,
32
- section: selectedItem.section,
33
- resultId: selectedItem.result_id,
34
- });
35
- // Select tracking for all other Constructor sections:
36
- // (ie: Search Suggestions, Products, Custom Cio sections, etc)
37
- // This does not apply to custom user defined sections that aren't part of Constructor index
46
+ catch (error) {
47
+ // eslint-disable-next-line no-console
48
+ console.log(error);
38
49
  }
39
- else if (selectedItem.result_id) {
40
- cioClient === null || cioClient === void 0 ? void 0 : cioClient.tracker.trackAutocompleteSelect(selectedItem.value, {
41
- originalQuery: previousQuery,
42
- section: selectedItem.section,
43
- });
44
- }
45
- }
46
- catch (error) {
47
- // eslint-disable-next-line no-console
48
- console.log(error);
49
50
  }
50
51
  }
51
- }
52
- },
53
- onIsOpenChange,
54
- });
52
+ } }, rest));
53
+ };
55
54
  exports.default = useDownShift;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultSections = void 0;
4
+ /* eslint-disable react-hooks/exhaustive-deps */
5
+ const react_1 = require("react");
6
+ const typeGuards_1 = require("../typeGuards");
7
+ exports.defaultSections = [
8
+ {
9
+ indexSectionName: 'Search Suggestions',
10
+ type: 'autocomplete',
11
+ },
12
+ {
13
+ indexSectionName: 'Products',
14
+ type: 'autocomplete',
15
+ },
16
+ ];
17
+ const convertLegacyParametersAndAddDefaults = (sections) => sections.map((config) => {
18
+ if ((0, typeGuards_1.isRecommendationsSection)(config)) {
19
+ if (config.identifier && !config.podId) {
20
+ return Object.assign(Object.assign({}, config), { podId: config.identifier });
21
+ }
22
+ if (!config.indexSectionName) {
23
+ return Object.assign(Object.assign({}, config), { indexSectionName: 'Products' });
24
+ }
25
+ }
26
+ if ((0, typeGuards_1.isAutocompleteSection)(config)) {
27
+ if (config.identifier && !config.indexSectionName) {
28
+ return Object.assign(Object.assign({}, config), { indexSectionName: config.identifier });
29
+ }
30
+ }
31
+ return config;
32
+ });
33
+ const normalizeSections = (sections) => {
34
+ if (sections) {
35
+ return convertLegacyParametersAndAddDefaults(sections);
36
+ }
37
+ return sections;
38
+ };
39
+ // Normalize and Memoize Objects to prevent infinite rerenders if users pass object literals to useCioAutocomplete
40
+ const useNormalizedProps = (options) => {
41
+ const { sections = exports.defaultSections, zeroStateSections, cioJsClientOptions, advancedParameters, } = options;
42
+ const sectionsMemoized = (0, react_1.useMemo)(() => normalizeSections(sections), [JSON.stringify(sections)]);
43
+ const zeroStateSectionsMemoized = (0, react_1.useMemo)(() => normalizeSections(zeroStateSections), [JSON.stringify(zeroStateSections)]);
44
+ const cioJsClientOptionsMemoized = (0, react_1.useMemo)(() => cioJsClientOptions, [JSON.stringify(cioJsClientOptions)]);
45
+ const advancedParametersMemoized = (0, react_1.useMemo)(() => advancedParameters, [JSON.stringify(advancedParameters)]);
46
+ return {
47
+ sections: sectionsMemoized,
48
+ zeroStateSections: zeroStateSectionsMemoized,
49
+ cioJsClientOptions: cioJsClientOptionsMemoized,
50
+ advancedParameters: advancedParametersMemoized,
51
+ };
52
+ };
53
+ exports.default = useNormalizedProps;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ /* eslint-disable max-params */
5
+ const react_1 = require("react");
6
+ const useActiveSections_1 = tslib_1.__importDefault(require("./useActiveSections"));
7
+ const useSectionsResults_1 = tslib_1.__importDefault(require("./useSectionsResults"));
8
+ const useActiveSectionsWithData_1 = tslib_1.__importDefault(require("./useActiveSectionsWithData"));
9
+ const useRemoveSections_1 = tslib_1.__importDefault(require("./useRemoveSections"));
10
+ function useSections(query, cioClient, sections, zeroStateSections, advancedParameters) {
11
+ const [podsData, setPodsData] = (0, react_1.useState)({});
12
+ // Get Active Sections defined by configuration object
13
+ const { activeSections, showZeroStateSections, setActiveSections } = (0, useActiveSections_1.default)(query, sections, podsData, zeroStateSections);
14
+ // create refs for active sections
15
+ const sectionsRefs = (0, react_1.useRef)(activeSections.map(() => (0, react_1.createRef)()));
16
+ // Get API results for each active section
17
+ const { recommendations, autocomplete } = (0, useSectionsResults_1.default)(query, cioClient, activeSections, advancedParameters);
18
+ // Access the Pods Data from the Recommendations response to update Active Sections configuration
19
+ (0, react_1.useEffect)(() => {
20
+ if (!recommendations.podsData) {
21
+ setPodsData(recommendations.podsData);
22
+ }
23
+ }, [recommendations.podsData]);
24
+ (0, useRemoveSections_1.default)(sections, podsData, setActiveSections, showZeroStateSections, zeroStateSections);
25
+ // Combine recommendations and autocomplete results in sectionsResults
26
+ const sectionsResults = (0, react_1.useMemo)(() => (Object.assign(Object.assign({}, autocomplete.results), recommendations.results)), [autocomplete.results, recommendations.results]);
27
+ // Return current active sections populated with data from the API response sectionsResults
28
+ const activeSectionsWithData = (0, useActiveSectionsWithData_1.default)(sectionsResults, activeSections, sectionsRefs, query);
29
+ return {
30
+ fetchRecommendationResults: recommendations.fetchRecommendationResults,
31
+ activeSections,
32
+ activeSectionsWithData,
33
+ zeroStateActiveSections: showZeroStateSections,
34
+ request: autocomplete.request,
35
+ totalNumResultsPerSection: autocomplete.totalNumResultsPerSection,
36
+ };
37
+ }
38
+ exports.default = useSections;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const react_1 = require("react");
4
+ const typeGuards_1 = require("../../typeGuards");
5
+ function useActiveSections(query, sections, podsData, zeroStateSections) {
6
+ const showZeroStateSections = !query.length && !!(zeroStateSections === null || zeroStateSections === void 0 ? void 0 : zeroStateSections.length);
7
+ const [activeSections, setActiveSections] = (0, react_1.useState)(showZeroStateSections ? zeroStateSections : sections);
8
+ // Merge Recommendation Pods Display Name from Dashboard
9
+ const activeSectionsTransformed = (0, react_1.useMemo)(() => activeSections.map((config) => {
10
+ const mergedConfig = config;
11
+ if ((0, typeGuards_1.isRecommendationsSection)(config)) {
12
+ const podData = podsData === null || podsData === void 0 ? void 0 : podsData[config.podId];
13
+ const libraryDisplayName = config.displayName;
14
+ const dashboardDisplayName = podData === null || podData === void 0 ? void 0 : podData.displayName;
15
+ mergedConfig.displayName = libraryDisplayName || dashboardDisplayName;
16
+ }
17
+ return mergedConfig;
18
+ }), [activeSections, podsData]);
19
+ return {
20
+ activeSections: activeSectionsTransformed,
21
+ showZeroStateSections,
22
+ setActiveSections,
23
+ };
24
+ }
25
+ exports.default = useActiveSections;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const react_1 = require("react");
4
+ const utils_1 = require("../../utils");
5
+ function useActiveSectionsWithData(sectionsResults, activeSections, sectionsRefs, query) {
6
+ const [activeSectionsWithData, setActiveSectionsWithData] = (0, react_1.useState)([]);
7
+ // Add to active sections the results data and refs when autocomplete results or recommendation results fetched
8
+ (0, react_1.useEffect)(() => {
9
+ const activeSectionsWithDataValue = (0, utils_1.getActiveSectionsWithData)(activeSections, sectionsResults, sectionsRefs);
10
+ if (activeSectionsWithDataValue.length || !query) {
11
+ setActiveSectionsWithData(activeSectionsWithDataValue);
12
+ }
13
+ }, [activeSections, sectionsResults, sectionsRefs, query]);
14
+ return activeSectionsWithData;
15
+ }
16
+ exports.default = useActiveSectionsWithData;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* eslint-disable max-params */
4
+ const react_1 = require("react");
5
+ const utils_1 = require("../../utils");
6
+ function useRemoveSections(sections, podsData, setActiveSections, showZeroStateSections, zeroStateSections) {
7
+ // Remove sections if necessary
8
+ (0, react_1.useEffect)(() => {
9
+ var _a, _b;
10
+ const features = (0, utils_1.getFeatures)((_b = (_a = Object.values(podsData || {})) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.request);
11
+ if (showZeroStateSections) {
12
+ if (!features.featureDisplayZeroStateRecommendations) {
13
+ setActiveSections([]);
14
+ }
15
+ else {
16
+ setActiveSections(zeroStateSections);
17
+ }
18
+ }
19
+ else {
20
+ setActiveSections(sections);
21
+ }
22
+ }, [zeroStateSections, showZeroStateSections, sections, podsData, setActiveSections]);
23
+ }
24
+ exports.default = useRemoveSections;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = require("react");
5
+ const useDebouncedFetchSections_1 = tslib_1.__importDefault(require("../useDebouncedFetchSections"));
6
+ const useFetchRecommendationPod_1 = tslib_1.__importDefault(require("../useFetchRecommendationPod"));
7
+ const typeGuards_1 = require("../../typeGuards");
8
+ function useSectionsResults(query, cioClient, activeSections, advancedParameters) {
9
+ // Fetch Autocomplete Results
10
+ const activeAutocompleteSections = (0, react_1.useMemo)(() => activeSections === null || activeSections === void 0 ? void 0 : activeSections.filter((config) => (0, typeGuards_1.isAutocompleteSection)(config)), [activeSections]);
11
+ const { sectionsData: autocompleteResults, request, totalNumResultsPerSection, } = (0, useDebouncedFetchSections_1.default)(query, cioClient, activeAutocompleteSections, advancedParameters);
12
+ // Fetch Recommendations Results
13
+ const activeRecommendationsSections = (0, react_1.useMemo)(() => activeSections === null || activeSections === void 0 ? void 0 : activeSections.filter((config) => (0, typeGuards_1.isRecommendationsSection)(config)), [activeSections]);
14
+ const { fetchRecommendationResults, recommendationsResults, podsData } = (0, useFetchRecommendationPod_1.default)(cioClient, activeRecommendationsSections, advancedParameters === null || advancedParameters === void 0 ? void 0 : advancedParameters.fetchZeroStateOnFocus);
15
+ return {
16
+ recommendations: {
17
+ results: recommendationsResults,
18
+ fetchRecommendationResults,
19
+ podsData,
20
+ },
21
+ autocomplete: {
22
+ results: autocompleteResults,
23
+ request,
24
+ totalNumResultsPerSection,
25
+ },
26
+ };
27
+ }
28
+ exports.default = useSectionsResults;
package/lib/cjs/utils.js CHANGED
@@ -144,14 +144,14 @@ const getCioClient = (apiKey, cioJsClientOptions) => {
144
144
  return null;
145
145
  };
146
146
  exports.getCioClient = getCioClient;
147
- const getActiveSectionsWithData = (activeSections, sectionResults, sectionsRefs) => {
147
+ const getActiveSectionsWithData = (activeSections, sectionsResults, sectionsRefs) => {
148
148
  const activeSectionsWithData = [];
149
- activeSections === null || activeSections === void 0 ? void 0 : activeSections.forEach((sectionConfig, index) => {
149
+ const getSectionData = (sectionConfig) => {
150
150
  const { type } = sectionConfig;
151
151
  let sectionData;
152
152
  switch (type) {
153
153
  case 'recommendations':
154
- sectionData = sectionResults[sectionConfig.podId];
154
+ sectionData = sectionsResults[sectionConfig.podId];
155
155
  break;
156
156
  case 'custom':
157
157
  // Copy id from data to the top level
@@ -162,8 +162,12 @@ const getActiveSectionsWithData = (activeSections, sectionResults, sectionsRefs)
162
162
  break;
163
163
  default:
164
164
  // Autocomplete
165
- sectionData = sectionResults[sectionConfig.indexSectionName];
165
+ sectionData = sectionsResults[sectionConfig.indexSectionName];
166
166
  }
167
+ return sectionData;
168
+ };
169
+ activeSections === null || activeSections === void 0 ? void 0 : activeSections.forEach((sectionConfig, index) => {
170
+ const sectionData = getSectionData(sectionConfig);
167
171
  if (Array.isArray(sectionData)) {
168
172
  const section = Object.assign(Object.assign({}, sectionConfig), { data: sectionData });
169
173
  // If ref passed as part of `SectionConfiguration`, use it.
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = '1.23.18';
3
+ exports.default = '1.23.20';
@@ -7,7 +7,8 @@ import { getItemPosition, getItemsForActiveSections, getFeatures, trackRecommend
7
7
  import useConsoleErrors from './useConsoleErrors';
8
8
  import useSections from './useSections';
9
9
  import useRecommendationsObserver from './useRecommendationsObserver';
10
- import { isAutocompleteSection, isCustomSection, isRecommendationsSection } from '../typeGuards';
10
+ import { isCustomSection, isRecommendationsSection } from '../typeGuards';
11
+ import useNormalizedProps from './useNormalizedProps';
11
12
  export const defaultSections = [
12
13
  {
13
14
  indexSectionName: 'Search Suggestions',
@@ -18,39 +19,9 @@ export const defaultSections = [
18
19
  type: 'autocomplete',
19
20
  },
20
21
  ];
21
- const convertLegacyParametersAndAddDefaults = (sections) => sections.map((config) => {
22
- if (isRecommendationsSection(config)) {
23
- if (config.identifier && !config.podId) {
24
- return { ...config, podId: config.identifier };
25
- }
26
- if (!config.indexSectionName) {
27
- return { ...config, indexSectionName: 'Products' };
28
- }
29
- }
30
- if (isAutocompleteSection(config)) {
31
- if (config.identifier && !config.indexSectionName) {
32
- return { ...config, indexSectionName: config.identifier };
33
- }
34
- }
35
- return config;
36
- });
37
22
  const useCioAutocomplete = (options) => {
38
- // eslint-disable-next-line react-hooks/exhaustive-deps
39
- const memoizedOptions = useMemo(() => options, [JSON.stringify(options)]);
40
- const { onSubmit, onChange, openOnFocus, apiKey, cioJsClient, cioJsClientOptions, placeholder = 'What can we help you find today?', autocompleteClassName = 'cio-autocomplete', advancedParameters, defaultInput, getSearchResultsUrl, onIsOpenChange, } = memoizedOptions;
41
- let { sections = defaultSections, zeroStateSections } = memoizedOptions;
42
- sections = useMemo(() => {
43
- if (sections) {
44
- return convertLegacyParametersAndAddDefaults(sections);
45
- }
46
- return sections;
47
- }, [sections]);
48
- zeroStateSections = useMemo(() => {
49
- if (zeroStateSections) {
50
- return convertLegacyParametersAndAddDefaults(zeroStateSections);
51
- }
52
- return zeroStateSections;
53
- }, [zeroStateSections]);
23
+ const { sections, zeroStateSections, cioJsClientOptions, advancedParameters } = useNormalizedProps(options);
24
+ const { onSubmit, onChange, openOnFocus, apiKey, cioJsClient, placeholder = 'What can we help you find today?', autocompleteClassName = 'cio-autocomplete', defaultInput, getSearchResultsUrl, ...rest } = options;
54
25
  const [query, setQuery] = useState(defaultInput || '');
55
26
  const previousQuery = usePrevious(query);
56
27
  const cioClient = useCioClient({ apiKey, cioJsClient, cioJsClientOptions });
@@ -59,7 +30,14 @@ const useCioAutocomplete = (options) => {
59
30
  const features = useMemo(() => getFeatures(request), [request]);
60
31
  // Get dropdown items array from active sections (autocomplete + recommendations + custom)
61
32
  const items = useMemo(() => getItemsForActiveSections(activeSectionsWithData), [activeSectionsWithData]);
62
- const { isOpen, getMenuProps, getLabelProps, openMenu, closeMenu, highlightedIndex, getInputProps, getItemProps: getItemPropsDownShift, } = useDownShift({ setQuery, items, onSubmit, cioClient, previousQuery, onIsOpenChange });
33
+ const { isOpen, getMenuProps, getLabelProps, openMenu, closeMenu, highlightedIndex, getInputProps, getItemProps: getItemPropsDownShift, } = useDownShift({
34
+ setQuery,
35
+ items,
36
+ onSubmit,
37
+ cioClient,
38
+ previousQuery,
39
+ ...rest,
40
+ });
63
41
  // Log console errors
64
42
  useConsoleErrors(sections, activeSections);
65
43
  // Track recommendation view
@@ -117,7 +95,7 @@ const useCioAutocomplete = (options) => {
117
95
  openMenu();
118
96
  }
119
97
  try {
120
- if (advancedParameters?.fetchZeroStateOnFocus && items?.length === 0) {
98
+ if (advancedParameters?.fetchZeroStateOnFocus) {
121
99
  fetchRecommendationResults();
122
100
  }
123
101
  cioClient?.tracker?.trackInputFocus();
@@ -1,7 +1,7 @@
1
1
  import { useCombobox } from 'downshift';
2
2
  import { trackSearchSubmit } from '../utils';
3
3
  let idCounter = 0;
4
- const useDownShift = ({ setQuery, items, onSubmit, cioClient, previousQuery = '', onIsOpenChange, }) => useCombobox({
4
+ const useDownShift = ({ setQuery, items, onSubmit, cioClient, previousQuery = '', ...rest }) => useCombobox({
5
5
  id: `cio-autocomplete-${idCounter++}`,
6
6
  items,
7
7
  itemToString: (item) => item?.value || '',
@@ -47,6 +47,6 @@ const useDownShift = ({ setQuery, items, onSubmit, cioClient, previousQuery = ''
47
47
  }
48
48
  }
49
49
  },
50
- onIsOpenChange,
50
+ ...rest,
51
51
  });
52
52
  export default useDownShift;
@@ -0,0 +1,50 @@
1
+ /* eslint-disable react-hooks/exhaustive-deps */
2
+ import { useMemo } from 'react';
3
+ import { isAutocompleteSection, isRecommendationsSection } from '../typeGuards';
4
+ export const defaultSections = [
5
+ {
6
+ indexSectionName: 'Search Suggestions',
7
+ type: 'autocomplete',
8
+ },
9
+ {
10
+ indexSectionName: 'Products',
11
+ type: 'autocomplete',
12
+ },
13
+ ];
14
+ const convertLegacyParametersAndAddDefaults = (sections) => sections.map((config) => {
15
+ if (isRecommendationsSection(config)) {
16
+ if (config.identifier && !config.podId) {
17
+ return { ...config, podId: config.identifier };
18
+ }
19
+ if (!config.indexSectionName) {
20
+ return { ...config, indexSectionName: 'Products' };
21
+ }
22
+ }
23
+ if (isAutocompleteSection(config)) {
24
+ if (config.identifier && !config.indexSectionName) {
25
+ return { ...config, indexSectionName: config.identifier };
26
+ }
27
+ }
28
+ return config;
29
+ });
30
+ const normalizeSections = (sections) => {
31
+ if (sections) {
32
+ return convertLegacyParametersAndAddDefaults(sections);
33
+ }
34
+ return sections;
35
+ };
36
+ // Normalize and Memoize Objects to prevent infinite rerenders if users pass object literals to useCioAutocomplete
37
+ const useNormalizedProps = (options) => {
38
+ const { sections = defaultSections, zeroStateSections, cioJsClientOptions, advancedParameters, } = options;
39
+ const sectionsMemoized = useMemo(() => normalizeSections(sections), [JSON.stringify(sections)]);
40
+ const zeroStateSectionsMemoized = useMemo(() => normalizeSections(zeroStateSections), [JSON.stringify(zeroStateSections)]);
41
+ const cioJsClientOptionsMemoized = useMemo(() => cioJsClientOptions, [JSON.stringify(cioJsClientOptions)]);
42
+ const advancedParametersMemoized = useMemo(() => advancedParameters, [JSON.stringify(advancedParameters)]);
43
+ return {
44
+ sections: sectionsMemoized,
45
+ zeroStateSections: zeroStateSectionsMemoized,
46
+ cioJsClientOptions: cioJsClientOptionsMemoized,
47
+ advancedParameters: advancedParametersMemoized,
48
+ };
49
+ };
50
+ export default useNormalizedProps;
@@ -0,0 +1,34 @@
1
+ /* eslint-disable max-params */
2
+ import { createRef, useEffect, useMemo, useRef, useState } from 'react';
3
+ import useActiveSections from './useActiveSections';
4
+ import useSectionsResults from './useSectionsResults';
5
+ import useActiveSectionsWithData from './useActiveSectionsWithData';
6
+ import useRemoveSections from './useRemoveSections';
7
+ export default function useSections(query, cioClient, sections, zeroStateSections, advancedParameters) {
8
+ const [podsData, setPodsData] = useState({});
9
+ // Get Active Sections defined by configuration object
10
+ const { activeSections, showZeroStateSections, setActiveSections } = useActiveSections(query, sections, podsData, zeroStateSections);
11
+ // create refs for active sections
12
+ const sectionsRefs = useRef(activeSections.map(() => createRef()));
13
+ // Get API results for each active section
14
+ const { recommendations, autocomplete } = useSectionsResults(query, cioClient, activeSections, advancedParameters);
15
+ // Access the Pods Data from the Recommendations response to update Active Sections configuration
16
+ useEffect(() => {
17
+ if (!recommendations.podsData) {
18
+ setPodsData(recommendations.podsData);
19
+ }
20
+ }, [recommendations.podsData]);
21
+ useRemoveSections(sections, podsData, setActiveSections, showZeroStateSections, zeroStateSections);
22
+ // Combine recommendations and autocomplete results in sectionsResults
23
+ const sectionsResults = useMemo(() => ({ ...autocomplete.results, ...recommendations.results }), [autocomplete.results, recommendations.results]);
24
+ // Return current active sections populated with data from the API response sectionsResults
25
+ const activeSectionsWithData = useActiveSectionsWithData(sectionsResults, activeSections, sectionsRefs, query);
26
+ return {
27
+ fetchRecommendationResults: recommendations.fetchRecommendationResults,
28
+ activeSections,
29
+ activeSectionsWithData,
30
+ zeroStateActiveSections: showZeroStateSections,
31
+ request: autocomplete.request,
32
+ totalNumResultsPerSection: autocomplete.totalNumResultsPerSection,
33
+ };
34
+ }
@@ -0,0 +1,22 @@
1
+ import { useMemo, useState } from 'react';
2
+ import { isRecommendationsSection } from '../../typeGuards';
3
+ export default function useActiveSections(query, sections, podsData, zeroStateSections) {
4
+ const showZeroStateSections = !query.length && !!zeroStateSections?.length;
5
+ const [activeSections, setActiveSections] = useState(showZeroStateSections ? zeroStateSections : sections);
6
+ // Merge Recommendation Pods Display Name from Dashboard
7
+ const activeSectionsTransformed = useMemo(() => activeSections.map((config) => {
8
+ const mergedConfig = config;
9
+ if (isRecommendationsSection(config)) {
10
+ const podData = podsData?.[config.podId];
11
+ const libraryDisplayName = config.displayName;
12
+ const dashboardDisplayName = podData?.displayName;
13
+ mergedConfig.displayName = libraryDisplayName || dashboardDisplayName;
14
+ }
15
+ return mergedConfig;
16
+ }), [activeSections, podsData]);
17
+ return {
18
+ activeSections: activeSectionsTransformed,
19
+ showZeroStateSections,
20
+ setActiveSections,
21
+ };
22
+ }
@@ -0,0 +1,13 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { getActiveSectionsWithData } from '../../utils';
3
+ export default function useActiveSectionsWithData(sectionsResults, activeSections, sectionsRefs, query) {
4
+ const [activeSectionsWithData, setActiveSectionsWithData] = useState([]);
5
+ // Add to active sections the results data and refs when autocomplete results or recommendation results fetched
6
+ useEffect(() => {
7
+ const activeSectionsWithDataValue = getActiveSectionsWithData(activeSections, sectionsResults, sectionsRefs);
8
+ if (activeSectionsWithDataValue.length || !query) {
9
+ setActiveSectionsWithData(activeSectionsWithDataValue);
10
+ }
11
+ }, [activeSections, sectionsResults, sectionsRefs, query]);
12
+ return activeSectionsWithData;
13
+ }
@@ -0,0 +1,20 @@
1
+ /* eslint-disable max-params */
2
+ import { useEffect } from 'react';
3
+ import { getFeatures } from '../../utils';
4
+ export default function useRemoveSections(sections, podsData, setActiveSections, showZeroStateSections, zeroStateSections) {
5
+ // Remove sections if necessary
6
+ useEffect(() => {
7
+ const features = getFeatures(Object.values(podsData || {})?.[0]?.request);
8
+ if (showZeroStateSections) {
9
+ if (!features.featureDisplayZeroStateRecommendations) {
10
+ setActiveSections([]);
11
+ }
12
+ else {
13
+ setActiveSections(zeroStateSections);
14
+ }
15
+ }
16
+ else {
17
+ setActiveSections(sections);
18
+ }
19
+ }, [zeroStateSections, showZeroStateSections, sections, podsData, setActiveSections]);
20
+ }