Skip to content

Commit

Permalink
Merge pull request #5 from cburbank/custom-styles
Browse files Browse the repository at this point in the history
feat(styles): Add styles prop to allow for custom inline styles
  • Loading branch information
hibiken authored Dec 29, 2016
2 parents a609388 + 96a107b commit 393b66d
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 11 deletions.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,35 @@ render() {
```
Now you can easily apply custom CSS styles using the classNames!

#### styles
Type `Object`,
Required: `false`

You can provide custom inline styles to elements.
Accepted keys are `root`, `label`, `input`, `autocompleteContainer`, `autocompleteItem`, `autocompleteItemActive`

```js
// custom style examples
render() {
const myStyles = {
root: { position: 'absolute' },
label: { color: 'red' },
input: { width: '100%' },
autocompleteContainer: { backgroundColor: 'green' },
autocompleteItem: { color: 'black' },
autocompleteItemActive: { color: 'blue' }
}

return (
<PlacesAutocomplete
value={this.state.address}
onChange={this.onChange}
styles={myStyles}
/>
)
}
```

#### placeholder
Type: `String`,
Required: `false`,
Expand Down
36 changes: 25 additions & 11 deletions src/PlacesAutocomplete.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'

const defaultStyles = {
autocompleteContainer: {
root: {
position: 'relative',
paddingBottom: '0px',
},
Expand All @@ -13,7 +13,7 @@ const defaultStyles = {
left: 0,
zIndex: 9998,
},
autocompleteWrapper: {
autocompleteContainer: {
position: 'absolute',
top: '100%',
backgroundColor: 'white',
Expand All @@ -22,9 +22,13 @@ const defaultStyles = {
zIndex: 9999,
},
autocompleteItem: {
backgroundColor: '#ffffff',
padding: '10px',
color: '#555',
cursor: 'pointer',
},
autocompleteItemActive: {
backgroundColor: '#fafafa'
}
}

Expand Down Expand Up @@ -152,18 +156,17 @@ class PlacesAutocomplete extends React.Component {
this.autocompleteService.getPlacePredictions({ input: event.target.value }, this.autocompleteCallback)
}

// TODO: this should be customizable.
autocompleteItemStyle(active) {
if (active) {
return { backgroundColor: '#fafafa' }
return { ...defaultStyles.autocompleteItemActive, ...this.props.styles.autocompleteItemActive }
} else {
return { backgroundColor: '#ffffff' }
return {}
}
}

renderLabel() {
if (this.props.hideLabel) { return null }
return (<label className={this.props.classNames.label || ''}>Location</label>)
return (<label style={this.props.styles.label} className={this.props.classNames.label || ''}>Location</label>)
}

renderOverlay() {
Expand All @@ -179,18 +182,19 @@ class PlacesAutocomplete extends React.Component {

renderAutocomplete() {
const { autocompleteItems } = this.state
const { styles } = this.props
if (autocompleteItems.length === 0) { return null }
return (
<div
id="PlacesAutocomplete__autocomplete-container"
className={this.props.classNames.autocompleteContainer || ''}
style={defaultStyles.autocompleteWrapper}>
style={{ ...defaultStyles.autocompleteContainer, ...styles.autocompleteContainer }}>
{autocompleteItems.map((p, idx) => (
<div
key={p.placeId}
onMouseOver={() => this._setActiveItemAtIndex(p.index)}
onClick={() => this.selectAddress(p.suggestion)}
style={{ ...this.autocompleteItemStyle(p.active), ...defaultStyles.autocompleteItem }}>
style={{ ...defaultStyles.autocompleteItem, ...styles.autocompleteItem, ...this.autocompleteItemStyle(p.active) }}>
{this.props.autocompleteItem({ suggestion: p.suggestion })}
</div>
))}
Expand All @@ -200,10 +204,10 @@ class PlacesAutocomplete extends React.Component {

// TODO: remove `classNames.container` in the next version release.
render() {
const { classNames, placeholder, value } = this.props
const { classNames, placeholder, styles, value } = this.props
return (
<div
style={defaultStyles.autocompleteContainer}
style={{ ...defaultStyles.root, ...styles.root }}
className={classNames.root || classNames.container || ''}
>
{this.renderLabel()}
Expand All @@ -214,6 +218,7 @@ class PlacesAutocomplete extends React.Component {
value={value}
onChange={this.handleInputChange}
onKeyDown={this.handleInputKeyDown}
style={styles.input}
/>
{this.renderOverlay()}
{this.renderAutocomplete()}
Expand All @@ -235,13 +240,22 @@ PlacesAutocomplete.propTypes = {
input: React.PropTypes.string,
autocompleteContainer: React.PropTypes.string,
}),
styles: React.PropTypes.shape({
root: React.PropTypes.object,
label: React.PropTypes.object,
input: React.PropTypes.object,
autocompleteContainer: React.PropTypes.object,
autocompleteItem: React.PropTypes.object,
autocompleteItemActive: React.PropTypes.object
})
};

PlacesAutocomplete.defaultProps = {
placeholder: 'Address',
hideLabel: false,
classNames: {},
autocompleteItem: ({ suggestion }) => (<div>{suggestion}</div>)
autocompleteItem: ({ suggestion }) => (<div>{suggestion}</div>),
styles: {}
}

export default PlacesAutocomplete
50 changes: 50 additions & 0 deletions src/tests/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,56 @@ describe('customizable autocompleteItem', () => {
})
})

describe('custom inline styles', () => {
let wrapper;
beforeEach(() => {
const styles = {
root: { position: 'absolute' },
label: { color: 'red' },
input: { width: '100%' },
autocompleteContainer: { backgroundColor: 'green' },
autocompleteItem: { color: 'black' },
autocompleteItemActive: { color: 'blue' }
}
const classNames = {
root: 'root-element',
label: 'label-element',
input: 'input-element',
autocompleteContainer: 'autocomplete-container'
}
wrapper = shallow(<PlacesAutocomplete styles={styles} classNames={classNames} value="LA" onChange={() => {}}/>)
})

it('lets you set custom styles for the root element', () => {
expect(wrapper.find('.root-element').props().style.position).to.equal('absolute')
})

it('lets you set custom styles for the label element', () => {
expect(wrapper.find('.label-element').props().style.color).to.equal('red')
})

it('lets you set custom styles for the input element', () => {
expect(wrapper.find('.input-element').props().style.width).to.equal('100%')
})

it('lets you set custom styles for the autocomplete container element', () => {
wrapper.setState({ autocompleteItems: [{ suggestion: 'San Francisco, CA', placeId: 1, active: false, index: 0 }] })
expect(wrapper.find('.autocomplete-container').props().style.backgroundColor).to.equal('green')
})

it('lets you set custom styles for autocomplete items', () => {
wrapper.setState({ autocompleteItems: [{ suggestion: 'San Francisco, CA', placeId: 1, active: false, index: 0 }] })
const item = wrapper.find("#PlacesAutocomplete__autocomplete-container").childAt(0)
expect(item.props().style.color).to.equal('black')
})

it('lets you set custom styles for active autocomplete items', () => {
wrapper.setState({ autocompleteItems: [{ suggestion: 'San Francisco, CA', placeId: 1, active: true, index: 0 }] })
const item = wrapper.find("#PlacesAutocomplete__autocomplete-container").childAt(0)
expect(item.props().style.color).to.equal('blue')
})

})

// TODO: test geocodeByAddress function
describe('geocodeByAddress', () => {
Expand Down

0 comments on commit 393b66d

Please sign in to comment.