@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.
- package/dist/constructorio-ui-autocomplete-bundled.js +11 -11
- package/lib/cjs/hooks/useCioAutocomplete.js +9 -34
- package/lib/cjs/hooks/useDownShift.js +44 -45
- package/lib/cjs/hooks/useNormalizedProps.js +53 -0
- package/lib/cjs/hooks/useSections/index.js +38 -0
- package/lib/cjs/hooks/useSections/useActiveSections.js +25 -0
- package/lib/cjs/hooks/useSections/useActiveSectionsWithData.js +16 -0
- package/lib/cjs/hooks/useSections/useRemoveSections.js +24 -0
- package/lib/cjs/hooks/useSections/useSectionsResults.js +28 -0
- package/lib/cjs/utils.js +8 -4
- package/lib/cjs/version.js +1 -1
- package/lib/mjs/hooks/useCioAutocomplete.js +13 -35
- package/lib/mjs/hooks/useDownShift.js +2 -2
- package/lib/mjs/hooks/useNormalizedProps.js +50 -0
- package/lib/mjs/hooks/useSections/index.js +34 -0
- package/lib/mjs/hooks/useSections/useActiveSections.js +22 -0
- package/lib/mjs/hooks/useSections/useActiveSectionsWithData.js +13 -0
- package/lib/mjs/hooks/useSections/useRemoveSections.js +20 -0
- package/lib/mjs/hooks/useSections/useSectionsResults.js +24 -0
- package/lib/mjs/utils.js +8 -4
- package/lib/mjs/version.js +1 -1
- package/lib/types/hooks/useCioAutocomplete.d.ts +1 -2
- package/lib/types/hooks/useDownShift.d.ts +3 -5
- package/lib/types/hooks/useNormalizedProps.d.ts +9 -0
- package/lib/types/hooks/{useSections.d.ts → useSections/index.d.ts} +3 -3
- package/lib/types/hooks/useSections/useActiveSections.d.ts +6 -0
- package/lib/types/hooks/useSections/useActiveSectionsWithData.d.ts +3 -0
- package/lib/types/hooks/useSections/useRemoveSections.d.ts +2 -0
- package/lib/types/hooks/useSections/useSectionsResults.d.ts +15 -0
- package/lib/types/types.d.ts +6 -3
- package/lib/types/utils.d.ts +1 -1
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
- package/lib/cjs/hooks/useSections.js +0 -63
- 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
|
-
|
|
43
|
-
const
|
|
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,
|
|
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 (
|
|
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 = (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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,
|
|
147
|
+
const getActiveSectionsWithData = (activeSections, sectionsResults, sectionsRefs) => {
|
|
148
148
|
const activeSectionsWithData = [];
|
|
149
|
-
|
|
149
|
+
const getSectionData = (sectionConfig) => {
|
|
150
150
|
const { type } = sectionConfig;
|
|
151
151
|
let sectionData;
|
|
152
152
|
switch (type) {
|
|
153
153
|
case 'recommendations':
|
|
154
|
-
sectionData =
|
|
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 =
|
|
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.
|
package/lib/cjs/version.js
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
39
|
-
const
|
|
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({
|
|
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
|
|
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 = '',
|
|
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
|
-
|
|
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
|
+
}
|