Skip to content

Commit

Permalink
Merge pull request #100 from i-like-robots/5.5
Browse files Browse the repository at this point in the history
5.5
  • Loading branch information
i-like-robots authored Nov 15, 2017
2 parents d2770e7 + 52284ef commit a657c16
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 37 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
language: node_js
node_js:
- "4"
- "6"
- "8"
after_success:
- cat coverage/lcov.info | coveralls
script:
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 5.5.0

- Refactored input into a controlled component (also fixes Preact compatibility)
- Refactored focus and blur handlers to capture events (also fixes Preact compatibility)
- Added `handleFocus` and `handleBlur` callbacks ([Pomax](https://github.com/Pomax))
- Updated dependencies ([ajmas](https://github.com/ajmas))

## 5.4.1

- Fixed return key submitting containing form when `minQueryLength` is set to 0 and suggestions are active ([Drahoslav7](https://github.com/Drahoslav7))
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ React.render(<App />, document.getElementById('app'))
- [`handleAddition`](#handleaddition-optional)
- [`handleDelete`](#handledelete-optional)
- [`handleInputChange`](#handleinputchange-optional)
- [`handleFocus`](#handlefocus-optional)
- [`handleBlur`](#handleblur-optional)
- [`allowNew`](#allownew-optional)
- [`tagComponent`](#tagcomponent-optional)

Expand Down Expand Up @@ -192,6 +194,14 @@ function (input) {
}
```

#### handleFocus (optional)

Optional event handler when the input receives focus. Receives no arguments.

#### handleBlur (optional)

Optional event handler when focus on the input is lost. Receives no arguments.

#### allowNew (optional)

Allows users to add new (not suggested) tags. Default: `false`.
Expand Down
13 changes: 5 additions & 8 deletions lib/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,25 +69,22 @@ class Input extends React.Component {
}

render () {
const sizerText = this.props.query || this.props.placeholder

const { expandable, placeholder, listboxId, selectedIndex } = this.props

const selectedId = `${listboxId}-${selectedIndex}`
const { query, placeholder, expandable, listboxId, selectedIndex } = this.props

return (
<div className={this.props.classNames.searchInput}>
<input
ref={(c) => { this.input = c }}
value={query}
placeholder={placeholder}
role='combobox'
aria-autocomplete='list'
aria-label={placeholder}
aria-owns={listboxId}
aria-activedescendant={selectedIndex > -1 ? selectedId : null}
aria-activedescendant={selectedIndex > -1 ? `${listboxId}-${selectedIndex}` : null}
aria-expanded={expandable}
placeholder={placeholder}
style={{ width: this.state.inputWidth }} />
<div ref={(c) => { this.sizer = c }} style={SIZER_STYLES}>{sizerText}</div>
<div ref={(c) => { this.sizer = c }} style={SIZER_STYLES}>{query || placeholder}</div>
</div>
)
}
Expand Down
18 changes: 14 additions & 4 deletions lib/ReactTags.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class ReactTags extends React.Component {
})
}

handleChange (e) {
handleInput (e) {
const query = e.target.value

if (this.props.handleInputChange) {
Expand Down Expand Up @@ -113,10 +113,18 @@ class ReactTags extends React.Component {

handleBlur () {
this.setState({ focused: false, selectedIndex: -1 })

if (this.props.handleBlur) {
this.props.handleBlur()
}
}

handleFocus () {
this.setState({ focused: true })

if (this.props.handleFocus) {
this.props.handleFocus()
}
}

addTag (tag) {
Expand Down Expand Up @@ -163,9 +171,9 @@ class ReactTags extends React.Component {
</div>
<div
className={this.state.classNames.search}
onBlur={this.handleBlur.bind(this)}
onFocus={this.handleFocus.bind(this)}
onChange={this.handleChange.bind(this)}
onBlurCapture={this.handleBlur.bind(this)}
onFocusCapture={this.handleFocus.bind(this)}
onInput={this.handleInput.bind(this)}
onKeyDown={this.handleKeyDown.bind(this)}>
<Input {...this.state}
ref={(c) => { this.input = c }}
Expand Down Expand Up @@ -213,6 +221,8 @@ ReactTags.propTypes = {
handleDelete: PropTypes.func.isRequired,
handleAddition: PropTypes.func.isRequired,
handleInputChange: PropTypes.func,
handleFocus: PropTypes.func,
handleBlur: PropTypes.func,
minQueryLength: PropTypes.number,
maxSuggestionsLength: PropTypes.number,
classNames: PropTypes.object,
Expand Down
30 changes: 16 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
"test": "jasmine",
"coverage": "istanbul cover -i 'dist-es5/**' jasmine",
"lint": "standard lib/*.js spec/*.js",
"dev": "webpack-dev-server --progress --colors",
"build:example": "webpack -p",
"build:es5": "buble lib -o dist-es5",
"build:es6": "buble lib -o dist-es6 -t node:6",
"dev": "webpack-dev-server --progress --colors --port ${PORT:-8080} --host 0.0.0.0",
"build:example": "webpack -p --config-name example",
"build:es5": "buble lib --objectAssign -o dist-es5",
"build:es6": "buble lib --objectAssign -o dist-es6 -t node:6",
"prepublish": "npm run build:es5 && npm run build:es6"
},
"files": [
Expand All @@ -31,10 +31,12 @@
"autosuggest",
"autocomplete"
],
"author": "Matt Hinchliffe",
"contributors": [
"Prakhar Srivastav",
"Matt Hinchliffe",
"Simon Hötten"
"Simon Hötten",
"Andre-John Mas",
"Mike Kamermans"
],
"license": "MIT",
"repository": "https://github.com/i-like-robots/react-tags",
Expand All @@ -44,19 +46,19 @@
"react-dom": "^15.0.0"
},
"devDependencies": {
"buble": "^0.12.5",
"buble-loader": "^0.2.2",
"coveralls": "^2.11.12",
"buble": "^0.17.0",
"buble-loader": "^0.4.1",
"coveralls": "^3.0.0",
"istanbul": "^0.4.4",
"jasmine": "^2.4.1",
"jsdom": "^9.4.1",
"jsdom": "^11.3.0",
"keycode": "^2.1.2",
"prop-types": "^15.5.0",
"react": "^15.5.0",
"react-dom": "^15.5.0",
"sinon": "^1.17.5",
"standard": "^7.1.2",
"webpack": "^1.9.4",
"webpack-dev-server": "^1.8.2"
"sinon": "^4.0.0",
"standard": "^10.0.3",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.8.2"
}
}
24 changes: 20 additions & 4 deletions spec/ReactTags.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,27 @@ const Subject = require('../dist-es5/ReactTags')
let props
let instance

function createInstance (data) {
function createInstance (data = {}) {
if (instance) {
teardownInstance()
}

const defaults = {
tags: [],
suggestions: [],
handleBlur: sinon.stub(),
handleFocus: sinon.stub(),
handleDelete: sinon.stub(),
handleAddition: sinon.stub(),
handleInputChange: sinon.stub()
}

props = Object.assign(defaults, data || {})
instance = ReactDOM.render(React.createElement(Subject, props), document.getElementById('app'))
props = Object.assign(defaults, data)

instance = ReactDOM.render(
React.createElement(Subject, props),
document.getElementById('app')
)
}

function teardownInstance () {
Expand All @@ -48,7 +54,7 @@ function type (value) {
key(char)
$('input').value += char
// React calls onchange for every update to maintain state at all times
TestUtils.Simulate.change($('input'))
TestUtils.Simulate.input($('input'))
})
}

Expand Down Expand Up @@ -123,6 +129,16 @@ describe('React Tags', () => {
TestUtils.Simulate.blur($('input'))
expect($('.is-focused')).toBeNull()
})

it('calls focus and blur callbacks when provided', () => {
createInstance({ autofocus: false })

TestUtils.Simulate.focus($('input'))
sinon.assert.calledOnce(props.handleFocus)

TestUtils.Simulate.blur($('input'))
sinon.assert.calledOnce(props.handleBlur)
})
})

describe('query', () => {
Expand Down
6 changes: 2 additions & 4 deletions spec/helpers/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@

const jsdom = require('jsdom')

global.document = jsdom.jsdom('<html><body><div id="app"></div></body></html>', {})
global.window = document.defaultView
const { window } = new jsdom.JSDOM('<html><body><div id="app"></div></body></html>', {})

// Add fetch polyfill
window.fetch = global.fetch
global.window = window

// from mocha-jsdom https://github.com/rstacruz/mocha-jsdom/blob/master/index.js#L80
for (const key in window) {
Expand Down
11 changes: 9 additions & 2 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ module.exports = {
entry: './example/main.js',
devtool: 'source-map',
module: {
loaders: [
{ test: /\.js$/, loader: 'buble', exclude: /node_modules/ }
rules: [
{
test: /\.jsx?$/,
loader: 'buble-loader',
exclude: /node_modules/,
options: {
objectAssign: 'Object.assign'
}
}
]
},
plugins: [
Expand Down

0 comments on commit a657c16

Please sign in to comment.