react-tagsinput icon indicating copy to clipboard operation
react-tagsinput copied to clipboard

Can't remove a tag when input filed has overflow

Open blima-igloosoftware opened this issue 1 year ago • 2 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!

blima-igloosoftware avatar Nov 09 '22 18:11 blima-igloosoftware

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

olahol avatar Nov 15 '22 15:11 olahol

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;

blima-igloosoftware avatar Nov 15 '22 17:11 blima-igloosoftware