All files / js/widgets MultiLineTextInputWidget.tsx

9.09% Statements 3/33
0% Branches 0/12
0% Functions 0/7
10.34% Lines 3/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 871x 1x   1x                                                                                                                                                                      
import React, { ChangeEvent, Component, createRef, RefObject } from "react";
import { getInputClass, WidgetProps } from "./types";
 
const style = {
  display: "block",
  overflow: "hidden",
  resize: "none",
} as const;
 
export class MultiLineTextInputWidget extends Component<WidgetProps> {
  textarea: RefObject<HTMLTextAreaElement>;
 
  constructor(props: WidgetProps) {
    super(props);
    this.textarea = createRef();
    this.onChange = this.onChange.bind(this);
    this.recalculateSize = this.recalculateSize.bind(this);
  }
 
  onChange(event: ChangeEvent<HTMLTextAreaElement>) {
    this.recalculateSize();
    this.props.onChange(event.target.value);
  }
 
  componentDidMount() {
    this.recalculateSize();
    window.addEventListener("resize", this.recalculateSize);
  }
 
  componentWillUnmount() {
    window.removeEventListener("resize", this.recalculateSize);
  }
 
  componentDidUpdate() {
    this.recalculateSize();
  }
 
  recalculateSize() {
    const node = this.textarea.current;
    if (!node) {
      return;
    }
 
    const style = window.getComputedStyle(node);
    const diff =
      style.getPropertyValue("box-sizing") === "border-box"
        ? 0
        : parseInt(style.getPropertyValue("padding-bottom") || "0", 10) +
          parseInt(style.getPropertyValue("padding-top") || "0", 10);
 
    const updateScrollPosition = node === document.activeElement;
    // Cross-browser compatibility for scroll position
    const oldScrollTop =
      document.documentElement.scrollTop || document.body.scrollTop;
    const oldHeight = node.offsetHeight;
 
    node.style.height = "auto";
    const newHeight = node.scrollHeight - diff;
    node.style.height = newHeight + "px";
 
    if (updateScrollPosition) {
      window.scrollTo(
        document.body.scrollLeft,
        oldScrollTop + (newHeight - oldHeight)
      );
    }
  }
 
  render() {
    const { type, value, placeholder, disabled } = this.props;
 
    return (
      <div>
        <textarea
          ref={this.textarea}
          className={getInputClass(type)}
          onChange={this.onChange}
          style={style}
          value={value}
          disabled={disabled}
          placeholder={placeholder}
        />
      </div>
    );
  }
}