create-instantsearch-app 5.1.1 → 5.2.2

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 (42) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/package.json +3 -3
  3. package/src/api/__tests__/__snapshots__/index.test.js.snap +3 -3
  4. package/src/templates/Angular InstantSearch/package.json +12 -13
  5. package/src/templates/Autocomplete/package.json +1 -1
  6. package/src/templates/InstantSearch.js/package.json +1 -1
  7. package/src/templates/InstantSearch.js widget/package.json.hbs +1 -1
  8. package/src/templates/JavaScript Helper 2/package.json +1 -1
  9. package/src/templates/React InstantSearch/package.json +1 -1
  10. package/src/templates/React InstantSearch/src/App.js.hbs +3 -1
  11. package/src/templates/React InstantSearch Hooks Native/.expo-shared/assets.json +4 -0
  12. package/src/templates/React InstantSearch Hooks Native/.gitignore.template +14 -0
  13. package/src/templates/React InstantSearch Hooks Native/.template.js +34 -0
  14. package/src/templates/React InstantSearch Hooks Native/App.tsx.hbs +72 -0
  15. package/src/templates/React InstantSearch Hooks Native/README.md +19 -0
  16. package/src/templates/React InstantSearch Hooks Native/app.json +30 -0
  17. package/src/templates/React InstantSearch Hooks Native/assets/adaptive-icon.png +0 -0
  18. package/src/templates/React InstantSearch Hooks Native/assets/favicon.png +0 -0
  19. package/src/templates/React InstantSearch Hooks Native/assets/icon.png +0 -0
  20. package/src/templates/React InstantSearch Hooks Native/assets/splash.png +0 -0
  21. package/src/templates/React InstantSearch Hooks Native/babel.config.js +6 -0
  22. package/src/templates/React InstantSearch Hooks Native/package.json +31 -0
  23. package/src/templates/React InstantSearch Hooks Native/src/Highlight.tsx +81 -0
  24. package/src/templates/React InstantSearch Hooks Native/src/InfiniteHits.tsx +56 -0
  25. package/src/templates/React InstantSearch Hooks Native/src/SearchBox.tsx.hbs +71 -0
  26. package/src/templates/React InstantSearch Hooks Native/tsconfig.json +6 -0
  27. package/src/templates/React InstantSearch Hooks Native/types/ProductHit.ts +28 -0
  28. package/src/templates/React InstantSearch Native/package.json +1 -1
  29. package/src/templates/React InstantSearch widget/package.json.hbs +1 -1
  30. package/src/templates/Vue InstantSearch/package.json +16 -15
  31. package/src/templates/Vue InstantSearch 2/package.json +16 -15
  32. package/src/templates/Vue InstantSearch with Vue 3/.editorconfig +9 -0
  33. package/src/templates/Vue InstantSearch with Vue 3/.gitignore.template +23 -0
  34. package/src/templates/Vue InstantSearch with Vue 3/.prettierrc +5 -0
  35. package/src/templates/Vue InstantSearch with Vue 3/.template.js +18 -0
  36. package/src/templates/Vue InstantSearch with Vue 3/README.md +21 -0
  37. package/src/templates/Vue InstantSearch with Vue 3/index.html +19 -0
  38. package/src/templates/Vue InstantSearch with Vue 3/package.json +20 -0
  39. package/src/templates/Vue InstantSearch with Vue 3/public/favicon.png +0 -0
  40. package/src/templates/Vue InstantSearch with Vue 3/src/App.vue +161 -0
  41. package/src/templates/Vue InstantSearch with Vue 3/src/main.js +7 -0
  42. package/src/templates/Vue InstantSearch with Vue 3/vite.config.js +8 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,42 @@
1
+ ## [5.2.2](https://github.com/algolia/create-instantsearch-app/compare/5.2.1...5.2.2) (2022-02-21)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **vue:** support optional chaining ([#564](https://github.com/algolia/create-instantsearch-app/issues/564)) ([2dfa2ec](https://github.com/algolia/create-instantsearch-app/commit/2dfa2ecebdbcea5604db451c0e0e57010b36de04))
7
+
8
+
9
+
10
+ ## [5.2.1](https://github.com/algolia/create-instantsearch-app/compare/5.2.0...5.2.1) (2022-02-16)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **Vue 3:** add vite plugin to correctly handle jsx ([#563](https://github.com/algolia/create-instantsearch-app/issues/563)) ([0a4162a](https://github.com/algolia/create-instantsearch-app/commit/0a4162ae2067a15b30242e0b54ae3ff768e836d9))
16
+
17
+
18
+
19
+ # [5.2.0](https://github.com/algolia/create-instantsearch-app/compare/5.1.2...5.2.0) (2022-02-14)
20
+
21
+
22
+ ### Features
23
+
24
+ * **templates:** introduce React InstantSearch Hooks Native template ([#559](https://github.com/algolia/create-instantsearch-app/issues/559)) ([495f014](https://github.com/algolia/create-instantsearch-app/commit/495f0140301185bba9192ccd779597d4d5028241))
25
+ * **vue:** add vue3 template ([#558](https://github.com/algolia/create-instantsearch-app/issues/558)) ([117067e](https://github.com/algolia/create-instantsearch-app/commit/117067ea0c4da0d08105d2de1e8b611f935b533a))
26
+
27
+
28
+
29
+ ## [5.1.2](https://github.com/algolia/create-instantsearch-app/compare/5.1.1...5.1.2) (2022-02-02)
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * **angular:** remove @types/algoliasearch dep ([#553](https://github.com/algolia/create-instantsearch-app/issues/553)) ([b280725](https://github.com/algolia/create-instantsearch-app/commit/b2807252dff74f79d887c746327f03f28f53840d))
35
+ * **angular:** update angular packages ([#555](https://github.com/algolia/create-instantsearch-app/issues/555)) ([9987264](https://github.com/algolia/create-instantsearch-app/commit/9987264f32582721ac2a8e7f3348fa3d54be3975))
36
+ * **React InstantSearch:** import RefinementList if DynamicWidgets used ([#554](https://github.com/algolia/create-instantsearch-app/issues/554)) ([402ec63](https://github.com/algolia/create-instantsearch-app/commit/402ec63261db8a60aa6927e84ec46d45eb27fef3))
37
+
38
+
39
+
1
40
  ## [5.1.1](https://github.com/algolia/create-instantsearch-app/compare/5.1.0...5.1.1) (2022-01-03)
2
41
 
3
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-instantsearch-app",
3
- "version": "5.1.1",
3
+ "version": "5.2.2",
4
4
  "license": "MIT",
5
5
  "description": "⚡️ Build InstantSearch apps at the speed of thought",
6
6
  "keywords": [
@@ -36,8 +36,8 @@
36
36
  "node": ">= 10"
37
37
  },
38
38
  "dependencies": {
39
- "@algolia/cache-in-memory": "4.11.0",
40
- "algoliasearch": "4.11.0",
39
+ "@algolia/cache-in-memory": "4",
40
+ "algoliasearch": "4",
41
41
  "chalk": "3.0.0",
42
42
  "commander": "4.1.1",
43
43
  "inquirer": "8.0.0",
@@ -6,10 +6,10 @@ exports[`Options with invalid name throws 1`] = `
6
6
  - name can only contain URL-friendly characters"
7
7
  `;
8
8
 
9
- exports[`Options with unknown template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete, Autocomplete.js 0, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, React InstantSearch widget, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
9
+ exports[`Options with unknown template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete, Autocomplete.js 0, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Hooks Native, React InstantSearch Native, React InstantSearch widget, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2, Vue InstantSearch with Vue 3"`;
10
10
 
11
- exports[`Options with wrong template path throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete, Autocomplete.js 0, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, React InstantSearch widget, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
11
+ exports[`Options with wrong template path throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete, Autocomplete.js 0, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Hooks Native, React InstantSearch Native, React InstantSearch widget, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2, Vue InstantSearch with Vue 3"`;
12
12
 
13
13
  exports[`Options without path throws 1`] = `"The option \`path\` is required."`;
14
14
 
15
- exports[`Options without template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete, Autocomplete.js 0, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, React InstantSearch widget, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
15
+ exports[`Options without template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete, Autocomplete.js 0, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Hooks Native, React InstantSearch Native, React InstantSearch widget, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2, Vue InstantSearch with Vue 3"`;
@@ -10,25 +10,24 @@
10
10
  },
11
11
  "private": true,
12
12
  "dependencies": {
13
- "@angular/animations": "12.2.0",
14
- "@angular/common": "12.2.0",
15
- "@angular/compiler": "12.2.0",
16
- "@angular/core": "12.2.0",
17
- "@angular/forms": "12.2.0",
18
- "@angular/platform-browser": "12.2.0",
19
- "@angular/platform-browser-dynamic": "12.2.0",
20
- "@angular/router": "12.2.0",
21
- "algoliasearch": "4.10.5",
13
+ "@angular/animations": "12.2.16",
14
+ "@angular/common": "12.2.16",
15
+ "@angular/compiler": "12.2.16",
16
+ "@angular/core": "12.2.16",
17
+ "@angular/forms": "12.2.16",
18
+ "@angular/platform-browser": "12.2.16",
19
+ "@angular/platform-browser-dynamic": "12.2.16",
20
+ "@angular/router": "12.2.16",
21
+ "algoliasearch": "4",
22
22
  "angular-instantsearch": "{{libraryVersion}}",
23
23
  "rxjs": "6.6.0",
24
24
  "tslib": "2.3.0",
25
25
  "zone.js": "0.11.4"
26
26
  },
27
27
  "devDependencies": {
28
- "@angular-devkit/build-angular": "12.2.3",
29
- "@angular/cli": "12.2.3",
30
- "@angular/compiler-cli": "12.2.0",
31
- "@types/algoliasearch": "4.0.0",
28
+ "@angular-devkit/build-angular": "12.2.16",
29
+ "@angular/cli": "12.2.16",
30
+ "@angular/compiler-cli": "12.2.16",
32
31
  "@types/jasmine": "3.8.0",
33
32
  "@types/node": "12.11.1",
34
33
  "jasmine-core": "3.8.0",
@@ -10,7 +10,7 @@
10
10
  "dependencies": {
11
11
  "@algolia/autocomplete-js": "{{libraryVersion}}",
12
12
  "@algolia/autocomplete-theme-classic": "{{libraryVersion}}",
13
- "algoliasearch": "4.10.5",
13
+ "algoliasearch": "4",
14
14
  "preact": "10.5.14"
15
15
  },
16
16
  "devDependencies": {
@@ -20,7 +20,7 @@
20
20
  "prettier": "1.19.1"
21
21
  },
22
22
  "dependencies": {
23
- "algoliasearch": "4.10.4",
23
+ "algoliasearch": "4",
24
24
  "instantsearch.js": "{{libraryVersion}}"
25
25
  }
26
26
  }
@@ -48,7 +48,7 @@
48
48
  "@testing-library/jest-dom": "5.11.9",
49
49
  "@typescript-eslint/eslint-plugin": "4.16.1",
50
50
  "@typescript-eslint/parser": "4.16.1",
51
- "algoliasearch": "4.8.5",
51
+ "algoliasearch": "4",
52
52
  "algoliasearch-helper": "3.4.4",
53
53
  "babel-jest": "26.6.3",
54
54
  "babel-plugin-add-import-extension": "1.5.0",
@@ -10,7 +10,7 @@
10
10
  "lint:fix": "npm run lint -- --fix"
11
11
  },
12
12
  "dependencies": {
13
- "algoliasearch": "3.30.0",
13
+ "algoliasearch": "4",
14
14
  "algoliasearch-helper": "{{libraryVersion}}"
15
15
  },
16
16
  "devDependencies": {
@@ -9,7 +9,7 @@
9
9
  "lint:fix": "npm run lint -- --fix"
10
10
  },
11
11
  "dependencies": {
12
- "algoliasearch": "3.35.1",
12
+ "algoliasearch": "4",
13
13
  "react": "16.12.0",
14
14
  "react-dom": "16.12.0",
15
15
  "react-instantsearch-dom": "{{libraryVersion}}",
@@ -7,10 +7,12 @@ import {
7
7
  {{#if flags.dynamicWidgets}}
8
8
  Configure,
9
9
  DynamicWidgets,
10
- {{/if}}
10
+ RefinementList,
11
+ {{else}}
11
12
  {{#if attributesForFaceting}}
12
13
  RefinementList,
13
14
  {{/if}}
15
+ {{/if}}
14
16
  Pagination,
15
17
  {{#if attributesToDisplay}}
16
18
  Highlight,
@@ -0,0 +1,4 @@
1
+ {
2
+ "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3
+ "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4
+ }
@@ -0,0 +1,14 @@
1
+ node_modules/
2
+ .expo/
3
+ dist/
4
+ npm-debug.*
5
+ *.jks
6
+ *.p8
7
+ *.p12
8
+ *.key
9
+ *.mobileprovision
10
+ *.orig.*
11
+ web-build/
12
+
13
+ # macOS
14
+ .DS_Store
@@ -0,0 +1,34 @@
1
+ const chalk = require('chalk');
2
+ const install = require('../../tasks/node/install');
3
+ const teardown = require('../../tasks/node/teardown');
4
+
5
+ module.exports = {
6
+ category: 'Mobile',
7
+ libraryName: 'react-instantsearch-hooks',
8
+ templateName: 'react-instantsearch-hooks-native',
9
+ appName: 'react-instantsearch-hooks-native-app',
10
+ keywords: [
11
+ 'algolia',
12
+ 'instantSearch',
13
+ 'react',
14
+ 'react-native',
15
+ 'react-instantsearch-hooks-native',
16
+ ],
17
+ tasks: {
18
+ setup(config) {
19
+ if (!config.silent && config.attributesForFaceting) {
20
+ console.log();
21
+ console.log(
22
+ `⚠️ The ${chalk.cyan(
23
+ 'attributesForFaceting'
24
+ )} option is not supported in this template.`
25
+ );
26
+ console.log();
27
+ }
28
+
29
+ return Promise.resolve();
30
+ },
31
+ install,
32
+ teardown,
33
+ },
34
+ };
@@ -0,0 +1,72 @@
1
+ import React, { useRef } from 'react';
2
+ import { FlatList, SafeAreaView, StyleSheet, Text, View } from 'react-native';
3
+ import { StatusBar } from 'expo-status-bar';
4
+ import algoliasearch from 'algoliasearch/lite';
5
+ import { InstantSearch } from 'react-instantsearch-hooks';
6
+
7
+ import { InfiniteHits } from './src/InfiniteHits';
8
+ import { SearchBox } from './src/SearchBox';
9
+ {{#if attributesToDisplay}}
10
+ import { Highlight } from './src/Highlight';
11
+ {{/if}}
12
+ import { ProductHit } from './types/ProductHit';
13
+
14
+ const searchClient = algoliasearch(
15
+ '{{appId}}',
16
+ '{{apiKey}}'
17
+ );
18
+
19
+ export default function App() {
20
+ const listRef = useRef<FlatList>(null);
21
+
22
+ return (
23
+ <SafeAreaView style={styles.safe}>
24
+ <StatusBar style="light" />
25
+ <View style={styles.container}>
26
+ <InstantSearch searchClient={searchClient} indexName="{{indexName}}">
27
+ <SearchBox
28
+ onChange={() =>
29
+ listRef.current?.scrollToOffset({ animated: false, offset: 0 })
30
+ }
31
+ />
32
+ <InfiniteHits ref={listRef} hitComponent={Hit} />
33
+ </InstantSearch>
34
+ </View>
35
+ </SafeAreaView>
36
+ );
37
+ }
38
+
39
+ type HitProps = {
40
+ hit: ProductHit;
41
+ };
42
+
43
+ function Hit({ hit }: HitProps) {
44
+ return (
45
+ {{#if attributesToDisplay}}
46
+ <Text>
47
+ <Highlight hit={hit} attribute="{{attributesToDisplay.[0]}}" />
48
+ </Text>
49
+ {{#each attributesToDisplay}}
50
+ {{#unless @first}}
51
+ <Text>
52
+ <Highlight hit={hit} attribute="{{this}}" />
53
+ </Text>
54
+ {{/unless}}
55
+ {{/each}}
56
+ {{else}}
57
+ <Text>{JSON.stringify(hit).slice(0, 100)}</Text>
58
+ {{/if}}
59
+ );
60
+ }
61
+
62
+ const styles = StyleSheet.create({
63
+ safe: {
64
+ flex: 1,
65
+ backgroundColor: '#252b33',
66
+ },
67
+ container: {
68
+ flex: 1,
69
+ backgroundColor: '#ffffff',
70
+ flexDirection: 'column',
71
+ },
72
+ });
@@ -0,0 +1,19 @@
1
+ # {{name}}
2
+
3
+ _This project was generated with [create-instantsearch-app](https://github.com/algolia/create-instantsearch-app) by [Algolia](https://algolia.com)._
4
+
5
+ ## Get started
6
+
7
+ To run this project locally, install the dependencies and run the local server:
8
+
9
+ ```sh
10
+ npm install
11
+ npm start
12
+ ```
13
+
14
+ Alternatively, you may use [Yarn](https://http://yarnpkg.com/):
15
+
16
+ ```sh
17
+ yarn
18
+ yarn start
19
+ ```
@@ -0,0 +1,30 @@
1
+ {
2
+ "expo": {
3
+ "name": "{{name}}",
4
+ "slug": "{{name}}",
5
+ "version": "1.0.0",
6
+ "orientation": "portrait",
7
+ "icon": "./assets/icon.png",
8
+ "splash": {
9
+ "image": "./assets/splash.png",
10
+ "resizeMode": "contain",
11
+ "backgroundColor": "#ffffff"
12
+ },
13
+ "updates": {
14
+ "fallbackToCacheTimeout": 0
15
+ },
16
+ "assetBundlePatterns": ["**/*"],
17
+ "ios": {
18
+ "supportsTablet": true
19
+ },
20
+ "android": {
21
+ "adaptiveIcon": {
22
+ "foregroundImage": "./assets/adaptive-icon.png",
23
+ "backgroundColor": "#FFFFFF"
24
+ }
25
+ },
26
+ "web": {
27
+ "favicon": "./assets/favicon.png"
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,6 @@
1
+ module.exports = function(api) {
2
+ api.cache(true);
3
+ return {
4
+ presets: ['babel-preset-expo'],
5
+ };
6
+ };
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "main": "node_modules/expo/AppEntry.js",
6
+ "scripts": {
7
+ "start": "expo start",
8
+ "android": "expo start --android",
9
+ "ios": "expo start --ios",
10
+ "web": "expo start --web",
11
+ "eject": "expo eject"
12
+ },
13
+ "dependencies": {
14
+ "algoliasearch": "4.12.1",
15
+ "expo": "~44.0.0",
16
+ "expo-status-bar": "~1.2.0",
17
+ "instantsearch.js": "4.38.1",
18
+ "react": "17.0.1",
19
+ "react-dom": "17.0.1",
20
+ "react-instantsearch-hooks": "{{libraryVersion}}",
21
+ "react-native": "0.64.3",
22
+ "react-native-web": "0.17.1"
23
+ },
24
+ "devDependencies": {
25
+ "@babel/core": "^7.12.9",
26
+ "@types/react": "~17.0.21",
27
+ "@types/react-native": "~0.64.12",
28
+ "expo-cli": "5.1.1",
29
+ "typescript": "~4.3.5"
30
+ }
31
+ }
@@ -0,0 +1,81 @@
1
+ import React, { Fragment } from 'react';
2
+ import { StyleSheet, Text } from 'react-native';
3
+ import { Hit as AlgoliaHit } from '@algolia/client-search';
4
+ import {
5
+ getHighlightedParts,
6
+ getPropertyByPath,
7
+ } from 'instantsearch.js/es/lib/utils';
8
+
9
+ type HighlightPartProps = {
10
+ children: React.ReactNode;
11
+ isHighlighted: boolean;
12
+ };
13
+
14
+ function HighlightPart({ children, isHighlighted }: HighlightPartProps) {
15
+ return (
16
+ <Text style={isHighlighted ? styles.highlighted : styles.nonHighlighted}>
17
+ {children}
18
+ </Text>
19
+ );
20
+ }
21
+
22
+ type HighlightProps<THit> = {
23
+ hit: THit;
24
+ attribute: keyof THit | string[];
25
+ className?: string;
26
+ separator?: string;
27
+ };
28
+
29
+ export function Highlight<THit extends AlgoliaHit<Record<string, unknown>>>({
30
+ hit,
31
+ attribute,
32
+ separator = ', ',
33
+ }: HighlightProps<THit>) {
34
+ const { value: attributeValue = '' } =
35
+ getPropertyByPath(hit._highlightResult, attribute as string) || {};
36
+ const parts = getHighlightedParts(attributeValue);
37
+
38
+ return (
39
+ <>
40
+ {parts.map((part, partIndex) => {
41
+ if (Array.isArray(part)) {
42
+ const isLastPart = partIndex === parts.length - 1;
43
+
44
+ return (
45
+ <Fragment key={partIndex}>
46
+ {part.map((subPart, subPartIndex) => (
47
+ <HighlightPart
48
+ key={subPartIndex}
49
+ isHighlighted={subPart.isHighlighted}
50
+ >
51
+ {subPart.value}
52
+ </HighlightPart>
53
+ ))}
54
+
55
+ {!isLastPart && separator}
56
+ </Fragment>
57
+ );
58
+ }
59
+
60
+ return (
61
+ <HighlightPart key={partIndex} isHighlighted={part.isHighlighted}>
62
+ {part.value}
63
+ </HighlightPart>
64
+ );
65
+ })}
66
+ </>
67
+ );
68
+ }
69
+
70
+ const styles = StyleSheet.create({
71
+ highlighted: {
72
+ fontWeight: 'bold',
73
+ backgroundColor: '#f5df4d',
74
+ color: '#6f6106',
75
+ },
76
+ nonHighlighted: {
77
+ fontWeight: 'normal',
78
+ backgroundColor: 'transparent',
79
+ color: 'black',
80
+ },
81
+ });
@@ -0,0 +1,56 @@
1
+ import React, { forwardRef } from 'react';
2
+ import { StyleSheet, View, FlatList } from 'react-native';
3
+ import { Hit as AlgoliaHit } from '@algolia/client-search';
4
+ import {
5
+ useInfiniteHits,
6
+ UseInfiniteHitsProps,
7
+ } from 'react-instantsearch-hooks';
8
+
9
+ type InfiniteHitsProps<THit> = UseInfiniteHitsProps & {
10
+ hitComponent: (props: { hit: THit }) => JSX.Element;
11
+ };
12
+
13
+ export const InfiniteHits = forwardRef(
14
+ <THit extends AlgoliaHit<Record<string, unknown>>>(
15
+ { hitComponent: Hit, ...props }: InfiniteHitsProps<THit>,
16
+ ref: React.ForwardedRef<FlatList<THit>>
17
+ ) => {
18
+ const { hits, isLastPage, showMore } = useInfiniteHits(props);
19
+
20
+ return (
21
+ <FlatList
22
+ ref={ref}
23
+ data={(hits as unknown) as THit[]}
24
+ keyExtractor={item => item.objectID}
25
+ ItemSeparatorComponent={() => <View style={styles.separator} />}
26
+ onEndReached={() => {
27
+ if (!isLastPage) {
28
+ showMore();
29
+ }
30
+ }}
31
+ renderItem={({ item }) => (
32
+ <View style={styles.item}>
33
+ <Hit hit={(item as unknown) as THit} />
34
+ </View>
35
+ )}
36
+ />
37
+ );
38
+ }
39
+ );
40
+
41
+ const styles = StyleSheet.create({
42
+ separator: {
43
+ borderBottomWidth: 1,
44
+ borderColor: '#ddd',
45
+ },
46
+ item: {
47
+ padding: 18,
48
+ },
49
+ });
50
+
51
+ declare module 'react' {
52
+ // eslint-disable-next-line no-shadow
53
+ function forwardRef<TRef, TProps = unknown>(
54
+ render: (props: TProps, ref: React.Ref<TRef>) => React.ReactElement | null
55
+ ): (props: TProps & React.RefAttributes<TRef>) => React.ReactElement | null;
56
+ }
@@ -0,0 +1,71 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { StyleSheet, View, TextInput } from 'react-native';
3
+ import { useSearchBox, UseSearchBoxProps } from 'react-instantsearch-hooks';
4
+
5
+ type SearchBoxProps = UseSearchBoxProps & {
6
+ onChange: (newValue: string) => void;
7
+ };
8
+
9
+ export function SearchBox({ onChange, ...props }: SearchBoxProps) {
10
+ const { query, refine } = useSearchBox(props);
11
+ const [value, setValue] = useState(query);
12
+ const inputRef = useRef<TextInput>(null);
13
+
14
+ // Track when the value coming from the React state changes to synchronize
15
+ // it with InstantSearch.
16
+ useEffect(() => {
17
+ if (query !== value) {
18
+ refine(value);
19
+ }
20
+ // We don't want to track when the React state value changes.
21
+ // eslint-disable-next-line react-hooks/exhaustive-deps
22
+ }, [value, refine]);
23
+
24
+ // Track when the InstantSearch query changes to synchronize it with
25
+ // the React state.
26
+ useEffect(() => {
27
+ // We bypass the state update if the input is focused to avoid concurrent
28
+ // updates when typing.
29
+ if (!inputRef.current?.isFocused() && query !== value) {
30
+ setValue(query);
31
+ }
32
+ // We don't want to track when the React state value changes.
33
+ // eslint-disable-next-line react-hooks/exhaustive-deps
34
+ }, [query]);
35
+
36
+ return (
37
+ <View style={styles.container}>
38
+ <TextInput
39
+ ref={inputRef}
40
+ style={styles.input}
41
+ value={value}
42
+ onChangeText={newValue => {
43
+ setValue(newValue);
44
+ onChange(newValue);
45
+ }}
46
+ clearButtonMode="while-editing"
47
+ autoCapitalize="none"
48
+ autoCorrect={false}
49
+ spellCheck={false}
50
+ autoCompleteType="off"
51
+ placeholder="{{searchPlaceholder}}"
52
+ />
53
+ </View>
54
+ );
55
+ }
56
+
57
+ const styles = StyleSheet.create({
58
+ container: {
59
+ backgroundColor: '#252b33',
60
+ padding: 18,
61
+ },
62
+ input: {
63
+ height: 48,
64
+ padding: 12,
65
+ fontSize: 16,
66
+ backgroundColor: '#fff',
67
+ borderRadius: 4,
68
+ borderWidth: 1,
69
+ borderColor: '#ddd',
70
+ },
71
+ });
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "expo/tsconfig.base",
3
+ "compilerOptions": {
4
+ "strict": true
5
+ }
6
+ }
@@ -0,0 +1,28 @@
1
+ import { Hit as AlgoliaHit } from '@algolia/client-search';
2
+
3
+ export type ProductHit = AlgoliaHit<{
4
+ brand: string;
5
+ categories: string[];
6
+ comments: number;
7
+ description: string;
8
+ free_shipping: boolean;
9
+ hierarchicalCategories: {
10
+ lvl0: string;
11
+ lvl1?: string;
12
+ lvl2?: string;
13
+ lvl3?: string;
14
+ lvl4?: string;
15
+ lvl5?: string;
16
+ lvl6?: string;
17
+ };
18
+ image: string;
19
+ name: string;
20
+ popularity: number;
21
+ price: number;
22
+ prince_range: string;
23
+ rating: number;
24
+ sale: boolean;
25
+ sale_price: string;
26
+ type: string;
27
+ url: string;
28
+ }>;
@@ -10,7 +10,7 @@
10
10
  "eject": "expo eject"
11
11
  },
12
12
  "dependencies": {
13
- "algoliasearch": "4.11.0",
13
+ "algoliasearch": "4",
14
14
  "expo": "44.0.3",
15
15
  "prop-types": "15.8.0",
16
16
  "react": "17.0.2",
@@ -39,7 +39,7 @@
39
39
  "release": "standard-version"
40
40
  },
41
41
  "dependencies": {
42
- "algoliasearch": "^4.9.1",
42
+ "algoliasearch": "4",
43
43
  "react": "^16.8.0",
44
44
  "react-dom": "^16.8.0",
45
45
  "react-instantsearch-dom": "^6.11.0"
@@ -9,24 +9,25 @@
9
9
  "lint:fix": "npm run lint -- --fix"
10
10
  },
11
11
  "dependencies": {
12
- "algoliasearch": "4.6.0",
13
- "core-js": "2.6.9",
14
- "vue": "2.6.10",
12
+ "algoliasearch": "4",
13
+ "core-js": "3.6.5",
14
+ "vue": "2.6.11",
15
15
  "vue-instantsearch": "{{libraryVersion}}"
16
16
  },
17
17
  "devDependencies": {
18
- "@vue/cli-plugin-babel": "3.6.0",
19
- "@vue/cli-plugin-eslint": "3.6.0",
20
- "@vue/cli-service": "3.6.0",
21
- "babel-eslint": "10.0.2",
22
- "eslint": "5.16.0",
23
- "eslint-config-algolia": "13.2.3",
24
- "eslint-config-prettier": "4.1.0",
25
- "eslint-plugin-import": "2.19.1",
26
- "eslint-plugin-prettier": "3.1.2",
27
- "eslint-plugin-vue": "5.2.2",
28
- "prettier": "1.19.1",
29
- "vue-template-compiler": "2.6.10"
18
+ "@babel/eslint-parser": "7.17.0",
19
+ "@vue/cli-plugin-babel": "4.5.15",
20
+ "@vue/cli-plugin-eslint": "4.5.15",
21
+ "@vue/cli-service": "4.5.15",
22
+ "@vue/eslint-config-prettier": "6.0.0",
23
+ "babel-eslint": "10.1.0",
24
+ "eslint": "6.7.2",
25
+ "eslint-config-algolia": "20.0.0",
26
+ "eslint-plugin-import": "2.25.4",
27
+ "eslint-plugin-prettier": "3.3.1",
28
+ "eslint-plugin-vue": "6.2.2",
29
+ "prettier": "2.2.1",
30
+ "vue-template-compiler": "2.6.11"
30
31
  },
31
32
  "browserslist": [
32
33
  "> 1%",
@@ -9,24 +9,25 @@
9
9
  "lint:fix": "npm run lint -- --fix"
10
10
  },
11
11
  "dependencies": {
12
- "algoliasearch": "3.32.0",
13
- "core-js": "2.6.9",
14
- "vue": "2.6.10",
12
+ "algoliasearch": "4",
13
+ "core-js": "3.6.5",
14
+ "vue": "2.6.11",
15
15
  "vue-instantsearch": "{{libraryVersion}}"
16
16
  },
17
17
  "devDependencies": {
18
- "@vue/cli-plugin-babel": "3.6.0",
19
- "@vue/cli-plugin-eslint": "3.6.0",
20
- "@vue/cli-service": "3.6.0",
21
- "babel-eslint": "10.0.2",
22
- "eslint": "5.16.0",
23
- "eslint-config-algolia": "13.2.3",
24
- "eslint-config-prettier": "4.1.0",
25
- "eslint-plugin-import": "2.19.1",
26
- "eslint-plugin-prettier": "3.1.2",
27
- "eslint-plugin-vue": "5.2.2",
28
- "prettier": "1.19.1",
29
- "vue-template-compiler": "2.6.10"
18
+ "@babel/eslint-parser": "7.17.0",
19
+ "@vue/cli-plugin-babel": "4.5.15",
20
+ "@vue/cli-plugin-eslint": "4.5.15",
21
+ "@vue/cli-service": "4.5.15",
22
+ "@vue/eslint-config-prettier": "6.0.0",
23
+ "babel-eslint": "10.1.0",
24
+ "eslint": "6.7.2",
25
+ "eslint-config-algolia": "20.0.0",
26
+ "eslint-plugin-import": "2.25.4",
27
+ "eslint-plugin-prettier": "3.3.1",
28
+ "eslint-plugin-vue": "6.2.2",
29
+ "prettier": "2.2.1",
30
+ "vue-template-compiler": "2.6.11"
30
31
  },
31
32
  "browserslist": [
32
33
  "> 1%",
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ indent_style = space
6
+ indent_size = 2
7
+ end_of_line = lf
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
@@ -0,0 +1,23 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ *.local
14
+
15
+ # Editor directories and files
16
+ .vscode
17
+ .idea
18
+ .DS_Store
19
+ *.suo
20
+ *.ntvs*
21
+ *.njsproj
22
+ *.sln
23
+ *.sw?
@@ -0,0 +1,5 @@
1
+ {
2
+ "singleQuote": true,
3
+ "proseWrap": "never",
4
+ "trailingComma": "es5"
5
+ }
@@ -0,0 +1,18 @@
1
+ const install = require('../../tasks/node/install');
2
+ const teardown = require('../../tasks/node/teardown');
3
+
4
+ module.exports = {
5
+ category: 'Web',
6
+ libraryName: 'vue-instantsearch',
7
+ supportedVersion: '>= 4.3.3 < 5.0.0',
8
+ flags: {
9
+ dynamicWidgets: '>=4.2.0',
10
+ },
11
+ templateName: 'vue-instantsearch-vue3',
12
+ appName: 'vue-instantsearch-app',
13
+ keywords: ['algolia', 'InstantSearch', 'Vue', 'vue-instantsearch'],
14
+ tasks: {
15
+ install,
16
+ teardown,
17
+ },
18
+ };
@@ -0,0 +1,21 @@
1
+ # {{name}}
2
+
3
+ _This project was generated with [create-instantsearch-app](https://github.com/algolia/create-instantsearch-app) by [Algolia](https://algolia.com)._
4
+
5
+ ## Get started
6
+
7
+ To run this project locally, install the dependencies and run the local server:
8
+
9
+ ```sh
10
+ npm install
11
+ npm run dev
12
+ ```
13
+
14
+ Alternatively, you may use [Yarn](https://http://yarnpkg.com/):
15
+
16
+ ```sh
17
+ yarn
18
+ yarn dev
19
+ ```
20
+
21
+ Open http://localhost:3000 to see your app.
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html>
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="icon" href="/favicon.png" />
8
+ <!--
9
+ Do not use @7 in production, use a complete version like x.x.x, see website for latest version:
10
+ https://www.algolia.com/doc/guides/building-search-ui/installation/react/#load-the-style
11
+ -->
12
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/algolia-min.css">
13
+ <title>{{name}}</title>
14
+ </head>
15
+ <body>
16
+ <div id="app"></div>
17
+ <script type="module" src="/src/main.js"></script>
18
+ </body>
19
+ </html>
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "vite build",
8
+ "preview": "vite preview"
9
+ },
10
+ "dependencies": {
11
+ "algoliasearch": "4.12.1",
12
+ "vue": "3.2.25",
13
+ "vue-instantsearch": "{{libraryVersion}}"
14
+ },
15
+ "devDependencies": {
16
+ "@vitejs/plugin-vue": "2.2.0",
17
+ "@vitejs/plugin-vue-jsx": "1.3.7",
18
+ "vite": "2.8.0"
19
+ }
20
+ }
@@ -0,0 +1,161 @@
1
+ <template>
2
+ <div>
3
+ <header class="header">
4
+ <h1 class="header-title">
5
+ <a href="/">{{ name }}</a>
6
+ </h1>
7
+ <p class="header-subtitle">
8
+ using
9
+ <a href="https://github.com/algolia/vue-instantsearch">
10
+ Vue InstantSearch
11
+ </a>
12
+ </p>
13
+ </header>
14
+
15
+ <div class="container">
16
+ <ais-instant-search
17
+ :search-client="searchClient"
18
+ index-name="{{indexName}}"
19
+ >
20
+ <div class="search-panel">
21
+ <div class="search-panel__filters">
22
+ {{#if flags.dynamicWidgets}}
23
+ <ais-dynamic-widgets>
24
+ {{#each attributesForFaceting}}
25
+ <ais-refinement-list attribute="{{this}}" />
26
+ {{/each}}
27
+ </ais-dynamic-widgets>
28
+ {{else}}
29
+ {{#each attributesForFaceting}}
30
+ <ais-refinement-list attribute="{{this}}" />
31
+ {{/each}}
32
+ {{/if}}
33
+ </div>
34
+
35
+ <div class="search-panel__results">
36
+ <div class="searchbox">
37
+ <ais-search-box placeholder="{{searchPlaceholder}}" />
38
+ </div>
39
+ {{#if attributesToDisplay}}
40
+ <ais-hits>
41
+ <template v-slot:item="{ item }">
42
+ <article>
43
+ <h1>
44
+ <ais-highlight
45
+ :hit="item"
46
+ attribute="{{attributesToDisplay.[0]}}"
47
+ />
48
+ </h1>
49
+ {{#each attributesToDisplay}}
50
+ {{#unless @first}}
51
+ <p>
52
+ <ais-highlight :hit="item" attribute="{{this}}" />
53
+ </p>
54
+ {{/unless}}
55
+ {{/each}}
56
+ </article>
57
+ </template>
58
+ </ais-hits>
59
+ {{else}}
60
+ <ais-hits />
61
+ {{/if}}
62
+
63
+ <div class="pagination">
64
+ <ais-pagination />
65
+ </div>
66
+ </div>
67
+ </div>
68
+ </ais-instant-search>
69
+ </div>
70
+ </div>
71
+ </template>
72
+
73
+ <script>
74
+ import algoliasearch from 'algoliasearch/lite';
75
+
76
+ export default {
77
+ data() {
78
+ return {
79
+ searchClient: algoliasearch('{{appId}}', '{{apiKey}}'),
80
+ };
81
+ },
82
+ };
83
+ </script>
84
+
85
+ <style>
86
+ body,
87
+ h1 {
88
+ margin: 0;
89
+ padding: 0;
90
+ }
91
+
92
+ body {
93
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
94
+ Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
95
+ }
96
+
97
+ h1 {
98
+ font-size: 1rem;
99
+ }
100
+
101
+ em {
102
+ background: cyan;
103
+ font-style: normal;
104
+ }
105
+
106
+ .header {
107
+ display: flex;
108
+ align-items: center;
109
+ min-height: 50px;
110
+ padding: 0.5rem 1rem;
111
+ background-image: linear-gradient(to right, #4dba87, #2f9088);
112
+ color: #fff;
113
+ margin-bottom: 1rem;
114
+ }
115
+
116
+ .header a {
117
+ color: #fff;
118
+ text-decoration: none;
119
+ }
120
+
121
+ .header-title {
122
+ font-size: 1.2rem;
123
+ font-weight: normal;
124
+ }
125
+
126
+ .header-title::after {
127
+ content: ' ▸ ';
128
+ padding: 0 0.5rem;
129
+ }
130
+
131
+ .header-subtitle {
132
+ font-size: 1.2rem;
133
+ }
134
+
135
+ .container {
136
+ max-width: 1200px;
137
+ margin: 0 auto;
138
+ padding: 1rem;
139
+ }
140
+
141
+ .search-panel {
142
+ display: flex;
143
+ }
144
+
145
+ .search-panel__filters {
146
+ flex: 1;
147
+ }
148
+
149
+ .search-panel__results {
150
+ flex: 3;
151
+ }
152
+
153
+ .searchbox {
154
+ margin-bottom: 2rem;
155
+ }
156
+
157
+ .pagination {
158
+ margin: 2rem auto;
159
+ text-align: center;
160
+ }
161
+ </style>
@@ -0,0 +1,7 @@
1
+ import { createApp } from 'vue';
2
+ import InstantSearch from 'vue-instantsearch/vue3/es';
3
+ import App from './App.vue';
4
+
5
+ const app = createApp(App);
6
+ app.use(InstantSearch);
7
+ app.mount('#app');
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from 'vite';
2
+ import vue from '@vitejs/plugin-vue';
3
+ import vueJsx from '@vitejs/plugin-vue-jsx';
4
+
5
+ // https://vitejs.dev/config/
6
+ export default defineConfig({
7
+ plugins: [vue(), vueJsx()],
8
+ });