Code coverage report for js/widgets/MultiLineTextInputWidget.tsx

# 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>
        );
      }
    }