@constructor-io/constructorio-ui-autocomplete 1.8.4 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,22 +5,32 @@ const react_1 = tslib_1.__importStar(require("react"));
5
5
  const CioAutocompleteProvider_1 = require("../CioAutocompleteProvider");
6
6
  const typeGuards_1 = require("../../../typeGuards");
7
7
  function SectionItem(props) {
8
- var _a;
8
+ var _a, _b, _c, _d, _e;
9
9
  const { item, children } = props;
10
- const { getItemProps } = (0, react_1.useContext)(CioAutocompleteProvider_1.CioAutocompleteContext);
10
+ const { getItemProps, advancedParameters } = (0, react_1.useContext)(CioAutocompleteProvider_1.CioAutocompleteContext);
11
+ const { displaySearchSuggestionImages, displaySearchSuggestionResultCounts } = advancedParameters || {};
11
12
  let defaultChildren;
12
13
  if ((0, typeGuards_1.isProduct)(item)) {
13
14
  defaultChildren = (react_1.default.createElement(react_1.default.Fragment, null,
14
- react_1.default.createElement("img", { "data-testid": 'cio-img', src: (_a = item.data) === null || _a === void 0 ? void 0 : _a.image_url, alt: item.value }),
15
- react_1.default.createElement("p", { "data-testid": 'cio-text' }, item.value)));
15
+ react_1.default.createElement("img", { "data-testid": 'cio-img', src: (_a = item.data) === null || _a === void 0 ? void 0 : _a.image_url, alt: item.value, className: 'cio-product-image' }),
16
+ react_1.default.createElement("p", { "data-testid": 'cio-text', className: 'cio-product-text' }, item.value)));
16
17
  }
17
18
  else if ((0, typeGuards_1.isInGroupSuggestion)(item)) {
18
19
  defaultChildren = react_1.default.createElement("p", { className: 'cio-term-in-group' },
19
20
  "in ",
20
21
  item.groupName);
21
22
  }
23
+ else if ((0, typeGuards_1.isSearchSuggestion)(item)) {
24
+ defaultChildren = (react_1.default.createElement(react_1.default.Fragment, null,
25
+ displaySearchSuggestionImages && ((_b = item.data) === null || _b === void 0 ? void 0 : _b.image_url) && (react_1.default.createElement("img", { src: (_c = item.data) === null || _c === void 0 ? void 0 : _c.image_url, alt: item.value, className: 'cio-suggestion-image' })),
26
+ react_1.default.createElement("p", { className: 'cio-suggestion-text' }, item.value),
27
+ displaySearchSuggestionResultCounts && ((_d = item.data) === null || _d === void 0 ? void 0 : _d.total_num_results) && (react_1.default.createElement("p", { className: 'cio-suggestion-count' },
28
+ "(", (_e = item.data) === null || _e === void 0 ? void 0 :
29
+ _e.total_num_results,
30
+ ")"))));
31
+ }
22
32
  else {
23
- defaultChildren = react_1.default.createElement("p", null, item.value);
33
+ defaultChildren = react_1.default.createElement("p", { className: 'cio-custom-text' }, item.value);
24
34
  }
25
35
  return react_1.default.createElement("li", Object.assign({}, getItemProps(item)), children || defaultChildren);
26
36
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.filteredSuggestionsDescription = exports.termsWithGroupSuggestionsDescription = exports.advancedParametersDefaultDescription = exports.advancedParametersDescription = exports.customStylesDescription = exports.multipleSectionsDescription = exports.openOnFocusDescription = exports.zeroStateSectionsDescription = exports.onSubmitDefault = exports.onSubmitDescription = exports.onChangeDescription = exports.onFocusDescription = exports.customSectionDescription = exports.recommendationsDescription = exports.sectionOrderDescription = exports.numResultsDescription = exports.contentDescription = exports.productsDescription = exports.searchSuggestionsDescription = exports.placeholderDescription = exports.cioJsClientDescription = exports.apiKeyDescription = exports.zeroStateDescription = exports.userEventsDescription = exports.sectionsDescription = exports.hookDescription = exports.componentDescription = exports.apiKey = void 0;
3
+ exports.termsWithImagesAndCountsDescription = exports.filteredSuggestionsDescription = exports.termsWithGroupSuggestionsDescription = exports.advancedParametersDefaultDescription = exports.advancedParametersDescription = exports.customStylesDescription = exports.multipleSectionsDescription = exports.openOnFocusDescription = exports.zeroStateSectionsDescription = exports.onSubmitDefault = exports.onSubmitDescription = exports.onChangeDescription = exports.onFocusDescription = exports.customSectionDescription = exports.recommendationsDescription = exports.sectionOrderDescription = exports.numResultsDescription = exports.contentDescription = exports.productsDescription = exports.searchSuggestionsDescription = exports.placeholderDescription = exports.cioJsClientDescription = exports.apiKeyDescription = exports.zeroStateDescription = exports.userEventsDescription = exports.sectionsDescription = exports.hookDescription = exports.componentDescription = exports.apiKey = void 0;
4
4
  // Autocomplete key index
5
5
  exports.apiKey = 'key_M57QS8SMPdLdLx4x';
6
6
  /// //////////////////////////////
@@ -208,3 +208,4 @@ To see this in action:
208
208
  4. Next, type "short" in the example autocomplete input field.
209
209
  - Notice how the user is presented with only short sleeved items as results.
210
210
  - This is because we are filtering to the "Shirts" group`;
211
+ exports.termsWithImagesAndCountsDescription = `Pass boolean flags for \`displaySearchSuggestionImages\` and \`displaySearchSuggestionResultCounts\` fields to display images and counts for search suggestions. These fields need to be made displayable before they can be used. Please contact your Constructor Integration Engineer for details.`;
@@ -109,6 +109,7 @@ const useCioAutocomplete = (options) => {
109
109
  cioClient,
110
110
  autocompleteClassName,
111
111
  selectedItem: items[highlightedIndex],
112
+ advancedParameters,
112
113
  };
113
114
  };
114
115
  exports.default = useCioAutocomplete;
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isCustomSection = exports.isInGroupSuggestion = exports.isProduct = void 0;
3
+ exports.isCustomSection = exports.isInGroupSuggestion = exports.isSearchSuggestion = exports.isProduct = void 0;
4
4
  function isProduct(item) {
5
- var _a;
6
- return ((_a = item.data) === null || _a === void 0 ? void 0 : _a.image_url) !== undefined;
5
+ return item.section === 'Products';
7
6
  }
8
7
  exports.isProduct = isProduct;
8
+ function isSearchSuggestion(item) {
9
+ return item.section === 'Search Suggestions';
10
+ }
11
+ exports.isSearchSuggestion = isSearchSuggestion;
9
12
  function isInGroupSuggestion(item) {
10
13
  return item.groupName !== undefined;
11
14
  }
package/lib/cjs/utils.js CHANGED
@@ -100,7 +100,11 @@ const getActiveSectionsWithData = (activeSections, sectionResults) => {
100
100
  const { identifier } = config;
101
101
  let data;
102
102
  if ((0, typeGuards_1.isCustomSection)(config)) {
103
- data = config.data;
103
+ // Copy id from data to the top level
104
+ data = config.data.map((item) => {
105
+ var _a;
106
+ return (Object.assign(Object.assign({}, item), { id: (item === null || item === void 0 ? void 0 : item.id) || ((_a = item === null || item === void 0 ? void 0 : item.data) === null || _a === void 0 ? void 0 : _a.id) }));
107
+ });
104
108
  }
105
109
  else {
106
110
  data = sectionResults[identifier];
@@ -1,22 +1,32 @@
1
1
  import React, { useContext } from 'react';
2
2
  import { CioAutocompleteContext } from '../CioAutocompleteProvider';
3
- import { isProduct, isInGroupSuggestion } from '../../../typeGuards';
3
+ import { isProduct, isInGroupSuggestion, isSearchSuggestion } from '../../../typeGuards';
4
4
  export default function SectionItem(props) {
5
5
  const { item, children } = props;
6
- const { getItemProps } = useContext(CioAutocompleteContext);
6
+ const { getItemProps, advancedParameters } = useContext(CioAutocompleteContext);
7
+ const { displaySearchSuggestionImages, displaySearchSuggestionResultCounts } = advancedParameters || {};
7
8
  let defaultChildren;
8
9
  if (isProduct(item)) {
9
10
  defaultChildren = (React.createElement(React.Fragment, null,
10
- React.createElement("img", { "data-testid": 'cio-img', src: item.data?.image_url, alt: item.value }),
11
- React.createElement("p", { "data-testid": 'cio-text' }, item.value)));
11
+ React.createElement("img", { "data-testid": 'cio-img', src: item.data?.image_url, alt: item.value, className: 'cio-product-image' }),
12
+ React.createElement("p", { "data-testid": 'cio-text', className: 'cio-product-text' }, item.value)));
12
13
  }
13
14
  else if (isInGroupSuggestion(item)) {
14
15
  defaultChildren = React.createElement("p", { className: 'cio-term-in-group' },
15
16
  "in ",
16
17
  item.groupName);
17
18
  }
19
+ else if (isSearchSuggestion(item)) {
20
+ defaultChildren = (React.createElement(React.Fragment, null,
21
+ displaySearchSuggestionImages && item.data?.image_url && (React.createElement("img", { src: item.data?.image_url, alt: item.value, className: 'cio-suggestion-image' })),
22
+ React.createElement("p", { className: 'cio-suggestion-text' }, item.value),
23
+ displaySearchSuggestionResultCounts && item.data?.total_num_results && (React.createElement("p", { className: 'cio-suggestion-count' },
24
+ "(",
25
+ item.data?.total_num_results,
26
+ ")"))));
27
+ }
18
28
  else {
19
- defaultChildren = React.createElement("p", null, item.value);
29
+ defaultChildren = React.createElement("p", { className: 'cio-custom-text' }, item.value);
20
30
  }
21
31
  return React.createElement("li", { ...getItemProps(item) }, children || defaultChildren);
22
32
  }
@@ -204,3 +204,4 @@ To see this in action:
204
204
  4. Next, type "short" in the example autocomplete input field.
205
205
  - Notice how the user is presented with only short sleeved items as results.
206
206
  - This is because we are filtering to the "Shirts" group`;
207
+ export const termsWithImagesAndCountsDescription = `Pass boolean flags for \`displaySearchSuggestionImages\` and \`displaySearchSuggestionResultCounts\` fields to display images and counts for search suggestions. These fields need to be made displayable before they can be used. Please contact your Constructor Integration Engineer for details.`;
@@ -120,6 +120,7 @@ const useCioAutocomplete = (options) => {
120
120
  cioClient,
121
121
  autocompleteClassName,
122
122
  selectedItem: items[highlightedIndex],
123
+ advancedParameters,
123
124
  };
124
125
  };
125
126
  export default useCioAutocomplete;
@@ -1,5 +1,8 @@
1
1
  export function isProduct(item) {
2
- return item.data?.image_url !== undefined;
2
+ return item.section === 'Products';
3
+ }
4
+ export function isSearchSuggestion(item) {
5
+ return item.section === 'Search Suggestions';
3
6
  }
4
7
  export function isInGroupSuggestion(item) {
5
8
  return item.groupName !== undefined;
package/lib/mjs/utils.js CHANGED
@@ -84,7 +84,11 @@ export const getActiveSectionsWithData = (activeSections, sectionResults) => {
84
84
  const { identifier } = config;
85
85
  let data;
86
86
  if (isCustomSection(config)) {
87
- data = config.data;
87
+ // Copy id from data to the top level
88
+ data = config.data.map((item) => ({
89
+ ...item,
90
+ id: item?.id || item?.data?.id,
91
+ }));
88
92
  }
89
93
  else {
90
94
  data = sectionResults[identifier];
package/lib/styles.css CHANGED
@@ -70,9 +70,11 @@
70
70
  padding: 0;
71
71
  }
72
72
 
73
- .cio-autocomplete .cio-item-SearchSuggestions {
74
- flex-direction: column;
73
+ .cio-autocomplete .cio-item.cio-item-SearchSuggestions {
74
+ flex-direction: row;
75
75
  min-width: 160px;
76
+ justify-content: space-between;
77
+ align-items: center;
76
78
  }
77
79
 
78
80
  .cio-autocomplete .cio-item {
@@ -103,12 +105,12 @@
103
105
  padding: 5px 0;
104
106
  }
105
107
 
106
- .cio-autocomplete .cio-item p {
108
+ .cio-autocomplete .cio-item .cio-product-text {
107
109
  margin: 0;
108
110
  overflow: hidden;
109
111
  }
110
112
 
111
- .cio-autocomplete .cio-item img {
113
+ .cio-autocomplete .cio-item .cio-product-image {
112
114
  width: 100%;
113
115
  max-width: 100px;
114
116
  max-height: 100px;
@@ -117,3 +119,19 @@
117
119
  .cio-autocomplete .cio-term-in-group {
118
120
  padding-left: 10px;
119
121
  }
122
+
123
+ .cio-autocomplete .cio-suggestion-image {
124
+ height: 32px;
125
+ width: 32px;
126
+ margin-right: 8px;
127
+ object-fit: contain;
128
+ }
129
+
130
+ .cio-autocomplete .cio-suggestion-text {
131
+ flex-grow: 1;
132
+ }
133
+
134
+ .cio-autocomplete .cio-suggestion-count {
135
+ font-size: 0.8rem;
136
+ margin-left: 8px;
137
+ }
@@ -21,5 +21,6 @@ export declare const CioAutocompleteContext: React.Context<{
21
21
  cioClient: import("@constructor-io/constructorio-client-javascript/lib/types").Nullable<import("@constructor-io/constructorio-client-javascript")>;
22
22
  autocompleteClassName: string;
23
23
  selectedItem: import("../../types").Item;
24
+ advancedParameters: import("../../types").AdvancedParameters | undefined;
24
25
  }>;
25
26
  export default function CioAutocompleteProvider(props: CioAutocompleteProps): JSX.Element;
@@ -27,3 +27,4 @@ export declare const advancedParametersDescription = "The stories below show how
27
27
  export declare const advancedParametersDefaultDescription = "Passing an `advancedParameters` object is optional. Passing an empty object for the `advancedParameters` field behaves the same as not passing an `advancedParameters` object at all.";
28
28
  export declare const termsWithGroupSuggestionsDescription = "Pass integers for the `numTermsWithGroupSuggestions` and `numGroupsSuggestedPerTerm` fields to add suggested group filters to search term suggestions. Not all suggested search terms will have group filters, so these integers are upper limits, used to specify the maximum number of terms with group filters and the maximum number of suggested group filters per term.\n\nTo see this in action:\n1. Type \"pan\" in the example below.\n - Notice how the user is presented with a search term of \"all week flex pant\" as well as \"all week flex pant in Chinos\" and \"all week flex pant baby in Athleisure Pants & Joggers\"\n2. Navigate to the \"Terms With Group Suggestions\" story (using the navigation menu to the left)\n3. Then use the Controls to adjust the values of `numTermsWithGroupSuggestions` to `3` and `numGroupsSuggestedPerTerm` to `1`\n4. Next, type \"pan\" in the example autocomplete input field.\n - Notice how the user is presented with three different search terms that have a maximum of one \"in {group}\" suggestion each";
29
29
  export declare const filteredSuggestionsDescription = "Pass a `filters` object under `advancedParameters` to apply filters to the suggestions. Any parameter supported by <a href=\"https://docs.constructor.io/rest_api/autocomplete_queries/\" target=\"__blank\">our autocomplete endpoint</a> can be passed under `advancedParameters`.\n\nTo see this in action:\n1. Type \"short\" in the example below.\n - Notice how the user is presented with only short pants as results.\n - This is because the results are currently filtered to belong to the \"Shorts\" group.\n2. Navigate to the \"Filtered Suggestions\" story (using the navigation menu to the left)\n3. Then use the Controls to adjust the values of `\"group_id\"` to `\"1030\"`.\n4. Next, type \"short\" in the example autocomplete input field.\n - Notice how the user is presented with only short sleeved items as results.\n - This is because we are filtering to the \"Shirts\" group";
30
+ export declare const termsWithImagesAndCountsDescription = "Pass boolean flags for `displaySearchSuggestionImages` and `displaySearchSuggestionResultCounts` fields to display images and counts for search suggestions. These fields need to be made displayable before they can be used. Please contact your Constructor Integration Engineer for details.";
@@ -22,5 +22,6 @@ declare const useCioAutocomplete: (options: UseCioAutocompleteOptions) => {
22
22
  cioClient: import("@constructor-io/constructorio-client-javascript/lib/types").Nullable<import("@constructor-io/constructorio-client-javascript")>;
23
23
  autocompleteClassName: string;
24
24
  selectedItem: import("../types").Item;
25
+ advancedParameters: import("../types").AdvancedParameters | undefined;
25
26
  };
26
27
  export default useCioAutocomplete;
@@ -1,4 +1,5 @@
1
- import { CustomSection, InGroupSuggestion, Item, Product, UserDefinedSection } from './types';
1
+ import { CustomSection, InGroupSuggestion, Item, Product, UserDefinedSection, SearchSuggestion } from './types';
2
2
  export declare function isProduct(item: Item): item is Product;
3
+ export declare function isSearchSuggestion(item: Item): item is SearchSuggestion;
3
4
  export declare function isInGroupSuggestion(item: Item): item is InGroupSuggestion;
4
5
  export declare function isCustomSection(config: UserDefinedSection): config is CustomSection;
@@ -1,7 +1,8 @@
1
1
  import { GetItemPropsOptions } from 'downshift';
2
2
  import { ReactNode } from 'react';
3
3
  import ConstructorIOClient from '@constructor-io/constructorio-client-javascript';
4
- import { IAutocompleteParameters } from '@constructor-io/constructorio-client-javascript/lib/types';
4
+ import { IAutocompleteParameters, SearchSuggestion as SearchSuggestionFromClient, Product as ProductFromClient, Item as ItemBase } from '@constructor-io/constructorio-client-javascript/lib/types';
5
+ export type { IAutocompleteParameters } from '@constructor-io/constructorio-client-javascript/lib/types';
5
6
  export type CioClientConfig = {
6
7
  apiKey?: string;
7
8
  cioJsClient?: ConstructorIOClient;
@@ -9,6 +10,8 @@ export type CioClientConfig = {
9
10
  export interface AdvancedParametersBase {
10
11
  numTermsWithGroupSuggestions?: number;
11
12
  numGroupsSuggestedPerTerm?: number;
13
+ displaySearchSuggestionImages?: boolean;
14
+ displaySearchSuggestionResultCounts?: boolean;
12
15
  }
13
16
  export type AdvancedParameters = AdvancedParametersBase & Omit<IAutocompleteParameters, 'resultsPerSection'>;
14
17
  export type CioAutocompleteProps = CioClientConfig & {
@@ -37,13 +40,6 @@ export type ItemPropsOptions = DownshiftGetItemPropsOptions & {
37
40
  indexOffset?: number;
38
41
  };
39
42
  export type GetItemProps = (options: ItemPropsOptions) => object;
40
- export interface ItemBase extends Record<string, any> {
41
- id: string;
42
- section: string;
43
- url?: string;
44
- value?: string;
45
- data?: Record<string, any>;
46
- }
47
43
  export type Item = Product | SearchSuggestion | InGroupSuggestion | ItemBase;
48
44
  export type GetAutocompleteResultsOptions = {
49
45
  [sectionIdentifier: string]: {
@@ -78,37 +74,13 @@ export interface CustomSection extends SectionConfiguration {
78
74
  }
79
75
  export type Section = AutocompleteSection | RecommendationsSection | CustomSection;
80
76
  export type UserDefinedSection = CustomSection | SectionConfiguration;
81
- export type Product = ItemBase & {
77
+ export type Product = ProductFromClient & {
82
78
  section: 'Products';
83
- data: {
84
- facets: {
85
- name: string;
86
- values: string[];
87
- }[];
88
- group_ids: string[];
89
- id: string;
90
- image_url: string;
91
- url: string;
92
- variation_id?: string;
93
- };
94
- is_slotted: boolean;
95
- labels: Record<string, unknown>;
96
- matched_terms: string[];
97
- value: string;
98
79
  };
99
- export type SearchSuggestion = ItemBase & {
80
+ export type SearchSuggestion = SearchSuggestionFromClient & {
100
81
  section: 'Search Suggestions';
101
- data: {
102
- id: string;
103
- url?: string;
104
- };
105
- is_slotted: boolean;
106
- labels: Record<string, unknown>;
107
- matched_terms: string[];
108
- value: string;
109
82
  };
110
83
  export type InGroupSuggestion = SearchSuggestion & {
111
84
  groupId: string;
112
85
  groupName: string;
113
86
  };
114
- export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructor-io/constructorio-ui-autocomplete",
3
- "version": "1.8.4",
3
+ "version": "1.9.0",
4
4
  "description": "Constructor.io Autocomplete UI library for web applications",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",