Skip to content
This repository was archived by the owner on Dec 16, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
444 changes: 444 additions & 0 deletions e2e/__snapshots__/templates.test.js.snap

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/api/__tests__/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ exports[`Options with invalid name throws 1`] = `
- name can only contain URL-friendly characters"
`;

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.js, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
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.js, 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"`;

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.js, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
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.js, 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"`;

exports[`Options without path throws 1`] = `"The option \`path\` is required."`;

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.js, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
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.js, 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"`;
2 changes: 2 additions & 0 deletions src/templates/React InstantSearch widget/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/dist
node_modules/
13 changes: 13 additions & 0 deletions src/templates/React InstantSearch widget/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// eslint-disable-next-line import/no-commonjs
module.exports = {
extends: ['algolia', 'algolia/jest', 'algolia/react', 'algolia/typescript'],
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
'jest/expect-expect': 'off',
},
settings: {
react: {
version: 'detect',
},
},
};
5 changes: 5 additions & 0 deletions src/templates/React InstantSearch widget/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
5 changes: 5 additions & 0 deletions src/templates/React InstantSearch widget/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"singleQuote": true,
"proseWrap": "never",
"trailingComma": "es5"
}
21 changes: 21 additions & 0 deletions src/templates/React InstantSearch widget/.template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const install = require('../../tasks/node/install');
const teardown = require('../../tasks/node/teardown');

module.exports = {
category: 'Widget',
libraryName: 'react-instantsearch',
supportedVersion: '>= 6.0.0 < 7.0.0',
templateName: 'react-instantsearch-widget',
appName: 'react-instantsearch-app',
keywords: [
'algolia',
'InstantSearch',
'React',
'react-instantsearch',
'widget',
],
tasks: {
install,
teardown,
},
};
96 changes: 96 additions & 0 deletions src/templates/React InstantSearch widget/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# {{name}}

_This project was generated with [create-instantsearch-app](https://github.com/algolia/create-instantsearch-app) by [Algolia](https://algolia.com)._

{{ description }}

## Install

```bash
npm install {{ packageName }}
# or
yarn add {{ packageName }}
```

## Widget

### Usage

```jsx
import instantsearch from 'instantsearch.js';
import algoliasearch from 'algoliasearch/lite';
import { {{ pascalCaseName }} } from '{{ packageName }}';

const searchClient = algoliasearch('appId', 'apiKey');

const App = () => (
<InstantSearch searchClient={searchClient} indexName="indexName">
<{{ pascalCaseName }} />
</InstantSearch>
);
```

## Connector

### Usage

```jsx
import { connect{{ pascalCaseName }} } from '{{ packageName }}';

// 1. Create a render function
const Render{{ pascalCaseName }} = (renderOptions, isFirstRender) => {
// Rendering logic
};

// 2. Create the custom widget
const Custom{{ pascalCaseName }} = connect{{ pascalCaseName }}(
Render{{ pascalCaseName }}
);

// 3. Instantiate
const App = () => (
<InstantSearch searchClient={searchClient} indexName="indexName">
<Custom{{ pascalCaseName }} />
</InstantSearch>
);
```

## Test

```bash
npm test
# or
yarn test
```

## Build

```bash
npm run build
# or
yarn build
```

## Release

```bash
npm run release
# or
yarn release
```

### First Release

```bash
npm run release -- --first-release
# or
yarn release --first-release
```

This will tag a release without bumping the version.

When you are ready, push the git tag and run `npm publish`.

If you want to publish it as a public scoped package, run `npm publish --access public` the first time.

[To know more about `standard-version`, read this →](https://github.com/conventional-changelog/standard-version#cli-usage)
8 changes: 8 additions & 0 deletions src/templates/React InstantSearch widget/babel.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// eslint-disable-next-line import/no-commonjs
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-react',
'@babel/preset-typescript',
],
};
12 changes: 12 additions & 0 deletions src/templates/React InstantSearch widget/example/index.html.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ packageName }} | example</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./index.tsx"></script>
</body>
</html>
22 changes: 22 additions & 0 deletions src/templates/React InstantSearch widget/example/index.tsx.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import algoliasearch from 'algoliasearch/lite';
import React from 'react';
import ReactDOM from 'react-dom';
import { InstantSearch, SearchBox, Hits } from 'react-instantsearch-dom';

import { {{ pascalCaseName }} } from '../src';

const searchClient = algoliasearch(
'latency',
'6be0576ff61c053d5f9a3225e2a90f76'
);

ReactDOM.render(
<React.StrictMode>
<InstantSearch indexName="instant_search" searchClient={searchClient}>
<{{ pascalCaseName }} />
<SearchBox />
<Hits />
</InstantSearch>
</React.StrictMode>,
document.getElementById('root')
);
80 changes: 80 additions & 0 deletions src/templates/React InstantSearch widget/package.json.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
"name": "{{ packageName }}",
"version": "1.0.0",
"description": "{{ description }}",
"keywords": [
"instantsearch-widget",
"instantsearch",
"react-instantsearch",
"react-instantsearch-widget-{{ name }}",
"widget",
"connector",
"algolia"
],
"license": "MIT",
"main": "./dist/index.cjs.js",
"module": "./dist/index.es.js",
"exports": {
"import": "./dist/index.es.js",
"require": "./dist/index.cjs.js"
},
"jsdelivr": "./dist/index.umd.js",
"unpkg": "./dist/index.umd.js",
"types": "./dist/index.d.ts",
"type": "module",
"files": [
"dist"
],
"scripts": {
"start": "vite example",
"prebuild": "rm -rf dist",
"build": "vite build && npm run build:types",
"build:types": "tsc -p tsconfig.declaration.json",
"lint": "eslint --ext .js,.ts,.tsx .",
"lint:fix": "npm run lint --fix",
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
"test:watch": "npm test -- --watch",
"test:types": "tsc",
"prerelease": "npm run build",
"release": "standard-version"
},
"dependencies": {
"algoliasearch": "^4.9.1",
"react": "^16.8.0",
"react-dom": "^16.8.0",
"react-instantsearch-dom": "^6.11.0"
},
"devDependencies": {
"@babel/core": "7.14.3",
"@babel/preset-env": "7.14.2",
"@babel/preset-react": "7.13.13",
"@babel/preset-typescript": "7.13.0",
"@testing-library/react": "11.2.7",
"@types/jest": "26.0.23",
"@types/node": "15.3.0",
"@types/react": "17.0.0",
"@types/react-dom": "17.0.0",
"@types/react-instantsearch-dom": "6.10.0",
"@typescript-eslint/eslint-plugin": "4.24.0",
"@typescript-eslint/parser": "4.24.0",
"@vitejs/plugin-react-refresh": "1.3.1",
"babel-eslint": "10.1.0",
"babel-jest": "26.6.3",
"eslint": "7.26.0",
"eslint-config-algolia": "18.0.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-eslint-comments": "3.2.0",
"eslint-plugin-import": "2.23.2",
"eslint-plugin-jest": "24.3.6",
"eslint-plugin-jsdoc": "34.8.1",
"eslint-plugin-jsx-a11y": "6.4.1",
"eslint-plugin-prettier": "3.4.0",
"eslint-plugin-react": "7.23.2",
"eslint-plugin-react-hooks": "4.2.0",
"jest": "26.6.3",
"prettier": "2.3.0",
"standard-version": "9.3.0",
"typescript": "4.2.4",
"vite": "2.3.3"
}
}
3 changes: 3 additions & 0 deletions src/templates/React InstantSearch widget/src/index.tsx.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { connect{{ pascalCaseName }} } from './lib/connector';
export { {{ pascalCaseName }}Component } from './lib/component';
export { {{ pascalCaseName }} } from './lib/widget';
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { render } from '@testing-library/react';
import React from 'react';
import { InstantSearch, Hits } from 'react-instantsearch-dom';

import { {{ pascalCaseName }} } from '../widget';

const runAllMicroTasks = (): Promise<void> => new Promise(setImmediate);

describe('nothing', () => {
it('tests nothing', async () => {
const searchClient = {
search(_requests: any[]) {
return Promise.resolve({
results: [
{
hits:
[
{
objectID: 'a',
name: 'test',
},
],
},
],
});
},
};

const { debug } = render(
<InstantSearch indexName="test_index" searchClient={searchClient}>
<{{ pascalCaseName }} />
<Hits hitComponent={({ hit }: { hit: any }) => hit.name} />
</InstantSearch>
);

await runAllMicroTasks();
debug();
});
});
15 changes: 15 additions & 0 deletions src/templates/React InstantSearch widget/src/lib/component.tsx.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';

import type { ProvidedProps } from './connector'

type Props = ProvidedProps & {
refine: () => {}
};

export const {{ pascalCaseName }}Component = ({}: Props) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we want to do? Here the Props is loose. It's not connected with the return of getProvidedProps from the connector. Do we want to type this template at that level? Or this is okay enough?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can it not be imported from the connector file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type of getProvidedProps won't include refine function, but the Props here in the component will. And we might want to specify in the connector as a generic, what kind of type the refine function will take. So these thoughts kept leading to another, and I wonder maybe the current version is incomplete but simple to start with.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could it be ReturnType & { refine } or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CleanShot 2021-06-08 at 16 44 05@2x

what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return (
<div>
{/* TODO: render something */}
</div>
);
};
32 changes: 32 additions & 0 deletions src/templates/React InstantSearch widget/src/lib/connector.ts.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { createConnector } from 'react-instantsearch-dom';

export type ProvidedProps = {
// TODO: fill props that are returned by `getProvidedProps`
}

export const connect{{ pascalCaseName }} = createConnector({
displayName: '{{ pascalCaseName }}',

getProvidedProps(props, searchState, searchResults): ProvidedProps {
return {
// TODO: return a props for the component
};
},

refine(props, searchState, nextRefinement) {
return {
// TODO: return a next searchState
};
},

cleanUp(props, searchState, context) {
return {
// TODO: return a searchState where this widget is removed from the widget tree
};
},

getSearchParameters(searchParameters, props, searchState) {
// TODO: update and return the searchParameters
return searchParameters;
},
});
14 changes: 14 additions & 0 deletions src/templates/React InstantSearch widget/src/lib/widget.tsx.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { {{ pascalCaseName }}Component } from './component';
import { connect{{ pascalCaseName }} } from './connector';

import type { ElementType } from 'react';

type WidgetParams = {
/**
* Placeholder text for input element.
*/
placeholder?: string;
};

export const {{ pascalCaseName }}: ElementType<WidgetParams> =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure ElementType is the right one, but anything else like ReactElement, Component, etc didn't work.

By "didn't work", I mean TS gave me error messages like

CleanShot 2021-05-25 at 16 48 25@2x

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as far as I can tell ElementType is correct

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could also be ReactNode, did you try that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, ReactNode, ReactElement, all didn't work

connect{{ pascalCaseName }}({{ pascalCaseName }}Component);
Loading