TelegramEditor
专为移动端打磨的 Telegram 富文本编辑器,严格遵循 Telegram Bot API HTML 规范。
核心特性
- ✅ 严格遵循 Telegram 规范 - 只输出 Telegram 支持的 8 种 HTML 标签(b, i, u, s, code, pre, a, blockquote, tg-spoiler)
- 📱 移动端体验优化 - 键盘上方固定工具栏、自动滚动、48px 最小点击区域
- 🎨 纯文本粘贴 - 自动过滤垃圾样式,只保留纯文本内容
- ⚡️ 轻量级 - 体积 ≈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 支持以下 HTML 标签(Telegram Bot API 官方支持):
| 格式 | 图标 | 标签 | 说明 |
|---|---|---|---|
| 粗体 | B | <b>文本</b> | 加粗文字强调 |
| 斜体 | I | <i>文本</i> | 斜体表示引用 |
| 下划线 | U | <u>文本</u> | 添加下划线突出 |
| S̶ | <s>文本</s> | 表示已删除内容 | |
行内代码 | </> | <code>代码</code> | 显示行内代码 |
| 代码块 | { } | <pre><code>代码</code></pre> | 多行代码块 |
| 隐藏文字 | 👁 | <span class="tg-spoiler">文本</span> | 点击后显示(使用 blur 效果) |
| 引用 | " | <blockquote expandable>文本</blockquote> | 引用内容 |
| 链接 | 🔗 | <a href="url">文本</a> | 可点击的超链接 |
所有按钮使用 Lucide React 图标库,提供清晰直观的视觉体验。
源码/预览模式
TelegramEditor 支持在可视化编辑和源码编辑之间切换,方便高级用户直接编辑 HTML 代码。
功能特性
- 一键切换 - 点击工具栏的源码/预览按钮即可切换模式
- 智能转换 - 自动处理换行符和 HTML 标签转换
- 双向同步 - 源码和预览模式的内容实时同步
- 源码高亮 - 源码模式使用等宽字体,便于阅读和编辑
转换规则
预览 → 源码:
- 段落标签
</p><p>转换为换行符\n - HTML 标签转换为 Telegram 格式(
<strong>→<b>,<em>→<i>) - 移除所有 CSS class 属性(保留
tg-spoiler)
源码 → 预览:
- 换行符
\n转换为段落标签<p></p> - 自动识别块级标签(
<blockquote>,<pre>),不额外包裹 - 保留所有 Telegram 支持的 HTML 标签
使用示例
// 用户在预览模式输入:
// 第一行
// 第二行
// 切换到源码模式显示:
// 第一行
// 第二行
// 用户在源码模式输入:
// <b>粗体</b>
// <i>斜体</i>
// 切换回预览模式显示:
// **粗体**
// *斜体*变量插入功能
TelegramEditor 支持插入 Telegram 变量,用于动态内容替换。点击工具栏的变量按钮(Variable 图标)即可打开变量选择器。
支持的变量列表
| 变量 | 说明 |
|---|---|
| {{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}} | 当前时间 |
使用示例
// 插入变量后的内容示例
"欢迎 {{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;
}交互流程:
- 默认: 文字完全模糊,无法阅读
- 悬停: 模糊度降低,提示可以点击
- 点击: 移除模糊效果,显示原文
- 显示后: 可正常选择和复制文字
移动端优化
键盘上方固定工具栏
工具栏固定在键盘上方,确保输入时不被遮挡:
.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 类名 |
autoFocus | boolean | false | 是否自动聚焦 |
disabled | boolean | false | 是否禁用 |
HTML 转换规则
TelegramEditor 会自动将标准 HTML 标签转换为 Telegram 支持的格式:
// 转换规则
'<strong>' → '<b>'
'<em>' → '<i>'
'<strike>' → '<s>'
'<del>' → '<s>'
'<blockquote>' → '<blockquote expandable>'所有 class 属性会被移除(除了 tg-spoiler):
<!-- 输入 -->
<a class="xc-telegram-editor-link" href="https://example.com">链接</a>
<!-- 输出 -->
<a href="https://example.com">链接</a>样式定制
可以通过覆盖 CSS 变量来定制组件样式:
.xc-telegram-editor {
--xc-editor-bg: #ffffff;
--xc-editor-border: #e5e7eb;
--xc-editor-text: #000000;
--xc-editor-toolbar-active: #3b82f6;
/* 布局变量(用于 Demo 演示等场景) */
--xc-editor-position: fixed; /* 默认 fixed,可改为 absolute/relative */
--xc-editor-variables-max-height: 50vh; /* 变量选择器最大高度 */
}在 Demo 中使用相对定位
在文档或 Demo 页面中,通常需要使用相对定位而非固定定位:
<TelegramEditor
className="demo-editor"
// ...
/>
<style>
.demo-editor {
--xc-editor-position: absolute;
--xc-editor-max-height: 300px;
}
</style>暗黑模式
组件自动支持暗黑模式:
@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 标签)
- 纯文本粘贴 - 粘贴时自动过滤所有样式,只保留纯文本,避免引入不支持的标签
- 仅移动端优化 - 工具栏固定在底部的设计主要针对移动端,桌面端建议隐藏工具栏或自定义位置
- iOS Safari - 已针对 iOS Safari 的选区和输入法问题进行优化
依赖
TelegramEditor 基于 Tiptap 构建,需要以下依赖:
@tiptap/react- React 集成@tiptap/starter-kit- 基础编辑器功能@tiptap/extension-link- 链接支持@tiptap/extension-placeholder- Placeholder 支持@tiptap/core- 核心库
所有依赖已包含在 @xcloud/ui-mobile 中,无需额外安装。