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}