react-input-autosize icon indicating copy to clipboard operation
react-input-autosize copied to clipboard

multiline/textarea support

Open des-des opened this issue 6 years ago • 2 comments

I was wondering if you wanted to add multiline support

I have hacked something in that looks like this

const sizerElem = this.props.multiline ? (
      <div
        ref={this.sizerRef}
        style={multilineSizerStyle}
        className="ba bw1 b--black"
      >
        {sizerValue.split("\n").map((line, i) => (
          <div
            style={{ whiteSpace: "pre-wrap" }}
            key={`sizer-line-${i}`}
            className="db ma0 bw0 pa0"
          >
            {line || "-"}
          </div>
        ))}
      </div>
    ) : (
      <div ref={this.sizerRef} style={sizerStyle}>
        {sizerValue}
      </div>
    );

    const inputElem = this.props.multiline ? (
      <textarea
        {...inputProps}
        ref={this.inputRef}
        rows={this.state.lines || 1}
      />
    ) : (
      <input {...inputProps} ref={this.inputRef} />
    );

Happy to clean up and make a pull request but would understand if you dont want to add this

des-des avatar Jan 18 '19 08:01 des-des

@des-des or you can use https://github.com/andreypopp/react-textarea-autosize

burtek avatar Dec 05 '19 12:12 burtek

I think there's a real need people have for a component that resizes horizontally up to a given width, then resizes vertically. I mocked this up by combining react-textarea-autosize with react-input-autosize, but it would be much cleaner if this was one component...

import React, { useState, useRef, useEffect } from 'react';
import AutosizeInput from 'react-input-autosize';
import TextareaAutosize from 'react-textarea-autosize';
import useComponentSize from '@rehooks/component-size';

// Component that auto-resizes both horizontally and vertically
// We acheive this by making a seamless cutover between input and textarea at a given cutover width
function AutosizeInputTextarea({ value, onChange, cutoverWidth }) {
  // We want to avoid various circumstances where the input and textarea might hand off to each other in a loop
  // Causing an infinite re-render cycle
  // The only thing that should cause a cutover between the two is user input, so we use a lock.
  const [cutoverLocked, setCutoverLocked] = useState(true);
  const [inputType, setInputType] = useState('input'); //'input' || 'textarea';

  const inputRef = useRef(null);
  const { width: inputWidth } = useComponentSize(inputRef);

  // Set autofocus to end of input for seamless cutover between input & textarea
  // https://stackoverflow.com/questions/35951771/react-autofocus-sets-cursor-to-beginning-of-input-value
  const onFocus = (e) => {
    const val = e.target.value;
    e.target.value = '';
    e.target.value = val;
  };

  // INPUT -> TEXTAREA if inputWidth > our cutover width
  useEffect(() => {
    if (!cutoverLocked && cutoverWidth > 0 && inputWidth > cutoverWidth) {
      setCutoverLocked(true);
      setInputType('textarea');
    }
  }, [inputWidth, cutoverWidth, cutoverLocked]);

  // TEXTAREA -> INPUT if textarea shrinks to a single line
  const onInputHeightChange = (height, additionalInfo) => {
    const lineHeight = additionalInfo.rowHeight;
    if (!cutoverLocked && height < 2 * lineHeight) {
      setCutoverLocked(true);
      setInputType('input');
    }
  };

  return (
    <>
      {inputType === 'textarea' ? (
        <TextareaAutosize
          className="autosize-textarea"
          autoFocus={true}
          style={{ width: cutoverWidth }}
          value={value}
          onChange={(e) => {
            onChange(e);
            setCutoverLocked(false);
          }}
          onFocus={onFocus}
          onHeightChange={onInputHeightChange}
        />
      ) : (
        <div ref={inputRef}>
          <AutosizeInput
            className="autosize-input"
            autoFocus={true}
            value={value}
            onChange={(e) => {
              onChange(e);
              setCutoverLocked(false);
            }}
            onFocus={onFocus}
          />
        </div>
      )}
    </>
  );
}

export default AutosizeInputTextarea;

(Feedback on how to improve this welcome 😛 )

dannykennedy avatar Jul 12 '20 01:07 dannykennedy