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

feat: custom root index #792

Merged
merged 5 commits into from
Jan 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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