TelegramEditor
专为移动端打磨的 Telegram 富文本编辑器,严格遵循 Telegram Bot API HTML 规范。
核心特性
- ✅ 严格遵循 Telegram 规范 - 完整支持 Telegram Bot API 的所有 HTML 标签,包括简写标签和特殊协议
- 📱 移动端体验优化 - 键盘上方工具栏、自动滚动、48px 最小点击区域
- 🎨 纯文本粘贴 - 自动过滤垃圾样式,只保留纯文本内容
- 🔧 自定义变量 - 支持外部传入自定义变量,与内置变量合并
- 💡 源码/预览模式 - 可视化编辑与源码编辑自由切换,支持高级 HTML 标签
- 🎯 按钮管理 - 支持拖拽排序的按钮/快捷键管理,可配置按钮类型
- 🔄 后端集成 - 自动转换为后端 API 格式,无需手动处理
- ⚡️ 轻量级 - 体积 ≈38KB (gzip 后 ≈14KB)
导入
import { TelegramEditor } from '@xcloud/ui-mobile'示例
基础示例
统一数据管理示例
后端数据回显示例
基础用法
TelegramEditor 是一个专为 Telegram Bot API 设计的富文本编辑器,输出的 HTML 严格遵循 Telegram 规范。
import { TelegramEditor } from '@xcloud/ui-mobile'
import { useState } from 'react'
function Example() {
const [html, setHtml] = useState('')
return (
<TelegramEditor
placeholder="输入消息..."
onChange={(telegramHtml) => {
setHtml(telegramHtml)
// 直接发送给 Telegram Bot API
sendToTelegramBot(telegramHtml)
}}
maxLength={4096}
/>
)
}受控模式
TelegramEditor 支持受控模式和非受控模式:
// 受控模式
function ControlledExample() {
const [value, setValue] = useState('<b>初始内容</b>')
return (
<TelegramEditor
value={value}
onChange={(html) => setValue(html)}
/>
)
}
// 非受控模式
function UncontrolledExample() {
return (
<TelegramEditor
defaultValue="<b>默认内容</b>"
onChange={(html) => console.log(html)}
/>
)
}支持的格式
TelegramEditor 完整支持 Telegram Bot API 的所有 HTML 标签:
基础格式(有 UI 工具)
| 格式 | 图标 | 标签 | 说明 |
|---|---|---|---|
| 粗体 | B | <b>, <strong> | 加粗文字强调 |
| 斜体 | I | <i>, <em> | 斜体表示引用 |
| 下划线 | U | <u>, <ins> | 添加下划线突出 |
| S̶ | <s>, <strike>, <del> | 表示已删除内容 | |
行内代码 | </> | <code> | 显示行内代码 |
| 代码块 | { } | <pre><code> | 多行代码块,支持 language-* class |
| 等宽文本 | ≡ | <pre> | 等宽格式文本块(不带语法高亮) |
| 隐藏文字 | 👁 | <span class="tg-spoiler"> 或 <tg-spoiler> | 点击后显示(blur 效果) |
| 引用 | " | <blockquote> 或 <blockquote expandable> | 引用内容,支持智能切换(见下文) |
| 链接 | 🔗 | <a href="url"> | 可点击的超链接,支持 tg:// 协议 |
引用按钮智能切换
引用按钮支持三状态智能切换,每次点击会循环切换状态:
- 未激活 → 普通引用:首次点击,创建
<blockquote>标签 - 普通引用 → 可展开引用:再次点击,添加
expandable属性,按钮显示 "(折叠)" 标识 - 可展开引用 → 取消引用:第三次点击,移除引用格式
// 使用示例
// 第一次点击:未激活 → <blockquote>内容</blockquote>
// 第二次点击:普通引用 → <blockquote expandable>内容</blockquote>
// 第三次点击:可展开引用 → 内容(取消引用)视觉反馈:
- 普通引用:按钮高亮,显示 "引用 (展开)"(10px小字,带括号)
- 可展开引用:按钮高亮,显示 "引用 (折叠)"(10px小字,带括号)
- 未激活:按钮无高亮
高级标签(源码模式支持)
以下标签可以在源码模式直接输入,编辑器会正确处理:
| 标签 | 说明 | 示例 |
|---|---|---|
<tg-spoiler> | Spoiler 简写标签 | <tg-spoiler>隐藏内容</tg-spoiler> |
<tg-emoji> | 自定义 emoji(需 Fragment 购买) | <tg-emoji emoji-id="5368324170671202286">🔥</tg-emoji> |
<a href="tg://user?id=123"> | 用户提及链接 | <a href="tg://user?id=123456789">@admin</a> |
<pre><code class="language-python"> | 带语言的代码块 | <pre><code class="language-python">print("Hello")</code></pre> |
<blockquote expandable> | 可展开的引用 | <blockquote expandable>长文本引用...</blockquote> |
所有按钮使用 Lucide React 图标库,提供清晰直观的视觉体验。
源码/预览模式
TelegramEditor 支持在可视化编辑和源码编辑之间切换,方便高级用户直接编辑 HTML 代码。
功能特性
- 一键切换 - 点击工具栏的源码/预览按钮即可切换模式
- 智能转换 - 自动处理换行符和 HTML 标签转换
- 双向同步 - 源码和预览模式的内容实时同步
- 源码高亮 - 源码模式使用等宽字体,便于阅读和编辑
转换规则
预览 → 源码:
- 段落标签
</p><p>转换为换行符\n - HTML 标签转换为 Telegram 格式(
<strong>→<b>,<em>→<i>) - 移除不必要的 CSS class 属性(保留
language-*和tg-spoiler) - 如果启用
useShorthandTags,将<span class="tg-spoiler">转换为<tg-spoiler>
源码 → 预览:
- 换行符
\n转换为段落标签<p></p> - 自动识别块级标签(
<blockquote>,<pre>),不额外包裹 <tg-spoiler>自动转换为<span class="tg-spoiler">(编辑器内部格式)- 保留所有 Telegram 支持的 HTML 标签(
<tg-emoji>,tg://链接等)
使用示例
// 在源码模式使用 Telegram 特殊标签
<TelegramEditor
defaultValue={`
<b>欢迎</b> <tg-spoiler>惊喜内容</tg-spoiler>
提及用户: <a href="tg://user?id=123456789">@admin</a>
自定义 emoji: <tg-emoji emoji-id="5368324170671202286">🔥</tg-emoji>
代码示例:
<pre><code class="language-python">
def hello():
print("Hello, Telegram!")
</code></pre>
`}
useShorthandTags={true} // 输出简写标签格式
/>切换效果:
从源码切换到预览:
<tg-spoiler>→ 显示为可点击的模糊文字<tg-emoji>→ 保持原样(编辑器不修改)tg://user?id=123→ 显示为可点击链接language-python→ 保留语言标识
从预览切换到源码:
- 模糊文字 →
<tg-spoiler>或<span class="tg-spoiler">(取决于useShorthandTags) - 保留所有 Telegram 特殊标签和协议
变量插入功能
TelegramEditor 支持插入变量用于动态内容替换,包括内置的 Telegram 变量和自定义变量。
内置变量列表
| 变量 | 说明 |
|---|---|
| {{t.id}} | Telegram 目标用户数字ID |
| {{t.name}} | Telegram 目标@用户名 |
| {{t.first_name}} | Telegram 目标用户名字 |
| {{t.last_name}} | Telegram 目标用户姓氏 |
| {{t.nickname}} | Telegram 目标Name 姓/名 |
| {{warn_num}} | 警告次数上限 (0:不警告, >0:警告上限数次) |
| {{warned_num}} | 已警告次数 |
| {{warn_remain_num}} | 剩余警告次数 |
| {{mute_time}} | 禁言时长 |
| {{kick_out}} | 踢出群 (0:不踢出群, 1:踢出群, 允许再次加入, 2:踢出群,直至管理员解禁) |
| {{time}} | 当前时间 |
自定义变量
除了内置变量,你还可以传入自定义变量,它们会与内置变量合并显示在变量选择器中:
import { TelegramEditor } from '@xcloud/ui-mobile'
function CustomVariablesExample() {
return (
<TelegramEditor
variables={[
{ key: 'order.id', label: '订单编号', value: '{{order.id}}' },
{ key: 'order.amount', label: '订单金额', value: '{{order.amount}}' },
{ key: 'product.name', label: '商品名称', value: '{{product.name}}' },
{ key: 'user.points', label: '用户积分', value: '{{user.points}}' },
]}
onChange={(html) => console.log(html)}
/>
)
}变量列表顺序:
- 内置 Telegram 变量(11个)
- 自定义变量(按传入顺序)
所有变量在工具栏的「变量」面板中显示,点击即可插入到编辑器光标位置。
使用示例
// 插入变量后的内容示例
"欢迎 {{t.first_name}} 加入群组!你还有 {{warn_remain_num}} 次警告机会。"
// 发送到 Telegram 后会自动替换为:
"欢迎 张三 加入群组!你还有 3 次警告机会。"变量选择器特性
- 弹窗式界面 - 从底部滑出,不遮挡编辑内容
- 搜索友好 - 每个变量都有清晰的中文说明
- 一键插入 - 点击变量即可插入到光标位置
- 自动关闭 - 插入后自动关闭选择器
- 暗黑模式支持 - 自动适配系统主题
Spoiler(隐藏文字)交互效果
在非 Telegram 环境中,Spoiler 使用 CSS blur 效果模拟隐藏状态,提供与 Telegram 相似的交互体验:
/* 默认模糊状态 */
.tg-spoiler:not(.revealed) {
color: transparent;
filter: blur(5px);
}
/* 悬停时减少模糊 */
.tg-spoiler:not(.revealed):hover {
filter: blur(3px);
}
/* 点击后显示 */
.tg-spoiler.revealed {
filter: none;
color: inherit;
}交互流程:
- 默认: 文字完全模糊,无法阅读
- 悬停: 模糊度降低,提示可以点击
- 点击: 移除模糊效果,显示原文
- 显示后: 可正常选择和复制文字
按钮管理
TelegramEditor 支持添加和管理按钮/快捷键,提供直观的拖拽排序界面。
按钮模式
编辑器支持两种按钮模式:
- 按钮模式 (button): 用于 Telegram 消息的内联按钮,支持 URL 链接、回调函数、WebApp 等
- 快捷键模式 (shortcut): 用于快捷回复,支持文本和链接
// 按钮模式
<TelegramEditor
buttonMode="button"
enabledButtonTypes={['url', 'callback', 'webapp']}
/>
// 快捷键模式
<TelegramEditor
buttonMode="shortcut"
enabledButtonTypes={['text', 'url']}
/>可配置按钮类型
通过 enabledButtonTypes 属性控制允许使用的按钮类型:
<TelegramEditor
buttonMode="button"
enabledButtonTypes={['url', 'callback']} // 只允许链接和回调
/>内置按钮类型:
| 类型 | 说明 | 适用模式 | 需要 value |
|---|---|---|---|
url | URL 链接 | button, shortcut | ✅ |
callback | 回调函数 | button | ✅ |
text | 纯文本 | shortcut | ❌ |
webapp | Web App | button | ✅ |
自定义按钮类型
除了内置类型,还可以添加自定义按钮类型:
<TelegramEditor
buttonMode="button"
customButtonTypes={{
callback: {
// 覆盖默认配置(包括中文文本)
label: '功能回调',
icon: '⚡',
valueLabel: '参数',
valuePlaceholder: 'sendCmd=/setlang',
validate: (value) => {
if (!value.startsWith('sendCmd=')) {
return '参数必须以 sendCmd= 开头'
}
return true
},
helpText: '格式:sendCmd=/命令'
},
custom_action: {
// 添加自定义类型
label: '自定义动作',
icon: '⚙️',
valueLabel: '动作参数',
valuePlaceholder: '{"action": "custom"}',
valueInputType: 'textarea',
validate: (value) => {
try {
JSON.parse(value)
return true
} catch {
return '请输入有效的 JSON'
}
}
}
}}
/>添加按钮模式配置
编辑器支持两种添加按钮的方式:
直接模式 (direct) - 默认方式
- 点击"在行末添加"→ 立即添加默认按钮
- 点击"添加一行"→ 立即创建新行
- 然后点击按钮进入编辑 Modal 修改
编辑模式 (edit) - 先填写后添加
- 点击"在行末添加"→ 打开编辑 Modal
- 点击"添加一行"→ 打开编辑 Modal
- 填写配置后保存才会添加按钮
- Modal 标题显示"添加按钮"
- 不显示删除按钮
// 直接模式(默认)
<TelegramEditor
buttonMode="button"
addButtonMode="direct" // 可省略,这是默认值
/>
// 编辑模式
<TelegramEditor
buttonMode="button"
addButtonMode="edit" // 先填写配置再添加
/>拖拽排序
按钮支持拖拽排序,包括:
- 行内拖拽: 在同一行内调整按钮顺序
- 跨行拖拽: 将按钮移动到其他行
- 行拖拽: 拖动整行调整行顺序
按钮限制
- 最多支持 7 行按钮
- 每行最多 8 个按钮
- 按钮和快捷键互斥(只能选择一种模式)
媒体URL管理
TelegramEditor 支持添加媒体地址(图片/视频 URL),用于发送带媒体的 Telegram 消息。
基础用法
import { TelegramEditor } from '@xcloud/ui-mobile';
import { useState } from 'react';
function MediaExample() {
const [mediaUrl, setMediaUrl] = useState('');
return (
<TelegramEditor
mediaUrl={mediaUrl}
onMediaUrlChange={setMediaUrl}
placeholder="输入消息..."
/>
);
}受控与非受控模式
媒体URL支持受控和非受控两种模式:
// 受控模式 - 通过 mediaUrl 和 onMediaUrlChange 控制
function ControlledMedia() {
const [url, setUrl] = useState('https://example.com/image.jpg');
return (
<TelegramEditor
mediaUrl={url}
onMediaUrlChange={setUrl}
/>
);
}
// 非受控模式 - 只使用 mediaUrl,组件内部管理状态
function UncontrolledMedia() {
return (
<TelegramEditor
mediaUrl="https://example.com/default.jpg"
/>
);
}与后端集成配合使用
媒体URL会自动包含在后端格式数据中:
import { TelegramEditor, type BackendMessageTemplate } from '@xcloud/ui-mobile';
function MediaWithBackend() {
const [mediaUrl, setMediaUrl] = useState('');
const handleBackendDataChange = (data: BackendMessageTemplate) => {
console.log(data.media); // 媒体地址
console.log(data.content); // HTML 内容
console.log(data.func); // 按钮数据
};
return (
<TelegramEditor
mediaUrl={mediaUrl}
onMediaUrlChange={setMediaUrl}
onBackendDataChange={handleBackendDataChange}
buttonMode="button"
/>
);
}后端集成
TelegramEditor 提供完整的后端格式转换功能,自动将编辑器数据转换为后端 API 格式。
自动导出
使用 onBackendDataChange 回调实时获取后端格式数据:
import { TelegramEditor, type BackendMessageTemplate } from '@xcloud/ui-mobile';
function MyComponent() {
const handleBackendDataChange = (data: BackendMessageTemplate) => {
console.log('后端格式数据:', data);
// 直接发送给后端 API
sendToBackend(data);
};
return (
<TelegramEditor
buttonMode="button"
mediaUrl="https://example.com/image.jpg"
onBackendDataChange={handleBackendDataChange}
/>
);
}后端数据格式
interface BackendMessageTemplate {
media: string; // 媒体地址
content: string; // HTML 内容(带 [HTML] 前缀)
func: BackendButton[][]; // 按钮(二维数组)
convenient: BackendShortcut[][]; // 快捷键(二维数组)
}
interface BackendButton {
id: string;
prefix: 'function';
type: 'link' | 'callback'; // 后端类型
text: string;
value?: string;
}
interface BackendShortcut {
id: string;
prefix: 'shortcut';
type: 'text' | 'link';
text: string;
value?: string;
}类型映射
编辑器会自动进行类型映射:
按钮模式 (button):
url→linkcallback→callbackwebapp→link
快捷键模式 (shortcut):
url→linktext→text
手动转换
如果需要手动转换,可以使用导出的转换函数:
import {
convertToBackendFormat,
convertFromBackendFormat,
type KeyboardMarkup,
} from '@xcloud/ui-mobile';
// 转换为后端格式
const backendData = convertToBackendFormat(
html,
keyboard,
'button',
'https://example.com/image.jpg'
);
// 从后端格式转换
const { html, keyboard, buttonMode, mediaUrl } = convertFromBackendFormat(backendData);使用示例
import { TelegramEditor, type BackendMessageTemplate } from '@xcloud/ui-mobile';
import { useState } from 'react';
function MessageEditor() {
const [backendData, setBackendData] = useState<BackendMessageTemplate | null>(null);
const handleSave = async () => {
if (backendData) {
// 直接发送给后端
await fetch('/api/messages', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(backendData),
});
}
};
return (
<div>
<TelegramEditor
buttonMode="button"
enabledButtonTypes={['url', 'callback']}
mediaUrl="https://example.com/banner.jpg"
onBackendDataChange={setBackendData}
/>
<button onClick={handleSave}>保存消息模板</button>
</div>
);
}移动端优化
键盘上方固定工具栏
工具栏固定在键盘上方,确保输入时不被遮挡:
.xc-telegram-editor-toolbar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 48px;
}工具栏横向滚动
当工具栏按钮数量较多时,支持横向滚动查看所有按钮:
.xc-telegram-editor-toolbar {
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch; /* iOS 平滑滚动 */
touch-action: pan-x; /* 允许横向滚动 */
scrollbar-width: none; /* 隐藏滚动条 */
}特性:
- 自动横向滚动,不会压缩按钮
- iOS 平滑滚动体验
- 隐藏滚动条,保持界面简洁
- 所有按钮保持 48px 最小宽度
自动滚动
键盘弹出时,编辑器自动滚动到底部,光标始终可见:
React.useEffect(() => {
const handleResize = () => {
setTimeout(() => {
window.scrollTo(0, document.body.scrollHeight)
editor?.commands.focus('end')
}, 300)
}
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [editor])最小点击区域
所有工具栏按钮都设置了 48px × 48px 的最小点击区域,符合移动端最佳实践。
组件 API
TelegramEditor Props
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
defaultValue | string | '' | 非受控模式下的初始内容 |
value | string | - | 受控模式下的值 |
onChange | (html: string, editor: Editor) => void | - | 内容变化回调 |
placeholder | string | '写点什么…' | Placeholder 文字 |
maxLength | number | 4096 | 最大字符数限制(Telegram API 限制) |
showCounter | boolean | true | 是否显示字符计数器 |
showToolbar | boolean | true | 是否显示工具栏 |
className | string | - | 附加的 CSS 类名 |
style | React.CSSProperties | - | 自定义样式(支持 CSS 变量覆盖) |
autoFocus | boolean | false | 是否自动聚焦 |
disabled | boolean | false | 是否禁用 |
variables | TelegramVariable[] | [] | 自定义变量列表(与内置变量合并) |
useShorthandTags | boolean | false | 是否使用 Telegram 简写标签格式 |
i18n | TelegramEditorI18n | defaultI18n | 国际化文本配置 |
onPreview | () => void | - | 预览/源码切换回调 |
toolbar | Partial<TelegramEditorToolbarProps> | - | 自定义工具栏属性 |
| 按钮管理 | |||
buttonMode | 'button' | 'shortcut' | - | 按钮模式(button: 消息按钮, shortcut: 快捷键) |
enabledButtonTypes | string[] | - | 允许使用的按钮类型列表 |
customButtonTypes | Record<string, ButtonTypeConfig> | {} | 自定义按钮类型配置 |
addButtonMode | 'direct' | 'edit' | 'direct' | 添加按钮的方式(direct: 直接添加, edit: 先填写配置) |
defaultKeyboard | KeyboardMarkup | [] | 默认按钮布局 |
onKeyboardChange | (keyboard: KeyboardMarkup) => void | - | 按钮布局变化回调 |
| 后端集成 | |||
mediaUrl | string | '' | 媒体地址(图片/视频 URL) |
onMediaUrlChange | (url: string) => void | - | 媒体地址变化回调 |
onBackendDataChange | (data: BackendMessageTemplate) => void | - | 后端格式数据变化回调(自动导出) |
TelegramVariable 接口
interface TelegramVariable {
/** 变量唯一标识 */
key: string
/** 变量显示标签 */
label: string
/** 变量插入值(例如 {{var_name}}) */
value: string
}ButtonTypeConfig 接口
interface ButtonTypeConfig {
/** 类型显示标签 */
label: string
/** 按钮图标(emoji 或文本) */
icon: string
/** value 字段标签 */
valueLabel: string
/** value 输入框占位符 */
valuePlaceholder: string
/** value 输入框类型 */
valueInputType?: 'text' | 'url' | 'textarea'
/** 验证函数(返回 true 或错误消息) */
validate?: (value: string) => boolean | string
/** 帮助文本 */
helpText?: string
}注意:
defaultButtonTypeConfigs中的文本(标签、错误消息等)默认为中文。如需其他语言,请通过customButtonTypes覆盖相应配置。
BackendMessageTemplate 接口
interface BackendMessageTemplate {
/** 媒体地址 */
media: string
/** HTML 内容(带 [HTML] 前缀) */
content: string
/** 按钮(二维数组,每行一个数组) */
func: BackendButton[][]
/** 快捷键(二维数组,每行一个数组) */
convenient: BackendShortcut[][]
}
interface BackendButton {
id: string
prefix: 'function'
type: 'link' | 'callback'
text: string
value?: string
}
interface BackendShortcut {
id: string
prefix: 'shortcut'
type: 'text' | 'link'
text: string
value?: string
}useShorthandTags 说明
控制输出 HTML 中 Spoiler 标签的格式:
// useShorthandTags={false} (默认)
<span class="tg-spoiler">隐藏内容</span>
// useShorthandTags={true}
<tg-spoiler>隐藏内容</tg-spoiler>两种格式都是 Telegram 官方支持的,选择哪种取决于你的使用场景。
HTML 转换规则
TelegramEditor 会自动将标准 HTML 标签转换为 Telegram 支持的格式:
基础标签转换
'<strong>' → '<b>'
'<em>' → '<i>'
'<strike>' → '<s>'
'<del>' → '<s>'
'<ins>' → '<s>'
// Telegram 不支持 <p> 标签,自动移除
'<p>段落1</p><p>段落2</p>' → '段落1\n段落2'**重要说明:**Telegram Bot API 不支持 <p> 标签。编辑器会自动将段落标签转换为换行符(\n)。
特殊标签处理
段落和换行处理:
<!-- 编辑器内部格式 -->
<p>第一段</p><p>第二段</p>
<!-- 输出为 Telegram 格式 -->
第一段
第二段
<!-- blockquote 内的段落也会被处理 -->
<blockquote expandable="true"><p>引用内容</p></blockquote>
<!-- 输出 -->
<blockquote expandable="true">引用内容</blockquote>代码块语言保留:
<!-- 输入 -->
<pre><code class="language-python">code</code></pre>
<!-- 输出(保留 language-* class) -->
<pre><code class="language-python">code</code></pre>Spoiler 标签转换:
<!-- 源码模式输入 -->
<tg-spoiler>隐藏内容</tg-spoiler>
<!-- 转换为编辑器内部格式 -->
<span class="tg-spoiler">隐藏内容</span>
<!-- 如果 useShorthandTags={true},输出时转回 -->
<tg-spoiler>隐藏内容</tg-spoiler>引用标签保留:
<!-- 普通引用 -->
<blockquote>引用内容</blockquote>
<!-- 可展开引用 -->
<blockquote expandable>长引用内容</blockquote>保留的特殊标签
以下标签会被完整保留,不做修改:
<!-- 自定义 emoji -->
<tg-emoji emoji-id="5368324170671202286">🔥</tg-emoji>
<!-- 用户提及链接 -->
<a href="tg://user?id=123456789">@username</a>
<!-- 带语言的代码块 -->
<pre><code class="language-python">print("Hello")</code></pre>Class 属性清理
所有不必要的 CSS class 会被移除:
<!-- 输入 -->
<a class="xc-telegram-editor-link" href="https://example.com">链接</a>
<code class="some-class">代码</code>
<blockquote class="custom-class">引用</blockquote>
<!-- 输出 -->
<a href="https://example.com">链接</a>
<code>代码</code>
<blockquote>引用</blockquote>**例外情况:**保留 language-* 和 tg-spoiler class。
样式定制
可以通过覆盖 CSS 变量来定制组件样式:
.xc-telegram-editor {
--xc-editor-bg: #ffffff;
--xc-editor-border: #e5e7eb;
--xc-editor-text: #000000;
--xc-editor-toolbar-active: #3b82f6;
/* 布局变量 */
--xc-editor-position: absolute; /* 默认 absolute,可改为 fixed/relative */
--xc-editor-variables-max-height: 50vh; /* 变量选择器最大高度 */
/* z-index 层级控制 */
--xc-editor-z-index-base: 10; /* 只需设置基础值,其他层级自动递增 */
}z-index 层级自定义
编辑器使用基于变量的 z-index 系统,通过设置一个基础值,所有层级会自动递增:
默认层级:
--xc-editor-z-index-base: 10(基础容器)--xc-editor-toolbar-z-index: 11(工具栏 = base + 1)--xc-editor-variables-z-index: 12(变量选择器 = base + 2)--xc-editor-modal-backdrop-z-index: 100(弹窗背景 = base + 90)--xc-editor-modal-z-index: 101(弹窗 = base + 91)
自定义示例:
// 提高整体 z-index 避免与其他组件冲突
<TelegramEditor
style={{ '--xc-editor-z-index-base': '20' } as React.CSSProperties}
/>
// 结果: base=20, toolbar=21, variables=22, modal-backdrop=110, modal=111
// 降低 z-index 在特定场景使用
<TelegramEditor
style={{ '--xc-editor-z-index-base': '5' } as React.CSSProperties}
/>
// 结果: base=5, toolbar=6, variables=7, modal-backdrop=95, modal=96使用场景:
当编辑器在具有固定按钮的页面中使用时(如 MobilePage 底部固定按钮 z-index: 50),可以通过调整基础值确保层级关系正确:
<MobilePage>
<TelegramEditor
// 确保编辑器层级低于页面固定按钮
style={{ '--xc-editor-z-index-base': '10' } as React.CSSProperties}
/>
{/* 固定按钮 z-index: 50 在编辑器之上 */}
</MobilePage>使用固定定位
在移动端应用中使用固定定位(键盘上方固定):
<TelegramEditor
style={{ '--xc-editor-position': 'fixed' } as React.CSSProperties}
// ...
/>在 Demo 中使用相对定位
在文档或 Demo 页面中,使用默认的绝对定位:
<TelegramEditor
className="demo-editor"
// 默认是 absolute,无需额外设置
// ...
/>暗黑模式
组件自动支持暗黑模式:
@media (prefers-color-scheme: dark) {
.xc-telegram-editor {
--xc-editor-bg: #1a1a1a;
--xc-editor-border: #2d2d2d;
--xc-editor-text: #ffffff;
--xc-editor-toolbar-bg: #1f1f1f;
--xc-editor-toolbar-active: #60a5fa;
}
}注意事项
- 字符限制 - Telegram Bot API 限制单条消息最多 4096 个字符(包含 HTML 标签)
- 纯文本粘贴 - 粘贴时自动过滤所有样式,只保留纯文本,避免引入不支持的标签
- 定位模式 - 默认使用
absolute定位,移动端应用可通过 CSS 变量改为fixed - iOS Safari - 已针对 iOS Safari 的选区和输入法问题进行优化
- 特殊标签 -
<tg-emoji>和tg://协议链接在编辑器中会被保留,但可能无法实时预览效果 - 代码语言 - 代码块的
language-*class 会被保留,但编辑器 UI 不提供语言选择器,需在源码模式手动添加 - 按钮限制 - 最多 7 行,每行最多 8 个按钮;按钮和快捷键互斥
- 后端格式 - 使用
onBackendDataChange可自动获取后端格式,无需手动转换
导出函数
convertToBackendFormat
将编辑器格式转换为后端 API 格式。
function convertToBackendFormat(
html: string,
keyboard: KeyboardMarkup,
buttonMode: 'button' | 'shortcut',
mediaUrl: string
): BackendMessageTemplate参数:
html: HTML 内容keyboard: 按钮布局(二维数组)buttonMode: 按钮模式mediaUrl: 媒体地址
**返回:**后端消息模板格式
convertFromBackendFormat
将后端格式转换为编辑器格式。
function convertFromBackendFormat(
data: BackendMessageTemplate
): {
html: string
keyboard: KeyboardMarkup
buttonMode: 'button' | 'shortcut'
mediaUrl: string
}参数:
data: 后端消息模板数据
**返回:**编辑器格式数据
依赖
TelegramEditor 基于 Tiptap 构建,需要以下依赖:
@tiptap/react- React 集成@tiptap/starter-kit- 基础编辑器功能@tiptap/extension-link- 链接支持@tiptap/extension-placeholder- Placeholder 支持@tiptap/core- 核心库
所有依赖已包含在 @xcloud/ui-mobile 中,无需额外安装。