Skip to content

Commit

Permalink
Merge pull request #109 from i-like-robots/6.0
Browse files Browse the repository at this point in the history
v6.0
  • Loading branch information
i-like-robots committed Jun 28, 2020
2 parents 18aa300 + 5f25446 commit 97d8ae2
Show file tree
Hide file tree
Showing 17 changed files with 636 additions and 471 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
.nyc_output
node_modules
npm-debug.log
dist-es5
dist-es6
dist
example/bundle.js
example/bundle.js.map
coverage
3 changes: 2 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
.nyc_output/
coverage/
example/
lib/
spec/
.DS_Store
.editorconfig
.travis.yml
gh-pages.sh
webpack.config.js
rollup.config.js
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Changelog

## 6.0.0

- Added `clearInput` method to programmatically clear input text
- Added `suggestionComponent` option to allow the rendering of a custom suggestion component ([tjphopkins](https://github.com/tjphopkins))
- Added `searchWrapper` to `classNames` option
- Added ES6 package and `"module"` entry point
- Added `id` option to configure the component ID
- Added `removeButtonText` option to configure the selected tag remove button title attribute
- Refactored `ariaLabel` option to `ariaLabelText` to match other text options
- Refactored `placeholder` option to `placeholderText` to match other text options
- Refactored keyboard event handlers to use `KeyboardEvent.key`
- Refactored event handlers and callbacks to use `on` prefixes
- Refactored `classNames` option to avoid creating new and merging objects for each top-level props change
- Refactored `deleteTag` method so it no longer clears the input text when a tag is removed
- Refactored `delimiters` option to be an array of `KeyboardEvent.key` values
- Refactored `onInput` callback to provide basic support for `delimiters` entered on soft keyboards
- Removed `clearInputOnDelete` option
- Removed `autofocus` option
- Removed `delimiterChars` option
- Updated React dependency to 16.5+

## 5.13.1

- Fixed an issue where cursor focus could be lost after removing a selected tag
Expand Down
173 changes: 99 additions & 74 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

React Tag Autocomplete is a simple tagging component ready to drop in your React projects. Originally based on the [React Tags project](http://prakhar.me/react-tags/example) by Prakhar Srivastav this version removes the drag-and-drop re-ordering functionality, adds appropriate roles and ARIA states and introduces a resizing text input. [View demo](http://i-like-robots.github.io/react-tags/).

**Version 6 of this component is in beta! Please [take a look here](https://github.com/i-like-robots/react-tags/tree/6.0)**
**Please note, this version is in beta, you can check out the [latest stable version here](https://github.com/i-like-robots/react-tags)** 📢

![Screenshot of React Tag Autocomplete](https://cloud.githubusercontent.com/assets/271645/25478773/54aa2bbe-2b3a-11e7-95cf-d419f3c24418.png)

Expand All @@ -15,7 +15,7 @@ This is a [Node.js] module available through the [npm] registry. Before installi
Installation is done using the [npm install] command:

```
npm install --save react-tag-autocomplete
npm install --save react-tag-autocomplete@pre-release
```

[Node.js]: https://nodejs.org/en/
Expand All @@ -28,6 +28,7 @@ Here's a sample implementation that initializes the component with a list of pre

```js
import React from 'react'
import ReactDOM from 'react-dom'
import ReactTags from 'react-tag-autocomplete'

class App extends React.Component {
Expand All @@ -46,62 +47,68 @@ class App extends React.Component {
{ id: 6, name: "Apricots" }
]
}

this.reactTags = React.createRef()
}

handleDelete (i) {
onDelete (i) {
const tags = this.state.tags.slice(0)
tags.splice(i, 1)
this.setState({ tags })
}

handleAddition (tag) {
onAddition (tag) {
const tags = [].concat(this.state.tags, tag)
this.setState({ tags })
}

render () {
return (
<ReactTags
ref={this.reactTags}
tags={this.state.tags}
suggestions={this.state.suggestions}
handleDelete={this.handleDelete.bind(this)}
handleAddition={this.handleAddition.bind(this)} />
onDelete={this.onDelete.bind(this)}
onAddition={this.onAddition.bind(this)} />
)
}
}

React.render(<App />, document.getElementById('app'))
ReactDOM.render(<App />, document.getElementById('app'))
```


### Options

- [`id`](#id-optional)
- [`tags`](#tags-optional)
- [`suggestions`](#suggestions-optional)
- [`suggestionsFilter`](#suggestionsfilter-optional)
- [`placeholder`](#placeholder-optional)
- [`ariaLabel`](#ariaLabel-optional)
- [`placeholderText`](#placeholdertext-optional)
- [`ariaLabelText`](#arialabeltext-optional)
- [`removeButtonText`](#removeButtontext-optional)
- [`noSuggestionsText`](#noSuggestionsText-optional)
- [`autofocus`](#autofocus-optional)
- [`autoresize`](#autoresize-optional)
- [`delimiters`](#delimiters-optional)
- [`delimiterChars`](#delimiterschars-optional)
- [`minQueryLength`](#minquerylength-optional)
- [`maxSuggestionsLength`](#maxsuggestionslength-optional)
- [`classNames`](#classnames-optional)
- [`handleAddition`](#handleaddition-optional)
- [`handleDelete`](#handledelete-optional)
- [`handleInputChange`](#handleinputchange-optional)
- [`handleFocus`](#handlefocus-optional)
- [`handleBlur`](#handleblur-optional)
- [`handleValidate`](#handlevalidate-optional)
- [`onAddition`](#onaddition-optional)
- [`onDelete`](#ondelete-optional)
- [`onInput`](#oninput-optional)
- [`onFocus`](#onfocus-optional)
- [`onBlur`](#onblur-optional)
- [`onValidate`](#onvalidate-optional)
- [`addOnBlur`](#addonblur-optional)
- [`allowNew`](#allownew-optional)
- [`allowBackspace`](#allowbackspace-optional)
- [`clearInputOnDelete`](#clearinputondelete-optional)
- [`tagComponent`](#tagcomponent-optional)
- [`inputAttributes`](#inputAttributes-optional)

#### id (optional)

The ID attribute given to the listbox element. Default: `ReactTags`.

#### tags (optional)

An array of selected tags. Each tag is an object which must have an `id` and a `name` property. Defaults to `[]`.
Expand Down Expand Up @@ -132,33 +139,29 @@ A callback function to filter suggestion items with. The callback receives two a

If no function is supplied the default filter is applied. Defaults to `null`.

#### placeholder (optional)
#### placeholderText (optional)

The placeholder string shown for the input. Defaults to `'Add new tag'`.

#### ariaLabel (optional)
#### ariaLabelText (optional)

The aria-label string for the input. Defaults to placeholder string.

#### noSuggestionsText (optional)
#### removeButtonText (optional)

Message shown if there are no matching suggestions. Defaults to `null`.
The title text to add to the remove selected tag button. Default `'Click to remove tag'`.

#### autofocus (optional)
#### noSuggestionsText (optional)

Boolean parameter to control whether the text-input should be autofocused on mount. Defaults to `true`.
Message shown if there are no matching suggestions. Defaults to `null`.

#### autoresize (optional)

Boolean parameter to control whether the text-input should be automatically resized to fit its value. Defaults to `true`.

#### delimiters (optional)

An array of numbers matching `KeyboardEvent.keyCode` values. When a corresponding key is pressed it will trigger tag selection or creation. Defaults to `[9, 13]` (Tab and return keys).

#### delimiterChars (optional)

Array of characters matching `KeyboardEvent.key` values. This is useful when needing to support a specific character irrespective of the keyboard layout. Defaults to `[]`.
Array of keys matching `KeyboardEvent.key` values. When a corresponding key is pressed it will trigger tag selection or creation. Defaults to `['Enter', 'Tab']`.

#### minQueryLength (optional)

Expand All @@ -180,42 +183,43 @@ Override the default class names used by the component. Defaults to:
selectedTag: 'react-tags__selected-tag',
selectedTagName: 'react-tags__selected-tag-name',
search: 'react-tags__search',
searchWrapper: 'react-tags__search-wrapper',
searchInput: 'react-tags__search-input',
suggestions: 'react-tags__suggestions',
suggestionActive: 'is-active',
suggestionDisabled: 'is-disabled'
}
```

#### handleAddition (required)
#### onAddition (required)

Function called when the user wants to add a tag. Receives the tag.

```js
function handleAddition(tag) {
function onAddition(tag) {
const tags = [...this.state.tags, tag]
this.setState({ tags })
}
```

#### handleDelete (required)
#### onDelete (required)

Function called when the user wants to delete a tag. Receives the tag index.

```js
function handleDelete(i) {
function onDelete(i) {
const tags = this.state.tags.slice(0)
tags.splice(i, 1)
this.setState({ tags })
}
```

#### handleInputChange (optional)
#### onInput (optional)

Optional event handler when the input value changes. Receives the current query.

```js
function handleInputChange(query) {
function onInput(query) {
if (!this.state.busy) {
this.setState({ busy: true })

Expand All @@ -226,20 +230,20 @@ function handleInputChange(query) {
}
```

#### handleFocus (optional)
#### onFocus (optional)

Optional callback function for when the input receives focus. Receives no arguments.

#### handleBlur (optional)
#### onBlur (optional)

Optional callback function for when focus on the input is lost. Receives no arguments.

#### handleValidate (optional)
#### onValidate (optional)

Optional validation function that determines if tag should be added. Receives the tag object and must return a boolean.

```js
function handleValidate(tag) {
function onValidate(tag) {
return tag.name.length >= 5;
}
```
Expand All @@ -256,60 +260,81 @@ Enable users to add new (not suggested) tags. Defaults to `false`.

Enable users to delete selected tags when backspace is pressed while focussed on the text input when empty. Defaults to `true`.

#### clearInputOnDelete (optional)
#### tagComponent (optional)

Clear the text input when a tag is deleted. Defaults to `true`.
Provide a custom tag component to render. Receives the tag, button text, and delete callback as props. Defaults to `null`.

#### tagComponent (optional)
```jsx
function TagComponent({ tag, removeButtonText, onDelete }) {
return (
<button type='button' title={removeButtonText} onClick={onDelete}>
{tag.name}
</button>
)
}
```

#### suggestionComponent (optional)

Provide a custom tag component to render. Defaults to `null`.
Provide a custom suggestion component to render. Receives the suggestion and current query as props. Defaults to `null`.

```jsx
function SuggestionComponent({ item, query }) {
return (
<span id={item.id} className={item.name === query ? 'match' : 'no-match'}>
{item.name}
</span>
)
}
```

#### inputAttributes (optional)

An object containing additional attributes that will be applied to the text input. _Please note_ that this prop cannot overwrite existing attributes, it can only add new ones. Defaults to `{}`.


### API

By adding a `ref` to any instances of this component you can access its API methods.

#### `addTag(tag)`

Adds a tag to the list of selected tags. This will trigger the validation and addition callbacks.

#### `deleteTag(index)`

Removes a tag from the list of selected tags. This will trigger the delete callback.

#### `clearInput()`

Clears the input and current query.


### Styling

It is possible to customize the appearance of the component, the included styles found in `/example/styles.css` are only an example.


### Development

The component is written in ES6 and uses [Webpack](http://webpack.github.io/) as its build tool.
The component is written in ES6 and uses [Rollup](https://rollupjs.org/) as its build tool. Tests are written with [Jasmine](https://jasmine.github.io/) using [JSDOM](https://github.com/jsdom/jsdom).

```
```sh
npm install
npm run dev # open http://localhost:8080
npm run dev # will open http://localhost:8080 and watch files for changes
```

### Upgrading

### Upgrading from 4.x to 5.x

1. The `delimiters` option has been removed, any references to this will now be ignored.
2. The `classNames` option has been updated:

```udiff
{
- root: 'ReactTags',
- tagInput: 'ReactTags__tagInput',
- selected: 'ReactTags__selected',
- tag: 'ReactTags__tag',
- tagName: 'ReactTags__tagName',
- suggestions: 'ReactTags__suggestions',
- isActive: 'is-active',
- isDisabled: 'is-disabled'
+ root: 'react-tags',
+ rootFocused: 'is-focused',
+ selected: 'react-tags__selected',
+ selectedTag: 'react-tags__selected-tag',
+ selectedTagName: 'react-tags__selected-tag-name',
+ search: 'react-tags__search',
+ searchInput: 'react-tags__search-input',
+ suggestions: 'react-tags__suggestions',
+ suggestionActive: 'is-active',
+ suggestionDisabled: 'is-disabled'
}
```
To see all changes refer to [the changelog](CHANGELOG.md).

#### Upgrading from 5.x to 6.x

For smaller changes refer to [the changelog](CHANGELOG.md).
- React 16.5 or above is now required.
- Event handlers and callbacks have been renamed to use `on` prefixes, e.g. the `handleAddition()` callback should now be called `onAddition()`.
- The `delimiters` option is now an array of `KeyboardEvent.key` values and not `KeyboardEvent.keyCode` codes, e.g. `[13, 9]` should now be written as `['Enter', 'Tab']`. See https://keycode.info/ for more information.
- The `placeholder` option has been renamed `placeholderText`
- The `ariaLabel` option has been renamed `ariaLabelText`
- The `delimiterChars` option has been removed, use the `delimiters` option instead.
- The `clearInputOnDelete` option has been removed and is now the default behaviour
- The `autofocus` option has been removed.
4 changes: 1 addition & 3 deletions example/countries.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 97d8ae2

Please sign in to comment.