@usereactify/search 4.1.0-beta.3 → 4.1.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.
@@ -30,7 +30,7 @@ const Filter = (props) => {
30
30
  if ("multi" === filter.displayType) {
31
31
  return (react_1.default.createElement(MultiList_1.default, Object.assign({ showCheckbox: false }, reactiveFilterListProps, { render: (reactivesearchFilterProps) => (react_1.default.createElement(FilterListInner, Object.assign({}, props, { reactivesearchFilterProps: reactivesearchFilterProps }))) })));
32
32
  }
33
- console.error(`filter with display type "${filter.displayType}" not yet supported`);
33
+ console.log(`filter with display type "${filter.displayType}" not yet supported`);
34
34
  return null;
35
35
  };
36
36
  exports.Filter = Filter;
@@ -7,7 +7,7 @@ exports.useReactiveFilterListProps = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
8
  const useReactiveReactProp_1 = require("./useReactiveReactProp");
9
9
  const useReactiveFilterListProps = (filter) => {
10
- const reactiveReactProp = (0, useReactiveReactProp_1.useReactiveReactProp)(filter.id);
10
+ const reactiveReactProp = (0, useReactiveReactProp_1.useReactiveReactProp)(filter.handle);
11
11
  const nestedField = react_1.default.useMemo(() => {
12
12
  const nestedFields = ["variants"];
13
13
  const topField = filter.field.split(".")[0];
@@ -93,7 +93,7 @@ const useReactiveFilterListProps = (filter) => {
93
93
  customQuery,
94
94
  defaultQuery,
95
95
  URLParams: true,
96
- componentId: filter.id,
96
+ componentId: filter.handle,
97
97
  dataField: filter.field,
98
98
  filterLabel: filter.name,
99
99
  react: reactiveReactProp,
@@ -1,3 +1,3 @@
1
- export declare const useReactiveReactProp: (currentId?: string | undefined) => {
1
+ export declare const useReactiveReactProp: (currentHandle?: string | undefined) => {
2
2
  and: string[];
3
3
  };
@@ -8,18 +8,18 @@ const react_1 = __importDefault(require("react"));
8
8
  const sensor_1 = require("../../sensor");
9
9
  const useFilters_1 = require("../useFilters");
10
10
  const provider_1 = require("../../provider");
11
- const useReactiveReactProp = (currentId) => {
11
+ const useReactiveReactProp = (currentHandle) => {
12
12
  const filters = (0, useFilters_1.useFilters)();
13
- const { additionalComponentIds } = (0, provider_1.useContext)();
13
+ const { additionalComponentHandles } = (0, provider_1.useContext)();
14
14
  return react_1.default.useMemo(() => {
15
15
  return {
16
16
  and: [
17
17
  "SearchInput",
18
18
  ...sensor_1.SENSOR_IDS,
19
- ...(additionalComponentIds !== null && additionalComponentIds !== void 0 ? additionalComponentIds : []),
20
- ...filters.map((filter) => filter.id),
21
- ].filter((id) => id !== currentId),
19
+ ...(additionalComponentHandles !== null && additionalComponentHandles !== void 0 ? additionalComponentHandles : []),
20
+ ...filters.map((filter) => filter.handle),
21
+ ].filter((handle) => handle !== currentHandle),
22
22
  };
23
- }, [filters, currentId]);
23
+ }, [filters, currentHandle]);
24
24
  };
25
25
  exports.useReactiveReactProp = useReactiveReactProp;
@@ -1,4 +1,4 @@
1
1
  import { Config } from "../types/config";
2
- export declare const useLiveConfig: (shopifyPermanentDomain: string) => {
2
+ export declare const useLiveConfig: (shopifyPermanentDomain: string, configId?: string | undefined) => {
3
3
  config: Config | undefined;
4
4
  };
@@ -41,7 +41,7 @@ function getCachedConfig() {
41
41
  }
42
42
  return;
43
43
  }
44
- const useLiveConfig = (shopifyPermanentDomain) => {
44
+ const useLiveConfig = (shopifyPermanentDomain, configId) => {
45
45
  const [config, setConfig] = react_1.default.useState(getCachedConfig());
46
46
  react_1.default.useEffect(() => {
47
47
  const cachedConfig = getCachedConfig();
@@ -49,14 +49,19 @@ const useLiveConfig = (shopifyPermanentDomain) => {
49
49
  return;
50
50
  (() => __awaiter(void 0, void 0, void 0, function* () {
51
51
  debug("fetching fresh config");
52
- const json = yield fetch(`https://config.search.reactify.app/?shop=${shopifyPermanentDomain}`).then((response) => response.json());
52
+ const searchParams = new URLSearchParams();
53
+ searchParams.set("shop", shopifyPermanentDomain);
54
+ if (configId) {
55
+ searchParams.set("id", configId);
56
+ }
57
+ const json = yield fetch(`https://config.search.reactify.app/?${searchParams.toString()}`).then((response) => response.json());
53
58
  setConfig(json.body);
54
59
  window.sessionStorage.setItem("reactify-search:config", JSON.stringify({
55
60
  expiresAt: new Date().getTime() + CACHE_EXPIRY,
56
61
  config: json.body,
57
62
  }));
58
63
  }))();
59
- }, [shopifyPermanentDomain]);
64
+ }, [shopifyPermanentDomain, configId]);
60
65
  return {
61
66
  config,
62
67
  };
@@ -1,5 +1,5 @@
1
1
  export declare const useSort: () => {
2
2
  sortOption: import("..").ConfigSort | undefined;
3
3
  sortOptions: import("..").ConfigSort[];
4
- setSortOption: (sortOptionId: string) => void;
4
+ setSortOption: (sortOptionHandle: string) => void;
5
5
  };
@@ -10,12 +10,12 @@ const hooks_1 = require("../hooks");
10
10
  const useSort = () => {
11
11
  const { track } = (0, hooks_1.useAnalytics)();
12
12
  const { sortOption, sortOptions, setSortOption } = (0, provider_1.useContext)();
13
- const handleSortChange = react_1.default.useCallback((sortOptionId) => {
14
- setSortOption(sortOptionId);
13
+ const handleSortChange = react_1.default.useCallback((sortOptionHandle) => {
14
+ setSortOption(sortOptionHandle);
15
15
  track({
16
16
  eventName: "sortChange",
17
17
  payload: {
18
- type: sortOptionId,
18
+ type: sortOptionHandle,
19
19
  },
20
20
  });
21
21
  }, [track, setSortOption]);
@@ -14,19 +14,20 @@ declare type Context = {
14
14
  onRedirect?: (type: "redirect" | "search", url: string) => void;
15
15
  submitSearch: (localSearchQuery?: string) => void;
16
16
  setSearchQuery: (searchQuery: string) => void;
17
- setSortOption: (sortOptionId: string) => void;
17
+ setSortOption: (sortOptionHandle: string) => void;
18
18
  showInstantSearchResults: boolean;
19
19
  setShowInstantSearchResults: (showInstantSearchResults: boolean) => void;
20
20
  theme?: Theme;
21
21
  curation?: ConfigCuration;
22
22
  /** Array of additional component IDs managed outside of Reactify Search */
23
- additionalComponentIds?: string[];
23
+ additionalComponentHandles?: string[];
24
24
  };
25
25
  declare const Context: React.Context<Context | undefined>;
26
26
  declare type Props = {
27
27
  index: string;
28
28
  shopifyPermanentDomain: string;
29
- filterStackId?: string;
29
+ configId?: string;
30
+ filterStackHandle?: string;
30
31
  collection?: Collection;
31
32
  noReactiveBase?: boolean;
32
33
  instantSearch?: boolean;
@@ -34,7 +35,7 @@ declare type Props = {
34
35
  credentials?: Credentials;
35
36
  theme?: Theme;
36
37
  /** Array of additional component IDs managed outside of Reactify Search */
37
- additionalComponentIds?: string[];
38
+ additionalComponentHandles?: string[];
38
39
  /**
39
40
  * Optional render function to display a component when the config is loading.
40
41
  */
package/dist/provider.js CHANGED
@@ -50,7 +50,7 @@ Sentry.init({
50
50
  });
51
51
  const Provider = (_a) => {
52
52
  var { renderBooting } = _a, props = __rest(_a, ["renderBooting"]);
53
- const { config } = (0, hooks_1.useLiveConfig)(props.shopifyPermanentDomain);
53
+ const { config } = (0, hooks_1.useLiveConfig)(props.shopifyPermanentDomain, props.configId);
54
54
  if (!config) {
55
55
  if (renderBooting)
56
56
  return renderBooting();
@@ -61,17 +61,17 @@ const Provider = (_a) => {
61
61
  scope.setTag("shop", props.shopifyPermanentDomain);
62
62
  if (!!props.collection)
63
63
  scope.setTag("collection", props.collection.handle);
64
- if (!!props.filterStackId)
65
- scope.setTag("filterStackId", props.filterStackId);
64
+ if (!!props.filterStackHandle)
65
+ scope.setTag("filter", props.filterStackHandle);
66
66
  if (!!props.instantSearch)
67
- scope.setTag("instantSearch", true);
67
+ scope.setTag("search", true);
68
68
  } },
69
69
  react_1.default.createElement(exports.ConfiguredProvider, Object.assign({}, props, { config: config }))));
70
70
  };
71
71
  exports.Provider = Provider;
72
72
  const ConfiguredProvider = (props) => {
73
73
  var _a, _b;
74
- const { index, config, children, collection, instantSearch, filterStackId, noReactiveBase, shopifyPermanentDomain, additionalComponentIds, onRedirect, } = props;
74
+ const { index, config, children, collection, instantSearch, filterStackHandle, noReactiveBase, shopifyPermanentDomain, additionalComponentHandles, onRedirect, } = props;
75
75
  const credentials = (_a = props.credentials) !== null && _a !== void 0 ? _a : defaultCredentials;
76
76
  const theme = (_b = props.theme) !== null && _b !== void 0 ? _b : {
77
77
  typography: {
@@ -110,13 +110,13 @@ const ConfiguredProvider = (props) => {
110
110
  setSearchQuery(searchQueryFromURL);
111
111
  }, [searchQueryFromURL]);
112
112
  react_1.default.useEffect(() => {
113
- if (searchSortFromURL && (sortOption === null || sortOption === void 0 ? void 0 : sortOption.id) !== searchSortFromURL) {
113
+ if (searchSortFromURL && (sortOption === null || sortOption === void 0 ? void 0 : sortOption.handle) !== searchSortFromURL) {
114
114
  setSortOption(searchSortFromURL, true);
115
115
  }
116
116
  }, [searchSortFromURL]);
117
117
  react_1.default.useEffect(() => {
118
- if (window.location.search === "" && (sortOption === null || sortOption === void 0 ? void 0 : sortOption.id)) {
119
- setSortOption(sortOptions[0].id, true);
118
+ if (window.location.search === "" && (sortOption === null || sortOption === void 0 ? void 0 : sortOption.handle)) {
119
+ setSortOption(sortOption.handle, true);
120
120
  }
121
121
  }, [window.location.href]);
122
122
  const [showInstantSearchResults, setShowInstantSearchResults] = react_1.default.useState(false);
@@ -140,7 +140,7 @@ const ConfiguredProvider = (props) => {
140
140
  // do not attempt to resolve a filter stack if in instantSearch mode
141
141
  const filterStack = instantSearch
142
142
  ? undefined
143
- : useFilterStack(config, collection, filterStackId);
143
+ : useFilterStack(config, collection, filterStackHandle);
144
144
  const curation = useCuration(config, collection, searchQuery);
145
145
  const contextValue = react_1.default.useMemo(() => ({
146
146
  index,
@@ -159,7 +159,7 @@ const ConfiguredProvider = (props) => {
159
159
  setShowInstantSearchResults,
160
160
  theme,
161
161
  curation,
162
- additionalComponentIds,
162
+ additionalComponentHandles,
163
163
  instantSearch: !!instantSearch,
164
164
  showInstantSearchResults: !!showInstantSearchResults && !!searchQuery,
165
165
  }), [
@@ -176,7 +176,7 @@ const ConfiguredProvider = (props) => {
176
176
  onRedirect,
177
177
  submitSearch,
178
178
  instantSearch,
179
- additionalComponentIds,
179
+ additionalComponentHandles,
180
180
  showInstantSearchResults,
181
181
  theme,
182
182
  ]);
@@ -200,15 +200,16 @@ const useSortState = (config, collection) => {
200
200
  .sort((a, b) => `${a.position}`.localeCompare(`${b.position}`))
201
201
  .filter(({ visibility }) => ["all", type].includes(visibility));
202
202
  }, [config, collection]);
203
- const [sortOptionState, setSortOptionState] = react_1.default.useState((_a = sortOptions[0]) === null || _a === void 0 ? void 0 : _a.id);
204
- const sortOption = react_1.default.useMemo(() => sortOptions.find(({ id }) => id === sortOptionState) || sortOptions[0], [sortOptions, sortOptionState]);
205
- const setSortOption = react_1.default.useCallback((sortOptionId, ignoreHistoryState = false) => {
206
- setSortOptionState(sortOptionId);
203
+ const [sortOptionState, setSortOptionState] = react_1.default.useState((_a = sortOptions[0]) === null || _a === void 0 ? void 0 : _a.handle);
204
+ const sortOption = react_1.default.useMemo(() => sortOptions.find(({ handle }) => handle === sortOptionState) ||
205
+ sortOptions[0], [sortOptions, sortOptionState]);
206
+ const setSortOption = react_1.default.useCallback((sortOptionHandle, ignoreHistoryState = false) => {
207
+ setSortOptionState(sortOptionHandle);
207
208
  if (!ignoreHistoryState) {
208
209
  const url = new URL(window.location.href);
209
210
  url.searchParams.has("sort")
210
- ? url.searchParams.set("sort", sortOptionId)
211
- : url.searchParams.append("sort", sortOptionId);
211
+ ? url.searchParams.set("sort", sortOptionHandle)
212
+ : url.searchParams.append("sort", sortOptionHandle);
212
213
  window.history.pushState({}, "", url.toString());
213
214
  }
214
215
  }, [window.location.href]);
@@ -220,22 +221,37 @@ const useSortState = (config, collection) => {
220
221
  // @todo we need a better name for the overall page like "Filter Stack" or something,
221
222
  // each block is then called a filter so like Size would be a "Filter" and then each
222
223
  // value within it is a "Filter Option"
223
- const useFilterStack = (config, collection, filterStackId) => react_1.default.useMemo(() => {
224
- var _a;
225
- // manually select filter stack by ID if provided
226
- if (filterStackId) {
227
- const filterStack = config.filters.find((filter) => filterStackId === filter.id);
228
- if (filterStack)
229
- return filterStack;
224
+ const useFilterStack = (config, collection, filterStackHandle) => react_1.default.useMemo(() => {
225
+ const type = !!collection ? "collection" : "search";
226
+ // select filters by type
227
+ const matchingFilterStacks = config.filters.filter((filter) => filter.type === type);
228
+ // select filter stack by handle if provided
229
+ if (filterStackHandle) {
230
+ const matchingFilterStack = matchingFilterStacks.find((filterStack) => filterStackHandle === filterStack.handle);
231
+ if (matchingFilterStack) {
232
+ return matchingFilterStack;
233
+ }
230
234
  }
231
- // automatically select filter stack by collection if provided
235
+ // select filter stack by collection if provided
232
236
  if (collection === null || collection === void 0 ? void 0 : collection.handle) {
233
- const filterStack = config.filters.find((filter) => { var _a; return (_a = filter.collections) === null || _a === void 0 ? void 0 : _a.includes(collection.handle); });
234
- if (filterStack)
235
- return filterStack;
237
+ const matchingFilterStack = matchingFilterStacks.find((filterStack) => { var _a; return (_a = filterStack.collections) === null || _a === void 0 ? void 0 : _a.includes(collection.handle); });
238
+ if (matchingFilterStack) {
239
+ return matchingFilterStack;
240
+ }
236
241
  }
237
- const type = !!collection ? "collection" : "search";
238
- return ((_a = config.filters.find((filter) => type === filter.type)) !== null && _a !== void 0 ? _a : config.filters[0]);
242
+ // select filter with "default" handle
243
+ let matchingFilterStack = matchingFilterStacks.find((filterStack) => filterStack.handle === "default");
244
+ if (matchingFilterStack) {
245
+ return matchingFilterStack;
246
+ }
247
+ // select any filter with "default" handle
248
+ matchingFilterStack = config.filters.find((filterStack) => filterStack.handle === "default");
249
+ if (matchingFilterStack) {
250
+ return matchingFilterStack;
251
+ }
252
+ // select any available filter as a last resort
253
+ matchingFilterStack = config.filters[0];
254
+ return matchingFilterStack;
239
255
  }, [config, collection]);
240
256
  const useCuration = (config, collection, searchQuery) => react_1.default.useMemo(() => {
241
257
  debug("resolveCuration.start", { config, collection, searchQuery });
@@ -107,6 +107,7 @@ export interface DefinedField {
107
107
  export interface Sort {
108
108
  id: string;
109
109
  name: string;
110
+ handle: string;
110
111
  field: string;
111
112
  position: number;
112
113
  enabled: boolean;
@@ -116,6 +117,7 @@ export interface Sort {
116
117
  export interface Filter {
117
118
  id: string;
118
119
  name: string;
120
+ handle: string;
119
121
  enabled: boolean;
120
122
  pageSize: number;
121
123
  keywords: string[];
@@ -135,6 +137,7 @@ export interface FilterOption {
135
137
  field: string;
136
138
  id: string;
137
139
  name: string;
140
+ handle: string;
138
141
  position: number;
139
142
  settingsCollapsedDesktop: boolean;
140
143
  settingsCollapsedMobile: boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@usereactify/search",
3
3
  "description": "React UI library for Reactify Search",
4
- "version": "4.1.0-beta.3",
4
+ "version": "4.1.0",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",