create-instantsearch-app 7.0.2 → 7.2.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.
Files changed (32) hide show
  1. package/README.md +0 -1
  2. package/package.json +5 -5
  3. package/src/cli/__tests__/postProcessAnswers.js +56 -0
  4. package/src/cli/index.js +85 -0
  5. package/src/cli/postProcessAnswers.js +3 -0
  6. package/src/templates/Angular InstantSearch/angular.json +3 -11
  7. package/src/templates/Angular InstantSearch/karma.conf.js +5 -8
  8. package/src/templates/Angular InstantSearch/src/app/app.component.ts +2 -5
  9. package/src/templates/Angular InstantSearch/src/app/app.module.ts +4 -9
  10. package/src/templates/Angular InstantSearch/src/environments/environment.prod.ts +1 -1
  11. package/src/templates/Angular InstantSearch/src/environments/environment.ts +1 -1
  12. package/src/templates/Angular InstantSearch/src/index.html +15 -12
  13. package/src/templates/Angular InstantSearch/src/main.ts +3 -2
  14. package/src/templates/Angular InstantSearch/src/polyfills.ts +1 -2
  15. package/src/templates/Angular InstantSearch/src/test.ts +7 -3
  16. package/src/templates/InstantSearch iOS/App/Assets.xcassets/AppIcon.appiconset/Contents.json +29 -29
  17. package/src/templates/InstantSearch.js/.template.js +1 -0
  18. package/src/templates/InstantSearch.js/index.html.hbs +8 -0
  19. package/src/templates/InstantSearch.js/{package.json → package.json.hbs} +5 -0
  20. package/src/templates/InstantSearch.js/src/app.js.hbs +95 -0
  21. package/src/templates/InstantSearch.js/src/global.d.ts.hbs +16 -0
  22. package/src/templates/InstantSearch.js widget/config/api-extractor.json +1 -1
  23. package/src/templates/InstantSearch.js widget/example/index.css +1 -1
  24. package/src/templates/InstantSearch.js widget/example/index.html +17 -14
  25. package/src/templates/React InstantSearch/index.html +1 -1
  26. package/src/templates/React InstantSearch Native/babel.config.js +1 -1
  27. package/src/templates/React InstantSearch Native/src/InfiniteHits.tsx +3 -3
  28. package/src/templates/Vue InstantSearch/public/index.html +13 -7
  29. package/src/templates/Vue InstantSearch/src/main.js +1 -1
  30. package/src/templates/Vue InstantSearch with Vue 3/index.html +5 -2
  31. /package/src/templates/JavaScript Client/{package.json → package.json.hbs} +0 -0
  32. /package/src/templates/React InstantSearch Native/{package.json → package.json.hbs} +0 -0
package/README.md CHANGED
@@ -16,7 +16,6 @@
16
16
  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
17
17
  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
18
18
 
19
-
20
19
  - [Get started](#get-started)
21
20
  - [Usage](#usage)
22
21
  - [API](#api)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-instantsearch-app",
3
- "version": "7.0.2",
3
+ "version": "7.2.0",
4
4
  "license": "MIT",
5
5
  "description": "⚡️ Build InstantSearch apps at the speed of thought",
6
6
  "keywords": [
@@ -38,20 +38,20 @@
38
38
  "algoliasearch": "4",
39
39
  "chalk": "3.0.0",
40
40
  "commander": "4.1.1",
41
- "inquirer": "8.0.0",
41
+ "inquirer": "8.2.0",
42
42
  "jstransformer-handlebars": "1.1.0",
43
43
  "load-json-file": "6.2.0",
44
44
  "lodash.camelcase": "4.3.0",
45
45
  "metalsmith": "2.5.1",
46
46
  "metalsmith-rename": "1.0.0",
47
- "prettier": "1.19.1",
47
+ "prettier": "^2.4.1",
48
48
  "semver": "6.1.1",
49
49
  "validate-npm-package-name": "3.0.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@instantsearch/testutils": "1.14.0",
52
+ "@instantsearch/testutils": "1.15.0",
53
53
  "jest-image-snapshot": "2.12.0",
54
54
  "walk-sync": "2.0.2"
55
55
  },
56
- "gitHead": "046ba8af4e49a0299d3297337965fc4e717550d6"
56
+ "gitHead": "c59c53cab5f6caddf44fca51e32063d737a96bce"
57
57
  }
@@ -185,4 +185,60 @@ describe('flags', () => {
185
185
  ).toEqual(expect.objectContaining({ insights: false }));
186
186
  });
187
187
  });
188
+
189
+ describe('autocomplete', () => {
190
+ test('with usage of autocomplete in searchInputType', async () => {
191
+ expect(
192
+ await postProcessAnswers({
193
+ configuration: {},
194
+ templateConfig: {
195
+ libraryName: 'instantsearch.js',
196
+ flags: {
197
+ autocomplete: '>= 4.52',
198
+ },
199
+ },
200
+ optionsFromArguments: {},
201
+ answers: { searchInputType: 'autocomplete' },
202
+ })
203
+ ).toEqual(
204
+ expect.objectContaining({
205
+ searchInputType: 'autocomplete',
206
+ flags: expect.objectContaining({ autocomplete: true }),
207
+ })
208
+ );
209
+ });
210
+
211
+ test('without usage of autocomplete in searchInputType', async () => {
212
+ expect(
213
+ await postProcessAnswers({
214
+ configuration: {},
215
+ templateConfig: {
216
+ libraryName: 'instantsearch.js',
217
+ flags: {
218
+ autocomplete: '>= 4.52',
219
+ },
220
+ },
221
+ optionsFromArguments: {},
222
+ answers: { searchInputType: 'searchbox' },
223
+ })
224
+ ).toEqual(
225
+ expect.objectContaining({
226
+ searchInputType: 'searchbox',
227
+ flags: expect.objectContaining({ autocomplete: false }),
228
+ })
229
+ );
230
+ });
231
+
232
+ test('without config', async () => {
233
+ expect(
234
+ (
235
+ await postProcessAnswers({
236
+ configuration: {},
237
+ templateConfig: {},
238
+ optionsFromArguments: {},
239
+ })
240
+ ).flags
241
+ ).toEqual(expect.objectContaining({ autocomplete: false }));
242
+ });
243
+ });
188
244
  });
package/src/cli/index.js CHANGED
@@ -201,6 +201,91 @@ const getQuestions = ({ appName }) => ({
201
201
  when: ({ appId, apiKey, indexName }) =>
202
202
  attributesForFaceting.length === 0 && appId && apiKey && indexName,
203
203
  },
204
+ {
205
+ type: 'list',
206
+ name: 'searchInputType',
207
+ message: 'Type of search input',
208
+ choices: [
209
+ {
210
+ name: 'Autocomplete with suggested and recent searches',
211
+ value: 'autocomplete',
212
+ },
213
+ { name: 'Regular search box', value: 'searchbox' },
214
+ ],
215
+ default: 'autocomplete',
216
+ when: ({ libraryVersion, template }) => {
217
+ const templatePath = getTemplatePath(template);
218
+ const templateConfig = getAppTemplateConfig(templatePath);
219
+
220
+ const selectedLibraryVersion = libraryVersion;
221
+ const requiredLibraryVersion =
222
+ templateConfig.flags && templateConfig.flags.autocomplete;
223
+ const supportsAutocomplete =
224
+ selectedLibraryVersion &&
225
+ requiredLibraryVersion &&
226
+ semver.satisfies(selectedLibraryVersion, requiredLibraryVersion, {
227
+ includePrerelease: true,
228
+ });
229
+
230
+ return supportsAutocomplete;
231
+ },
232
+ },
233
+ {
234
+ type: 'input',
235
+ name: 'querySuggestionsIndexName',
236
+ message: 'Index name for suggested searches',
237
+ suffix: `\n ${chalk.gray('This must be a Query Suggestions index')}`,
238
+ default: 'instant_search_demo_query_suggestions',
239
+ when: ({ searchInputType }) => searchInputType === 'autocomplete',
240
+ },
241
+ {
242
+ type: 'list',
243
+ name: 'autocompleteLibraryVersion',
244
+ message: () => `Autocomplete version`,
245
+ choices: async () => {
246
+ const libraryName = '@algolia/autocomplete-js';
247
+
248
+ try {
249
+ const versions = await fetchLibraryVersions(libraryName);
250
+ const latestStableVersion = semver.maxSatisfying(versions, '1', {
251
+ includePrerelease: false,
252
+ });
253
+
254
+ if (!latestStableVersion) {
255
+ return versions;
256
+ }
257
+
258
+ return [
259
+ new inquirer.Separator('Latest stable version (recommended)'),
260
+ latestStableVersion,
261
+ new inquirer.Separator('All versions'),
262
+ ...versions,
263
+ ];
264
+ } catch (err) {
265
+ const fallbackLibraryVersion = '1.11.0';
266
+
267
+ console.log();
268
+ console.error(
269
+ chalk.red(
270
+ `Cannot fetch versions for library "${chalk.cyan(libraryName)}".`
271
+ )
272
+ );
273
+ console.log();
274
+ console.log(
275
+ `Fallback to ${chalk.cyan(
276
+ fallbackLibraryVersion
277
+ )}, please upgrade the dependency after generating the app.`
278
+ );
279
+ console.log();
280
+
281
+ return [
282
+ new inquirer.Separator('Available versions'),
283
+ fallbackLibraryVersion,
284
+ ];
285
+ }
286
+ },
287
+ when: ({ searchInputType }) => searchInputType === 'autocomplete',
288
+ },
204
289
  ],
205
290
  widget: [
206
291
  {
@@ -77,6 +77,9 @@ async function postProcessAnswers({
77
77
  insights:
78
78
  Boolean(templateConfig.flags && templateConfig.flags.insights) &&
79
79
  semver.satisfies(libraryVersion, templateConfig.flags.insights),
80
+ autocomplete:
81
+ Boolean(templateConfig.flags && templateConfig.flags.autocomplete) &&
82
+ combinedAnswers.searchInputType === 'autocomplete',
80
83
  },
81
84
  };
82
85
  }
@@ -22,13 +22,8 @@
22
22
  "main": "src/main.ts",
23
23
  "polyfills": "src/polyfills.ts",
24
24
  "tsConfig": "tsconfig.app.json",
25
- "assets": [
26
- "src/favicon.ico",
27
- "src/assets"
28
- ],
29
- "styles": [
30
- "src/styles.css"
31
- ],
25
+ "assets": ["src/favicon.ico", "src/assets"],
26
+ "styles": ["src/styles.css"],
32
27
  "scripts": []
33
28
  },
34
29
  "configurations": {
@@ -89,10 +84,7 @@
89
84
  "polyfills": "src/polyfills.ts",
90
85
  "tsConfig": "tsconfig.spec.json",
91
86
  "karmaConfig": "karma.conf.js",
92
- "assets": [
93
- "src/favicon.ico",
94
- "src/assets"
95
- ],
87
+ "assets": ["src/favicon.ico", "src/assets"],
96
88
  "styles": [
97
89
  "node_modules/instantsearch.css/themes/satellite.css",
98
90
  "src/styles.css"
@@ -10,7 +10,7 @@ module.exports = function (config) {
10
10
  require('karma-chrome-launcher'),
11
11
  require('karma-jasmine-html-reporter'),
12
12
  require('karma-coverage'),
13
- require('@angular-devkit/build-angular/plugins/karma')
13
+ require('@angular-devkit/build-angular/plugins/karma'),
14
14
  ],
15
15
  client: {
16
16
  jasmine: {
@@ -19,18 +19,15 @@ module.exports = function (config) {
19
19
  // for example, you can disable the random execution with `random: false`
20
20
  // or set a specific seed with `seed: 4321`
21
21
  },
22
- clearContext: false // leave Jasmine Spec Runner output visible in browser
22
+ clearContext: false, // leave Jasmine Spec Runner output visible in browser
23
23
  },
24
24
  jasmineHtmlReporter: {
25
- suppressAll: true // removes the duplicated traces
25
+ suppressAll: true, // removes the duplicated traces
26
26
  },
27
27
  coverageReporter: {
28
28
  dir: require('path').join(__dirname, './coverage/{{name}}'),
29
29
  subdir: '.',
30
- reporters: [
31
- { type: 'html' },
32
- { type: 'text-summary' }
33
- ]
30
+ reporters: [{ type: 'html' }, { type: 'text-summary' }],
34
31
  },
35
32
  reporters: ['progress', 'kjhtml'],
36
33
  port: 9876,
@@ -39,6 +36,6 @@ module.exports = function (config) {
39
36
  autoWatch: true,
40
37
  browsers: ['Chrome'],
41
38
  singleRun: false,
42
- restartOnFileChange: true
39
+ restartOnFileChange: true,
43
40
  });
44
41
  };
@@ -1,15 +1,12 @@
1
1
  import { Component } from '@angular/core';
2
2
  import algoliasearch from 'algoliasearch/lite';
3
3
 
4
- const searchClient = algoliasearch(
5
- '{{appId}}',
6
- '{{apiKey}}'
7
- );
4
+ const searchClient = algoliasearch('{{appId}}', '{{apiKey}}');
8
5
 
9
6
  @Component({
10
7
  selector: 'app-root',
11
8
  templateUrl: './app.component.html',
12
- styleUrls: ['./app.component.css']
9
+ styleUrls: ['./app.component.css'],
13
10
  })
14
11
  export class AppComponent {
15
12
  config = {
@@ -5,14 +5,9 @@ import { NgAisModule } from 'angular-instantsearch';
5
5
  import { AppComponent } from './app.component';
6
6
 
7
7
  @NgModule({
8
- declarations: [
9
- AppComponent
10
- ],
11
- imports: [
12
- NgAisModule.forRoot(),
13
- BrowserModule
14
- ],
8
+ declarations: [AppComponent],
9
+ imports: [NgAisModule.forRoot(), BrowserModule],
15
10
  providers: [],
16
- bootstrap: [AppComponent]
11
+ bootstrap: [AppComponent],
17
12
  })
18
- export class AppModule { }
13
+ export class AppModule {}
@@ -1,3 +1,3 @@
1
1
  export const environment = {
2
- production: true
2
+ production: true,
3
3
  };
@@ -3,7 +3,7 @@
3
3
  // The list of file replacements can be found in `angular.json`.
4
4
 
5
5
  export const environment = {
6
- production: false
6
+ production: false,
7
7
  };
8
8
 
9
9
  /*
@@ -1,14 +1,17 @@
1
- <!doctype html>
1
+ <!DOCTYPE html>
2
2
  <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <title>{{name}}</title>
6
- <base href="/">
7
- <meta name="viewport" content="width=device-width, initial-scale=1">
8
- <link rel="icon" type="image/x-icon" href="favicon.ico">
9
- <link href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/satellite.css" rel="stylesheet" />
10
- </head>
11
- <body>
12
- <app-root></app-root>
13
- </body>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>{{name}}</title>
6
+ <base href="/" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8
+ <link rel="icon" type="image/x-icon" href="favicon.ico" />
9
+ <link
10
+ href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/satellite.css"
11
+ rel="stylesheet"
12
+ />
13
+ </head>
14
+ <body>
15
+ <app-root></app-root>
16
+ </body>
14
17
  </html>
@@ -8,5 +8,6 @@ if (environment.production) {
8
8
  enableProdMode();
9
9
  }
10
10
 
11
- platformBrowserDynamic().bootstrapModule(AppModule)
12
- .catch(err => console.error(err));
11
+ platformBrowserDynamic()
12
+ .bootstrapModule(AppModule)
13
+ .catch((err) => console.error(err));
@@ -57,8 +57,7 @@
57
57
  /***************************************************************************************************
58
58
  * Zone JS is required by default for Angular itself.
59
59
  */
60
- import 'zone.js'; // Included with Angular CLI.
61
-
60
+ import 'zone.js'; // Included with Angular CLI.
62
61
 
63
62
  /***************************************************************************************************
64
63
  * APPLICATION IMPORTS
@@ -4,11 +4,15 @@ import 'zone.js/testing';
4
4
  import { getTestBed } from '@angular/core/testing';
5
5
  import {
6
6
  BrowserDynamicTestingModule,
7
- platformBrowserDynamicTesting
7
+ platformBrowserDynamicTesting,
8
8
  } from '@angular/platform-browser-dynamic/testing';
9
9
 
10
10
  declare const require: {
11
- context(path: string, deep?: boolean, filter?: RegExp): {
11
+ context(
12
+ path: string,
13
+ deep?: boolean,
14
+ filter?: RegExp
15
+ ): {
12
16
  keys(): string[];
13
17
  <T>(id: string): T;
14
18
  };
@@ -18,7 +22,7 @@ declare const require: {
18
22
  getTestBed().initTestEnvironment(
19
23
  BrowserDynamicTestingModule,
20
24
  platformBrowserDynamicTesting(),
21
- { teardown: { destroyAfterEach: true }},
25
+ { teardown: { destroyAfterEach: true } }
22
26
  );
23
27
 
24
28
  // Then we find all the tests.
@@ -1,48 +1,48 @@
1
1
  {
2
- "images" : [
2
+ "images": [
3
3
  {
4
- "idiom" : "iphone",
5
- "size" : "20x20",
6
- "scale" : "2x"
4
+ "idiom": "iphone",
5
+ "size": "20x20",
6
+ "scale": "2x"
7
7
  },
8
8
  {
9
- "idiom" : "iphone",
10
- "size" : "20x20",
11
- "scale" : "3x"
9
+ "idiom": "iphone",
10
+ "size": "20x20",
11
+ "scale": "3x"
12
12
  },
13
13
  {
14
- "idiom" : "iphone",
15
- "size" : "29x29",
16
- "scale" : "2x"
14
+ "idiom": "iphone",
15
+ "size": "29x29",
16
+ "scale": "2x"
17
17
  },
18
18
  {
19
- "idiom" : "iphone",
20
- "size" : "29x29",
21
- "scale" : "3x"
19
+ "idiom": "iphone",
20
+ "size": "29x29",
21
+ "scale": "3x"
22
22
  },
23
23
  {
24
- "idiom" : "iphone",
25
- "size" : "40x40",
26
- "scale" : "2x"
24
+ "idiom": "iphone",
25
+ "size": "40x40",
26
+ "scale": "2x"
27
27
  },
28
28
  {
29
- "idiom" : "iphone",
30
- "size" : "40x40",
31
- "scale" : "3x"
29
+ "idiom": "iphone",
30
+ "size": "40x40",
31
+ "scale": "3x"
32
32
  },
33
33
  {
34
- "idiom" : "iphone",
35
- "size" : "60x60",
36
- "scale" : "2x"
34
+ "idiom": "iphone",
35
+ "size": "60x60",
36
+ "scale": "2x"
37
37
  },
38
38
  {
39
- "idiom" : "iphone",
40
- "size" : "60x60",
41
- "scale" : "3x"
39
+ "idiom": "iphone",
40
+ "size": "60x60",
41
+ "scale": "3x"
42
42
  }
43
43
  ],
44
- "info" : {
45
- "version" : 1,
46
- "author" : "xcode"
44
+ "info": {
45
+ "version": 1,
46
+ "author": "xcode"
47
47
  }
48
- }
48
+ }
@@ -8,6 +8,7 @@ module.exports = {
8
8
  flags: {
9
9
  dynamicWidgets: '>= 4.30',
10
10
  insights: '>= 4.55',
11
+ autocomplete: '>= 4.52',
11
12
  },
12
13
  templateName: 'instantsearch.js',
13
14
  appName: 'instantsearch.js-app',
@@ -9,6 +9,9 @@
9
9
  <link rel="shortcut icon" href="./favicon.png">
10
10
 
11
11
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/satellite-min.css">
12
+ {{#if flags.autocomplete}}
13
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-theme-classic@1.11.0/dist/theme.min.css">
14
+ {{/if}}
12
15
  <link rel="stylesheet" href="./src/index.css">
13
16
  <link rel="stylesheet" href="./src/app.css">
14
17
 
@@ -50,6 +53,11 @@
50
53
 
51
54
  <script src="https://cdn.jsdelivr.net/npm/algoliasearch@4.10.5/dist/algoliasearch-lite.umd.js"></script>
52
55
  <script src="https://cdn.jsdelivr.net/npm/instantsearch.js@{{libraryVersion}}"></script>
56
+ {{#if flags.autocomplete}}
57
+ <script src="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-js@{{autocompleteLibraryVersion}}/dist/umd/index.production.min.js"></script>
58
+ <script src="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-plugin-query-suggestions@{{autocompleteLibraryVersion}}/dist/umd/index.production.min.js"></script>
59
+ <script src="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-plugin-recent-searches@{{autocompleteLibraryVersion}}/dist/umd/index.production.min.js"></script>
60
+ {{/if}}
53
61
  <script src="./src/app.js"></script>
54
62
  </body>
55
63
 
@@ -14,6 +14,11 @@
14
14
  "prettier": "2.6.2"
15
15
  },
16
16
  "dependencies": {
17
+ {{#if flags.autocomplete}}
18
+ "@algolia/autocomplete-js": "{{autocompleteLibraryVersion}}",
19
+ "@algolia/autocomplete-plugin-recent-searches": "{{autocompleteLibraryVersion}}",
20
+ "@algolia/autocomplete-plugin-query-suggestions": "{{autocompleteLibraryVersion}}",
21
+ {{/if}}
17
22
  "algoliasearch": "4",
18
23
  "instantsearch.js": "{{libraryVersion}}"
19
24
  }
@@ -1,4 +1,13 @@
1
1
  const { algoliasearch, instantsearch } = window;
2
+ {{#if flags.autocomplete}}
3
+ const { autocomplete } = window['@algolia/autocomplete-js'];
4
+ const { createLocalStorageRecentSearchesPlugin } = window[
5
+ '@algolia/autocomplete-plugin-recent-searches'
6
+ ];
7
+ const { createQuerySuggestionsPlugin } = window[
8
+ '@algolia/autocomplete-plugin-query-suggestions'
9
+ ];
10
+ {{/if}}
2
11
 
3
12
  const searchClient = algoliasearch('{{appId}}', '{{apiKey}}');
4
13
 
@@ -8,13 +17,21 @@ const search = instantsearch({
8
17
  {{#if flags.insights}}insights: true,{{/if}}
9
18
  });
10
19
 
20
+ {{#if flags.autocomplete}}
21
+ const virtualSearchBox = instantsearch.connectors.connectSearchBox(() => {});
22
+ {{/if}}
23
+
11
24
  search.addWidgets([
25
+ {{#unless flags.autocomplete}}
12
26
  instantsearch.widgets.searchBox({
13
27
  container: '#searchbox',
14
28
  {{#if searchPlaceholder}}
15
29
  placeholder: '{{searchPlaceholder}}',
16
30
  {{/if}}
17
31
  }),
32
+ {{else}}
33
+ virtualSearchBox({}),
34
+ {{/unless}}
18
35
  instantsearch.widgets.hits({
19
36
  container: '#hits',
20
37
  {{#if attributesToDisplay}}
@@ -74,3 +91,81 @@ search.addWidgets([
74
91
  ]);
75
92
 
76
93
  search.start();
94
+
95
+ {{#if flags.autocomplete}}
96
+ const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
97
+ key: 'instantsearch',
98
+ limit: 3,
99
+ transformSource({ source }) {
100
+ return {
101
+ ...source,
102
+ onSelect({ setIsOpen, setQuery, item, event }) {
103
+ onSelect({ setQuery, setIsOpen, event, query: item.label });
104
+ },
105
+ };
106
+ },
107
+ });
108
+
109
+ const querySuggestionsPlugin = createQuerySuggestionsPlugin({
110
+ searchClient,
111
+ indexName: '{{querySuggestionsIndexName}}',
112
+ getSearchParams() {
113
+ return recentSearchesPlugin.data.getAlgoliaSearchParams({ hitsPerPage: 6 });
114
+ },
115
+ transformSource({ source }) {
116
+ return {
117
+ ...source,
118
+ sourceId: 'querySuggestionsPlugin',
119
+ onSelect({ setIsOpen, setQuery, event, item }) {
120
+ onSelect({ setQuery, setIsOpen, event, query: item.query });
121
+ },
122
+ getItems(params) {
123
+ if (!params.state.query) {
124
+ return [];
125
+ }
126
+
127
+ return source.getItems(params);
128
+ },
129
+ };
130
+ },
131
+ });
132
+
133
+ autocomplete({
134
+ container: '#searchbox',
135
+ {{#if searchPlaceholder}}
136
+ placeholder: '{{searchPlaceholder}}',
137
+ {{/if}}
138
+ openOnFocus: true,
139
+ detachedMediaQuery: 'none',
140
+ onSubmit({ state }) {
141
+ setInstantSearchUiState({ query: state.query });
142
+ },
143
+ plugins: [recentSearchesPlugin, querySuggestionsPlugin],
144
+ });
145
+
146
+ function setInstantSearchUiState(indexUiState) {
147
+ search.mainIndex.setIndexUiState({ page: 1, ...indexUiState });
148
+ }
149
+
150
+ function onSelect({ setIsOpen, setQuery, event, query }) {
151
+ if (isModifierEvent(event)) {
152
+ return;
153
+ }
154
+
155
+ setQuery(query);
156
+ setIsOpen(false);
157
+ setInstantSearchUiState({ query });
158
+ }
159
+
160
+ function isModifierEvent(event) {
161
+ const isMiddleClick = event.button === 1;
162
+
163
+ return (
164
+ isMiddleClick ||
165
+ event.altKey ||
166
+ event.ctrlKey ||
167
+ event.metaKey ||
168
+ event.shiftKey
169
+ );
170
+ }
171
+ {{/if}}
@@ -1,3 +1,8 @@
1
+ {{#if flags.autocomplete}}
2
+ import { autocomplete } from '@algolia/autocomplete-js';
3
+ import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches';
4
+ import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions';
5
+ {{/if}}
1
6
  import algoliasearch from 'algoliasearch/lite';
2
7
  import instantsearch from 'instantsearch.js/dist/instantsearch.production.min';
3
8
 
@@ -5,5 +10,16 @@ declare global {
5
10
  interface Window {
6
11
  algoliasearch: typeof algoliasearch;
7
12
  instantsearch: typeof instantsearch;
13
+ {{#if flags.autocomplete}}
14
+ '@algolia/autocomplete-js': {
15
+ autocomplete: typeof autocomplete;
16
+ };
17
+ '@algolia/autocomplete-plugin-recent-searches': {
18
+ createLocalStorageRecentSearchesPlugin: typeof createLocalStorageRecentSearchesPlugin;
19
+ };
20
+ '@algolia/autocomplete-plugin-query-suggestions': {
21
+ createQuerySuggestionsPlugin: typeof createQuerySuggestionsPlugin;
22
+ };
23
+ {{/if}}
8
24
  }
9
25
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Config file for API Extractor. For more info, please visit: https://api-extractor.com
3
3
  */
4
- {
4
+ {
5
5
  "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
6
6
 
7
7
  /**
@@ -2,6 +2,6 @@ body {
2
2
  font-family: sans-serif;
3
3
  }
4
4
 
5
- [class^=ais-] {
5
+ [class^='ais-'] {
6
6
  font-size: 1em;
7
7
  }
@@ -1,17 +1,20 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/algolia-min.css">
8
- <link rel="stylesheet" href="style.css">
9
- <title>{{ name }} example</title>
10
- </head>
11
- <body>
12
- <div id="search-box"></div>
13
- <div id="example"></div>
14
- <div id="hits"></div>
15
- <script src="index.ts"></script>
16
- </body>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <link
8
+ rel="stylesheet"
9
+ href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/algolia-min.css"
10
+ />
11
+ <link rel="stylesheet" href="style.css" />
12
+ <title>{{ name }} example</title>
13
+ </head>
14
+ <body>
15
+ <div id="search-box"></div>
16
+ <div id="example"></div>
17
+ <div id="hits"></div>
18
+ <script src="index.ts"></script>
19
+ </body>
17
20
  </html>
@@ -7,7 +7,7 @@
7
7
  content="width=device-width, initial-scale=1, shrink-to-fit=no"
8
8
  />
9
9
 
10
- <link rel="shortcut icon" href="favicon.png">
10
+ <link rel="shortcut icon" href="favicon.png" />
11
11
 
12
12
  <!--
13
13
  Do not use @7 in production, use a complete version like x.x.x, see website for latest version:
@@ -1,4 +1,4 @@
1
- module.exports = function(api) {
1
+ module.exports = function (api) {
2
2
  api.cache(true);
3
3
  return {
4
4
  presets: ['babel-preset-expo'],
@@ -20,8 +20,8 @@ export const InfiniteHits = forwardRef(
20
20
  return (
21
21
  <FlatList
22
22
  ref={ref}
23
- data={(hits as unknown) as THit[]}
24
- keyExtractor={item => item.objectID}
23
+ data={hits as unknown as THit[]}
24
+ keyExtractor={(item) => item.objectID}
25
25
  ItemSeparatorComponent={() => <View style={styles.separator} />}
26
26
  onEndReached={() => {
27
27
  if (!isLastPage) {
@@ -30,7 +30,7 @@ export const InfiniteHits = forwardRef(
30
30
  }}
31
31
  renderItem={({ item }) => (
32
32
  <View style={styles.item}>
33
- <Hit hit={(item as unknown) as THit} />
33
+ <Hit hit={item as unknown as THit} />
34
34
  </View>
35
35
  )}
36
36
  />
@@ -1,20 +1,26 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <meta charset="utf-8">
5
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
- <meta name="viewport" content="width=device-width,initial-scale=1.0">
7
- <link rel="icon" href="<%= BASE_URL %>favicon.png">
8
- <!--
4
+ <meta charset="utf-8" />
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
+ <meta name="viewport" content="width=device-width,initial-scale=1.0" />
7
+ <link rel="icon" href="<%= BASE_URL %>favicon.png" />
8
+ <!--
9
9
  Do not use @7 in production, use a complete version like x.x.x, see website for latest version:
10
10
  https://www.algolia.com/doc/guides/building-search-ui/installation/react/#load-the-style
11
11
  -->
12
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/satellite-min.css">
12
+ <link
13
+ rel="stylesheet"
14
+ href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/satellite-min.css"
15
+ />
13
16
  <title>{{name}}</title>
14
17
  </head>
15
18
  <body>
16
19
  <noscript>
17
- <strong>We're sorry but {{name}} doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
20
+ <strong
21
+ >We're sorry but {{name}} doesn't work properly without JavaScript
22
+ enabled. Please enable it to continue.</strong
23
+ >
18
24
  </noscript>
19
25
  <div id="app"></div>
20
26
  <!-- built files will be auto injected -->
@@ -7,5 +7,5 @@ Vue.config.productionTip = false;
7
7
  Vue.use(InstantSearch);
8
8
 
9
9
  new Vue({
10
- render: h => h(App),
10
+ render: (h) => h(App),
11
11
  }).$mount('#app');
@@ -2,14 +2,17 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
5
+ <meta http-equiv="X-UA-Compatible" content="ie=edge" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <link rel="icon" href="/favicon.png" />
8
8
  <!--
9
9
  Do not use @7 in production, use a complete version like x.x.x, see website for latest version:
10
10
  https://www.algolia.com/doc/guides/building-search-ui/installation/react/#load-the-style
11
11
  -->
12
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/satellite-min.css">
12
+ <link
13
+ rel="stylesheet"
14
+ href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/satellite-min.css"
15
+ />
13
16
  <title>{{name}}</title>
14
17
  </head>
15
18
  <body>