olahol / react-tagsinput

Highly customizable React component for inputing tags.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can't remove a tag when input filed has overflow

blima-igloosoftware opened this issue · comments

Hello, first of all, thank you for this library and for maintaining it.

I am having an issue with removing a tag when I have a dense populated input field. The bug happens only when I try to delete tags on top of the overflow.

I recorded a quick video to better explain it:
TagBug.webm

Does anyone know why this is happening? and If there is a quick solution?
One solution that came in mind was to control the onRemove method on the tag, but it seems like this method isn't exposed?

Thanks in advance!

commented

Can you post some example code and which browser and React version you are using?

Can you post some example code and which browser and React version you are using?

Version: React: "^16.12.0"
Browsers: Google Chrome Version 107.0.5304.107 (Official Build) (64-bit)

import React, {
  Fragment,
  useRef,
  useState,
  useEffect,
  forwardRef,
} from 'react';
import PropTypes from 'prop-types';
import { randomId } from '@igloosoftware/iglue';
import TagsInput from '@incoqnito.io/react-tagsinput';
import '@incoqnito.io/react-tagsinput/react-tagsinput.css';
import classNames from 'classnames';

import styles from './TagBox.scss';
import FormInputMessage, { ALLOWED_MESSAGE_TYPES } from '../../atoms/FormInputMessage';

const TagBox = forwardRef((props, forwardedRef) => {
  const [tags, setTags] = useState(props.tags);
  const tagsInput = useRef(null);

  // In case a ref is passed to TagBox (eg. AddModal.js)
  // set that ref to point to the correct element
  useEffect(() => {
    if (!forwardedRef) {
      return;
    }

    forwardedRef.current = tagsInput.current;
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  const {
    error,
    border,
    message,
    onChange,
    messageId,
    inputProps,
    ...rest
  } = props;

  const inputMessageId = useRef(messageId || randomId());

  const handleChange = (newTags) => {
    setTags(newTags);

    if (typeof onChange === 'function') {
      onChange(newTags);
    }
  };

  let wrapperClass = classNames('react-tagsinput',
    {
      [styles['react-tagsinput--error']]: error,
      [styles['react-tagsinput-noborder']]: !border,
      'react-tagsinput-placeholder': !tags.length,
    });
  let newInputProps = Object.assign({}, inputProps);

  if (tags.length) {
    newInputProps.placeholder = '';
  }

  const isDescribedBy = [
    ...(message ? [inputMessageId.current] : []),
  ].filter(Boolean).join(' ');

  return <Fragment>
    <TagsInput
      {...rest}
      ref={tagsInput}
      value={tags}
      onChange={handleChange}
      className={wrapperClass}
      inputProps={newInputProps}
      focusedClassName={styles['react-tagsinput--focused']}
      tagProps={{
        className: `${styles['react-tagsinput-tag']}`,
        classNameRemove: `${styles['react-tagsinput-remove']}`,
        'aria-describedby': isDescribedBy.length ? isDescribedBy : undefined,
      }} />
    {message &&
    <FormInputMessage
      id={inputMessageId.current}
      type={error ? ALLOWED_MESSAGE_TYPES.ERROR : ALLOWED_MESSAGE_TYPES.INFO}
      message={message} />
    }
  </Fragment>;
});

TagBox.displayName = 'TagBox';

TagBox.propTypes = {
  tags: PropTypes.array,
  error: PropTypes.bool,
  border: PropTypes.bool,
  message: PropTypes.string,
  onChange: PropTypes.func,
  validate: PropTypes.func,
  addOnBlur: PropTypes.bool,
  messageId: PropTypes.string,
  inputProps: PropTypes.object,
  onlyUnique: PropTypes.bool,
};

TagBox.defaultProps = {
  tags: [],
  error: false,
  border: false,
  onChange: null,
  addOnBlur: false,
  onlyUnique: false,
  inputProps: {
    title: '',
    className: 'react-tagsinput-input',
    placeholder: '',
  },
};

export default TagBox;