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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | 53x 53x 53x 53x 53x 53x 53x 38x 53x 38x 53x 18x 18x 53x 16x 16x 16x 53x 53x | import React, { useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; import { PluggableList } from 'unified'; import { processHtml, htmlEncode } from './utils'; import shortcuts from './shortcuts'; import * as styles from './styles'; import './style/index.less'; export * from './SelectionText'; export interface TextareaCodeEditorProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> { prefixCls?: string; /** * Support dark-mode/night-mode */ ['data-color-mode']?: 'dark' | 'light'; /** * Set what programming language the code belongs to. */ language?: string; /** * Optional padding for code. Default: `10`. */ padding?: number; /** * rehypePlugins (Array.<Plugin>, default: `[[rehypePrism, { ignoreMissing: true }]]`) * List of [rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins) to use. See the next section for examples on how to pass options */ rehypePlugins?: PluggableList; /** * The minimum height of the editor. Default: `16`. */ minHeight?: number; onKeyDown?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void | boolean; /** * The number of spaces for indentation when pressing tab key. Default: `2`. */ indentWidth?: number; } export default React.forwardRef<HTMLTextAreaElement, TextareaCodeEditorProps>((props, ref) => { const { prefixCls = 'w-tc-editor', value: _, padding = 10, minHeight = 16, placeholder, language, 'data-color-mode': dataColorMode, className, style, rehypePlugins, onChange, indentWidth = 2, ...other } = props; const [value, setValue] = useState(props.value || ''); useEffect(() => setValue(props.value || ''), [props.value]); const textRef = useRef<HTMLTextAreaElement>(null); useImperativeHandle<HTMLTextAreaElement, HTMLTextAreaElement>(ref, () => textRef.current!, [textRef]); const contentStyle = { paddingTop: padding, paddingRight: padding, paddingBottom: padding, paddingLeft: padding, }; const htmlStr = useMemo( () => processHtml( `<pre aria-hidden=true><code ${language && value ? `class="language-${language}"` : ''} >${htmlEncode( String(value || ''), )}</code><br /></pre>`, rehypePlugins, ), [value, language, rehypePlugins], ); const preView = useMemo( () => ( <div style={{ ...styles.editor, ...contentStyle, minHeight }} className={`${prefixCls}-preview ${language ? `language-${language}` : ''}`} dangerouslySetInnerHTML={{ __html: htmlStr, }} /> ), // eslint-disable-next-line react-hooks/exhaustive-deps [prefixCls, language, htmlStr], ); const change = (evn: React.ChangeEvent<HTMLTextAreaElement>) => { setValue(evn.target.value); onChange && onChange(evn); }; const keyDown = (evn: React.KeyboardEvent<HTMLTextAreaElement>) => { Iif (other.readOnly) return; Eif (!other.onKeyDown || other.onKeyDown(evn) !== false) { shortcuts(evn, indentWidth); } }; const textareaProps: React.TextareaHTMLAttributes<HTMLTextAreaElement> = { autoComplete: 'off', autoCorrect: 'off', spellCheck: 'false', autoCapitalize: 'off', ...other, placeholder, onKeyDown: keyDown, style: { ...styles.editor, ...styles.textarea, ...contentStyle, minHeight, ...(placeholder && !value ? { WebkitTextFillColor: 'inherit' } : {}), }, onChange: change, className: `${prefixCls}-text`, value: value, }; return ( <div style={{ ...styles.container, ...style }} className={`${prefixCls} ${className || ''}`} data-color-mode={dataColorMode} > <textarea {...textareaProps} ref={textRef} /> {preView} </div> ); }); |