react-input-autosize
react-input-autosize copied to clipboard
multiline/textarea support
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 or you can use https://github.com/andreypopp/react-textarea-autosize
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 😛 )