Added first autocomplete implementation on tags selector

This commit is contained in:
Alejandro Celaya
2018-08-31 18:00:33 +02:00
parent 1519f89318
commit b0bce7498a
11 changed files with 184 additions and 55 deletions

View File

@@ -5,7 +5,7 @@ import editIcon from '@fortawesome/fontawesome-free-solid/faPencilAlt';
import PropTypes from 'prop-types';
import React from 'react';
import { Link } from 'react-router-dom';
import colorGenerator, { colorGeneratorType } from '../utils/ColorGenerator';
import TagBullet from '../utils/TagBullet';
import './TagCard.scss';
import DeleteTagConfirmModal from './helpers/DeleteTagConfirmModal';
import EditTagModal from './helpers/EditTagModal';
@@ -14,16 +14,12 @@ export default class TagCard extends React.Component {
static propTypes = {
tag: PropTypes.string,
currentServerId: PropTypes.string,
colorGenerator: colorGeneratorType,
};
static defaultProps = {
colorGenerator,
};
state = { isDeleteModalOpen: false, isEditModalOpen: false };
render() {
const { tag, colorGenerator, currentServerId } = this.props;
const { tag, currentServerId } = this.props;
const toggleDelete = () =>
this.setState(({ isDeleteModalOpen }) => ({ isDeleteModalOpen: !isDeleteModalOpen }));
const toggleEdit = () =>
@@ -45,10 +41,7 @@ export default class TagCard extends React.Component {
<FontAwesomeIcon icon={editIcon} />
</button>
<h5 className="tag-card__tag-title">
<div
style={{ backgroundColor: colorGenerator.getColorForKey(tag) }}
className="tag-card__tag-bullet"
/>
<TagBullet tag={tag} />
<Link to={`/server/${currentServerId}/list-short-urls/1?tag=${tag}`}>
{tag}
</Link>

View File

@@ -16,17 +16,6 @@
padding-right: 5px;
}
.tag-card__tag-bullet {
$width: 20px;
border-radius: 50%;
width: $width;
height: $width;
display: inline-block;
vertical-align: -4px;
margin-right: 7px;
}
.tag-card__btn {
float: right;
}

View File

@@ -59,9 +59,7 @@ export default function reducer(state = defaultState, action) {
case FILTER_TAGS:
return {
...state,
filteredTags: state.tags.filter(
(tag) => tag.toLowerCase().match(action.searchTerm),
),
filteredTags: state.tags.filter((tag) => tag.toLowerCase().match(action.searchTerm)),
};
default:
return state;

24
src/utils/TagBullet.js Normal file
View File

@@ -0,0 +1,24 @@
import React from 'react';
import * as PropTypes from 'prop-types';
import colorGenerator, { colorGeneratorType } from './ColorGenerator';
import './TagBullet.scss';
const propTypes = {
tag: PropTypes.string.isRequired,
colorGenerator: colorGeneratorType,
};
const defaultProps = {
colorGenerator,
};
export default function TagBullet({ tag, colorGenerator }) {
return (
<div
style={{ backgroundColor: colorGenerator.getColorForKey(tag) }}
className="tag-bullet"
/>
);
}
TagBullet.propTypes = propTypes;
TagBullet.defaultProps = defaultProps;

10
src/utils/TagBullet.scss Normal file
View File

@@ -0,0 +1,10 @@
.tag-bullet {
$width: 20px;
border-radius: 50%;
width: $width;
height: $width;
display: inline-block;
vertical-align: -4px;
margin-right: 7px;
}

View File

@@ -1,40 +1,102 @@
import React from 'react';
import { connect } from 'react-redux';
import TagsInput from 'react-tagsinput';
import PropTypes from 'prop-types';
import Autosuggest from 'react-autosuggest';
import { pick, identity } from 'ramda';
import { listTags } from '../tags/reducers/tagsList';
import colorGenerator, { colorGeneratorType } from './ColorGenerator';
import './TagsSelector.scss';
import TagBullet from './TagBullet';
const defaultProps = {
colorGenerator,
placeholder: 'Add tags to the URL',
};
const propTypes = {
tags: PropTypes.arrayOf(PropTypes.string).isRequired,
onChange: PropTypes.func.isRequired,
placeholder: PropTypes.string,
colorGenerator: colorGeneratorType,
};
export class TagsSelectorComponent extends React.Component {
static propTypes = {
tags: PropTypes.arrayOf(PropTypes.string).isRequired,
onChange: PropTypes.func.isRequired,
placeholder: PropTypes.string,
colorGenerator: colorGeneratorType,
tagsList: PropTypes.shape({
tags: PropTypes.arrayOf(PropTypes.string),
}),
};
static defaultProps = {
colorGenerator,
placeholder: 'Add tags to the URL',
};
export default function TagsSelector({ tags, onChange, placeholder, colorGenerator }) {
const renderTag = ({ tag, key, disabled, onRemove, classNameRemove, getTagDisplayValue, ...other }) => (
<span key={key} style={{ backgroundColor: colorGenerator.getColorForKey(tag) }} {...other}>
{getTagDisplayValue(tag)}
{!disabled && <span className={classNameRemove} onClick={() => onRemove(key)} />}
</span>
);
componentDidMount() {
const { listTags } = this.props;
return (
<TagsInput
value={tags}
inputProps={{ placeholder }}
onlyUnique
renderTag={renderTag}
listTags();
}
// FIXME Workaround to be able to add tags on Android
addOnBlur
onChange={onChange}
/>
);
render() {
const { tags, onChange, placeholder, colorGenerator, tagsList } = this.props;
const renderTag = ({ tag, key, disabled, onRemove, classNameRemove, getTagDisplayValue, ...other }) => (
<span key={key} style={{ backgroundColor: colorGenerator.getColorForKey(tag) }} {...other}>
{getTagDisplayValue(tag)}
{!disabled && <span className={classNameRemove} onClick={() => onRemove(key)} />}
</span>
);
const renderAutocompleteInput = (data) => {
const { addTag, ...rest } = data;
const handleOnChange = (e, { method }) => {
if (method === 'enter') {
e.preventDefault();
} else {
rest.onChange(e);
}
};
// eslint-disable-next-line no-extra-parens
const inputValue = (rest.value && rest.value.trim().toLowerCase()) || '';
const inputLength = inputValue.length;
const suggestions = tagsList.tags.filter((state) => state.toLowerCase().slice(0, inputLength) === inputValue);
return (
<Autosuggest
ref={rest.ref}
suggestions={suggestions}
inputProps={{ ...rest, onChange: handleOnChange }}
highlightFirstSuggestion
shouldRenderSuggestions={(value) => value && value.trim().length > 0}
getSuggestionValue={(suggestion) => {
console.log(suggestion);
return suggestion;
}}
renderSuggestion={(suggestion) => (
<React.Fragment>
<TagBullet tag={suggestion} />
{suggestion}
</React.Fragment>
)}
onSuggestionSelected={(e, { suggestion }) => {
addTag(suggestion);
}}
onSuggestionsClearRequested={identity}
onSuggestionsFetchRequested={identity}
/>
);
};
return (
<TagsInput
value={tags}
inputProps={{ placeholder }}
onlyUnique
renderTag={renderTag}
renderInput={renderAutocompleteInput}
// FIXME Workaround to be able to add tags on Android
addOnBlur
onChange={onChange}
/>
);
}
}
TagsSelector.defaultProps = defaultProps;
TagsSelector.propTypes = propTypes;
const TagsSelector = connect(pick([ 'tagsList' ]), { listTags })(TagsSelectorComponent);
export default TagsSelector;

View File

@@ -0,0 +1,16 @@
@import './base';
.react-autosuggest__suggestions-list {
list-style-type: none;
padding: 0;
margin-bottom: 6px;
}
.react-autosuggest__suggestion {
margin-left: -6px;
padding: 5px 8px;
}
.react-autosuggest__suggestion--highlighted {
background-color: $lightGrey;
}