diff --git a/core/README.md b/core/README.md index 53b20dbe..2ffe9b68 100644 --- a/core/README.md +++ b/core/README.md @@ -114,6 +114,34 @@ function App() { } ``` +## Remove Code Highlight + +The following example can help you exclude code highlighting code from being included in the bundle. `@uiw/react-textarea-code-editor/nohighlight` component does not contain the ~~`rehype-prism-plus`~~ code highlighting package. + +```jsx +import React, { useState } from "react"; +import CodeEditor from '@uiw/react-textarea-code-editor/nohighlight'; + +export default function App() { + const [code, setCode] = useState( + `function add(a, b) {\n return a + b;\n}` + ); + return ( + setCode(evn.target.value)} + padding={15} + style={{ + backgroundColor: "#f5f5f5", + fontFamily: 'ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace', + }} + /> + ); +} +``` + ## Support Nextjs Use examples in nextjs. [#31](https://github.com/uiwjs/react-textarea-code-editor/issues/31#issuecomment-909363339) diff --git a/core/package.json b/core/package.json index 6d8b03c6..a8cc6442 100644 --- a/core/package.json +++ b/core/package.json @@ -6,6 +6,21 @@ "funding": "https://jaywcjlove.github.io/#/sponsor", "main": "cjs/index.js", "module": "esm/index.js", + "exports": { + "./README.md": "./README.md", + "./package.json": "./package.json", + "./dist.css": "./dist.css", + ".": { + "import": "./esm/index.js", + "types": "./cjs/index.d.ts", + "require": "./cjs/index.js" + }, + "./nohighlight": { + "import": "./esm/index.nohighlight.js", + "types": "./cjs/index.nohighlight.d.ts", + "require": "./cjs/index.nohighlight.js" + } + }, "repository": { "type": "git", "url": "https://github.com/uiwjs/react-textarea-code-editor.git" diff --git a/core/src/Editor.tsx b/core/src/Editor.tsx new file mode 100644 index 00000000..ca9c1088 --- /dev/null +++ b/core/src/Editor.tsx @@ -0,0 +1,130 @@ +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 { + 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., 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) => void | boolean; +} + +export default React.forwardRef((props, ref) => { + const { + prefixCls = 'w-tc-editor', + value: _, + padding = 10, + minHeight = 16, + placeholder, + language, + 'data-color-mode': dataColorMode, + className, + style, + rehypePlugins, + onChange, + ...other + } = props; + + const [value, setValue] = useState(props.value || ''); + useEffect(() => setValue(props.value || ''), [props.value]); + const textRef = useRef(null); + useImperativeHandle(ref, () => textRef.current!, [textRef]); + + const contentStyle = { + paddingTop: padding, + paddingRight: padding, + paddingBottom: padding, + paddingLeft: padding, + }; + + const htmlStr = useMemo( + () => + processHtml( + ``, + rehypePlugins, + ), + [value, language, rehypePlugins], + ); + const preView = useMemo( + () => ( +
+ ), + // eslint-disable-next-line react-hooks/exhaustive-deps + [prefixCls, language, htmlStr], + ); + + const change = (evn: React.ChangeEvent) => { + setValue(evn.target.value); + onChange && onChange(evn); + }; + + const keyDown = (evn: React.KeyboardEvent) => { + if (other.readOnly) return; + if (!other.onKeyDown || other.onKeyDown(evn) !== false) { + shortcuts(evn); + } + }; + + const textareaProps: React.TextareaHTMLAttributes = { + 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 ( +
+