@hxa-rn/react-native-pell-rich-editor
v1.10.1
Published
react-native-pell-rich-editor for HarmonyOS
Readme
react-native-pell-rich-editor
本项目基于 wxik/react-native-rich-editor 开发,并适配 React Native for OpenHarmony。 如果在使用过程中有任何问题,可以在 GitCode 提交 Issue,我们会及时跟进。
项目介绍
@hxa-rn/react-native-pell-rich-editor 是一个 React Native 富文本编辑器,支持编辑 HTML 内容,并通过工具栏提供常用的文本格式化功能。本仓库在保留原始 React Native 实现的基础上新增 HarmonyOS(OpenHarmony)适配,HarmonyOS 端使用 ArkWeb 承载富文本编辑页面,并通过 React Native Fabric 组件完成 JavaScript 与原生侧通信。
- 富文本编辑:编辑器页面基于
contenteditable实现,文本输入、粘贴、按键与光标变化通过回调输出到 JavaScript 侧。 - 格式化工具栏:
RichToolbar提供加粗、斜体、下划线、标题、列表、对齐、引用、代码块等操作,并支持自定义图标、自定义渲染与自定义操作集合。 - 内容读写:
setContentHTML设置编辑器 HTML,onChange与getContentHtml读取当前 HTML。 - 富媒体与链接:
insertImage、insertVideo、insertLink插入远程图片、视频和超链接。 - 撤销与重做:通过
actions.undo、actions.redo触发编辑器历史操作。 - 自定义脚本:
command、commandDOM、injectJavascript向编辑器页面注入脚本执行自定义逻辑。 - HarmonyOS 适配:原生侧以 HAR 模块提供,使用 ArkWeb 承载编辑页面,并通过 Fabric 组件与 JavaScript 侧通信。
集成指南
安装
在 React Native 工程根目录执行:
npm install @hxa-rn/react-native-pell-rich-editor需要宿主工程提供 react-native(>=0.72)。
Autolinking
本包已配置 React Native for OpenHarmony Autolinking,安装依赖后由宿主工程自动接入,无需手动注册。
导入
import {
RichEditor,
RichToolbar,
actions,
defaultActions,
createHTML,
getContentCSS,
} from '@hxa-rn/react-native-pell-rich-editor';使用说明
基础用法
import React, {useRef} from 'react';
import {RichEditor, RichToolbar, actions} from '@hxa-rn/react-native-pell-rich-editor';
export default function EditorScreen(): JSX.Element {
const editorRef = useRef<RichEditor>(null);
return (
<>
<RichEditor
ref={editorRef}
initialContentHTML="<p>Hello HarmonyOS</p>"
placeholder="在这里输入富文本内容"
initialHeight={180}
editorStyle={{backgroundColor: '#ffffff', color: '#18202b', placeholderColor: '#8d99a8'}}
onChange={(value: string) => console.log(value)}
onHeightChange={(value: number) => console.log(value)}
onLink={(url: string) => console.log(url)}
onCursorPosition={(y: number) => console.log('光标所在行的 y', y)}
onCursorRect={(rect: {x: number; y: number; width: number; height: number}) =>
console.log('光标矩形', rect)
}
/>
<RichToolbar
editor={editorRef}
actions={[
actions.setBold,
actions.setItalic,
actions.setUnderline,
actions.heading1,
actions.insertBulletsList,
actions.undo,
actions.redo,
]}
selectedIconTint="#2878f0"
/>
</>
);
}RichToolbar 通过 editor 属性持有 RichEditor 的 ref,未传 actions 时使用默认操作集合 defaultActions。onChange 在内容变化时返回当前 HTML;getContentHtml 在类型定义中已标记为 @deprecated,新代码建议使用 onChange。onHeightChange 返回内容实际高度,通常用它驱动编辑器容器高度。editorStyle 用于设置编辑器背景色、文字色、光标色与占位符颜色,HarmonyOS 端由 ArkWeb 页面渲染。
通过 Ref 操作编辑器内容
const editorRef = useRef<RichEditor>(null);
// 在光标位置插入文本或 HTML
editorRef.current?.insertText('HarmonyOS');
editorRef.current?.insertHTML('<blockquote>引用内容</blockquote>');
// 插入远程图片与视频,第二个参数为内联样式
editorRef.current?.insertImage('https://picsum.photos/480/240', 'max-width:98%;display:block;margin:8px auto;');
editorRef.current?.insertVideo('https://media.w3.org/2010/05/sintel/trailer.mp4', 'width:100%;');
// 设置选中文本的格式
editorRef.current?.preCode('javascript');
editorRef.current?.setFontSize('4'); // 1–7(4 ≈ 18px)
editorRef.current?.setFontName('serif');
editorRef.current?.setForeColor('#d4380d');
editorRef.current?.setHiliteColor('#fff566');
// 焦点与键盘
editorRef.current?.focusContentEditor();
editorRef.current?.blurContentEditor();
editorRef.current?.dismissKeyboard();setFontSize 的取值是浏览器字号 1–7(分别为 10px、13px、16px、18px、24px、32px、48px),只接受 1–7:底层走的是 document.execCommand('fontSize'),传 CSS 长度(如 '18px')会被浏览器忽略、表现为"点了没变化"。insertImage、insertVideo 的第一个参数为资源地址,远程资源依赖网络连通性。
接口文档
以下 API 依据入口文件 src/index.js 的导出,以及 src/RichEditor.js、src/RichToolbar.js 中的属性默认值和 JSDoc 整理。
RichEditor
富文本编辑器组件,HarmonyOS 端基于 ArkWeb 承载编辑页面。
| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| html | string | 未声明 | 直接设置编辑器 HTML。 |
| initialContentHTML | string | '' | 编辑器初始化内容。 |
| placeholder | string | '' | 空内容时的占位文本。 |
| disabled | boolean | false | 是否禁止编辑。 |
| useContainer | boolean | true | 是否将编辑器包裹在容器中。 |
| initialHeight | number \| string | 0 | useContainer 为 false 时的编辑器初始高度。 |
| initialFocus | boolean | false | 初始化后是否请求聚焦。 |
| autoCorrect | boolean | false | 是否开启自动更正。 |
| autoCapitalize | 'off' \| 'none' \| 'on' \| 'sentences' \| 'words' \| 'characters' | 'off' | 文本自动大写策略。 |
| enterKeyHint | 'done' \| 'go' \| 'next' \| 'search' \| 'send' | 未声明 | 软键盘回车键类型。 |
| pasteAsPlainText | boolean | false | 粘贴时是否转为纯文本。 |
| defaultParagraphSeparator | string | 'div' | 回车时插入的 HTML 元素。 |
| defaultHttps | boolean | true | 无协议的链接是否补全 https://。 |
| firstFocusEnd | boolean | true | 首次聚焦时光标是否移到文本末尾。 |
| contentInset | {top?: number; bottom?: number; left?: number; right?: number} | {} | 编辑器内容内边距。 |
| style | StyleProp<ViewStyle> | {} | 容器或编辑器的样式。 |
| editorStyle | {backgroundColor?: string; color?: string; caretColor?: string; placeholderColor?: string; contentCSSText?: string; initialCSSText?: string; cssText?: string} | 未声明 | 编辑器背景色、文字色、光标色、占位符颜色及内容 CSS。 |
| styleWithCSS | boolean | 未声明 | 使用 style 而非专用标签生成格式化结果。 |
| dataDetectorTypes | DataDetectorTypes \| DataDetectorTypes[] | ['none'] | 数据检测类型,透传给底层 WebView。 |
| editorInitializedCallback | () => void | () => {} | 编辑器初始化完成回调。 |
| onChange | (text: string) => void | 未声明 | 内容变更回调,返回当前 HTML。 |
| onPaste | (data: string) => void | 未声明 | 用户粘贴内容回调。 |
| onKeyUp | ({keyCode: number, key: string}) => void | 未声明 | 按键抬起回调。 |
| onKeyDown | ({keyCode: number, key: string}) => void | 未声明 | 按键按下回调。 |
| onInput | ({data: string, inputType: string}) => void | 未声明 | 输入事件回调。 |
| onLink | (url: string) => void | 未声明 | 链接点击回调。 |
| onFocus / onBlur | () => void | 未声明 | 聚焦、失焦回调。 |
| onCursorPosition | (offsetY: number) => void | 未声明 | 光标位置回调:回传光标所在行的纵坐标(相对 WebView 顶部,见「使用限制」)。 |
| onCursorRect | (rect: {x: number, y: number, width: number, height: number}) => void | 未声明 | 光标矩形回调:回传光标的 x / y / 宽 / 高(页面坐标,见「使用限制」)。 |
| onHeightChange | (height: number) => void | 未声明 | 内容高度变化回调。 |
| onMessage | (message: {type: string; id: string; data?: any}) => void | 未声明 | 编辑器页面自定义消息回调。 |
| onMediaLoad | (event: {type: 'image' \| 'video'; url: string}) => void | 未声明 | HarmonyOS 端媒体资源加载成功回调。 |
| onMediaError | (event: {type: 'image' \| 'video'; url: string}) => void | 未声明 | HarmonyOS 端媒体资源加载失败回调。 |
| onNativeError | (error: {code: string; message: string; nonce?: number}) => void | 未声明 | HarmonyOS 端原生错误回调。 |
RichToolbar
富文本格式化工具栏组件。
| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| editor | React.createRef | 未声明 | RichEditor 实例的 ref。 |
| getEditor | () => RichEditor | 未声明 | 返回 RichEditor 实例的函数,与 editor 二选一。 |
| actions | A[] | defaultActions | 工具栏允许的操作集合。 |
| disabled | boolean | false | 是否禁用工具栏。 |
| iconTint | string | '#71787F' | 未选中图标的颜色。 |
| selectedIconTint | string | 未声明 | 选中图标的颜色。 |
| disabledIconTint | string | 未声明 | 禁用状态图标的颜色。 |
| iconSize | number | 20 | 图标尺寸。 |
| iconGap | number | 16 | 图标间距。 |
| iconMap | Record<string, (icon: IconRecord) => React.Element \| ImageSourcePropType> | 未声明 | 自定义图标集合。 |
| renderAction | (action: string, selected: boolean) => React.ReactElement | 未声明 | 自定义操作渲染函数。 |
| horizontal | boolean | 未声明 | 是否横向排列。 |
| style | StyleProp<ViewStyle> | 未声明 | 工具栏样式。 |
| flatContainerStyle | StyleProp<ViewStyle> | 未声明 | 工具栏列表容器样式。 |
| itemStyle | StyleProp<ViewStyle> | 未声明 | 单个操作项样式。 |
| unselectedButtonStyle | StyleProp<ViewStyle> | 未声明 | 未选中按钮样式。 |
| selectedButtonStyle | StyleProp<ViewStyle> | 未声明 | 选中按钮样式。 |
| disabledButtonStyle | StyleProp<ViewStyle> | 未声明 | 禁用按钮样式。 |
| onPressAddImage | () => void | 未声明 | 点击插入图片按钮的回调。 |
| onInsertLink | () => void | 未声明 | 点击插入链接按钮的回调。 |
| insertVideo | () => void | 未声明 | 点击插入视频按钮的回调。 |
| children | React.ReactNode | 未声明 | 工具栏列表之后追加的内容。 |
RichEditor Ref 方法
| 方法 | 说明 |
| --- | --- |
| setContentHTML(html: string) | 设置编辑器 HTML 内容。 |
| getContentHtml(): Promise<string> | 读取当前 HTML,已标记为 @deprecated,建议使用 onChange。 |
| setPlaceholder(placeholder: string) | 设置占位文本。 |
| setContentStyle(styles) | 设置编辑器内容样式。 |
| setDisable(disabled: boolean) | 切换编辑器禁用状态。 |
| insertText(text: string) | 在光标位置插入文本。 |
| insertHTML(html: string) | 在光标位置插入 HTML。 |
| insertImage(attributes, style?) | 插入图片。 |
| insertVideo(attributes, style?) | 插入视频。 |
| insertLink(title: string, url: string) | 插入链接。 |
| preCode(type: string) | 插入代码块。 |
| setFontSize(size: FONT_SIZE) | 设置选中文本字号,取值为 1–7。 |
| setFontName(name: string) | 设置选中文本字体。 |
| setForeColor(color: string) | 设置选中文本颜色。 |
| setHiliteColor(color: string) | 设置选中文本背景色。 |
| focusContentEditor() / blurContentEditor() | 让编辑器获得、失去焦点。 |
| dismissKeyboard() | 收起软键盘。 |
| command(command: string) | 在编辑器页面中执行脚本,$ 指向 document。 |
| commandDOM(command: string) | 在编辑器页面中执行 DOM 操作,$ 指向 document.querySelector。 |
| injectJavascript(type: string) | 向编辑器页面注入脚本。 |
| registerToolbar(listener: SelectionChangeListener) | 注册选区变化监听。 |
| sendAction(type: string, action: string, data?, options?) | 发送自定义操作到编辑器。 |
actions
编辑器操作名称枚举,用于 RichToolbar 的 actions 属性。
| 常量 | 值 | 说明 |
| --- | --- | --- |
| actions.setBold | 'bold' | 加粗。 |
| actions.setItalic | 'italic' | 斜体。 |
| actions.setUnderline | 'underline' | 下划线。 |
| actions.setStrikethrough | 'strikeThrough' | 删除线。 |
| actions.setSubscript | 'subscript' | 下标。 |
| actions.setSuperscript | 'superscript' | 上标。 |
| actions.heading1 – actions.heading6 | 'heading1' – 'heading6' | 一到六级标题。 |
| actions.setParagraph | 'paragraph' | 正文段落。 |
| actions.removeFormat | 'removeFormat' | 清除格式。 |
| actions.alignLeft | 'justifyLeft' | 左对齐。 |
| actions.alignCenter | 'justifyCenter' | 居中对齐。 |
| actions.alignRight | 'justifyRight' | 右对齐。 |
| actions.alignFull | 'justifyFull' | 两端对齐。 |
| actions.insertBulletsList | 'unorderedList' | 无序列表。 |
| actions.insertOrderedList | 'orderedList' | 有序列表。 |
| actions.checkboxList | 'checkboxList' | 复选框列表。 |
| actions.indent / actions.outdent | 'indent' / 'outdent' | 增加、减少缩进。 |
| actions.blockquote | 'quote' | 引用。 |
| actions.code | 'code' | 代码块。 |
| actions.table | 'table' | 表格。 |
| actions.setHR | 'horizontalRule' | 水平分割线的兼容常量:页面侧没有它的实现,工具栏不会内置转发,需要宿主自己接同名回调(onPress/setHR)来插入。 |
| actions.insertLine / actions.line | 'line' | 插入水平分割线(<hr>),走编辑器内置派发。 |
| actions.insertLink | 'link' | 插入链接。 |
| actions.insertImage | 'image' | 插入图片。 |
| actions.insertVideo | 'video' | 插入视频。 |
| actions.insertText | 'text' | 插入文本。 |
| actions.insertHTML | 'html' | 插入 HTML。 |
| actions.fontSize | 'fontSize' | 字号。 |
| actions.fontName | 'fontName' | 字体。 |
| actions.foreColor | 'foreColor' | 文字颜色。 |
| actions.hiliteColor | 'hiliteColor' | 文字背景色。 |
| actions.undo / actions.redo | 'undo' / 'redo' | 撤销、重做。 |
| actions.keyboard | 'keyboard' | 收起键盘。 |
| actions.content | 'content' | 编辑器内容区域标识。 |
| actions.updateHeight | 'UPDATE_HEIGHT' | 更新编辑器高度。 |
| actions.init | 'init' | 编辑器初始化。 |
| actions.setEditorHeight | 'SET_EDITOR_HEIGHT' | 设置编辑器高度。 |
| actions.setFooterHeight | 'SET_FOOTER_HEIGHT' | 设置底部区域高度。 |
| actions.setPlatform | 'SET_PLATFORM' | 设置运行平台。 |
| actions.setCustomCSS | 'SET_CUSTOM_CSS' | 设置自定义 CSS。 |
| actions.setTextColor | 'SET_TEXT_COLOR' | 设置文本颜色。 |
| actions.setBackgroundColor | 'SET_BACKGROUND_COLOR' | 设置背景颜色。 |
| actions.setTitlePlaceholder | 'SET_TITLE_PLACEHOLDER' | 设置标题占位文本。 |
| actions.setContentPlaceholder | 'SET_CONTENT_PLACEHOLDER' | 设置内容占位文本。 |
| actions.setTitleFocusHandler | 'SET_TITLE_FOCUS_HANDLER' | 设置标题聚焦处理。 |
| actions.setContentFocusHandler | 'SET_CONTENT_FOCUS_HANDLER' | 设置内容聚焦处理。 |
| actions.prepareInsert | 'PREPARE_INSERT' | 插入前准备。 |
| actions.restoreSelection | 'RESTORE_SELECTION' | 恢复选区。 |
其他导出项
| 导出项 | 说明 |
| --- | --- |
| defaultActions | actions 数组,RichToolbar 未指定 actions 时使用的默认操作集合。 |
| createHTML(options?) | 生成编辑器页面的 HTML 字符串。 |
| getContentCSS() | 返回编辑器页面的默认内容 CSS。 |
快速验证(运行 Example)
前置条件
| 依赖 | 版本要求 |
| :-- | --- |
| Node.js | >=20 |
| React Native for OpenHarmony | 0.72.139 |
| HarmonyOS SDK | API 21+ |
运行步骤
获取开发分支源码:
git clone -b react-native-pell-rich-editor_dev https://gitcode.com/hxa-rn/react-native-pell-rich-editor.git进入仓库根目录:
cd react-native-pell-rich-editor安装仓库根目录依赖,
npm install会同时完成适配包的构建:npm install安装tgz:
npm pack进入示例工程目录:
cd example安装示例工程依赖:
npm install生成 React Native JavaScript Bundle:
npm run dev使用 DevEco Studio 打开
example/harmony,同步依赖并完成签名配置后,构建运行entry模块。
约束与限制
兼容性
| 依赖 | 要求 |
| --- | --- |
| React Native for OpenHarmony | >=0.72 |
| HarmonyOS SDK | API 21–24,对应 compatibleSdkVersion 6.0.1(21) 与 targetSdkVersion 6.1.1(24) |
| Example 工程 compatibleSdkVersion | 6.0.1(21) |
| Example 工程 targetSdkVersion | 6.1.1(24) |
| Node.js | >=18 |
使用限制
command、commandDOM和injectJavascript会执行调用方提供的页面脚本,必须由调用方保证脚本来源可信。onCursorPosition回传的offsetY是光标(选区焦点端)所在行的纵坐标,相对 WebView 顶部;宿主拿到的最终值还会加上 WebView 自身的layout.y。它与onCursorRect由同一次测量产生(规则见下条):折叠光标量「焦点两侧区间」判定所在行,软换行处取下一行行首(与屏幕上光标一致);都量不到时退回该块的元素矩形顶边(此时是块顶而非行),再量不到就不上报,不猜值。onCursorRect回传光标(选区焦点端)的{x, y, width, height},与onCursorPosition由同一次测量产生、并同样加上了 WebView 在 RN 中的偏移(页面坐标)。取值规则:有选区时用引擎给出的选区矩形;折叠光标时不采用引擎的折叠 range 矩形(实测它在软换行处与光标的绘制位置不一致),而是量「焦点两侧区间」——两侧在同一行时x取左侧文字的右边界、y/ 行高取该行;两侧不同行(软换行处)则取下一行行首的x/y/ 行高。量不到位时该回调不上报,不硬凑矩形。- 软换行处(某行行首与上一行行末是同一个字符位置)以光标实际绘制的位置为准:ArkWeb 把该处光标画在下一行行首,本库据此上报该行的
x/y(实测长段落第二行行首为x=10、y=80)。注意引擎自身的折叠 range 矩形在这一点上与绘制位置不一致(它按字符归属报上一行末尾,x=314/y=61),因此本库不采用它,而是量「焦点两侧区间」自行判定。 - 插入代码块(
preCode/actions.code)时,代码块下方会自动补一个空的块级元素(<div><br></div>,标签取决于defaultParagraphSeparator),让宿主和用户都能直接在代码块下方落点编辑;在代码块最后一行空行上回车跳出时,光标同样落进一个块级元素,而不是裸<br>。该空块会出现在getContentHtml与onChange的内容里。 - 输入法行为、光标偏移和部分 HTML 格式化效果可能受 ArkWeb 内核及具体设备差异影响,应在目标设备上验收。
- 远程图片、视频和外部链接依赖网络连通性;编辑器的本地 HTML 编辑不依赖远程网络。
系统权限
本库不依赖额外的 HarmonyOS 系统权限。
开源 License
本项目采用 MIT,与上游项目保持一致。
问题反馈渠道
如在使用过程中遇到问题,请在 GitCode 提交Issue,我们会及时跟进。
- 提交问题时建议附上项目版本、RN 版本、OpenHarmony SDK/API 版本、DevEco Studio 版本、设备信息、复现步骤及相关日志。
- 涉及签名、账号、密钥或用户数据时,请勿在 Issue 中上传敏感信息;可按组织安全流程提交脱敏日志。
