diff --git a/.eslintrc.js b/.eslintrc.js index 6c0194e..d0b2318 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -94,7 +94,7 @@ module.exports = { 'react/style-prop-object': 2, 'react/jsx-boolean-value': [2, 'always'], - 'react/jsx-closing-bracket-location': [2, { 'selfClosing': 'after-props', 'nonEmpty': 'after-props' }], + 'react/jsx-closing-bracket-location': [2, 'tag-aligned'], 'react/jsx-curly-spacing': [2, 'never', { 'allowMultiline': true }], 'react/jsx-equals-spacing': [2, 'never'], 'react/jsx-filename-extension': [2, { 'extensions': ['.js'] }], diff --git a/demo/src/components/App/components/Example0/Example0.js b/demo/src/components/App/components/Example0/Example0.js index 851abf4..bbda170 100644 --- a/demo/src/components/App/components/Example0/Example0.js +++ b/demo/src/components/App/components/Example0/Example0.js @@ -31,7 +31,8 @@ function Example(props) { id={exampleId} items={[]} inputProps={inputProps} - theme={theme} /> + theme={theme} + /> ); diff --git a/demo/src/components/App/components/Example1/Example1.js b/demo/src/components/App/components/Example1/Example1.js index 08c0da5..2d3f4ce 100644 --- a/demo/src/components/App/components/Example1/Example1.js +++ b/demo/src/components/App/components/Example1/Example1.js @@ -50,7 +50,8 @@ function Example(props) { items={items} renderItem={renderItem} inputProps={inputProps} - theme={theme} /> + theme={theme} + /> ); diff --git a/demo/src/components/App/components/Example10/Example10.js b/demo/src/components/App/components/Example10/Example10.js index 7d96044..2854228 100644 --- a/demo/src/components/App/components/Example10/Example10.js +++ b/demo/src/components/App/components/Example10/Example10.js @@ -9,7 +9,7 @@ import SourceCodeLink from 'SourceCodeLink/SourceCodeLink'; const exampleId = '10'; const file = `demo/src/components/App/components/Example${exampleId}/Example${exampleId}.js`; -function CustomInput(props) { +const renderInputComponent = inputProps => { const style = { border: '0 solid green', borderBottomWidth: '1px', @@ -17,23 +17,19 @@ function CustomInput(props) { }; return ( - + ); -} +}; -function mapStateToProps(state) { - return { - value: state[exampleId].value - }; -} +const mapStateToProps = state => ({ + value: state[exampleId].value +}); -function mapDispatchToProps(dispatch) { - return { - onChange: event => dispatch(updateInputValue(exampleId, event.target.value)) - }; -} +const mapDispatchToProps = dispatch => ({ + onChange: event => dispatch(updateInputValue(exampleId, event.target.value)) +}); -function Example(props) { +const Example = props => { const { value, onChange } = props; const inputProps = { placeholder: 'Custom input', @@ -45,14 +41,15 @@ function Example(props) {
+ theme={theme} + />
); -} +}; Example.propTypes = { value: PropTypes.string.isRequired, diff --git a/demo/src/components/App/components/Example2/Example2.js b/demo/src/components/App/components/Example2/Example2.js index 5dd58ea..6597b24 100644 --- a/demo/src/components/App/components/Example2/Example2.js +++ b/demo/src/components/App/components/Example2/Example2.js @@ -51,7 +51,8 @@ function Example(props) { renderItem={renderItem} inputProps={inputProps} focusedItemIndex={2} - theme={theme} /> + theme={theme} + /> ); diff --git a/demo/src/components/App/components/Example3/Example3.js b/demo/src/components/App/components/Example3/Example3.js index 67038ea..ea1399e 100644 --- a/demo/src/components/App/components/Example3/Example3.js +++ b/demo/src/components/App/components/Example3/Example3.js @@ -75,7 +75,8 @@ function Example(props) { getSectionItems={getSectionItems} renderItem={renderItem} inputProps={inputProps} - theme={theme} /> + theme={theme} + /> ); diff --git a/demo/src/components/App/components/Example4/Example4.js b/demo/src/components/App/components/Example4/Example4.js index 444982c..7de5de6 100644 --- a/demo/src/components/App/components/Example4/Example4.js +++ b/demo/src/components/App/components/Example4/Example4.js @@ -77,7 +77,8 @@ function Example(props) { inputProps={inputProps} focusedSectionIndex={0} focusedItemIndex={1} - theme={theme} /> + theme={theme} + /> ); diff --git a/demo/src/components/App/components/Example5/Example5.js b/demo/src/components/App/components/Example5/Example5.js index 1c9210a..592f7f7 100644 --- a/demo/src/components/App/components/Example5/Example5.js +++ b/demo/src/components/App/components/Example5/Example5.js @@ -68,7 +68,8 @@ function Example(props) { itemProps={itemProps} focusedSectionIndex={focusedSectionIndex} focusedItemIndex={focusedItemIndex} - theme={theme} /> + theme={theme} + /> ); diff --git a/demo/src/components/App/components/Example6/Example6.js b/demo/src/components/App/components/Example6/Example6.js index cfdd88b..847937a 100644 --- a/demo/src/components/App/components/Example6/Example6.js +++ b/demo/src/components/App/components/Example6/Example6.js @@ -63,7 +63,8 @@ function Example(props) { inputProps={inputProps} focusedSectionIndex={focusedSectionIndex} focusedItemIndex={focusedItemIndex} - theme={theme} /> + theme={theme} + /> ); diff --git a/demo/src/components/App/components/Example7/Example7.js b/demo/src/components/App/components/Example7/Example7.js index 64331a0..2e08b7e 100644 --- a/demo/src/components/App/components/Example7/Example7.js +++ b/demo/src/components/App/components/Example7/Example7.js @@ -87,7 +87,8 @@ function Example(props) { inputProps={inputProps} focusedSectionIndex={focusedSectionIndex} focusedItemIndex={focusedItemIndex} - theme={theme} /> + theme={theme} + /> ); diff --git a/demo/src/components/App/components/Example8/Example8.js b/demo/src/components/App/components/Example8/Example8.js index 3e3d4dd..0397b5c 100644 --- a/demo/src/components/App/components/Example8/Example8.js +++ b/demo/src/components/App/components/Example8/Example8.js @@ -96,7 +96,8 @@ function Example(props) { inputProps={inputProps} focusedSectionIndex={focusedSectionIndex} focusedItemIndex={focusedItemIndex} - theme={theme} /> + theme={theme} + /> ); diff --git a/demo/src/components/App/components/Example9/Example9.js b/demo/src/components/App/components/Example9/Example9.js index 6697308..2357e99 100644 --- a/demo/src/components/App/components/Example9/Example9.js +++ b/demo/src/components/App/components/Example9/Example9.js @@ -143,7 +143,8 @@ function Example(props) { focusedSectionIndex={focusedSectionIndex} focusedItemIndex={focusedItemIndex} itemProps={itemProps} - theme={theme} /> + theme={theme} + /> ); diff --git a/demo/src/components/App/components/ForkMeOnGitHub/ForkMeOnGitHub.js b/demo/src/components/App/components/ForkMeOnGitHub/ForkMeOnGitHub.js index ab54506..c29076a 100644 --- a/demo/src/components/App/components/ForkMeOnGitHub/ForkMeOnGitHub.js +++ b/demo/src/components/App/components/ForkMeOnGitHub/ForkMeOnGitHub.js @@ -11,7 +11,8 @@ export default function ForkMeOnGitHub(props) { className={styles.image} src="//camo.githubusercontent.com/a6677b08c955af8400f44c6298f40e7d19cc5b2d/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677261795f3664366436642e706e67" alt="Fork me on GitHub" - data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" /> + data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" + /> ); } diff --git a/demo/src/components/App/components/SourceCodeLink/SourceCodeLink.js b/demo/src/components/App/components/SourceCodeLink/SourceCodeLink.js index 4d98904..169bec9 100644 --- a/demo/src/components/App/components/SourceCodeLink/SourceCodeLink.js +++ b/demo/src/components/App/components/SourceCodeLink/SourceCodeLink.js @@ -10,7 +10,8 @@ export default function SourceCodeLink(props) { className={styles.link} href={`//github.com/moroshko/react-autowhatever/tree/master/${file}`} target="_blank" - rel="noopener noreferrer"> + rel="noopener noreferrer" + > Source code ); diff --git a/demo/standalone/app.js b/demo/standalone/app.js index 800e9b1..b52ee7a 100644 --- a/demo/standalone/app.js +++ b/demo/standalone/app.js @@ -42,7 +42,8 @@ class App extends React.Component { // eslint-disable-line no-undef items={items} renderItem={renderItem} inputProps={inputProps} - focusedItemIndex={2} /> + focusedItemIndex={2} + /> ); } } diff --git a/demo/standalone/compiled.app.js b/demo/standalone/compiled.app.js index c487ec9..91728f3 100644 --- a/demo/standalone/compiled.app.js +++ b/demo/standalone/compiled.app.js @@ -115,7 +115,8 @@ , { items: items, renderItem: renderItem, inputProps: inputProps, - focusedItemIndex: 2 }); + focusedItemIndex: 2 + }); } }]); diff --git a/package.json b/package.json index 5c753be..3ffdfeb 100644 --- a/package.json +++ b/package.json @@ -44,15 +44,15 @@ "babel-register": "^6.16.3", "chai": "^3.5.0", "css-loader": "^0.25.0", - "eslint": "^3.7.1", + "eslint": "^3.8.1", "eslint-plugin-react": "^6.4.1", "extract-text-webpack-plugin": "^1.0.1", - "jsdom": "^9.6.0", + "jsdom": "^9.8.0", "less": "^2.7.1", "less-loader": "^2.2.3", "mocha": "^3.1.2", "openurl": "^1.1.1", - "postcss-loader": "^0.13.0", + "postcss-loader": "^1.0.0", "react": "^15.3.2", "react-addons-test-utils": "^15.3.2", "react-dom": "^15.3.2", diff --git a/src/Autowhatever.js b/src/Autowhatever.js index 3fd1e7e..95dbf5a 100644 --- a/src/Autowhatever.js +++ b/src/Autowhatever.js @@ -6,6 +6,7 @@ import ItemsList from './ItemsList'; const alwaysTrue = () => true; const emptyObject = {}; +const defaultRenderInputComponent = props => ; const defaultRenderItemsContainer = props =>
; const defaultTheme = { container: 'react-autowhatever__container', @@ -23,6 +24,7 @@ export default class Autowhatever extends Component { static propTypes = { id: PropTypes.string, // Used in aria-* attributes. If multiple Autowhatever's are rendered on a page, they must have unique ids. multiSection: PropTypes.bool, // Indicates whether a multi section layout should be rendered. + renderInputComponent: PropTypes.func, // Renders the input component. items: PropTypes.array.isRequired, // Array of items or sections to render. renderItemsContainer: PropTypes.func, // Renders the items container. renderItem: PropTypes.func, // This function renders a single item. @@ -47,6 +49,7 @@ export default class Autowhatever extends Component { static defaultProps = { id: '1', multiSection: false, + renderInputComponent: defaultRenderInputComponent, renderItemsContainer: defaultRenderItemsContainer, shouldRenderSection: alwaysTrue, renderItem: () => { @@ -177,7 +180,8 @@ export default class Autowhatever extends Component { section={section} renderSectionTitle={renderSectionTitle} theme={theme} - sectionKeyPrefix={sectionKeyPrefix} /> + sectionKeyPrefix={sectionKeyPrefix} + /> + ref={this.storeItemsListReference} + />
); /* eslint-enable react/jsx-key */ @@ -219,7 +224,8 @@ export default class Autowhatever extends Component { onFocusedItemChange={this.onFocusedItemChange} getItemId={this.getItemId} theme={theme} - keyPrefix={`react-autowhatever-${id}-`} /> + keyPrefix={`react-autowhatever-${id}-`} + /> ); } @@ -273,7 +279,7 @@ export default class Autowhatever extends Component { render() { const { theme } = this; const { - id, multiSection, renderItemsContainer, + id, multiSection, renderInputComponent, renderItemsContainer, focusedSectionIndex, focusedItemIndex } = this.props; const renderedItems = multiSection ? this.renderSections() : this.renderItems(); @@ -285,7 +291,7 @@ export default class Autowhatever extends Component { isOpen && 'containerOpen' ); const itemsContainerId = `react-autowhatever-${id}`; - const inputProps = { + const inputComponent = renderInputComponent({ type: 'text', value: '', autoComplete: 'off', @@ -299,21 +305,17 @@ export default class Autowhatever extends Component { ...this.props.inputProps, onKeyDown: this.props.inputProps.onKeyDown && this.onKeyDown, ref: this.storeInputReference - }; - const itemsContainerProps = { + }); + const itemsContainer = renderItemsContainer({ id: itemsContainerId, ...theme(`react-autowhatever-${id}-items-container`, 'itemsContainer'), - ref: this.storeItemsContainerReference - }; - const InputComponent = this.props.inputComponent || 'input'; - const itemsContainer = renderItemsContainer({ - ...itemsContainerProps, + ref: this.storeItemsContainerReference, children: renderedItems }); return (
- + {inputComponent} {itemsContainer}
); diff --git a/src/ItemsList.js b/src/ItemsList.js index 78d39c4..36760ae 100644 --- a/src/ItemsList.js +++ b/src/ItemsList.js @@ -71,7 +71,8 @@ export default class ItemsList extends Component { itemIndex={itemIndex} item={item} renderItem={renderItem} - renderItemData={renderItemData} /> + renderItemData={renderItemData} + /> ); /* eslint-enable react/jsx-key */ }) diff --git a/test/input-component/Autowhatever.test.js b/test/input-component/Autowhatever.test.js new file mode 100644 index 0000000..4811201 --- /dev/null +++ b/test/input-component/Autowhatever.test.js @@ -0,0 +1,15 @@ +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; +import { expect } from 'chai'; +import { init, getStoredInput } from '../helpers'; +import AutowhateverApp from './AutowhateverApp'; + +describe('Autowhatever with inputComponent', () => { + beforeEach(() => { + init(TestUtils.renderIntoDocument()); + }); + + it('should store the input on the instance', () => { + expect(getStoredInput().getAttribute('id')).to.equal('my-custom-input'); + }); +}); diff --git a/test/input-component/AutowhateverApp.js b/test/input-component/AutowhateverApp.js new file mode 100644 index 0000000..89007dc --- /dev/null +++ b/test/input-component/AutowhateverApp.js @@ -0,0 +1,61 @@ +import React, { Component } from 'react'; +import Autowhatever from '../../src/Autowhatever'; +import items from './items'; + +export const renderItem = item => item.text; + +export const inputComponent = props => ( +
+ +
+); + +export default class AutowhateverApp extends Component { + constructor() { + super(); + + this.state = { + value: '' + }; + + this.storeAutowhateverReference = this.storeAutowhateverReference.bind(this); + this.onChange = this.onChange.bind(this); + } + + storeAutowhateverReference(autowhatever) { + if (autowhatever !== null) { + this.autowhatever = autowhatever; + } + } + + onChange(event) { + this.setState({ + value: event.target.value + }); + } + + onClick(event, { itemIndex }) { + this.setState({ + value: items[itemIndex].text + }); + } + + render() { + const { value } = this.state; + const inputProps = { + id: 'my-custom-input', + value, + onChange: this.onChange + }; + + return ( + + ); + } +} diff --git a/test/input-component/items.js b/test/input-component/items.js new file mode 100644 index 0000000..b74b3f7 --- /dev/null +++ b/test/input-component/items.js @@ -0,0 +1,17 @@ +export default [ + { + text: 'Apple' + }, + { + text: 'Banana' + }, + { + text: 'Cherry' + }, + { + text: 'Grapefruit' + }, + { + text: 'Lemon' + } +]; diff --git a/test/multi-section/AutowhateverApp.js b/test/multi-section/AutowhateverApp.js index dcde974..d1f2a11 100644 --- a/test/multi-section/AutowhateverApp.js +++ b/test/multi-section/AutowhateverApp.js @@ -73,7 +73,8 @@ export default class AutowhateverApp extends Component { inputProps={inputProps} focusedSectionIndex={focusedSectionIndex} focusedItemIndex={focusedItemIndex} - ref={this.storeAutowhateverReference} /> + ref={this.storeAutowhateverReference} + /> ); } } diff --git a/test/plain-list/AutowhateverApp.js b/test/plain-list/AutowhateverApp.js index bfde38b..e1922b0 100644 --- a/test/plain-list/AutowhateverApp.js +++ b/test/plain-list/AutowhateverApp.js @@ -74,7 +74,8 @@ export default class AutowhateverApp extends Component { inputProps={inputProps} itemProps={itemProps} focusedItemIndex={focusedItemIndex} - ref={this.storeAutowhateverReference} /> + ref={this.storeAutowhateverReference} + /> ); } }