import React, { useEffect, Fragment, useContext, JSX } from 'react'; import type * as CSS from 'csstype'; import { EditorContext, type ContextStore, type ExecuteCommandState } from '../../Context'; import shortcuts from './shortcuts'; import Textarea, { type TextAreaProps } from './Textarea'; import { type IProps } from '../../Types'; import { TextAreaCommandOrchestrator, type ICommand } from '../../commands/'; import './index.less'; export type RenderTextareaHandle = { dispatch: ContextStore['dispatch']; onChange?: TextAreaProps['onChange']; useContext?: { commands: ContextStore['commands']; extraCommands: ContextStore['extraCommands']; commandOrchestrator?: TextAreaCommandOrchestrator; }; shortcuts?: ( e: KeyboardEvent | React.KeyboardEvent, commands: ICommand[], commandOrchestrator?: TextAreaCommandOrchestrator, dispatch?: React.Dispatch, state?: ExecuteCommandState, ) => void; }; export interface ITextAreaProps extends Omit, 'value' | 'onScroll'>, IProps { value?: string; onScroll?: (e: React.UIEvent) => void; renderTextarea?: ( props: React.TextareaHTMLAttributes | React.HTMLAttributes, opts: RenderTextareaHandle, ) => JSX.Element; } export type TextAreaRef = { text?: HTMLTextAreaElement; warp?: HTMLDivElement; }; type MarkdownComponent = React.ComponentType<{ prefixCls?: string }>; export function createTextArea(options?: { Markdown?: MarkdownComponent; useMinHeight?: boolean }) { const MarkdownComponent = options?.Markdown; const useMinHeight = options?.useMinHeight ?? false; return function TextArea(props: ITextAreaProps) { const { prefixCls, className, onScroll, renderTextarea, ...otherProps } = props || {}; const { markdown, scrollTop, commands, minHeight, highlightEnable, extraCommands, dispatch } = useContext(EditorContext); const textRef = React.useRef(null); const executeRef = React.useRef(); const warp = React.createRef(); useEffect(() => { const state: ContextStore = {}; if (warp.current) { state.textareaWarp = warp.current || undefined; warp.current.scrollTop = scrollTop || 0; } if (dispatch) { dispatch({ ...state }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { if (textRef.current && dispatch) { const commandOrchestrator = new TextAreaCommandOrchestrator(textRef.current); executeRef.current = commandOrchestrator; dispatch({ textarea: textRef.current, commandOrchestrator }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const textStyle: CSS.Properties = MarkdownComponent && highlightEnable ? {} : { WebkitTextFillColor: 'initial', overflow: 'auto' }; return (
{renderTextarea ? ( React.cloneElement( renderTextarea( { ...otherProps, value: markdown, autoComplete: 'off', autoCorrect: 'off', spellCheck: 'false', autoCapitalize: 'off', className: `${prefixCls}-text-input`, style: { WebkitTextFillColor: 'inherit', overflow: 'auto', }, }, { dispatch, onChange: otherProps.onChange, shortcuts, useContext: { commands, extraCommands, commandOrchestrator: executeRef.current }, }, ), { ref: textRef, }, ) ) : ( {MarkdownComponent && highlightEnable && }