|
1 |
| -import React, { useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; |
2 |
| -import { PluggableList } from 'unified'; |
3 |
| -import { processHtml, htmlEncode } from './utils'; |
4 |
| -import shortcuts from './shortcuts'; |
5 |
| -import * as styles from './styles'; |
6 |
| -import './style/index.less'; |
7 |
| - |
8 |
| -export * from './SelectionText'; |
9 |
| - |
10 |
| -export interface TextareaCodeEditorProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> { |
11 |
| - prefixCls?: string; |
12 |
| - /** |
13 |
| - * Support dark-mode/night-mode |
14 |
| - */ |
15 |
| - ['data-color-mode']?: 'dark' | 'light'; |
16 |
| - /** |
17 |
| - * Set what programming language the code belongs to. |
18 |
| - */ |
19 |
| - language?: string; |
20 |
| - /** |
21 |
| - * Optional padding for code. Default: `10`. |
22 |
| - */ |
23 |
| - padding?: number; |
24 |
| - /** |
25 |
| - * rehypePlugins (Array.<Plugin>, default: `[[rehypePrism, { ignoreMissing: true }]]`) |
26 |
| - * 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 |
27 |
| - */ |
28 |
| - rehypePlugins?: PluggableList; |
29 |
| - /** |
30 |
| - * The minimum height of the editor. Default: `16`. |
31 |
| - */ |
32 |
| - minHeight?: number; |
33 |
| - onKeyDown?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void | boolean; |
34 |
| -} |
| 1 | +import React from 'react'; |
| 2 | +import { Pluggable } from 'unified'; |
| 3 | +import Editor, { TextareaCodeEditorProps } from './Editor'; |
| 4 | +import rehypePrism from 'rehype-prism-plus'; |
35 | 5 |
|
36 | 6 | export default React.forwardRef<HTMLTextAreaElement, TextareaCodeEditorProps>((props, ref) => {
|
37 |
| - const { |
38 |
| - prefixCls = 'w-tc-editor', |
39 |
| - value: _, |
40 |
| - padding = 10, |
41 |
| - minHeight = 16, |
42 |
| - placeholder, |
43 |
| - language, |
44 |
| - 'data-color-mode': dataColorMode, |
45 |
| - className, |
46 |
| - style, |
47 |
| - rehypePlugins, |
48 |
| - onChange, |
49 |
| - ...other |
50 |
| - } = props; |
51 |
| - |
52 |
| - const [value, setValue] = useState(props.value || ''); |
53 |
| - useEffect(() => setValue(props.value || ''), [props.value]); |
54 |
| - const textRef = useRef<HTMLTextAreaElement>(null); |
55 |
| - useImperativeHandle<HTMLTextAreaElement, HTMLTextAreaElement>(ref, () => textRef.current!, [textRef]); |
56 |
| - |
57 |
| - const contentStyle = { |
58 |
| - paddingTop: padding, |
59 |
| - paddingRight: padding, |
60 |
| - paddingBottom: padding, |
61 |
| - paddingLeft: padding, |
62 |
| - }; |
63 |
| - |
64 |
| - const htmlStr = useMemo( |
65 |
| - () => |
66 |
| - processHtml( |
67 |
| - `<pre aria-hidden=true><code ${language && value ? `class="language-${language}"` : ''} >${htmlEncode( |
68 |
| - String(value || ''), |
69 |
| - )}</code><br /></pre>`, |
70 |
| - rehypePlugins, |
71 |
| - ), |
72 |
| - [value, language, rehypePlugins], |
73 |
| - ); |
74 |
| - const preView = useMemo( |
75 |
| - () => ( |
76 |
| - <div |
77 |
| - style={{ ...styles.editor, ...contentStyle, minHeight }} |
78 |
| - className={`${prefixCls}-preview ${language ? `language-${language}` : ''}`} |
79 |
| - dangerouslySetInnerHTML={{ |
80 |
| - __html: htmlStr, |
81 |
| - }} |
82 |
| - /> |
83 |
| - ), |
84 |
| - // eslint-disable-next-line react-hooks/exhaustive-deps |
85 |
| - [prefixCls, language, htmlStr], |
86 |
| - ); |
87 |
| - |
88 |
| - const change = (evn: React.ChangeEvent<HTMLTextAreaElement>) => { |
89 |
| - setValue(evn.target.value); |
90 |
| - onChange && onChange(evn); |
91 |
| - }; |
92 |
| - |
93 |
| - const keyDown = (evn: React.KeyboardEvent<HTMLTextAreaElement>) => { |
94 |
| - if (other.readOnly) return; |
95 |
| - if (!other.onKeyDown || other.onKeyDown(evn) !== false) { |
96 |
| - shortcuts(evn); |
97 |
| - } |
98 |
| - }; |
99 |
| - |
100 |
| - const textareaProps: React.TextareaHTMLAttributes<HTMLTextAreaElement> = { |
101 |
| - autoComplete: 'off', |
102 |
| - autoCorrect: 'off', |
103 |
| - spellCheck: 'false', |
104 |
| - autoCapitalize: 'off', |
105 |
| - ...other, |
106 |
| - placeholder, |
107 |
| - onKeyDown: keyDown, |
108 |
| - style: { |
109 |
| - ...styles.editor, |
110 |
| - ...styles.textarea, |
111 |
| - ...contentStyle, |
112 |
| - minHeight, |
113 |
| - ...(placeholder && !value ? { WebkitTextFillColor: 'inherit' } : {}), |
114 |
| - }, |
115 |
| - onChange: change, |
116 |
| - className: `${prefixCls}-text`, |
117 |
| - value: value, |
118 |
| - }; |
119 |
| - |
120 |
| - return ( |
121 |
| - <div |
122 |
| - style={{ ...styles.container, ...style }} |
123 |
| - className={`${prefixCls} ${className || ''}`} |
124 |
| - data-color-mode={dataColorMode} |
125 |
| - > |
126 |
| - <textarea {...textareaProps} ref={textRef} /> |
127 |
| - {preView} |
128 |
| - </div> |
129 |
| - ); |
| 7 | + const { rehypePlugins = [[rehypePrism, { ignoreMissing: true }]] as Pluggable[], ...reset } = props; |
| 8 | + return <Editor {...reset} rehypePlugins={rehypePlugins} ref={ref} />; |
130 | 9 | });
|
0 commit comments