diff --git a/README.md b/README.md
index aa6b5e0e..3668def3 100644
--- a/README.md
+++ b/README.md
@@ -175,6 +175,7 @@ class Example extends React.Component {
| [`getSectionSuggestions`](#get-section-suggestions-prop) | Function | ✓ when `multiSection={true}` | Implement it to teach Autosuggest where to find the suggestions for every section. |
| [`renderInputComponent`](#render-input-component-prop) | Function | | Use it only if you need to customize the rendering of the input. |
| [`renderSuggestionsContainer`](#render-suggestions-container-prop) | Function | | Use it if you want to customize things inside the suggestions container beyond rendering the suggestions themselves. |
+| [`renderSectionContainer`](#render-sections-container-prop) | Function | | Use it if you want to customize things inside the sections container beyond rendering the sections themselves. |
| [`theme`](#theme-prop) | Object | | Use your imagination to style the Autosuggest. |
| [`id`](#id-prop) | String | | Use it only if you have multiple Autosuggest components on a page. |
@@ -602,6 +603,39 @@ function renderSuggestionsContainer({ containerProps, children }) {
}
```
+
+
+#### renderSectionContainer (optional)
+
+You shouldn't specify `renderSectionContainer` unless you want to customize the content or behaviour of the sections container beyond rendering the sections themselves. For example, you might want to add a custom text before/after the sections list.
+
+The signature is:
+
+```js
+function renderSectionContainer({ containerProps, children, query })
+```
+
+where:
+
+- `containerProps` - props that you MUST pass to the topmost element that is returned from `renderSectionContainer`.
+- `children` - the sections themselves. It's up to you where to render them.
+- `query` - Same as `query` in [`renderSuggestion`](#render-suggestion-prop).
+
+For example:
+
+```js
+function renderSectionContainer({ containerProps, children, query }) {
+ return (
+
+ {children}
+
+ Press Enter to search {query}
+
+
+ );
+}
+```
+
#### theme (optional)
diff --git a/src/Autosuggest.js b/src/Autosuggest.js
index 6f3269da..29260655 100644
--- a/src/Autosuggest.js
+++ b/src/Autosuggest.js
@@ -9,6 +9,9 @@ const defaultShouldRenderSuggestions = (value) => value.trim().length > 0;
const defaultRenderSuggestionsContainer = ({ containerProps, children }) => (
{children}
);
+const defaultRenderSectionContainer = ({ containerProps, children }) => (
+ {children}
+);
const REASON_SUGGESTIONS_REVEALED = 'suggestions-revealed';
const REASON_SUGGESTIONS_UPDATED = 'suggestions-updated';
@@ -47,6 +50,7 @@ export default class Autosuggest extends Component {
onSuggestionHighlighted: PropTypes.func,
renderInputComponent: PropTypes.func,
renderSuggestionsContainer: PropTypes.func,
+ renderSectionContainer: PropTypes.func,
getSuggestionValue: PropTypes.func.isRequired,
renderSuggestion: PropTypes.func.isRequired,
inputProps: (props, propName) => {
@@ -100,6 +104,7 @@ export default class Autosuggest extends Component {
static defaultProps = {
renderSuggestionsContainer: defaultRenderSuggestionsContainer,
+ renderSectionContainer: defaultRenderSectionContainer,
shouldRenderSuggestions: defaultShouldRenderSuggestions,
alwaysRenderSuggestions: false,
multiSection: false,
@@ -545,6 +550,17 @@ export default class Autosuggest extends Component {
});
};
+ renderSectionContainer = ({ containerProps, children, section }) => {
+ const { renderSectionContainer } = this.props;
+
+ return renderSectionContainer({
+ containerProps,
+ children,
+ query: this.getQuery(),
+ section,
+ });
+ };
+
render() {
const {
suggestions,
@@ -803,6 +819,7 @@ export default class Autosuggest extends Component {
items={items}
renderInputComponent={renderInputComponent}
renderItemsContainer={this.renderSuggestionsContainer}
+ renderSectionContainer={this.renderSectionContainer}
renderItem={renderSuggestion}
renderItemData={renderSuggestionData}
renderSectionTitle={renderSectionTitle}
diff --git a/src/Autowhatever.js b/src/Autowhatever.js
index fe2ee8e7..4bf6b9a4 100644
--- a/src/Autowhatever.js
+++ b/src/Autowhatever.js
@@ -10,6 +10,9 @@ const defaultRenderInputComponent = (props) => ;
const defaultRenderItemsContainer = ({ containerProps, children }) => (
{children}
);
+const defaultRenderSectionContainer = ({ containerProps, children }) => (
+ {children}
+);
const defaultTheme = {
container: 'react-autowhatever__container',
containerOpen: 'react-autowhatever__container--open',
@@ -33,6 +36,7 @@ export default class Autowhatever extends Component {
multiSection: PropTypes.bool, // Indicates whether a multi section layout should be rendered.
renderInputComponent: PropTypes.func, // When specified, it is used to render the input element.
renderItemsContainer: PropTypes.func, // Renders the items container.
+ renderSectionContainer: PropTypes.func, // Renders the section container.
items: PropTypes.array.isRequired, // Array of items or sections to render.
renderItem: PropTypes.func, // This function renders a single item.
renderItemData: PropTypes.object, // Arbitrary data that will be passed to renderItem()
@@ -59,6 +63,7 @@ export default class Autowhatever extends Component {
multiSection: false,
renderInputComponent: defaultRenderInputComponent,
renderItemsContainer: defaultRenderItemsContainer,
+ renderSectionContainer: defaultRenderSectionContainer,
renderItem: () => {
throw new Error('`renderItem` must be provided');
},
@@ -191,6 +196,7 @@ export default class Autowhatever extends Component {
items,
renderItem,
renderItemData,
+ renderSectionContainer,
renderSectionTitle,
highlightedSectionIndex,
highlightedItemIndex,
@@ -203,41 +209,41 @@ export default class Autowhatever extends Component {
const isFirstSection = sectionIndex === 0;
// `key` is provided by theme()
- /* eslint-disable react/jsx-key */
- return (
-
-
-
-
- );
- /* eslint-enable react/jsx-key */
+ return renderSectionContainer({
+ section,
+ containerProps: theme(
+ `${sectionKeyPrefix}container`,
+ 'sectionContainer',
+ isFirstSection && 'sectionContainerFirst'
+ ),
+ children: (
+
+
+
+
+ ),
+ });
});
}
diff --git a/test/render-section-container/AutosuggestApp.js b/test/render-section-container/AutosuggestApp.js
new file mode 100644
index 00000000..e9e3f2b1
--- /dev/null
+++ b/test/render-section-container/AutosuggestApp.js
@@ -0,0 +1,95 @@
+import React, { Component } from 'react';
+import sinon from 'sinon';
+import Autosuggest from '../../src/Autosuggest';
+import languages from '../plain-list/languages';
+import { escapeRegexCharacters } from '../../demo/src/components/utils/utils.js';
+
+const getMatchingLanguages = value => {
+ const escapedValue = escapeRegexCharacters(value.trim());
+ const regex = new RegExp('^' + escapedValue, 'i');
+
+ return languages.filter(language => regex.test(language.name));
+};
+
+let app = null;
+
+const onChange = (event, { newValue }) => {
+ app.setState({
+ value: newValue
+ });
+};
+
+const onSuggestionsFetchRequested = ({ value }) => {
+ app.setState({
+ suggestions: [{ title: 'languages', languages: getMatchingLanguages(value) }]
+ });
+};
+
+const onSuggestionsClearRequested = () => {
+ app.setState({
+ suggestions: []
+ });
+};
+
+const getSuggestionValue = suggestion => suggestion.name;
+
+const renderSuggestion = suggestion => suggestion.name;
+
+export const renderSectionContainer = sinon.spy(
+ ({ containerProps, children, query, section }) =>
+
+ Showing results for {query} in {section.title}
+
+ {children}
+
+);
+
+const renderSectionTitle = () => null;
+
+const getSectionSuggestions = section => section.languages;
+
+export default class AutosuggestApp extends Component {
+ constructor() {
+ super();
+
+ app = this;
+
+ this.state = {
+ value: '',
+ suggestions: []
+ };
+ }
+
+ storeAutosuggestReference = autosuggest => {
+ if (autosuggest !== null) {
+ this.input = autosuggest.input;
+ }
+ };
+
+ alwaysRenderSuggestions = () => true;
+
+ render() {
+ const { value, suggestions } = this.state;
+ const inputProps = {
+ value,
+ onChange
+ };
+
+ return (
+
+ );
+ }
+}
diff --git a/test/render-section-container/AutosuggestApp.test.js b/test/render-section-container/AutosuggestApp.test.js
new file mode 100644
index 00000000..08c3314f
--- /dev/null
+++ b/test/render-section-container/AutosuggestApp.test.js
@@ -0,0 +1,46 @@
+import sinon from 'sinon';
+import React from 'react';
+import TestUtils from 'react-dom/test-utils';
+import { expect } from 'chai';
+import {
+ init,
+ childrenMatcher,
+ getInnerHTML,
+ getElementWithClass,
+ setInputValue
+} from '../helpers';
+import AutosuggestApp, { renderSectionContainer } from './AutosuggestApp';
+
+describe('Autosuggest with renderSectionContainer', () => {
+ beforeEach(() => {
+ init(TestUtils.renderIntoDocument( ));
+ renderSectionContainer.resetHistory();
+ setInputValue('c ');
+ });
+
+ it('should render whatever renderSectionContainer returns', () => {
+ expect(getElementWithClass('my-section-container-header')).not.to.equal(
+ null
+ );
+ expect(getInnerHTML(getElementWithClass('my-query'))).to.equal('c');
+ });
+
+ it('should call renderSectionContainer once with the right parameters', () => {
+ expect(renderSectionContainer).to.have.been.calledOnce;
+ expect(renderSectionContainer).to.be.calledWith({
+ containerProps: sinon.match({
+ key: sinon.match.string,
+ className: sinon.match.string,
+ }),
+ children: childrenMatcher,
+ query: 'c',
+ section: sinon.match({
+ title: sinon.match.string,
+ languages: sinon.match.every(sinon.match({
+ name: sinon.match.string,
+ year: sinon.match.number
+ }))
+ })
+ });
+ });
+});