Skip to content

Commit 89c6e86

Browse files
Eunjae LeeHaroenv
Eunjae Lee
andauthoredFeb 22, 2021
feat(smartSort): add widget (#4648)
* feat(smartSort): add widget * chore: update types * rename the template key from default to text * add tests for component and widget * provide defaultTemplates for smart-sort widget * clean up storybook * remove test code that is no longer needed * fix type error * move refine to connectorState * use setQueryParameter instead of mergeSearchParameters * rename template from text to button * update templates to include root and text * update client-search and algoliasearch to 4.8.5 * clean up the condition for isSmartSorted * Revert "clean up the condition for isSmartSorted" This reverts commit 996c09a. * update bundlesize * update the storybook * fix type for client v3 * remove relevancyStrictness from widgetParams and add isVirtualReplica to conditionally render the widget * Update src/connectors/smart-sort/connectSmartSort.ts Co-authored-by: Haroen Viaene <hello@haroen.me> * clean up the story * Update src/connectors/smart-sort/connectSmartSort.ts Co-authored-by: Haroen Viaene <hello@haroen.me> * use Template type Co-authored-by: Haroen Viaene <hello@haroen.me>
1 parent 2271b43 commit 89c6e86

File tree

12 files changed

+1055
-125
lines changed

12 files changed

+1055
-125
lines changed
 

‎package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
"qs": "^6.5.1"
6363
},
6464
"devDependencies": {
65-
"@algolia/client-search": "4.8.2",
65+
"@algolia/client-search": "4.8.5",
6666
"@babel/cli": "7.8.4",
6767
"@babel/core": "7.9.6",
6868
"@babel/plugin-proposal-class-properties": "7.8.3",
@@ -92,7 +92,7 @@
9292
"@wdio/selenium-standalone-service": "5.16.5",
9393
"@wdio/spec-reporter": "5.16.5",
9494
"@wdio/static-server-service": "5.16.5",
95-
"algoliasearch": "4.8.2",
95+
"algoliasearch": "4.8.5",
9696
"algoliasearch-v3": "npm:algoliasearch@3.35.1",
9797
"babel-eslint": "10.0.3",
9898
"babel-jest": "24.9.0",
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/** @jsx h */
2+
3+
import { h } from 'preact';
4+
import Template from '../Template/Template';
5+
import {
6+
SmartSortCSSClasses,
7+
SmartSortTemplates,
8+
} from '../../widgets/smart-sort/smart-sort';
9+
10+
type SmartSortProps = {
11+
cssClasses: SmartSortCSSClasses;
12+
templates: SmartSortTemplates;
13+
isSmartSorted: boolean;
14+
isVirtualReplica: boolean;
15+
refine(relevancyStrictness: number | undefined): void;
16+
};
17+
18+
const SmartSort = ({
19+
cssClasses,
20+
templates,
21+
isSmartSorted,
22+
isVirtualReplica,
23+
refine,
24+
}: SmartSortProps) =>
25+
isVirtualReplica ? (
26+
<div className={cssClasses.root}>
27+
<Template
28+
templateKey="text"
29+
templates={templates}
30+
rootProps={{
31+
className: cssClasses.text,
32+
}}
33+
data={{ isSmartSorted }}
34+
/>
35+
<button
36+
type="button"
37+
className={cssClasses.button}
38+
onClick={() => {
39+
if (isSmartSorted) {
40+
refine(0);
41+
} else {
42+
refine(undefined);
43+
}
44+
}}
45+
>
46+
<Template
47+
rootTagName="span"
48+
templateKey="button"
49+
templates={templates}
50+
data={{ isSmartSorted }}
51+
/>
52+
</button>
53+
</div>
54+
) : null;
55+
56+
export default SmartSort;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/** @jsx h */
2+
3+
import { h } from 'preact';
4+
import { render, fireEvent } from '@testing-library/preact';
5+
6+
import SmartSort from '../SmartSort';
7+
8+
const cssClasses = {
9+
root: 'root',
10+
text: 'text',
11+
button: 'button',
12+
};
13+
14+
const templates = {
15+
text: '',
16+
button: ({ isSmartSorted }) => {
17+
return isSmartSorted ? 'See all results' : 'See relevant results';
18+
},
19+
};
20+
21+
describe('SmartSort', () => {
22+
it('render nothing if not virtual replica', () => {
23+
const { container } = render(
24+
<SmartSort
25+
cssClasses={cssClasses}
26+
templates={templates}
27+
isSmartSorted={false}
28+
isVirtualReplica={false}
29+
refine={() => {}}
30+
/>
31+
);
32+
expect(container).toMatchInlineSnapshot(`<div />`);
33+
});
34+
35+
it('render the default status', () => {
36+
const { container } = render(
37+
<SmartSort
38+
cssClasses={cssClasses}
39+
templates={templates}
40+
isSmartSorted={false}
41+
isVirtualReplica={true}
42+
refine={() => {}}
43+
/>
44+
);
45+
expect(container).toMatchInlineSnapshot(`
46+
<div>
47+
<div
48+
class="root"
49+
>
50+
<div
51+
class="text"
52+
/>
53+
<button
54+
class="button"
55+
type="button"
56+
>
57+
<span>
58+
See relevant results
59+
</span>
60+
</button>
61+
</div>
62+
</div>
63+
`);
64+
});
65+
66+
it('refine on button click', () => {
67+
const refine = jest.fn();
68+
const { getByText } = render(
69+
<SmartSort
70+
cssClasses={cssClasses}
71+
templates={templates}
72+
isSmartSorted={false}
73+
isVirtualReplica={true}
74+
refine={refine}
75+
/>
76+
);
77+
fireEvent.click(getByText('See relevant results'));
78+
expect(refine).toHaveBeenCalledTimes(1);
79+
});
80+
81+
it('render sorted status', () => {
82+
const { container } = render(
83+
<SmartSort
84+
cssClasses={cssClasses}
85+
templates={templates}
86+
isSmartSorted={true}
87+
isVirtualReplica={true}
88+
refine={() => {}}
89+
/>
90+
);
91+
expect(container).toMatchInlineSnapshot(`
92+
<div>
93+
<div
94+
class="root"
95+
>
96+
<div
97+
class="text"
98+
/>
99+
<button
100+
class="button"
101+
type="button"
102+
>
103+
<span>
104+
See all results
105+
</span>
106+
</button>
107+
</div>
108+
</div>
109+
`);
110+
});
111+
112+
it('refine with `undefined` on "See relevant results"', () => {
113+
const refine = jest.fn();
114+
const { getByText } = render(
115+
<SmartSort
116+
cssClasses={cssClasses}
117+
templates={templates}
118+
isSmartSorted={false}
119+
isVirtualReplica={true}
120+
refine={refine}
121+
/>
122+
);
123+
fireEvent.click(getByText('See relevant results'));
124+
expect(refine).toHaveBeenCalledTimes(1);
125+
expect(refine).toHaveBeenCalledWith(undefined);
126+
});
127+
128+
it('refine with `0` on "Seeing all results"', () => {
129+
const refine = jest.fn();
130+
const { getByText } = render(
131+
<SmartSort
132+
cssClasses={cssClasses}
133+
templates={templates}
134+
isSmartSorted={true}
135+
isVirtualReplica={true}
136+
refine={refine}
137+
/>
138+
);
139+
fireEvent.click(getByText('See all results'));
140+
expect(refine).toHaveBeenCalledTimes(1);
141+
expect(refine).toHaveBeenCalledWith(0);
142+
});
143+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
import algoliasearchHelper, {
2+
SearchParameters,
3+
SearchResults,
4+
} from 'algoliasearch-helper';
5+
import connectSmartSort from '../connectSmartSort';
6+
import {
7+
createInitOptions,
8+
createRenderOptions,
9+
createDisposeOptions,
10+
} from '../../../../test/mock/createWidget';
11+
import { noop } from '../../../lib/utils';
12+
import { createSearchClient } from '../../../../test/mock/createSearchClient';
13+
import { createSingleSearchResponse } from '../../../../test/mock/createAPIResponse';
14+
15+
const createHelper = () => {
16+
return algoliasearchHelper(createSearchClient(), '', {});
17+
};
18+
19+
describe('connectSmartSort', () => {
20+
it('is a widget', () => {
21+
const render = jest.fn();
22+
const unmount = jest.fn();
23+
24+
const customSmartSort = connectSmartSort(render, unmount);
25+
const widget = customSmartSort({});
26+
27+
expect(widget).toEqual(
28+
expect.objectContaining({
29+
$$type: 'ais.smartSort',
30+
init: expect.any(Function),
31+
render: expect.any(Function),
32+
dispose: expect.any(Function),
33+
})
34+
);
35+
});
36+
37+
it('dispose relevancyStrictness set by the widget', () => {
38+
const helper = createHelper();
39+
const makeWidget = connectSmartSort(noop);
40+
const widget = makeWidget({});
41+
widget.init!(createInitOptions({ helper }));
42+
const { refine } = widget.getWidgetRenderState(
43+
createRenderOptions({
44+
helper,
45+
})
46+
);
47+
refine(10);
48+
expect(
49+
widget.getWidgetSearchParameters!(helper.state, {
50+
uiState: {},
51+
}).relevancyStrictness
52+
).toEqual(10);
53+
54+
const nextState = widget.dispose!(
55+
createDisposeOptions({ state: helper.state })
56+
) as SearchParameters;
57+
expect(nextState.relevancyStrictness).toBeUndefined();
58+
});
59+
60+
it('apply relevancyStrictness to helper on refine()', () => {
61+
const helper = createHelper();
62+
const makeWidget = connectSmartSort(noop);
63+
const widget = makeWidget({});
64+
65+
widget.init!(createInitOptions({ helper }));
66+
const { refine } = widget.getWidgetRenderState(
67+
createRenderOptions({ helper })
68+
);
69+
70+
expect(helper.state.relevancyStrictness).toBeUndefined();
71+
72+
refine(0);
73+
expect(helper.state.relevancyStrictness).toEqual(0);
74+
75+
refine(11);
76+
expect(helper.state.relevancyStrictness).toEqual(11);
77+
});
78+
79+
it('decide isSmartSorted based on appliedRelevancyStrictness', () => {
80+
const helper = createHelper();
81+
const makeWidget = connectSmartSort(noop);
82+
const widget = makeWidget({});
83+
84+
widget.init!(createInitOptions({ helper }));
85+
86+
let renderState = widget.getWidgetRenderState(
87+
createRenderOptions({
88+
helper,
89+
results: new SearchResults(helper.state, [
90+
createSingleSearchResponse({
91+
hits: [],
92+
appliedRelevancyStrictness: 60,
93+
}),
94+
]),
95+
})
96+
);
97+
expect(renderState.isSmartSorted).toBe(true);
98+
99+
renderState = widget.getWidgetRenderState(
100+
createRenderOptions({
101+
helper,
102+
results: new SearchResults(helper.state, [
103+
createSingleSearchResponse({
104+
hits: [],
105+
appliedRelevancyStrictness: 0,
106+
}),
107+
]),
108+
})
109+
);
110+
expect(renderState.isSmartSorted).toBe(false);
111+
});
112+
113+
it('decide isVirtualReplica based on appliedRelevancyStrictness', () => {
114+
const helper = createHelper();
115+
const makeWidget = connectSmartSort(noop);
116+
const widget = makeWidget({});
117+
118+
widget.init!(createInitOptions({ helper }));
119+
120+
let renderState = widget.getWidgetRenderState(
121+
createRenderOptions({
122+
helper,
123+
results: new SearchResults(helper.state, [
124+
createSingleSearchResponse({
125+
hits: [],
126+
appliedRelevancyStrictness: 60,
127+
}),
128+
]),
129+
})
130+
);
131+
expect(renderState.isVirtualReplica).toBe(true);
132+
133+
renderState = widget.getWidgetRenderState(
134+
createRenderOptions({
135+
helper,
136+
results: new SearchResults(helper.state, [
137+
createSingleSearchResponse({
138+
hits: [],
139+
appliedRelevancyStrictness: 0,
140+
}),
141+
]),
142+
})
143+
);
144+
expect(renderState.isVirtualReplica).toBe(true);
145+
146+
renderState = widget.getWidgetRenderState(
147+
createRenderOptions({
148+
helper,
149+
results: new SearchResults(helper.state, [
150+
createSingleSearchResponse({
151+
hits: [],
152+
appliedRelevancyStrictness: undefined,
153+
}),
154+
]),
155+
})
156+
);
157+
expect(renderState.isVirtualReplica).toBe(false);
158+
});
159+
160+
describe('getRenderState', () => {
161+
it('return the render state', () => {
162+
const helper = createHelper();
163+
const renderFn = jest.fn();
164+
const unmountFn = jest.fn();
165+
const makeWidget = connectSmartSort(renderFn, unmountFn);
166+
const widget = makeWidget({});
167+
168+
const renderState1 = widget.getRenderState(
169+
{},
170+
createInitOptions({ helper })
171+
);
172+
expect(renderState1.smartSort).toEqual({
173+
isSmartSorted: false,
174+
isVirtualReplica: false,
175+
refine: expect.any(Function),
176+
widgetParams: {},
177+
});
178+
179+
widget.init!(createInitOptions());
180+
const renderState2 = widget.getRenderState(
181+
{},
182+
createRenderOptions({
183+
helper,
184+
results: new SearchResults(helper.state, [
185+
createSingleSearchResponse({
186+
hits: [],
187+
appliedRelevancyStrictness: 15,
188+
}),
189+
]),
190+
})
191+
);
192+
expect(renderState2.smartSort).toEqual({
193+
isSmartSorted: true,
194+
isVirtualReplica: true,
195+
refine: expect.any(Function),
196+
widgetParams: {},
197+
});
198+
});
199+
});
200+
201+
describe('getWidgetRenderState', () => {
202+
it('return the widget render state', () => {
203+
const helper = createHelper();
204+
const makeWidget = connectSmartSort(noop);
205+
const widget = makeWidget({});
206+
207+
const widgetRenderState1 = widget.getWidgetRenderState(
208+
createInitOptions({ helper })
209+
);
210+
expect(widgetRenderState1).toEqual({
211+
isSmartSorted: false,
212+
isVirtualReplica: false,
213+
refine: expect.any(Function),
214+
widgetParams: {},
215+
});
216+
217+
widget.init!(createInitOptions());
218+
const widgetRenderState2 = widget.getWidgetRenderState(
219+
createRenderOptions({
220+
helper,
221+
results: new SearchResults(helper.state, [
222+
createSingleSearchResponse({
223+
hits: [],
224+
appliedRelevancyStrictness: 20,
225+
}),
226+
]),
227+
})
228+
);
229+
expect(widgetRenderState2).toEqual({
230+
isSmartSorted: true,
231+
isVirtualReplica: true,
232+
refine: expect.any(Function),
233+
widgetParams: {},
234+
});
235+
});
236+
});
237+
238+
describe('getWidgetUiState', () => {
239+
it('does not have relevancyStrictness by default', () => {
240+
const helper = createHelper();
241+
const makeWidget = connectSmartSort(noop);
242+
const widget = makeWidget({});
243+
244+
const widgetUiState = widget.getWidgetUiState!(
245+
{},
246+
{ helper, searchParameters: helper.state }
247+
);
248+
expect(widgetUiState.smartSort?.relevancyStrictness).toBeUndefined();
249+
});
250+
251+
it('add refined parameters', () => {
252+
const helper = createHelper();
253+
const makeWidget = connectSmartSort(noop);
254+
const widget = makeWidget({});
255+
256+
widget.init!(createInitOptions({ helper }));
257+
const { refine } = widget.getWidgetRenderState(
258+
createRenderOptions({ helper })
259+
);
260+
refine(25);
261+
262+
expect(
263+
widget.getWidgetUiState!({}, { helper, searchParameters: helper.state })
264+
).toEqual({
265+
smartSort: { relevancyStrictness: 25 },
266+
});
267+
});
268+
269+
it('overwrite existing uiState with searchParameters', () => {
270+
const helper = createHelper();
271+
const makeWidget = connectSmartSort(noop);
272+
const widget = makeWidget({});
273+
274+
expect(
275+
widget.getWidgetUiState!(
276+
{ smartSort: { relevancyStrictness: 25 } },
277+
{ helper, searchParameters: helper.state }
278+
)
279+
).toEqual({
280+
smartSort: { relevancyStrictness: undefined },
281+
});
282+
283+
const { refine } = widget.getWidgetRenderState(
284+
createRenderOptions({ helper })
285+
);
286+
refine(30);
287+
288+
// applies 30 from searchParameters
289+
expect(
290+
widget.getWidgetUiState!(
291+
{ smartSort: { relevancyStrictness: 25 } },
292+
{ helper, searchParameters: helper.state }
293+
)
294+
).toEqual({
295+
smartSort: { relevancyStrictness: 30 },
296+
});
297+
});
298+
});
299+
300+
describe('getWidgetSearchParameters', () => {
301+
it('does not include relevancyStrictness by default', () => {
302+
const makeWidget = connectSmartSort(noop);
303+
const widget = makeWidget({});
304+
305+
const searchParameters = widget.getWidgetSearchParameters!(
306+
new SearchParameters(),
307+
{
308+
uiState: {},
309+
}
310+
);
311+
expect(searchParameters.relevancyStrictness).toBeUndefined();
312+
});
313+
314+
it('return parameters set by uiState', () => {
315+
const makeWidget = connectSmartSort(noop);
316+
const widget = makeWidget({});
317+
318+
const searchParameters = widget.getWidgetSearchParameters!(
319+
new SearchParameters(),
320+
{
321+
uiState: {
322+
smartSort: {
323+
relevancyStrictness: 15,
324+
},
325+
},
326+
}
327+
);
328+
expect(searchParameters).toEqual(
329+
new SearchParameters({ relevancyStrictness: 15 })
330+
);
331+
});
332+
333+
it('store refined state', () => {
334+
const helper = createHelper();
335+
const makeWidget = connectSmartSort(noop);
336+
const widget = makeWidget({});
337+
338+
const { refine } = widget.getWidgetRenderState(
339+
createRenderOptions({ helper })
340+
);
341+
refine(25);
342+
343+
const searchParameters = widget.getWidgetSearchParameters!(helper.state, {
344+
uiState: {},
345+
});
346+
expect(searchParameters.relevancyStrictness).toEqual(25);
347+
});
348+
349+
it('override parameters with the value from uiState', () => {
350+
const helper = createHelper();
351+
const makeWidget = connectSmartSort(noop);
352+
const widget = makeWidget({});
353+
354+
const { refine } = widget.getWidgetRenderState(
355+
createRenderOptions({ helper })
356+
);
357+
refine(25);
358+
359+
const searchParameters = widget.getWidgetSearchParameters!(
360+
new SearchParameters(),
361+
{
362+
uiState: {
363+
smartSort: {
364+
relevancyStrictness: 15,
365+
},
366+
},
367+
}
368+
);
369+
expect(searchParameters.relevancyStrictness).toEqual(15);
370+
});
371+
});
372+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { Connector } from '../../types';
2+
import { noop } from '../../lib/utils';
3+
4+
export type SmartSortConnectorParams = {};
5+
6+
type Refine = (relevancyStrictness: number) => void;
7+
8+
export type SmartSortRendererOptions = {
9+
isSmartSorted: boolean;
10+
isVirtualReplica: boolean;
11+
refine: Refine;
12+
};
13+
14+
export type SmartSortConnector = Connector<
15+
SmartSortRendererOptions,
16+
SmartSortConnectorParams
17+
>;
18+
19+
const connectSmartSort: SmartSortConnector = function connectSmartSort(
20+
renderFn = noop,
21+
unmountFn = noop
22+
) {
23+
return widgetParams => {
24+
type ConnectorState = {
25+
refine?: Refine;
26+
};
27+
28+
const connectorState: ConnectorState = {};
29+
30+
return {
31+
$$type: 'ais.smartSort',
32+
33+
init(initOptions) {
34+
const { instantSearchInstance } = initOptions;
35+
renderFn(
36+
{
37+
...this.getWidgetRenderState(initOptions),
38+
instantSearchInstance,
39+
},
40+
true
41+
);
42+
},
43+
44+
render(renderOptions) {
45+
const { instantSearchInstance } = renderOptions;
46+
47+
renderFn(
48+
{
49+
...this.getWidgetRenderState(renderOptions),
50+
instantSearchInstance,
51+
},
52+
false
53+
);
54+
},
55+
56+
dispose({ state }) {
57+
unmountFn();
58+
59+
return state.setQueryParameter('relevancyStrictness', undefined);
60+
},
61+
62+
getRenderState(renderState, renderOptions) {
63+
return {
64+
...renderState,
65+
smartSort: this.getWidgetRenderState(renderOptions),
66+
};
67+
},
68+
69+
getWidgetRenderState({ results, helper }) {
70+
if (!connectorState.refine) {
71+
connectorState.refine = (relevancyStrictness: number | undefined) => {
72+
helper
73+
.setQueryParameter('relevancyStrictness', relevancyStrictness)
74+
.search();
75+
};
76+
}
77+
78+
const { appliedRelevancyStrictness } = results || {};
79+
80+
return {
81+
isSmartSorted:
82+
typeof appliedRelevancyStrictness !== 'undefined' &&
83+
appliedRelevancyStrictness > 0,
84+
isVirtualReplica: appliedRelevancyStrictness !== undefined,
85+
refine: connectorState.refine,
86+
widgetParams,
87+
};
88+
},
89+
90+
getWidgetSearchParameters(state, { uiState }) {
91+
return state.setQueryParameter(
92+
'relevancyStrictness',
93+
uiState.smartSort?.relevancyStrictness ?? state.relevancyStrictness
94+
);
95+
},
96+
97+
getWidgetUiState(uiState, { searchParameters }) {
98+
return {
99+
...uiState,
100+
smartSort: {
101+
...uiState.smartSort,
102+
relevancyStrictness: searchParameters.relevancyStrictness,
103+
},
104+
};
105+
},
106+
};
107+
};
108+
};
109+
110+
export default connectSmartSort;

‎src/types/algoliasearch.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export type SearchResponse<
4949
THit
5050
> = DefaultSearchClient extends DummySearchClientV4
5151
? SearchResponseV4<THit>
52-
: SearchResponseV3<THit>;
52+
: SearchResponseV3<THit> & { appliedRelevancyStrictness?: number };
5353

5454
export type SearchForFacetValuesResponse = DefaultSearchClient extends DummySearchClientV4
5555
? SearchForFacetValuesResponseV4

‎src/types/widget.ts

+13
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ import {
6666
RangeConnectorParams,
6767
RangeRendererOptions,
6868
} from '../connectors/range/connectRange';
69+
import {
70+
SmartSortConnectorParams,
71+
SmartSortRendererOptions,
72+
} from '../connectors/smart-sort/connectSmartSort';
6973
import {
7074
MenuConnectorParams,
7175
MenuRendererOptions,
@@ -164,6 +168,9 @@ export type IndexUiState = {
164168
*/
165169
boundingBox: string;
166170
};
171+
smartSort?: {
172+
relevancyStrictness?: number;
173+
};
167174
sortBy?: string;
168175
page?: number;
169176
hitsPerPage?: number;
@@ -357,6 +364,10 @@ export type IndexRenderState = Partial<{
357364
}
358365
>;
359366
};
367+
smartSort: WidgetRenderState<
368+
SmartSortRendererOptions,
369+
SmartSortConnectorParams
370+
>;
360371
}>;
361372

362373
export type WidgetRenderState<
@@ -403,6 +414,7 @@ export type Widget<
403414
| 'ais.ratingMenu'
404415
| 'ais.refinementList'
405416
| 'ais.searchBox'
417+
| 'ais.smartSort'
406418
| 'ais.sortBy'
407419
| 'ais.stats'
408420
| 'ais.toggleRefinement'
@@ -438,6 +450,7 @@ export type Widget<
438450
| 'ais.ratingMenu'
439451
| 'ais.refinementList'
440452
| 'ais.searchBox'
453+
| 'ais.smartSort'
441454
| 'ais.sortBy'
442455
| 'ais.stats'
443456
| 'ais.toggleRefinement'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { render } from 'preact';
2+
import smartSort from '../smart-sort';
3+
import algoliasearchHelper, { SearchResults } from 'algoliasearch-helper';
4+
import { createSearchClient } from '../../../../test/mock/createSearchClient';
5+
import {
6+
createInitOptions,
7+
createRenderOptions,
8+
} from '../../../../test/mock/createWidget';
9+
import { createSingleSearchResponse } from '../../../../test/mock/createAPIResponse';
10+
11+
jest.mock('preact', () => {
12+
const module = require.requireActual('preact');
13+
14+
module.render = jest.fn();
15+
16+
return module;
17+
});
18+
19+
const templates = {
20+
text: '',
21+
button: ({ isSmartSorted }) => {
22+
return isSmartSorted ? 'See all results' : 'See relevant results';
23+
},
24+
};
25+
26+
describe('smartSort', () => {
27+
beforeEach(() => {
28+
(render as jest.Mock).mockReset();
29+
});
30+
31+
describe('Usage', () => {
32+
it('throws without container', () => {
33+
expect(() => {
34+
// @ts-ignore wrong options
35+
smartSort({ container: undefined });
36+
}).toThrowErrorMatchingInlineSnapshot(`
37+
"The \`container\` option is required.
38+
39+
See documentation: https://www.algolia.com/doc/api-reference/widgets/smart-sort/js/"
40+
`);
41+
});
42+
});
43+
44+
it('render', () => {
45+
const helper = algoliasearchHelper(createSearchClient(), '', {});
46+
const widget = smartSort({
47+
container: document.createElement('div'),
48+
cssClasses: {
49+
root: 'my-SmartSort',
50+
},
51+
templates,
52+
});
53+
widget.init!(createInitOptions({ helper, state: helper.state }));
54+
55+
const results = {
56+
nbHits: 20,
57+
nbSortedHits: 14,
58+
appliedRelevancyStrictness: 70,
59+
};
60+
61+
widget.render!(
62+
createRenderOptions({
63+
results: new SearchResults(helper.state, [
64+
createSingleSearchResponse(results),
65+
]),
66+
})
67+
);
68+
const [, secondRender] = (render as jest.Mock).mock.calls;
69+
70+
expect(render).toHaveBeenCalledTimes(2);
71+
expect(secondRender[0].props).toEqual(
72+
expect.objectContaining({
73+
cssClasses: {
74+
root: 'ais-SmartSort my-SmartSort',
75+
text: 'ais-SmartSort-text',
76+
button: 'ais-SmartSort-button',
77+
},
78+
isSmartSorted: true,
79+
isVirtualReplica: true,
80+
refine: expect.any(Function),
81+
templates,
82+
})
83+
);
84+
});
85+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default {
2+
text: '',
3+
button: ({ isSmartSorted }) =>
4+
isSmartSorted ? 'See all results' : 'See relevant results',
5+
};

‎src/widgets/smart-sort/smart-sort.tsx

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/** @jsx h */
2+
3+
import { h, render } from 'preact';
4+
import cx from 'classnames';
5+
import {
6+
getContainerNode,
7+
createDocumentationMessageGenerator,
8+
} from '../../lib/utils';
9+
import { component } from '../../lib/suit';
10+
import { WidgetFactory, Renderer, Template } from '../../types';
11+
import connectSmartSort, {
12+
SmartSortConnectorParams,
13+
SmartSortRendererOptions,
14+
} from '../../connectors/smart-sort/connectSmartSort';
15+
import SmartSort from '../../components/SmartSort/SmartSort';
16+
import defaultTemplates from './defaultTemplates';
17+
18+
export type SmartSortCSSClasses = Partial<{
19+
root: string;
20+
text: string;
21+
button: string;
22+
}>;
23+
24+
export type SmartSortTemplates = Partial<{
25+
text: Template<{ isSmartSorted: boolean }>;
26+
button: Template<{ isSmartSorted: boolean }>;
27+
}>;
28+
29+
type SmartSortWidgetParams = {
30+
container: string | HTMLElement;
31+
cssClasses?: SmartSortCSSClasses;
32+
templates?: SmartSortTemplates;
33+
};
34+
35+
type SmartSortRendererWidgetParams = {
36+
container: HTMLElement;
37+
cssClasses: SmartSortCSSClasses;
38+
templates: SmartSortTemplates;
39+
} & SmartSortWidgetParams;
40+
41+
type SmartSortWidget = WidgetFactory<
42+
SmartSortRendererOptions,
43+
SmartSortConnectorParams,
44+
SmartSortWidgetParams
45+
>;
46+
47+
const withUsage = createDocumentationMessageGenerator({
48+
name: 'smart-sort',
49+
});
50+
51+
const suit = component('SmartSort');
52+
53+
const renderer: Renderer<
54+
SmartSortRendererOptions,
55+
SmartSortRendererWidgetParams
56+
> = ({ isSmartSorted, isVirtualReplica, refine, widgetParams }) => {
57+
const { container, cssClasses, templates } = widgetParams;
58+
59+
render(
60+
<SmartSort
61+
cssClasses={cssClasses}
62+
templates={templates}
63+
isSmartSorted={isSmartSorted}
64+
isVirtualReplica={isVirtualReplica}
65+
refine={refine}
66+
/>,
67+
container
68+
);
69+
};
70+
71+
const smartSort: SmartSortWidget = widgetParams => {
72+
const {
73+
container,
74+
templates: userTemplates = {} as SmartSortTemplates,
75+
cssClasses: userCssClasses = {} as SmartSortCSSClasses,
76+
} = widgetParams;
77+
78+
if (!container) {
79+
throw new Error(withUsage('The `container` option is required.'));
80+
}
81+
82+
const cssClasses: SmartSortCSSClasses = {
83+
root: cx(suit(), userCssClasses.root),
84+
text: cx(suit({ descendantName: 'text' }), userCssClasses.text),
85+
button: cx(suit({ descendantName: 'button' }), userCssClasses.button),
86+
};
87+
88+
const templates: SmartSortTemplates = {
89+
...defaultTemplates,
90+
...userTemplates,
91+
};
92+
93+
const containerNode = getContainerNode(container);
94+
const makeWidget = connectSmartSort(renderer, () => {
95+
render(null, containerNode);
96+
});
97+
98+
return {
99+
...makeWidget({
100+
container: containerNode,
101+
cssClasses,
102+
templates,
103+
}),
104+
$$widgetType: 'ais.smartSort',
105+
};
106+
};
107+
108+
export default smartSort;

‎stories/smart-sort.stories.ts

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { storiesOf } from '@storybook/html';
2+
import { withHits } from '../.storybook/decorators';
3+
import smartSort from '../src/widgets/smart-sort/smart-sort';
4+
5+
const searchOptions = {
6+
appId: 'C7RIRJRYR9',
7+
apiKey: '77af6d5ffb27caa5ff4937099fcb92e8',
8+
indexName: 'test_Bestbuy_vr_price_asc',
9+
};
10+
11+
storiesOf('Sorting/SmartSort', module)
12+
.add(
13+
'default',
14+
withHits(({ search, container }) => {
15+
search.addWidgets([
16+
smartSort({
17+
container,
18+
cssClasses: {
19+
root: 'my-SmartSort',
20+
},
21+
}),
22+
]);
23+
}, searchOptions)
24+
)
25+
.add(
26+
'explicit value',
27+
withHits(({ search, container }) => {
28+
search.addWidgets([
29+
smartSort({
30+
container,
31+
templates: {
32+
button: ({ isSmartSorted }) =>
33+
isSmartSorted ? 'See all results' : 'See relevant results',
34+
},
35+
}),
36+
]);
37+
}, searchOptions)
38+
);

‎yarn.lock

+122-122
Original file line numberDiff line numberDiff line change
@@ -2,109 +2,109 @@
22
# yarn lockfile v1
33

44

5-
"@algolia/cache-browser-local-storage@4.8.2":
6-
version "4.8.2"
7-
resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.8.2.tgz#e94c50d360c53fc48d107484de2012f3a0bbed9a"
8-
integrity sha512-X2528jVZk+iPmsA4gF2AxH7RnREF10O98yV8QWwXcXcEYD7qjCsidPUGXcRsZCWOkCdZPA2IMJBiPDxZqfrQqA==
9-
dependencies:
10-
"@algolia/cache-common" "4.8.2"
11-
12-
"@algolia/cache-common@4.8.2":
13-
version "4.8.2"
14-
resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.8.2.tgz#e992e29ffeec75e2bc77eef5280efca71ac27d56"
15-
integrity sha512-ER3QxHH2vmatfO4rRv504ByAiqqoj6kg0RcoBEetQflxRcRznmX7uFBXI3Zo42OoPKM3NMzFted50YO0Um5VLA==
16-
17-
"@algolia/cache-in-memory@4.8.2":
18-
version "4.8.2"
19-
resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.8.2.tgz#12d66469d5ff7142d092272e01e02abfb6a1315d"
20-
integrity sha512-CYse8/ZNPr/pMo6inQ0Uu+HWFFN9OcfJw67YCvU+1yz8NaS3rQ2HxU+zu1M/BCKMA89/dYF0jjBMT5rm6E4cdw==
21-
dependencies:
22-
"@algolia/cache-common" "4.8.2"
23-
24-
"@algolia/client-account@4.8.2":
25-
version "4.8.2"
26-
resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.8.2.tgz#ad4066085d871fb5ea10dcf6a40a423480d3bbdc"
27-
integrity sha512-cRtZ2xiLUfsanrpjYkxyNwE+4SbyUvbe8CL9HwpTJPsP0Jsv69H4H71lL7v0pQY5OWkFxKMsqVxCMH7Px3740w==
28-
dependencies:
29-
"@algolia/client-common" "4.8.2"
30-
"@algolia/client-search" "4.8.2"
31-
"@algolia/transporter" "4.8.2"
32-
33-
"@algolia/client-analytics@4.8.2":
34-
version "4.8.2"
35-
resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.8.2.tgz#29592bc9a2d39a50c17ede959bdc14812edd0fba"
36-
integrity sha512-+vnFokDGxi0vAaumbAgvDuvXWs0VvLk3gDkjkegXD8MMUTs3ByTZApCM4NPnIdbcUroFAJxbyzZQT9/CRZHgcA==
37-
dependencies:
38-
"@algolia/client-common" "4.8.2"
39-
"@algolia/client-search" "4.8.2"
40-
"@algolia/requester-common" "4.8.2"
41-
"@algolia/transporter" "4.8.2"
42-
43-
"@algolia/client-common@4.8.2":
44-
version "4.8.2"
45-
resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.8.2.tgz#989ca2a396938db833578a65c63bce1b1785bde9"
46-
integrity sha512-jO9RvC0FPxxhe/nynGxVEYmNltE5xgYV1Y6zviwl/80PwsrGfWp/rVDh4CVZaBOntmsOp+y0aqQwNYjLMVWXBg==
47-
dependencies:
48-
"@algolia/requester-common" "4.8.2"
49-
"@algolia/transporter" "4.8.2"
50-
51-
"@algolia/client-recommendation@4.8.2":
52-
version "4.8.2"
53-
resolved "https://registry.yarnpkg.com/@algolia/client-recommendation/-/client-recommendation-4.8.2.tgz#f8483adca6ce829414d8e8c5b58420b22d160d49"
54-
integrity sha512-evngF6Odrw93gXkXrOYPXxTWwDQ2K01sadB3Xpa1hQb+vjiBwcA/54w6nKyE4aiII1loT5q+Uj+G1f8HwBuksw==
55-
dependencies:
56-
"@algolia/client-common" "4.8.2"
57-
"@algolia/requester-common" "4.8.2"
58-
"@algolia/transporter" "4.8.2"
59-
60-
"@algolia/client-search@4.8.2":
61-
version "4.8.2"
62-
resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.8.2.tgz#714d1604bfdf5b8ba33247ee571c6f3c2abc6c31"
63-
integrity sha512-JtmhdBKsA3Ll9ITvBfvMjsfuOY5oOPlaS9ahBGeb2OFfC1Myb6kbjXl73VtSVh4Bh0MpTsT4SdBdYCJFctRsQg==
64-
dependencies:
65-
"@algolia/client-common" "4.8.2"
66-
"@algolia/requester-common" "4.8.2"
67-
"@algolia/transporter" "4.8.2"
68-
69-
"@algolia/logger-common@4.8.2":
70-
version "4.8.2"
71-
resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.8.2.tgz#7cecc05b2725f3d68babdc26aed24f2fb60bc4bf"
72-
integrity sha512-Sse29WFBZH4CSCnbMTh8t6uAFaJtNyRRcpDjFfvkSNdPAN/pxLAY9GYUzJmP4J+ILdJn6ZWMNpvwhNQ8p2I+mg==
73-
74-
"@algolia/logger-console@4.8.2":
75-
version "4.8.2"
76-
resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.8.2.tgz#65aca402330f20a23551e63014dc3ff5586ce39b"
77-
integrity sha512-hpZvy708iOeX6tcgy9qXVzlH8Avd3UA7AMwd1wAK5dG8PwAcrhO9wRQuE1AemvuVIEhshbWGQl9pDGXsejO+4g==
78-
dependencies:
79-
"@algolia/logger-common" "4.8.2"
80-
81-
"@algolia/requester-browser-xhr@4.8.2":
82-
version "4.8.2"
83-
resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.8.2.tgz#4f3396aa842e30a8c76916640086a96135b245a9"
84-
integrity sha512-Vdv38BtgwAeVPThwOVRVrR8mDiRLADwqXt1c87dnHHL1Rs3/FMRQ9ogKMKnaJMAH+OeXf+yzNxh+QCISPKaMkQ==
85-
dependencies:
86-
"@algolia/requester-common" "4.8.2"
87-
88-
"@algolia/requester-common@4.8.2":
89-
version "4.8.2"
90-
resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.8.2.tgz#42bb83c4d90f9a19ad4728524a763264723cbed4"
91-
integrity sha512-dN6MuKQQTp7+IBZNIRC9KUCrWVQRM3LaSLLB9lM7evjt++2jJTlhUu2Vncd78VbSy2kviojelxZ/mXTITRRxoA==
92-
93-
"@algolia/requester-node-http@4.8.2":
94-
version "4.8.2"
95-
resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.8.2.tgz#29e7a8404193dcf686b16909f1fce9f96f0ba150"
96-
integrity sha512-pnpDRzIfibJ67rPQvq1me+bqhfflS2w9MlbVMhKdPsSuO8GKAZQ4GJgvIphvpSmhVnB7drdbZZ3J0KVP/y7jeg==
97-
dependencies:
98-
"@algolia/requester-common" "4.8.2"
99-
100-
"@algolia/transporter@4.8.2":
101-
version "4.8.2"
102-
resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.8.2.tgz#1c401e209d54a20296249158c64ad263891ee057"
103-
integrity sha512-r3ecEn+4GWW8ntydDmGGlZ5Iqds080bt2RtAUVNbPPwyuXAs9HUqwkYQiTIHSmeYtAlQ6YOYVnX3W6W8FhbhaA==
104-
dependencies:
105-
"@algolia/cache-common" "4.8.2"
106-
"@algolia/logger-common" "4.8.2"
107-
"@algolia/requester-common" "4.8.2"
5+
"@algolia/cache-browser-local-storage@4.8.5":
6+
version "4.8.5"
7+
resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.8.5.tgz#3eb10758c794d3cc8fc4e9f09e339d5b9589dc9c"
8+
integrity sha512-9rs/Yi82ilgifweJamOy4DlJ4xPGsCN/zg+RKy4vjytNhOrkEHLRQC8vPZ3OhD8KVlw9lRQIZTlgjgFl8iMeeA==
9+
dependencies:
10+
"@algolia/cache-common" "4.8.5"
11+
12+
"@algolia/cache-common@4.8.5":
13+
version "4.8.5"
14+
resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.8.5.tgz#86f8a6878bd2fc5c8d889e48d18d3033faa0bcd8"
15+
integrity sha512-4SvRWnagKtwBFAy8Rsfmv0/Uk53fZL+6dy2idwdx6SjMGKSs0y1Qv+thb4h/k/H5MONisAoT9C2rgZ/mqwh5yw==
16+
17+
"@algolia/cache-in-memory@4.8.5":
18+
version "4.8.5"
19+
resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.8.5.tgz#13055d54775f99aa4e1ce051e73079d0f207a3e6"
20+
integrity sha512-XBBfqs28FbjwLboY3sxvuzBgYsuXdFsj2mUvkgxfb0GVEzwW4I0NM7KzSPwT+iht55WS1PgIOnynjmhPsrubCw==
21+
dependencies:
22+
"@algolia/cache-common" "4.8.5"
23+
24+
"@algolia/client-account@4.8.5":
25+
version "4.8.5"
26+
resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.8.5.tgz#92df1dd0a7bea06e329873c7098c72cc4dd8e9d6"
27+
integrity sha512-DjXMpeCdY4J4IDBfowiG6Xl9ec/FhG1NpPQM0Uv4xXsc/TeeZ1JgbgNDhWe9jW0jBEALy+a/RmPrZ0vsxcadsg==
28+
dependencies:
29+
"@algolia/client-common" "4.8.5"
30+
"@algolia/client-search" "4.8.5"
31+
"@algolia/transporter" "4.8.5"
32+
33+
"@algolia/client-analytics@4.8.5":
34+
version "4.8.5"
35+
resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.8.5.tgz#1aa731a146b347022a0a9e0eb009f2b2f8d9825f"
36+
integrity sha512-PQEY+chbHmZnRJdaWsvUYzDpEPr60az0EPUexdouvXGZId15/SnDaXjnf89F7tYmCzkHdUtG4bSvPzAupQ4AFA==
37+
dependencies:
38+
"@algolia/client-common" "4.8.5"
39+
"@algolia/client-search" "4.8.5"
40+
"@algolia/requester-common" "4.8.5"
41+
"@algolia/transporter" "4.8.5"
42+
43+
"@algolia/client-common@4.8.5":
44+
version "4.8.5"
45+
resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.8.5.tgz#77e5d9bbfcb421fa8812cdd91943961c64793148"
46+
integrity sha512-Dn8vog2VrGsJeOcBMcSAEIjBtPyogzUBGlh1DtVd0m8GN6q+cImCESl6DY846M2PTYWsLBKBksq37eUfSe9FxQ==
47+
dependencies:
48+
"@algolia/requester-common" "4.8.5"
49+
"@algolia/transporter" "4.8.5"
50+
51+
"@algolia/client-recommendation@4.8.5":
52+
version "4.8.5"
53+
resolved "https://registry.yarnpkg.com/@algolia/client-recommendation/-/client-recommendation-4.8.5.tgz#f02f8f8ff3983597cae677ec0bc3eb01ae26121a"
54+
integrity sha512-ffawCC1C25rCa8/JU2niRZgwr8aV9b2qsLVMo73GXFzi2lceXPAe9K68mt/BGHU+w7PFUwVHsV2VmB+G/HQRVw==
55+
dependencies:
56+
"@algolia/client-common" "4.8.5"
57+
"@algolia/requester-common" "4.8.5"
58+
"@algolia/transporter" "4.8.5"
59+
60+
"@algolia/client-search@4.8.5":
61+
version "4.8.5"
62+
resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.8.5.tgz#970a5c91847822dbd82565f97bd2a0c37a5d56e6"
63+
integrity sha512-Ru2MljGZWrSQ0CVsDla11oGEPL/RinmVkLJfBtQ+/pk1868VfpAQFGKtOS/b8/xLrMA0Vm4EfC3Mgclk/p3KJA==
64+
dependencies:
65+
"@algolia/client-common" "4.8.5"
66+
"@algolia/requester-common" "4.8.5"
67+
"@algolia/transporter" "4.8.5"
68+
69+
"@algolia/logger-common@4.8.5":
70+
version "4.8.5"
71+
resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.8.5.tgz#ef275c532c21424f4b29b26ec2e27de2c973ad95"
72+
integrity sha512-PS6NS6bpED0rAxgCPGhjZJg9why0PnoVEE7ZoCbPq6lsAOc6FPlQLri4OiLyU7wx8RWDoVtOadyzulqAAsfPSQ==
73+
74+
"@algolia/logger-console@4.8.5":
75+
version "4.8.5"
76+
resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.8.5.tgz#8fe547fdcf76574963503f7c4ff2673e792ae886"
77+
integrity sha512-3+4gLSbwzuGmrb5go3IZNcFIYVMSbB4c8UMtWEJ/gDBtgGZIvT6f/KlvVSOHIhthSxaM3Y13V6Qile/SpGqc6A==
78+
dependencies:
79+
"@algolia/logger-common" "4.8.5"
80+
81+
"@algolia/requester-browser-xhr@4.8.5":
82+
version "4.8.5"
83+
resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.8.5.tgz#95e01e2dca38358055f08440f46d4f0b9f735280"
84+
integrity sha512-M/Gf2vv/fU4+CqDW+wok7HPpEcLym3NtDzU9zaPzGYI/9X7o36581oyfnzt2pNfsXSQVj5a2pZVUWC3Z4SO27w==
85+
dependencies:
86+
"@algolia/requester-common" "4.8.5"
87+
88+
"@algolia/requester-common@4.8.5":
89+
version "4.8.5"
90+
resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.8.5.tgz#952dec3b36c14495af158914cd6c0e2c9ce72b5e"
91+
integrity sha512-OIhsdwIrJVAlVlP7cwlt+RoR5AmxAoTGrFokOY9imVmgqXUUljdKO/DjhRL8vwYGFEidZ9efIjAIQ2B3XOhT9A==
92+
93+
"@algolia/requester-node-http@4.8.5":
94+
version "4.8.5"
95+
resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.8.5.tgz#a1e5a6d23a9a4e78abd5a2416f1a6c232b0a7e14"
96+
integrity sha512-viHAjfo53A3VSE7Bb/nzgpSMZ3prPp2qti7Wg8w7qxhntppKp3Fln6t4Vp+BoPOqruLsj139xXhheAKeRcYa0w==
97+
dependencies:
98+
"@algolia/requester-common" "4.8.5"
99+
100+
"@algolia/transporter@4.8.5":
101+
version "4.8.5"
102+
resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.8.5.tgz#86f4e286cb4eba6e62f1c0393c33cc17ff262fa9"
103+
integrity sha512-Rb3cMlh/GoJK0+g+49GNA3IvR/EXsDEBwpyM+FOotSwxgiGt1wGBHM0K2v0GHwIEcuww02pl6KMDVlilA+qh0g==
104+
dependencies:
105+
"@algolia/cache-common" "4.8.5"
106+
"@algolia/logger-common" "4.8.5"
107+
"@algolia/requester-common" "4.8.5"
108108

109109
"@babel/cli@7.8.4":
110110
version "7.8.4"
@@ -3425,25 +3425,25 @@ algoliasearch@^3.35.1:
34253425
semver "^5.1.0"
34263426
tunnel-agent "^0.6.0"
34273427

3428-
algoliasearch@4.8.2:
3429-
version "4.8.2"
3430-
resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.8.2.tgz#499d187afe2169bc66c921cf7d5271c3fe0b3598"
3431-
integrity sha512-wQg1UpiXO6iXMXXyrmhKopjd3K4GGq5N/0qEjPB5OYzdvj4ju9rDIW8bYL9ghv9jD5IDrcyFsqCzlSKqn/RVXw==
3432-
dependencies:
3433-
"@algolia/cache-browser-local-storage" "4.8.2"
3434-
"@algolia/cache-common" "4.8.2"
3435-
"@algolia/cache-in-memory" "4.8.2"
3436-
"@algolia/client-account" "4.8.2"
3437-
"@algolia/client-analytics" "4.8.2"
3438-
"@algolia/client-common" "4.8.2"
3439-
"@algolia/client-recommendation" "4.8.2"
3440-
"@algolia/client-search" "4.8.2"
3441-
"@algolia/logger-common" "4.8.2"
3442-
"@algolia/logger-console" "4.8.2"
3443-
"@algolia/requester-browser-xhr" "4.8.2"
3444-
"@algolia/requester-common" "4.8.2"
3445-
"@algolia/requester-node-http" "4.8.2"
3446-
"@algolia/transporter" "4.8.2"
3428+
algoliasearch@4.8.5:
3429+
version "4.8.5"
3430+
resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.8.5.tgz#17a97b01c46c1ac5c1cd99d950d65e7064c8b8a9"
3431+
integrity sha512-GjKjpeevpePEJYinGokASNtIkl1t5EseNMlqDNAc+sXE8+iyyeqTyiJsN7bwlRG2BIremuslE/NlwdEfUuBLJw==
3432+
dependencies:
3433+
"@algolia/cache-browser-local-storage" "4.8.5"
3434+
"@algolia/cache-common" "4.8.5"
3435+
"@algolia/cache-in-memory" "4.8.5"
3436+
"@algolia/client-account" "4.8.5"
3437+
"@algolia/client-analytics" "4.8.5"
3438+
"@algolia/client-common" "4.8.5"
3439+
"@algolia/client-recommendation" "4.8.5"
3440+
"@algolia/client-search" "4.8.5"
3441+
"@algolia/logger-common" "4.8.5"
3442+
"@algolia/logger-console" "4.8.5"
3443+
"@algolia/requester-browser-xhr" "4.8.5"
3444+
"@algolia/requester-common" "4.8.5"
3445+
"@algolia/requester-node-http" "4.8.5"
3446+
"@algolia/transporter" "4.8.5"
34473447

34483448
anchor-markdown-header@^0.5.5:
34493449
version "0.5.7"

0 commit comments

Comments
 (0)
Please sign in to comment.