Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

Commit

Permalink
feat: custom root index (#792)
Browse files Browse the repository at this point in the history
* feat(createIndex): support root as props

* refactor(createIndex): rewrite as a functionnal component

* feat(stories): add Index with custom root

* fix(createInstantSearch): really test the root prop

* docs(Index): add root
  • Loading branch information
samouss authored Jan 4, 2018
1 parent a9cd26b commit d793b0a
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 59 deletions.
1 change: 1 addition & 0 deletions packages/react-instantsearch/src/core/Index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import React, { Component, Children } from 'react';
* @kind widget
* @name <Index>
* @propType {string} indexName - index in which to search.
* @propType {{ Root: string|function, props: object }} [root] - Use this to customize the root element. Default value: `{ Root: 'div' }`
* @example
* import {InstantSearch, Index, SearchBox, Hits, Configure} from 'react-instantsearch/dom';
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`createIndex expect to create Index with a custom root props 1`] = `
<Index
indexName="name"
root={
Object {
"Root": "span",
"props": Object {
"style": Object {
"flex": 1,
},
},
}
}
/>
`;

exports[`createIndex wraps Index 1`] = `
Object {
"children": undefined,
"indexName": "name",
"root": Object {
"Root": "div",
},
}
<Index
indexName="name"
root={
Object {
"Root": "div",
}
}
/>
`;
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`createInstantSearch expect to create InstantSearch with a custom root props 1`] = `
Object {
"children": undefined,
"createURL": undefined,
"indexName": "name",
"onSearchParameters": undefined,
"onSearchStateChange": undefined,
"refresh": false,
"resultsState": undefined,
"root": Object {
"Root": "span",
"props": Object {
"style": Object {
"flex": 1,
},
},
},
"searchParameters": undefined,
"searchState": undefined,
"stalledSearchDelay": 200,
}
`;

exports[`createInstantSearch wraps InstantSearch 1`] = `
Object {
"children": undefined,
Expand Down
45 changes: 25 additions & 20 deletions packages/react-instantsearch/src/core/createIndex.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
import React from 'react';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Index from './Index';

/**
* Creates a specialized root Index component. It accepts
* a specification of the root Element.
* @param {object} root - the defininition of the root of an Index sub tree.
* @returns {object} a Index root
* @param {object} defaultRoot - the defininition of the root of an Index sub tree.
* @return {object} a Index root
*/
export default function createIndex(root) {
return class CreateIndex extends Component {
static propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]),
indexName: PropTypes.string.isRequired,
};
const createIndex = defaultRoot => {
const CreateIndex = ({ indexName, root, children }) => (
<Index indexName={indexName} root={root}>
{children}
</Index>
);

render() {
return (
<Index indexName={this.props.indexName} root={root}>
{this.props.children}
</Index>
);
}
CreateIndex.propTypes = {
indexName: PropTypes.string.isRequired,
root: PropTypes.shape({
Root: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
props: PropTypes.object,
}),
children: PropTypes.node,
};
}

CreateIndex.defaultProps = {
root: defaultRoot,
};

return CreateIndex;
};

export default createIndex;
25 changes: 20 additions & 5 deletions packages/react-instantsearch/src/core/createIndex.test.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
/* eslint-env jest, jasmine */
/* eslint-disable no-console */
import React from 'react';
import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });

import createIndex from './createIndex';
import Index from './Index';

Enzyme.configure({ adapter: new Adapter() });

describe('createIndex', () => {
const CustomIndex = createIndex({ Root: 'div' });

it('wraps Index', () => {
const wrapper = shallow(<CustomIndex indexName="name" />);
expect(wrapper.is(Index)).toBe(true);
expect(wrapper.props()).toMatchSnapshot();
expect(wrapper).toMatchSnapshot();
});

it('expect to create Index with a custom root props', () => {
const root = {
Root: 'span',
props: {
style: {
flex: 1,
},
},
};

const wrapper = shallow(<CustomIndex indexName="name" root={root} />);

expect(wrapper.is(Index)).toBe(true);
expect(wrapper.props().root).toEqual(root);
expect(wrapper).toMatchSnapshot();
});
});
36 changes: 10 additions & 26 deletions packages/react-instantsearch/src/core/createInstantSearch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,16 @@ Enzyme.configure({ adapter: new Adapter() });
describe('createInstantSearch', () => {
const algoliaClient = { addAlgoliaAgent: jest.fn() };
const algoliaClientFactory = jest.fn(() => algoliaClient);
const createCustomInstantSearch = root =>
createInstantSearch(algoliaClientFactory, {
Root: 'div',
...root,
});
const CustomInstantSearch = createInstantSearch(algoliaClientFactory, {
Root: 'div',
});

beforeEach(() => {
algoliaClient.addAlgoliaAgent.mockClear();
algoliaClientFactory.mockClear();
});

it('wraps InstantSearch', () => {
const CustomInstantSearch = createCustomInstantSearch();

const wrapper = shallow(
<CustomInstantSearch appId="app" apiKey="key" indexName="name" />
);
Expand All @@ -37,8 +33,6 @@ describe('createInstantSearch', () => {
});

it('creates an algolia client using the provided factory', () => {
const CustomInstantSearch = createCustomInstantSearch();

shallow(<CustomInstantSearch appId="app" apiKey="key" indexName="name" />);

expect(algoliaClientFactory).toHaveBeenCalledTimes(1);
Expand All @@ -50,8 +44,6 @@ describe('createInstantSearch', () => {
});

it('updates the algoliaClient when appId or apiKey changes', () => {
const CustomInstantSearch = createCustomInstantSearch();

const wrapper = shallow(
<CustomInstantSearch appId="app" apiKey="key" indexName="name" />
);
Expand All @@ -65,8 +57,6 @@ describe('createInstantSearch', () => {
});

it('uses the provided algoliaClient', () => {
const CustomInstantSearch = createCustomInstantSearch();

const wrapper = shallow(
<CustomInstantSearch algoliaClient={algoliaClient} indexName="name" />
);
Expand All @@ -77,7 +67,6 @@ describe('createInstantSearch', () => {
});

it('updates the algoliaClient when provided algoliaClient is passed down', () => {
const CustomInstantSearch = createCustomInstantSearch();
const newAlgoliaClient = {
addAlgoliaAgent: jest.fn(),
};
Expand All @@ -97,28 +86,23 @@ describe('createInstantSearch', () => {
});

it('expect to create InstantSearch with a custom root props', () => {
const CustomInstantSearch = createCustomInstantSearch({
const root = {
Root: 'span',
props: {
style: {
flex: 1,
},
},
});
};

const wrapper = shallow(
<CustomInstantSearch algoliaClient={algoliaClient} indexName="name" />
<CustomInstantSearch indexName="name" root={root} />
);

expect(algoliaClient.addAlgoliaAgent).toHaveBeenCalledTimes(1);
// eslint-disable-next-line no-shadow, no-unused-vars
const { algoliaClient, ...propsWithoutClient } = wrapper.props();

expect(wrapper.props().root).toEqual({
Root: 'span',
props: {
style: {
flex: 1,
},
},
});
expect(wrapper.props().root).toEqual(root);
expect(propsWithoutClient).toMatchSnapshot();
});
});
32 changes: 31 additions & 1 deletion stories/MultiIndex.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
connectStateResults,
} from '../packages/react-instantsearch/connectors';
import Autosuggest from 'react-autosuggest';
import { displayName, filterProps } from './util';

const stories = storiesOf('<Index>', module);

Expand Down Expand Up @@ -166,7 +167,36 @@ stories
<Pagination />
</Index>
</InstantSearch>
));
))
.addWithJSX(
'with custom root',
() => (
<InstantSearch
appId="latency"
apiKey="6be0576ff61c053d5f9a3225e2a90f76"
indexName="ikea"
>
<SearchBox />
<Index
indexName="products"
root={{
Root: 'div',
props: {
style: {
background: 'linear-gradient(80deg, #00D8FF, #00A7FF)',
},
},
}}
>
<CustomProducts />
</Index>
</InstantSearch>
),
{
displayName,
filterProps,
}
);

const AutoComplete = connectAutoComplete(
({ hits, currentRefinement, refine }) => (
Expand Down

0 comments on commit d793b0a

Please sign in to comment.