Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-tag-autocomplete

Package Overview
Dependencies
Maintainers
1
Versions
86
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-tag-autocomplete - npm Package Compare versions

Comparing version 6.1.0 to 6.2.0

11

CHANGELOG.md
# Changelog
## 6.2.0
- Added `newTagText` option to display a prompt in the suggestions list to create a new tag when the `allowNew` option is enabled ([cml391](https://github.com/cml391))
- Refactored call of `onAddition` callback to always provide a new object instead of passing the selected tag by reference.
- Refactored `classNames` option to merge the provided prop with defaults ([alexandernst](https://github.com/alexandernst))
- Fixed updates to the `placeholder` option which did not recalculate input size ([LarsHassler](https://github.com/LarsHassler))
- Updated React peer dependency support to include 17+
- Updated example page with a new demo
## 6.1.0

@@ -26,3 +35,3 @@

- Removed `delimiterChars` option
- Updated React dependency to 16.5+
- Updated React peer dependency to 16.5+

@@ -29,0 +38,0 @@ ## 5.13.1

202

dist/ReactTags.cjs.js
'use strict';
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = require('react');
var PropTypes = require('prop-types');
var React = _interopDefault(require('react'));
var PropTypes = _interopDefault(require('prop-types'));
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
var Tag = (props) => (
React.createElement( 'button', { type: 'button', className: props.classNames.selectedTag, title: props.removeButtonText, onClick: props.onDelete },
React.createElement( 'span', { className: props.classNames.selectedTagName }, props.tag.name)
React__default['default'].createElement( 'button', { type: 'button', className: props.classNames.selectedTag, title: props.removeButtonText, onClick: props.onDelete },
React__default['default'].createElement( 'span', { className: props.classNames.selectedTagName }, props.tag.name)
)

@@ -32,3 +35,3 @@ );

class Input extends React.Component {
class Input extends React__default['default'].Component {
constructor (props) {

@@ -38,4 +41,4 @@ super(props);

this.input = React.createRef();
this.sizer = React.createRef();
this.input = React__default['default'].createRef();
this.sizer = React__default['default'].createRef();
}

@@ -50,4 +53,4 @@

componentDidUpdate ({ query, placeholder }) {
if (query !== this.props.query || placeholder !== this.props.placeholder) {
componentDidUpdate ({ query, placeholderText }) {
if (query !== this.props.query || placeholderText !== this.props.placeholderText) {
this.updateInputWidth();

@@ -83,6 +86,6 @@ }

return (
React.createElement( 'div', { className: classNames.searchWrapper },
React.createElement( 'input', Object.assign({},
React__default['default'].createElement( 'div', { className: classNames.searchWrapper },
React__default['default'].createElement( 'input', Object.assign({},
inputAttributes, inputEventHandlers, { ref: this.input, value: query, placeholder: placeholderText, className: classNames.searchInput, role: 'combobox', 'aria-autocomplete': 'list', 'aria-label': ariaLabelText || placeholderText, 'aria-owns': id, 'aria-activedescendant': index > -1 ? `${id}-${index}` : null, 'aria-expanded': expanded, style: { width: this.state.inputWidth } })),
React.createElement( 'div', { ref: this.sizer, style: SIZER_STYLES }, query || placeholderText)
React__default['default'].createElement( 'div', { ref: this.sizer, style: SIZER_STYLES }, query || placeholderText)
)

@@ -115,6 +118,6 @@ )

const DefaultSuggestionComponent = ({ item, query }) => (
React.createElement( 'span', { dangerouslySetInnerHTML: { __html: markIt(item.name, query) } })
React__default['default'].createElement( 'span', { dangerouslySetInnerHTML: { __html: markIt(item.name, query) } })
);
class Suggestions extends React.Component {
class Suggestions extends React__default['default'].Component {
onMouseDown (item, e) {

@@ -146,6 +149,10 @@ // focus is shifted on mouse down but calling preventDefault prevents this

return (
React.createElement( 'li', {
React__default['default'].createElement( 'li', {
id: key, key: key, role: 'option', className: classNames.join(' '), 'aria-disabled': item.disabled === true, onMouseDown: this.onMouseDown.bind(this, item) },
item.disableMarkIt ? item.name
: React.createElement( SuggestionComponent, { item: item, query: this.props.query })
item.prefix
? React__default['default'].createElement( 'span', { className: this.props.classNames.suggestionPrefix }, item.prefix, ' ')
: null,
item.disableMarkIt
? item.name
: React__default['default'].createElement( SuggestionComponent, { item: item, query: this.props.query })
)

@@ -156,4 +163,4 @@ )

return (
React.createElement( 'div', { className: this.props.classNames.suggestions },
React.createElement( 'ul', { role: 'listbox', id: this.props.id }, options)
React__default['default'].createElement( 'div', { className: this.props.classNames.suggestions },
React__default['default'].createElement( 'ul', { role: 'listbox', id: this.props.id }, options)
)

@@ -164,2 +171,17 @@ )

function focusNextElement(scope, currentTarget) {
const interactiveEls = scope.querySelectorAll("a,button,input");
const currentEl = Array.prototype.findIndex.call(
interactiveEls,
(element) => element === currentTarget
);
const nextEl = interactiveEls[currentEl - 1] || interactiveEls[currentEl + 1];
if (nextEl) {
nextEl.focus();
}
}
const KEYS = {

@@ -186,16 +208,19 @@ ENTER: 'Enter',

suggestionActive: 'is-active',
suggestionDisabled: 'is-disabled'
suggestionDisabled: 'is-disabled',
suggestionPrefix: 'react-tags__suggestion-prefix'
};
function findMatchIndex (options, query) {
return options.findIndex((option) => matchExact(query).test(option.name))
}
function pressDelimiter () {
if (this.state.query.length >= this.props.minQueryLength) {
// Check if the user typed in an existing suggestion.
const match = this.state.options.findIndex((option) => {
return matchExact(this.state.query).test(option.name)
});
const match = findMatchIndex(this.state.options, this.state.query);
const index = this.state.index === -1 ? match : this.state.index;
const tag = index > -1 ? this.state.options[index] : null;
if (index > -1 && this.state.options[index]) {
this.addTag(this.state.options[index]);
if (tag) {
this.addTag(tag);
} else if (this.props.allowNew) {

@@ -244,10 +269,18 @@ this.addTag({ name: this.state.query });

if (options.length === 0 && props.noSuggestionsText) {
options.push({ id: 0, name: props.noSuggestionsText, disabled: true, disableMarkIt: true });
options = options.slice(0, props.maxSuggestionsLength);
if (props.allowNew) {
if (props.newTagText && findMatchIndex(options, state.query) === -1) {
options.push({ id: 0, name: state.query, prefix: props.newTagText, disableMarkIt: true });
}
} else {
if (props.noSuggestionsText && options.length === 0) {
options.push({ id: 0, name: props.noSuggestionsText, disabled: true, disableMarkIt: true });
}
}
return options.slice(0, props.maxSuggestionsLength)
return options
}
class ReactTags extends React.Component {
class ReactTags extends React__default['default'].Component {
constructor (props) {

@@ -273,5 +306,5 @@ super(props);

this.container = React.createRef();
this.input = React.createRef();
this.suggestions = React.createRef();
this.container = React__default['default'].createRef();
this.input = React__default['default'].createRef();
this.suggestions = React__default['default'].createRef();
}

@@ -354,13 +387,3 @@

if (this.container.current) {
const interactiveEls = this.container.current.querySelectorAll('a,button,input');
const currentEl = Array.prototype.findIndex.call(interactiveEls, (element) => {
return element === event.currentTarget
});
const nextEl = interactiveEls[currentEl - 1] || interactiveEls[currentEl + 1];
if (nextEl) {
nextEl.focus();
}
focusNextElement(this.container.current, event.currentTarget);
}

@@ -380,3 +403,3 @@

this.props.onAddition(tag);
this.props.onAddition({ id: tag.id, name: tag.name });

@@ -401,20 +424,21 @@ this.clearInput();

const expanded = this.state.focused && this.state.query.length >= this.props.minQueryLength;
const classNames = [this.props.classNames.root];
const classNames = Object.assign({}, CLASS_NAMES, this.props.classNames);
const rootClassNames = [classNames.root];
this.state.focused && classNames.push(this.props.classNames.rootFocused);
this.state.focused && rootClassNames.push(classNames.rootFocused);
return (
React.createElement( 'div', { ref: this.container, className: classNames.join(' '), onClick: this.onClick.bind(this) },
React.createElement( 'div', {
className: this.props.classNames.selected, 'aria-relevant': 'additions removals', 'aria-live': 'polite' },
React__default['default'].createElement( 'div', { ref: this.container, className: rootClassNames.join(' '), onClick: this.onClick.bind(this) },
React__default['default'].createElement( 'div', {
className: classNames.selected, 'aria-relevant': 'additions removals', 'aria-live': 'polite' },
this.props.tags.map((tag, i) => (
React.createElement( TagComponent, {
key: i, tag: tag, removeButtonText: this.props.removeButtonText, classNames: this.props.classNames, onDelete: this.onDeleteTag.bind(this, i) })
React__default['default'].createElement( TagComponent, {
key: i, tag: tag, removeButtonText: this.props.removeButtonText, classNames: classNames, onDelete: this.onDeleteTag.bind(this, i) })
))
),
React.createElement( 'div', { className: this.props.classNames.search },
React.createElement( Input, Object.assign({},
this.state, { id: this.props.id, ref: this.input, classNames: this.props.classNames, inputAttributes: this.props.inputAttributes, inputEventHandlers: this.inputEventHandlers, autoresize: this.props.autoresize, expanded: expanded, placeholderText: this.props.placeholderText, ariaLabelText: this.props.ariaLabelText })),
React.createElement( Suggestions, Object.assign({},
this.state, { id: this.props.id, ref: this.suggestions, classNames: this.props.classNames, expanded: expanded, addTag: this.addTag.bind(this), suggestionComponent: this.props.suggestionComponent }))
React__default['default'].createElement( 'div', { className: classNames.search },
React__default['default'].createElement( Input, Object.assign({},
this.state, { id: this.props.id, ref: this.input, classNames: classNames, inputAttributes: this.props.inputAttributes, inputEventHandlers: this.inputEventHandlers, autoresize: this.props.autoresize, expanded: expanded, placeholderText: this.props.placeholderText, ariaLabelText: this.props.ariaLabelText })),
React__default['default'].createElement( Suggestions, Object.assign({},
this.state, { id: this.props.id, ref: this.suggestions, classNames: classNames, expanded: expanded, addTag: this.addTag.bind(this), suggestionComponent: this.props.suggestionComponent }))
)

@@ -444,2 +468,3 @@ )

noSuggestionsText: null,
newTagText: null,
suggestions: [],

@@ -462,36 +487,37 @@ suggestionsFilter: defaultSuggestionsFilter,

ReactTags.propTypes = {
id: PropTypes.string,
tags: PropTypes.arrayOf(PropTypes.object),
placeholderText: PropTypes.string,
ariaLabelText: PropTypes.string,
removeButtonText: PropTypes.string,
noSuggestionsText: PropTypes.string,
suggestions: PropTypes.arrayOf(PropTypes.object),
suggestionsFilter: PropTypes.func,
suggestionsTransform: PropTypes.func,
autoresize: PropTypes.bool,
delimiters: PropTypes.arrayOf(PropTypes.string),
onDelete: PropTypes.func.isRequired,
onAddition: PropTypes.func.isRequired,
onInput: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
onValidate: PropTypes.func,
minQueryLength: PropTypes.number,
maxSuggestionsLength: PropTypes.number,
classNames: PropTypes.object,
allowNew: PropTypes.bool,
allowBackspace: PropTypes.bool,
addOnBlur: PropTypes.bool,
tagComponent: PropTypes.oneOfType([
PropTypes.func,
PropTypes.element
id: PropTypes__default['default'].string,
tags: PropTypes__default['default'].arrayOf(PropTypes__default['default'].object),
placeholderText: PropTypes__default['default'].string,
ariaLabelText: PropTypes__default['default'].string,
removeButtonText: PropTypes__default['default'].string,
noSuggestionsText: PropTypes__default['default'].string,
newTagText: PropTypes__default['default'].string,
suggestions: PropTypes__default['default'].arrayOf(PropTypes__default['default'].object),
suggestionsFilter: PropTypes__default['default'].func,
suggestionsTransform: PropTypes__default['default'].func,
autoresize: PropTypes__default['default'].bool,
delimiters: PropTypes__default['default'].arrayOf(PropTypes__default['default'].string),
onDelete: PropTypes__default['default'].func.isRequired,
onAddition: PropTypes__default['default'].func.isRequired,
onInput: PropTypes__default['default'].func,
onFocus: PropTypes__default['default'].func,
onBlur: PropTypes__default['default'].func,
onValidate: PropTypes__default['default'].func,
minQueryLength: PropTypes__default['default'].number,
maxSuggestionsLength: PropTypes__default['default'].number,
classNames: PropTypes__default['default'].object,
allowNew: PropTypes__default['default'].bool,
allowBackspace: PropTypes__default['default'].bool,
addOnBlur: PropTypes__default['default'].bool,
tagComponent: PropTypes__default['default'].oneOfType([
PropTypes__default['default'].func,
PropTypes__default['default'].element
]),
suggestionComponent: PropTypes.oneOfType([
PropTypes.func,
PropTypes.element
suggestionComponent: PropTypes__default['default'].oneOfType([
PropTypes__default['default'].func,
PropTypes__default['default'].element
]),
inputAttributes: PropTypes.object
inputAttributes: PropTypes__default['default'].object
};
module.exports = ReactTags;

@@ -44,4 +44,4 @@ import React from 'react';

componentDidUpdate ({ query, placeholder }) {
if (query !== this.props.query || placeholder !== this.props.placeholder) {
componentDidUpdate ({ query, placeholderText }) {
if (query !== this.props.query || placeholderText !== this.props.placeholderText) {
this.updateInputWidth();

@@ -140,3 +140,7 @@ }

id: key, key: key, role: 'option', className: classNames.join(' '), 'aria-disabled': item.disabled === true, onMouseDown: this.onMouseDown.bind(this, item) },
item.disableMarkIt ? item.name
item.prefix
? React.createElement( 'span', { className: this.props.classNames.suggestionPrefix }, item.prefix, ' ')
: null,
item.disableMarkIt
? item.name
: React.createElement( SuggestionComponent, { item: item, query: this.props.query })

@@ -155,2 +159,17 @@ )

function focusNextElement(scope, currentTarget) {
const interactiveEls = scope.querySelectorAll("a,button,input");
const currentEl = Array.prototype.findIndex.call(
interactiveEls,
(element) => element === currentTarget
);
const nextEl = interactiveEls[currentEl - 1] || interactiveEls[currentEl + 1];
if (nextEl) {
nextEl.focus();
}
}
const KEYS = {

@@ -177,16 +196,19 @@ ENTER: 'Enter',

suggestionActive: 'is-active',
suggestionDisabled: 'is-disabled'
suggestionDisabled: 'is-disabled',
suggestionPrefix: 'react-tags__suggestion-prefix'
};
function findMatchIndex (options, query) {
return options.findIndex((option) => matchExact(query).test(option.name))
}
function pressDelimiter () {
if (this.state.query.length >= this.props.minQueryLength) {
// Check if the user typed in an existing suggestion.
const match = this.state.options.findIndex((option) => {
return matchExact(this.state.query).test(option.name)
});
const match = findMatchIndex(this.state.options, this.state.query);
const index = this.state.index === -1 ? match : this.state.index;
const tag = index > -1 ? this.state.options[index] : null;
if (index > -1 && this.state.options[index]) {
this.addTag(this.state.options[index]);
if (tag) {
this.addTag(tag);
} else if (this.props.allowNew) {

@@ -235,7 +257,15 @@ this.addTag({ name: this.state.query });

if (options.length === 0 && props.noSuggestionsText) {
options.push({ id: 0, name: props.noSuggestionsText, disabled: true, disableMarkIt: true });
options = options.slice(0, props.maxSuggestionsLength);
if (props.allowNew) {
if (props.newTagText && findMatchIndex(options, state.query) === -1) {
options.push({ id: 0, name: state.query, prefix: props.newTagText, disableMarkIt: true });
}
} else {
if (props.noSuggestionsText && options.length === 0) {
options.push({ id: 0, name: props.noSuggestionsText, disabled: true, disableMarkIt: true });
}
}
return options.slice(0, props.maxSuggestionsLength)
return options
}

@@ -344,13 +374,3 @@

if (this.container.current) {
const interactiveEls = this.container.current.querySelectorAll('a,button,input');
const currentEl = Array.prototype.findIndex.call(interactiveEls, (element) => {
return element === event.currentTarget
});
const nextEl = interactiveEls[currentEl - 1] || interactiveEls[currentEl + 1];
if (nextEl) {
nextEl.focus();
}
focusNextElement(this.container.current, event.currentTarget);
}

@@ -370,3 +390,3 @@

this.props.onAddition(tag);
this.props.onAddition({ id: tag.id, name: tag.name });

@@ -391,20 +411,21 @@ this.clearInput();

const expanded = this.state.focused && this.state.query.length >= this.props.minQueryLength;
const classNames = [this.props.classNames.root];
const classNames = Object.assign({}, CLASS_NAMES, this.props.classNames);
const rootClassNames = [classNames.root];
this.state.focused && classNames.push(this.props.classNames.rootFocused);
this.state.focused && rootClassNames.push(classNames.rootFocused);
return (
React.createElement( 'div', { ref: this.container, className: classNames.join(' '), onClick: this.onClick.bind(this) },
React.createElement( 'div', { ref: this.container, className: rootClassNames.join(' '), onClick: this.onClick.bind(this) },
React.createElement( 'div', {
className: this.props.classNames.selected, 'aria-relevant': 'additions removals', 'aria-live': 'polite' },
className: classNames.selected, 'aria-relevant': 'additions removals', 'aria-live': 'polite' },
this.props.tags.map((tag, i) => (
React.createElement( TagComponent, {
key: i, tag: tag, removeButtonText: this.props.removeButtonText, classNames: this.props.classNames, onDelete: this.onDeleteTag.bind(this, i) })
key: i, tag: tag, removeButtonText: this.props.removeButtonText, classNames: classNames, onDelete: this.onDeleteTag.bind(this, i) })
))
),
React.createElement( 'div', { className: this.props.classNames.search },
React.createElement( 'div', { className: classNames.search },
React.createElement( Input, Object.assign({},
this.state, { id: this.props.id, ref: this.input, classNames: this.props.classNames, inputAttributes: this.props.inputAttributes, inputEventHandlers: this.inputEventHandlers, autoresize: this.props.autoresize, expanded: expanded, placeholderText: this.props.placeholderText, ariaLabelText: this.props.ariaLabelText })),
this.state, { id: this.props.id, ref: this.input, classNames: classNames, inputAttributes: this.props.inputAttributes, inputEventHandlers: this.inputEventHandlers, autoresize: this.props.autoresize, expanded: expanded, placeholderText: this.props.placeholderText, ariaLabelText: this.props.ariaLabelText })),
React.createElement( Suggestions, Object.assign({},
this.state, { id: this.props.id, ref: this.suggestions, classNames: this.props.classNames, expanded: expanded, addTag: this.addTag.bind(this), suggestionComponent: this.props.suggestionComponent }))
this.state, { id: this.props.id, ref: this.suggestions, classNames: classNames, expanded: expanded, addTag: this.addTag.bind(this), suggestionComponent: this.props.suggestionComponent }))
)

@@ -434,2 +455,3 @@ )

noSuggestionsText: null,
newTagText: null,
suggestions: [],

@@ -458,2 +480,3 @@ suggestionsFilter: defaultSuggestionsFilter,

noSuggestionsText: PropTypes.string,
newTagText: PropTypes.string,
suggestions: PropTypes.arrayOf(PropTypes.object),

@@ -460,0 +483,0 @@ suggestionsFilter: PropTypes.func,

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react'), require('prop-types')) :
typeof define === 'function' && define.amd ? define(['react', 'prop-types'], factory) :
(global = global || self, global.ReactTags = factory(global.React, global.PropTypes));
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ReactTags = factory(global.React, global.PropTypes));
}(this, (function (React, PropTypes) { 'use strict';
React = React && Object.prototype.hasOwnProperty.call(React, 'default') ? React['default'] : React;
PropTypes = PropTypes && Object.prototype.hasOwnProperty.call(PropTypes, 'default') ? PropTypes['default'] : PropTypes;
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
function Tag (props) { return (
React.createElement( 'button', { type: 'button', className: props.classNames.selectedTag, title: props.removeButtonText, onClick: props.onDelete },
React.createElement( 'span', { className: props.classNames.selectedTagName }, props.tag.name)
React__default['default'].createElement( 'button', { type: 'button', className: props.classNames.selectedTag, title: props.removeButtonText, onClick: props.onDelete },
React__default['default'].createElement( 'span', { className: props.classNames.selectedTagName }, props.tag.name)
)

@@ -39,4 +41,4 @@ ); }

this.input = React.createRef();
this.sizer = React.createRef();
this.input = React__default['default'].createRef();
this.sizer = React__default['default'].createRef();
}

@@ -57,5 +59,5 @@

var query = ref.query;
var placeholder = ref.placeholder;
var placeholderText = ref.placeholderText;
if (query !== this.props.query || placeholder !== this.props.placeholder) {
if (query !== this.props.query || placeholderText !== this.props.placeholderText) {
this.updateInputWidth();

@@ -66,3 +68,3 @@ }

Input.prototype.copyInputStyles = function copyInputStyles () {
var this$1 = this;
var this$1$1 = this;

@@ -72,3 +74,3 @@ var inputStyle = window.getComputedStyle(this.input.current);

STYLE_PROPS.forEach(function (prop) {
this$1.sizer.current.style[prop] = inputStyle[prop];
this$1$1.sizer.current.style[prop] = inputStyle[prop];
});

@@ -104,6 +106,6 @@ };

return (
React.createElement( 'div', { className: classNames.searchWrapper },
React.createElement( 'input', Object.assign({},
React__default['default'].createElement( 'div', { className: classNames.searchWrapper },
React__default['default'].createElement( 'input', Object.assign({},
inputAttributes, inputEventHandlers, { ref: this.input, value: query, placeholder: placeholderText, className: classNames.searchInput, role: 'combobox', 'aria-autocomplete': 'list', 'aria-label': ariaLabelText || placeholderText, 'aria-owns': id, 'aria-activedescendant': index > -1 ? (id + "-" + index) : null, 'aria-expanded': expanded, style: { width: this.state.inputWidth } })),
React.createElement( 'div', { ref: this.sizer, style: SIZER_STYLES }, query || placeholderText)
React__default['default'].createElement( 'div', { ref: this.sizer, style: SIZER_STYLES }, query || placeholderText)
)

@@ -114,3 +116,3 @@ )

return Input;
}(React.Component));
}(React__default['default'].Component));

@@ -143,3 +145,3 @@ function escapeForRegExp (string) {

return (
React.createElement( 'span', { dangerouslySetInnerHTML: { __html: markIt(item.name, query) } })
React__default['default'].createElement( 'span', { dangerouslySetInnerHTML: { __html: markIt(item.name, query) } })
);

@@ -164,3 +166,3 @@ };

Suggestions.prototype.render = function render () {
var this$1 = this;
var this$1$1 = this;

@@ -174,18 +176,22 @@ if (!this.props.expanded || !this.props.options.length) {

var options = this.props.options.map(function (item, index) {
var key = (this$1.props.id) + "-" + index;
var key = (this$1$1.props.id) + "-" + index;
var classNames = [];
if (this$1.props.index === index) {
classNames.push(this$1.props.classNames.suggestionActive);
if (this$1$1.props.index === index) {
classNames.push(this$1$1.props.classNames.suggestionActive);
}
if (item.disabled) {
classNames.push(this$1.props.classNames.suggestionDisabled);
classNames.push(this$1$1.props.classNames.suggestionDisabled);
}
return (
React.createElement( 'li', {
id: key, key: key, role: 'option', className: classNames.join(' '), 'aria-disabled': item.disabled === true, onMouseDown: this$1.onMouseDown.bind(this$1, item) },
item.disableMarkIt ? item.name
: React.createElement( SuggestionComponent, { item: item, query: this$1.props.query })
React__default['default'].createElement( 'li', {
id: key, key: key, role: 'option', className: classNames.join(' '), 'aria-disabled': item.disabled === true, onMouseDown: this$1$1.onMouseDown.bind(this$1$1, item) },
item.prefix
? React__default['default'].createElement( 'span', { className: this$1$1.props.classNames.suggestionPrefix }, item.prefix, ' ')
: null,
item.disableMarkIt
? item.name
: React__default['default'].createElement( SuggestionComponent, { item: item, query: this$1$1.props.query })
)

@@ -196,4 +202,4 @@ )

return (
React.createElement( 'div', { className: this.props.classNames.suggestions },
React.createElement( 'ul', { role: 'listbox', id: this.props.id }, options)
React__default['default'].createElement( 'div', { className: this.props.classNames.suggestions },
React__default['default'].createElement( 'ul', { role: 'listbox', id: this.props.id }, options)
)

@@ -204,4 +210,19 @@ )

return Suggestions;
}(React.Component));
}(React__default['default'].Component));
function focusNextElement(scope, currentTarget) {
var interactiveEls = scope.querySelectorAll("a,button,input");
var currentEl = Array.prototype.findIndex.call(
interactiveEls,
function (element) { return element === currentTarget; }
);
var nextEl = interactiveEls[currentEl - 1] || interactiveEls[currentEl + 1];
if (nextEl) {
nextEl.focus();
}
}
var KEYS = {

@@ -228,18 +249,19 @@ ENTER: 'Enter',

suggestionActive: 'is-active',
suggestionDisabled: 'is-disabled'
suggestionDisabled: 'is-disabled',
suggestionPrefix: 'react-tags__suggestion-prefix'
};
function findMatchIndex (options, query) {
return options.findIndex(function (option) { return matchExact(query).test(option.name); })
}
function pressDelimiter () {
var this$1 = this;
if (this.state.query.length >= this.props.minQueryLength) {
// Check if the user typed in an existing suggestion.
var match = this.state.options.findIndex(function (option) {
return matchExact(this$1.state.query).test(option.name)
});
var match = findMatchIndex(this.state.options, this.state.query);
var index = this.state.index === -1 ? match : this.state.index;
var tag = index > -1 ? this.state.options[index] : null;
if (index > -1 && this.state.options[index]) {
this.addTag(this.state.options[index]);
if (tag) {
this.addTag(tag);
} else if (this.props.allowNew) {

@@ -288,7 +310,15 @@ this.addTag({ name: this.state.query });

if (options.length === 0 && props.noSuggestionsText) {
options.push({ id: 0, name: props.noSuggestionsText, disabled: true, disableMarkIt: true });
options = options.slice(0, props.maxSuggestionsLength);
if (props.allowNew) {
if (props.newTagText && findMatchIndex(options, state.query) === -1) {
options.push({ id: 0, name: state.query, prefix: props.newTagText, disableMarkIt: true });
}
} else {
if (props.noSuggestionsText && options.length === 0) {
options.push({ id: 0, name: props.noSuggestionsText, disabled: true, disableMarkIt: true });
}
}
return options.slice(0, props.maxSuggestionsLength)
return options
}

@@ -317,5 +347,5 @@

this.container = React.createRef();
this.input = React.createRef();
this.suggestions = React.createRef();
this.container = React__default['default'].createRef();
this.input = React__default['default'].createRef();
this.suggestions = React__default['default'].createRef();
}

@@ -402,13 +432,3 @@

if (this.container.current) {
var interactiveEls = this.container.current.querySelectorAll('a,button,input');
var currentEl = Array.prototype.findIndex.call(interactiveEls, function (element) {
return element === event.currentTarget
});
var nextEl = interactiveEls[currentEl - 1] || interactiveEls[currentEl + 1];
if (nextEl) {
nextEl.focus();
}
focusNextElement(this.container.current, event.currentTarget);
}

@@ -428,3 +448,3 @@

this.props.onAddition(tag);
this.props.onAddition({ id: tag.id, name: tag.name });

@@ -446,3 +466,3 @@ this.clearInput();

ReactTags.prototype.render = function render () {
var this$1 = this;
var this$1$1 = this;

@@ -452,20 +472,21 @@ var TagComponent = this.props.tagComponent || Tag;

var expanded = this.state.focused && this.state.query.length >= this.props.minQueryLength;
var classNames = [this.props.classNames.root];
var classNames = Object.assign({}, CLASS_NAMES, this.props.classNames);
var rootClassNames = [classNames.root];
this.state.focused && classNames.push(this.props.classNames.rootFocused);
this.state.focused && rootClassNames.push(classNames.rootFocused);
return (
React.createElement( 'div', { ref: this.container, className: classNames.join(' '), onClick: this.onClick.bind(this) },
React.createElement( 'div', {
className: this.props.classNames.selected, 'aria-relevant': 'additions removals', 'aria-live': 'polite' },
React__default['default'].createElement( 'div', { ref: this.container, className: rootClassNames.join(' '), onClick: this.onClick.bind(this) },
React__default['default'].createElement( 'div', {
className: classNames.selected, 'aria-relevant': 'additions removals', 'aria-live': 'polite' },
this.props.tags.map(function (tag, i) { return (
React.createElement( TagComponent, {
key: i, tag: tag, removeButtonText: this$1.props.removeButtonText, classNames: this$1.props.classNames, onDelete: this$1.onDeleteTag.bind(this$1, i) })
React__default['default'].createElement( TagComponent, {
key: i, tag: tag, removeButtonText: this$1$1.props.removeButtonText, classNames: classNames, onDelete: this$1$1.onDeleteTag.bind(this$1$1, i) })
); })
),
React.createElement( 'div', { className: this.props.classNames.search },
React.createElement( Input, Object.assign({},
this.state, { id: this.props.id, ref: this.input, classNames: this.props.classNames, inputAttributes: this.props.inputAttributes, inputEventHandlers: this.inputEventHandlers, autoresize: this.props.autoresize, expanded: expanded, placeholderText: this.props.placeholderText, ariaLabelText: this.props.ariaLabelText })),
React.createElement( Suggestions, Object.assign({},
this.state, { id: this.props.id, ref: this.suggestions, classNames: this.props.classNames, expanded: expanded, addTag: this.addTag.bind(this), suggestionComponent: this.props.suggestionComponent }))
React__default['default'].createElement( 'div', { className: classNames.search },
React__default['default'].createElement( Input, Object.assign({},
this.state, { id: this.props.id, ref: this.input, classNames: classNames, inputAttributes: this.props.inputAttributes, inputEventHandlers: this.inputEventHandlers, autoresize: this.props.autoresize, expanded: expanded, placeholderText: this.props.placeholderText, ariaLabelText: this.props.ariaLabelText })),
React__default['default'].createElement( Suggestions, Object.assign({},
this.state, { id: this.props.id, ref: this.suggestions, classNames: classNames, expanded: expanded, addTag: this.addTag.bind(this), suggestionComponent: this.props.suggestionComponent }))
)

@@ -489,3 +510,3 @@ )

return ReactTags;
}(React.Component));
}(React__default['default'].Component));

@@ -498,2 +519,3 @@ ReactTags.defaultProps = {

noSuggestionsText: null,
newTagText: null,
suggestions: [],

@@ -516,34 +538,35 @@ suggestionsFilter: defaultSuggestionsFilter,

ReactTags.propTypes = {
id: PropTypes.string,
tags: PropTypes.arrayOf(PropTypes.object),
placeholderText: PropTypes.string,
ariaLabelText: PropTypes.string,
removeButtonText: PropTypes.string,
noSuggestionsText: PropTypes.string,
suggestions: PropTypes.arrayOf(PropTypes.object),
suggestionsFilter: PropTypes.func,
suggestionsTransform: PropTypes.func,
autoresize: PropTypes.bool,
delimiters: PropTypes.arrayOf(PropTypes.string),
onDelete: PropTypes.func.isRequired,
onAddition: PropTypes.func.isRequired,
onInput: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
onValidate: PropTypes.func,
minQueryLength: PropTypes.number,
maxSuggestionsLength: PropTypes.number,
classNames: PropTypes.object,
allowNew: PropTypes.bool,
allowBackspace: PropTypes.bool,
addOnBlur: PropTypes.bool,
tagComponent: PropTypes.oneOfType([
PropTypes.func,
PropTypes.element
id: PropTypes__default['default'].string,
tags: PropTypes__default['default'].arrayOf(PropTypes__default['default'].object),
placeholderText: PropTypes__default['default'].string,
ariaLabelText: PropTypes__default['default'].string,
removeButtonText: PropTypes__default['default'].string,
noSuggestionsText: PropTypes__default['default'].string,
newTagText: PropTypes__default['default'].string,
suggestions: PropTypes__default['default'].arrayOf(PropTypes__default['default'].object),
suggestionsFilter: PropTypes__default['default'].func,
suggestionsTransform: PropTypes__default['default'].func,
autoresize: PropTypes__default['default'].bool,
delimiters: PropTypes__default['default'].arrayOf(PropTypes__default['default'].string),
onDelete: PropTypes__default['default'].func.isRequired,
onAddition: PropTypes__default['default'].func.isRequired,
onInput: PropTypes__default['default'].func,
onFocus: PropTypes__default['default'].func,
onBlur: PropTypes__default['default'].func,
onValidate: PropTypes__default['default'].func,
minQueryLength: PropTypes__default['default'].number,
maxSuggestionsLength: PropTypes__default['default'].number,
classNames: PropTypes__default['default'].object,
allowNew: PropTypes__default['default'].bool,
allowBackspace: PropTypes__default['default'].bool,
addOnBlur: PropTypes__default['default'].bool,
tagComponent: PropTypes__default['default'].oneOfType([
PropTypes__default['default'].func,
PropTypes__default['default'].element
]),
suggestionComponent: PropTypes.oneOfType([
PropTypes.func,
PropTypes.element
suggestionComponent: PropTypes__default['default'].oneOfType([
PropTypes__default['default'].func,
PropTypes__default['default'].element
]),
inputAttributes: PropTypes.object
inputAttributes: PropTypes__default['default'].object
};

@@ -550,0 +573,0 @@

{
"name": "react-tag-autocomplete",
"version": "6.1.0",
"version": "6.2.0",
"description": "React Tag Autocomplete is a simple tagging component ready to drop in your React projects.",

@@ -15,4 +15,4 @@ "main": "dist/ReactTags.cjs.js",

"coverage": "nyc --include 'dist/**' npm test",
"dev": "NODE_ENV=development rollup -c example/rollup.config.js --watch",
"example": "NODE_ENV=production rollup -c example/rollup.config.js",
"dev": "rollup --environment=NODE_ENV:development -c example/rollup.config.js --watch",
"example": "rollup --environment=NODE_ENV:production -c example/rollup.config.js",
"build": "rollup -c rollup.config.js"

@@ -40,3 +40,6 @@ },

"Herdis Maria",
"Sibiraj S"
"Sibiraj S",
"Cristina Lozano",
"Alexander Nestorov",
"Lars Haßler"
],

@@ -47,23 +50,23 @@ "license": "MIT",

"prop-types": "^15.5.0",
"react": "^16.5.0",
"react-dom": "^16.5.0"
"react": "^16.5.0 || ^17.0.0",
"react-dom": "^16.5.0 || ^17.0.0"
},
"devDependencies": {
"@rollup/plugin-buble": "^0.21.0",
"@rollup/plugin-commonjs": "^11.0.2",
"@rollup/plugin-node-resolve": "^7.1.0",
"@rollup/plugin-replace": "^2.3.0",
"coveralls": "^3.0.0",
"jasmine": "^3.5.0",
"jsdom": "^16.1.0",
"@rollup/plugin-commonjs": "^19.0.0",
"@rollup/plugin-node-resolve": "^13.0.0",
"@rollup/plugin-replace": "^2.4.2",
"coveralls": "^3.1.0",
"jasmine": "^3.7.0",
"jsdom": "^16.6.0",
"match-sorter": "^4.2.0",
"nyc": "^15.0.0",
"prop-types": "^15.7.0",
"react": "^16.10.0",
"react-dom": "^16.10.0",
"rollup": "^1.30.0",
"rollup-plugin-serve": "^1.0.0",
"rollup-plugin-terser": "^5.2.0",
"sinon": "^8.1.0",
"standard": "^14.3.0"
"nyc": "^15.1.0",
"prop-types": "^15.7.2",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"rollup": "^2.52.6",
"rollup-plugin-serve": "^1.1.0",
"rollup-plugin-terser": "^7.0.2",
"sinon": "^11.1.0",
"standard": "^16.0.2"
},

@@ -70,0 +73,0 @@ "engines": {

@@ -90,2 +90,3 @@ # React Tag Autocomplete

- [`noSuggestionsText`](#noSuggestionsText-optional)
- [`newTagText`](#newtagtext-optional)
- [`autoresize`](#autoresize-optional)

@@ -96,4 +97,4 @@ - [`delimiters`](#delimiters-optional)

- [`classNames`](#classnames-optional)
- [`onAddition`](#onaddition-optional)
- [`onDelete`](#ondelete-optional)
- [`onAddition`](#onaddition-required)
- [`onDelete`](#ondelete-required)
- [`onInput`](#oninput-optional)

@@ -107,2 +108,3 @@ - [`onFocus`](#onfocus-optional)

- [`tagComponent`](#tagcomponent-optional)
- [`suggestionComponent`](#suggestioncomponent-optional)
- [`inputAttributes`](#inputAttributes-optional)

@@ -176,2 +178,6 @@

#### newTagText (optional)
Enables users to show a prompt to add a new tag at the bottom of the suggestions list if `allowNew` is enabled. Defaults to `null`.
#### autoresize (optional)

@@ -209,3 +215,4 @@

suggestionActive: 'is-active',
suggestionDisabled: 'is-disabled'
suggestionDisabled: 'is-disabled',
suggestionPrefix: 'react-tags__suggestion-prefix'
}

@@ -212,0 +219,0 @@ ```

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc