Skip to content

TelegramEditor

专为移动端打磨的 Telegram 富文本编辑器,严格遵循 Telegram Bot API HTML 规范

核心特性

  • 严格遵循 Telegram 规范 - 只输出 Telegram 支持的 8 种 HTML 标签(b, i, u, s, code, pre, a, blockquote, tg-spoiler)
  • 📱 移动端体验优化 - 键盘上方固定工具栏、自动滚动、48px 最小点击区域
  • 🎨 纯文本粘贴 - 自动过滤垃圾样式,只保留纯文本内容
  • ⚡️ 轻量级 - 体积 ≈38KB (gzip 后 ≈14KB)

导入

tsx
import { TelegramEditor } from '@xcloud/ui-mobile'

示例

基础用法

TelegramEditor 是一个专为 Telegram Bot API 设计的富文本编辑器,输出的 HTML 严格遵循 Telegram 规范。

tsx
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 支持受控模式和非受控模式:

tsx
// 受控模式
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>表示已删除内容
行内代码</><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 标签

使用示例

tsx
// 用户在预览模式输入:
// 第一行
// 第二行

// 切换到源码模式显示:
// 第一行
// 第二行

// 用户在源码模式输入:
// <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}}当前时间

使用示例

typescript
// 插入变量后的内容示例
"欢迎 {{t.first_name}} 加入群组!你还有 {{warn_remain_num}} 次警告机会。"

// 发送到 Telegram 后会自动替换为:
"欢迎 张三 加入群组!你还有 3 次警告机会。"

变量选择器特性

  • 弹窗式界面 - 从底部滑出,不遮挡编辑内容
  • 搜索友好 - 每个变量都有清晰的中文说明
  • 一键插入 - 点击变量即可插入到光标位置
  • 自动关闭 - 插入后自动关闭选择器
  • 暗黑模式支持 - 自动适配系统主题

Spoiler(隐藏文字)交互效果

在非 Telegram 环境中,Spoiler 使用 CSS blur 效果模拟隐藏状态,提供与 Telegram 相似的交互体验:

css
/* 默认模糊状态 */
.tg-spoiler:not(.revealed) {
  color: transparent;
  filter: blur(5px);
}

/* 悬停时减少模糊 */
.tg-spoiler:not(.revealed):hover {
  filter: blur(3px);
}

/* 点击后显示 */
.tg-spoiler.revealed {
  filter: none;
  color: inherit;
}

交互流程:

  1. 默认: 文字完全模糊,无法阅读
  2. 悬停: 模糊度降低,提示可以点击
  3. 点击: 移除模糊效果,显示原文
  4. 显示后: 可正常选择和复制文字

移动端优化

键盘上方固定工具栏

工具栏固定在键盘上方,确保输入时不被遮挡:

css
.xc-telegram-editor-toolbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 48px;
}

工具栏横向滚动

当工具栏按钮数量较多时,支持横向滚动查看所有按钮:

css
.xc-telegram-editor-toolbar {
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch; /* iOS 平滑滚动 */
  touch-action: pan-x; /* 允许横向滚动 */
  scrollbar-width: none; /* 隐藏滚动条 */
}

特性:

  • 自动横向滚动,不会压缩按钮
  • iOS 平滑滚动体验
  • 隐藏滚动条,保持界面简洁
  • 所有按钮保持 48px 最小宽度

自动滚动

键盘弹出时,编辑器自动滚动到底部,光标始终可见:

tsx
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

属性类型默认值描述
defaultValuestring''非受控模式下的初始内容
valuestring-受控模式下的值
onChange(html: string, editor: Editor) => void-内容变化回调
placeholderstring'写点什么…'Placeholder 文字
maxLengthnumber4096最大字符数限制(Telegram API 限制)
showCounterbooleantrue是否显示字符计数器
showToolbarbooleantrue是否显示工具栏
classNamestring-附加的 CSS 类名
autoFocusbooleanfalse是否自动聚焦
disabledbooleanfalse是否禁用

HTML 转换规则

TelegramEditor 会自动将标准 HTML 标签转换为 Telegram 支持的格式:

typescript
// 转换规则
'<strong>''<b>'
'<em>''<i>'
'<strike>''<s>'
'<del>''<s>'
'<blockquote>''<blockquote expandable>'

所有 class 属性会被移除(除了 tg-spoiler):

html
<!-- 输入 -->
<a class="xc-telegram-editor-link" href="https://example.com">链接</a>

<!-- 输出 -->
<a href="https://example.com">链接</a>

样式定制

可以通过覆盖 CSS 变量来定制组件样式:

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 页面中,通常需要使用相对定位而非固定定位:

tsx
<TelegramEditor
  className="demo-editor"
  // ...
/>

<style>
  .demo-editor {
    --xc-editor-position: absolute;
    --xc-editor-max-height: 300px;
  }
</style>

暗黑模式

组件自动支持暗黑模式:

css
@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;
  }
}

注意事项

  1. 字符限制 - Telegram Bot API 限制单条消息最多 4096 个字符(包含 HTML 标签)
  2. 纯文本粘贴 - 粘贴时自动过滤所有样式,只保留纯文本,避免引入不支持的标签
  3. 仅移动端优化 - 工具栏固定在底部的设计主要针对移动端,桌面端建议隐藏工具栏或自定义位置
  4. iOS Safari - 已针对 iOS Safari 的选区和输入法问题进行优化

依赖

TelegramEditor 基于 Tiptap 构建,需要以下依赖:

  • @tiptap/react - React 集成
  • @tiptap/starter-kit - 基础编辑器功能
  • @tiptap/extension-link - 链接支持
  • @tiptap/extension-placeholder - Placeholder 支持
  • @tiptap/core - 核心库

所有依赖已包含在 @xcloud/ui-mobile 中,无需额外安装。

相关资源

基于 MIT 许可发布