Skip to content
This repository has been archived by the owner on Jul 19, 2019. It is now read-only.

Commit

Permalink
Add renderWrapper prop
Browse files Browse the repository at this point in the history
  • Loading branch information
Johannes Reuter committed Feb 25, 2018
1 parent 41388f7 commit 1e42ec1
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ We try to follow [http://keepachangelog.com/](http://keepachangelog.com/) recomm

## [Unreleased]
_(add items here for easier creation of next log entry)_
### Added
- `props.renderWrapper` which allows a custom rendering function for the wrapper element of input and menu

## [1.8.1] - 2018-02-11
### Fixed
Expand Down
7 changes: 7 additions & 0 deletions examples/custom-menu/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ class App extends React.Component {
) : items}
</div>
)}
renderWrapper={(wrapperStyles, wrapperProps, renderedInput, renderedMenu, renderedDebugInfo) => (
<span style = {{ ...wrapperStyles }} {...wrapperProps}>
Enter value here: {renderedInput}
{renderedMenu}
{renderedDebugInfo}
</span>
)}
isItemSelectable={(item) => !item.header}
/>
</div>
Expand Down
62 changes: 42 additions & 20 deletions lib/Autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,21 @@ class Autocomplete extends React.Component {
* will win if it contains a `style` entry.
*/
wrapperStyle: PropTypes.object,
/**
* Arguments: `wrapperStyles: Object, wrapperProps: Object,
* renderedInput: Any, renderedMenu: Any`
*
* Invoked to generate the wrapper element. The `wrapperStyles` and
* `wrapperProps` objects are the corresponding properties of the
* `<Autocomplete />` component itself.
* `renderedInput` and `renderedMenu` are the generated input and
* menu elements.
* The default implementation uses a div-element as the wrapper with input
* and menu as direct children. You can use this function to change the
* wrapper, e.g. by using an inline-element like span or omit it completely
* by using a fragment (supported from react version 16).
*/
renderWrapper: PropTypes.func,
/**
* Whether or not to automatically highlight the top match in the dropdown
* menu.
Expand Down Expand Up @@ -175,6 +190,13 @@ class Autocomplete extends React.Component {
renderMenu(items, value, style) {
return <div style={{ ...style, ...this.menuStyle }} children={items}/>
},
renderWrapper(wrapperStyle, wrapperProps, renderedInput, renderedMenu, renderedDebugInfo) {
return (<div style={{ ...wrapperStyle }} {...wrapperProps}>
{renderedInput}
{renderedMenu}
{renderedDebugInfo}
</div>)
},
menuStyle: {
borderRadius: '3px',
boxShadow: '0 2px 12px rgba(0, 0, 0, 0.1)',
Expand Down Expand Up @@ -570,29 +592,29 @@ class Autocomplete extends React.Component {

const { inputProps } = this.props
const open = this.isOpen()
return (
<div style={{ ...this.props.wrapperStyle }} {...this.props.wrapperProps}>
{this.props.renderInput({
...inputProps,
role: 'combobox',
'aria-autocomplete': 'list',
'aria-expanded': open,
autoComplete: 'off',
ref: this.exposeAPI,
onFocus: this.handleInputFocus,
onBlur: this.handleInputBlur,
onChange: this.handleChange,
onKeyDown: this.composeEventHandlers(this.handleKeyDown, inputProps.onKeyDown),
onClick: this.composeEventHandlers(this.handleInputClick, inputProps.onClick),
value: this.props.value,
})}
{open && this.renderMenu()}
{this.props.debug && (
return this.props.renderWrapper(
this.props.wrapperStyle,
this.props.wrapperProps,
this.props.renderInput({
...inputProps,
role: 'combobox',
'aria-autocomplete': 'list',
'aria-expanded': open,
autoComplete: 'off',
ref: this.exposeAPI,
onFocus: this.handleInputFocus,
onBlur: this.handleInputBlur,
onChange: this.handleChange,
onKeyDown: this.composeEventHandlers(this.handleKeyDown, inputProps.onKeyDown),
onClick: this.composeEventHandlers(this.handleInputClick, inputProps.onClick),
value: this.props.value,
}),
open && this.renderMenu(),
this.props.debug && (
<pre style={{ marginLeft: 300 }}>
{JSON.stringify(this._debugStates.slice(Math.max(0, this._debugStates.length - 5), this._debugStates.length), null, 2)}
</pre>
)}
</div>
)
)
}
}
Expand Down
22 changes: 22 additions & 0 deletions lib/__tests__/Autocomplete-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,28 @@ describe('Autocomplete mouse event handlers', () => {
})
})

describe('Autocomplete.props.renderWrapper', () => {
it('should be invoked in `render` to render the root element', () => {
const renderWrapper = jest.fn((wrapperStyles, wrapperProps, renderedInput, renderedMenu, renderedDebugInfo) => {
expect(wrapperStyles).toMatchSnapshot()
expect(wrapperProps).toMatchSnapshot()
return (
<span>
{renderedInput}
{renderedMenu}
{renderedDebugInfo}
</span>
)
})
const tree = shallow(AutocompleteComponentJSX({
value: 'pants',
renderWrapper,
}))
expect(renderWrapper).toHaveBeenCalledTimes(1)
expect(tree).toMatchSnapshot()
})
})

describe('Autocomplete.props.renderInput', () => {
it('should be invoked in `render` to create the <input> element', () => {
const renderInput = jest.fn(props => {
Expand Down
25 changes: 25 additions & 0 deletions lib/__tests__/__snapshots__/Autocomplete-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,28 @@ exports[`Autocomplete.props.renderInput should be invoked in \`render\` to creat
</div>
</div>
`;
exports[`Autocomplete.props.renderWrapper should be invoked in \`render\` to render the root element 1`] = `
Object {
"display": "inline-block",
}
`;
exports[`Autocomplete.props.renderWrapper should be invoked in \`render\` to render the root element 2`] = `Object {}`;
exports[`Autocomplete.props.renderWrapper should be invoked in \`render\` to render the root element 3`] = `
<span>
<input
aria-autocomplete="list"
aria-expanded={false}
autoComplete="off"
onBlur={[Function]}
onChange={[Function]}
onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
role="combobox"
value="pants"
/>
</span>
`;

0 comments on commit 1e42ec1

Please sign in to comment.