Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multiline/textarea support #153

Open
des-des opened this issue Jan 18, 2019 · 2 comments
Open

multiline/textarea support #153

des-des opened this issue Jan 18, 2019 · 2 comments

Comments

@des-des
Copy link

des-des commented Jan 18, 2019

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

@burtek
Copy link

burtek commented Dec 5, 2019

@dannykennedy
Copy link

dannykennedy commented Jul 12, 2020

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 😛 )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants