main

mattermost/focalboard

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

markdownEditor.tsx

TLDR

This file, markdownEditor.tsx, contains the implementation of a Markdown editor component for displaying and editing Markdown text.

Methods

There are no methods defined in this file.

Classes

MarkdownEditor

The MarkdownEditor class is the main class defined in this file. It is a React component that provides a Markdown editor interface. It takes various props for customization, such as id, text, placeholderText, className, readonly, onChange, onFocus, onBlur, onKeyDown, onEditorCancel, autofocus, and saveOnEnter.

The component renders an HTML preview of the Markdown text when not in edit mode. When clicked, it switches to edit mode where the user can modify the Markdown text. The edited text can be saved or canceled.

The component uses a lazy-loaded child component, MarkdownEditorInput, for the edit mode. The MarkdownEditorInput component provides an input area for editing the Markdown text.

The MarkdownEditor component toggles between edit mode and preview mode based on the value of the isEditing state. The resulting UI is wrapped inside a div element with class names "MarkdownEditor", "octo-editor", and any additional class name(s) provided in the className prop. The active edit mode is indicated by the "active" class.

The MarkdownEditor component exports the MarkdownEditor class.

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

import {Utils} from '../utils'
import './markdownEditor.scss'

const MarkdownEditorInput = React.lazy(() => import('./markdownEditorInput/markdownEditorInput'))

type Props = {
    id?: string
    text?: string
    placeholderText?: string
    className?: string
    readonly?: boolean

    onChange?: (text: string) => void
    onFocus?: () => void
    onBlur?: (text: string) => void
    onKeyDown?: (e: React.KeyboardEvent) => void
    onEditorCancel?: () => void
    autofocus?: boolean
    saveOnEnter?: boolean
}

const MarkdownEditor = (props: Props): JSX.Element => {
    const {placeholderText, onFocus, onEditorCancel, onBlur, onChange, text, id, saveOnEnter} = props
    const [isEditing, setIsEditing] = useState(Boolean(props.autofocus))
    const html: string = Utils.htmlFromMarkdown(text || placeholderText || '')

    const previewElement = (
        <div
            data-testid='preview-element'
            className={text ? 'octo-editor-preview' : 'octo-editor-preview octo-placeholder'}
            dangerouslySetInnerHTML={{__html: html}}
            onClick={(e) => {
                const LINK_TAG_NAME = 'a'
                const element = e.target as Element
                if (element.tagName.toLowerCase() === LINK_TAG_NAME) {
                    e.stopPropagation()
                    return
                }

                if (!props.readonly && !isEditing) {
                    setIsEditing(true)
                }
            }}
        />
    )

    const editorOnBlur = (newText: string) => {
        setIsEditing(false)
        onBlur && onBlur(newText)
    }

    const editorElement = (
        <Suspense fallback={<></>}>
            <MarkdownEditorInput
                id={id}
                onChange={onChange}
                onFocus={onFocus}
                onEditorCancel={onEditorCancel}
                onBlur={editorOnBlur}
                initialText={text}
                isEditing={isEditing}
                saveOnEnter={saveOnEnter}
            />
        </Suspense>
    )

    const element = (
        <div className={`MarkdownEditor octo-editor ${props.className || ''} ${isEditing ? 'active' : ''}`}>
            {isEditing ? editorElement : previewElement}
        </div>
    )

    return element
}

export {MarkdownEditor}