main

mattermost/focalboard

Last updated at: 29/12/2023 09:41

editableArea.tsx

TLDR

This file contains the implementation of the EditableArea component, which is a React component used for displaying an editable text area. It calculates the height of the text area based on its content and adjusts it dynamically.

Methods

getBorderWidth

This method calculates the total border width of an element by summing the top and bottom border widths.

Classes

None

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {forwardRef, useEffect, useRef} from 'react'

import {EditableProps, Focusable, useEditable} from './editable'

import './editableArea.scss'

function getBorderWidth(style: CSSStyleDeclaration): number {
    return parseInt(style.borderTopWidth || '0', 10) + parseInt(style.borderBottomWidth || '0', 10)
}

const EditableArea = (props: EditableProps, ref: React.Ref<Focusable>): JSX.Element => {
    const elementRef = useRef<HTMLTextAreaElement>(null)
    const referenceRef = useRef<HTMLTextAreaElement>(null)
    const heightRef = useRef(0)
    const elementProps = useEditable(props, ref, elementRef)

    useEffect(() => {
        if (!elementRef.current || !referenceRef.current) {
            return
        }

        const height = referenceRef.current.scrollHeight
        const textarea = elementRef.current

        if (height > 0 && height !== heightRef.current) {
            const style = getComputedStyle(textarea)
            const borderWidth = getBorderWidth(style)

            // Directly change the height to avoid circular rerenders
            textarea.style.height = String(height + borderWidth) + 'px'

            heightRef.current = height
        }
    })

    const heightProps = {
        height: heightRef.current,
        rows: 1,
    }

    return (
        <div className={'EditableAreaWrap'}>
            <textarea
                {...elementProps}
                {...heightProps}
                ref={elementRef}
                className={'EditableArea ' + elementProps.className}
            />
            <div className={'EditableAreaContainer'}>
                <textarea
                    ref={referenceRef}
                    className={'EditableAreaReference ' + elementProps.className}
                    dir='auto'
                    disabled={true}
                    rows={1}
                    value={elementProps.value}
                    aria-hidden={true}
                />
            </div>
        </div>
    )
}

export default forwardRef(EditableArea)