Skip to content

TelegramEditor

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

核心特性

  • 严格遵循 Telegram 规范 - 完整支持 Telegram Bot API 的所有 HTML 标签,包括简写标签和特殊协议
  • 📱 移动端体验优化 - 键盘上方工具栏、自动滚动、48px 最小点击区域
  • 🎨 纯文本粘贴 - 自动过滤垃圾样式,只保留纯文本内容
  • 🔧 自定义变量 - 支持外部传入自定义变量,与内置变量合并
  • 💡 源码/预览模式 - 可视化编辑与源码编辑自由切换,支持高级 HTML 标签
  • 🎯 按钮管理 - 支持拖拽排序的按钮/快捷键管理,可配置按钮类型
  • 🔄 后端集成 - 自动转换为后端 API 格式,无需手动处理
  • ⚡️ 轻量级 - 体积 ≈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 完整支持 Telegram Bot API 的所有 HTML 标签:

基础格式(有 UI 工具)

格式图标标签说明
粗体B<b>, <strong>加粗文字强调
斜体I<i>, <em>斜体表示引用
下划线U<u>, <ins>添加下划线突出
删除线<s>, <strike>, <del>表示已删除内容
行内代码</><code>显示行内代码
代码块{ }<pre><code>多行代码块,支持 language-* class
等宽文本<pre>等宽格式文本块(不带语法高亮)
隐藏文字👁<span class="tg-spoiler"><tg-spoiler>点击后显示(blur 效果)
引用"<blockquote><blockquote expandable>引用内容,支持智能切换(见下文)
链接🔗<a href="url">可点击的超链接,支持 tg:// 协议

引用按钮智能切换

引用按钮支持三状态智能切换,每次点击会循环切换状态:

  1. 未激活普通引用:首次点击,创建 <blockquote> 标签
  2. 普通引用可展开引用:再次点击,添加 expandable 属性,按钮显示 "(折叠)" 标识
  3. 可展开引用取消引用:第三次点击,移除引用格式
tsx
// 使用示例
// 第一次点击:未激活 → <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:// 链接等)

使用示例

tsx
// 在源码模式使用 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}}当前时间

自定义变量

除了内置变量,你还可以传入自定义变量,它们会与内置变量合并显示在变量选择器中:

tsx
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)}
    />
  )
}

变量列表顺序:

  1. 内置 Telegram 变量(11个)
  2. 自定义变量(按传入顺序)

所有变量在工具栏的「变量」面板中显示,点击即可插入到编辑器光标位置。

使用示例

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. 显示后: 可正常选择和复制文字

按钮管理

TelegramEditor 支持添加和管理按钮/快捷键,提供直观的拖拽排序界面。

按钮模式

编辑器支持两种按钮模式:

  • 按钮模式 (button): 用于 Telegram 消息的内联按钮,支持 URL 链接、回调函数、WebApp 等
  • 快捷键模式 (shortcut): 用于快捷回复,支持文本和链接
tsx
// 按钮模式
<TelegramEditor
  buttonMode="button"
  enabledButtonTypes={['url', 'callback', 'webapp']}
/>

// 快捷键模式
<TelegramEditor
  buttonMode="shortcut"
  enabledButtonTypes={['text', 'url']}
/>

可配置按钮类型

通过 enabledButtonTypes 属性控制允许使用的按钮类型:

tsx
<TelegramEditor
  buttonMode="button"
  enabledButtonTypes={['url', 'callback']}  // 只允许链接和回调
/>

内置按钮类型:

类型说明适用模式需要 value
urlURL 链接button, shortcut
callback回调函数button
text纯文本shortcut
webappWeb Appbutton

自定义按钮类型

除了内置类型,还可以添加自定义按钮类型:

tsx
<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 标题显示"添加按钮"
  • 不显示删除按钮
tsx
// 直接模式(默认)
<TelegramEditor
  buttonMode="button"
  addButtonMode="direct"  // 可省略,这是默认值
/>

// 编辑模式
<TelegramEditor
  buttonMode="button"
  addButtonMode="edit"  // 先填写配置再添加
/>

拖拽排序

按钮支持拖拽排序,包括:

  • 行内拖拽: 在同一行内调整按钮顺序
  • 跨行拖拽: 将按钮移动到其他行
  • 行拖拽: 拖动整行调整行顺序

按钮限制

  • 最多支持 7 行按钮
  • 每行最多 8 个按钮
  • 按钮和快捷键互斥(只能选择一种模式)

媒体URL管理

TelegramEditor 支持添加媒体地址(图片/视频 URL),用于发送带媒体的 Telegram 消息。

基础用法

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

function MediaExample() {
  const [mediaUrl, setMediaUrl] = useState('');

  return (
    <TelegramEditor
      mediaUrl={mediaUrl}
      onMediaUrlChange={setMediaUrl}
      placeholder="输入消息..."
    />
  );
}

受控与非受控模式

媒体URL支持受控和非受控两种模式:

tsx
// 受控模式 - 通过 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会自动包含在后端格式数据中:

tsx
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 回调实时获取后端格式数据:

tsx
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}
    />
  );
}

后端数据格式

typescript
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):

  • urllink
  • callbackcallback
  • webapplink

快捷键模式 (shortcut):

  • urllink
  • texttext

手动转换

如果需要手动转换,可以使用导出的转换函数:

tsx
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);

使用示例

tsx
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>
  );
}

移动端优化

键盘上方固定工具栏

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

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 类名
styleReact.CSSProperties-自定义样式(支持 CSS 变量覆盖)
autoFocusbooleanfalse是否自动聚焦
disabledbooleanfalse是否禁用
variablesTelegramVariable[][]自定义变量列表(与内置变量合并)
useShorthandTagsbooleanfalse是否使用 Telegram 简写标签格式
i18nTelegramEditorI18ndefaultI18n国际化文本配置
onPreview() => void-预览/源码切换回调
toolbarPartial<TelegramEditorToolbarProps>-自定义工具栏属性
按钮管理
buttonMode'button' | 'shortcut'-按钮模式(button: 消息按钮, shortcut: 快捷键)
enabledButtonTypesstring[]-允许使用的按钮类型列表
customButtonTypesRecord<string, ButtonTypeConfig>{}自定义按钮类型配置
addButtonMode'direct' | 'edit''direct'添加按钮的方式(direct: 直接添加, edit: 先填写配置)
defaultKeyboardKeyboardMarkup[]默认按钮布局
onKeyboardChange(keyboard: KeyboardMarkup) => void-按钮布局变化回调
后端集成
mediaUrlstring''媒体地址(图片/视频 URL)
onMediaUrlChange(url: string) => void-媒体地址变化回调
onBackendDataChange(data: BackendMessageTemplate) => void-后端格式数据变化回调(自动导出)

TelegramVariable 接口

typescript
interface TelegramVariable {
  /** 变量唯一标识 */
  key: string
  /** 变量显示标签 */
  label: string
  /** 变量插入值(例如 {{var_name}}) */
  value: string
}

ButtonTypeConfig 接口

typescript
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 接口

typescript
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 标签的格式:

tsx
// useShorthandTags={false} (默认)
<span class="tg-spoiler">隐藏内容</span>

// useShorthandTags={true}
<tg-spoiler>隐藏内容</tg-spoiler>

两种格式都是 Telegram 官方支持的,选择哪种取决于你的使用场景。

HTML 转换规则

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

基础标签转换

typescript
'<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)。

特殊标签处理

段落和换行处理:

html
<!-- 编辑器内部格式 -->
<p>第一段</p><p>第二段</p>

<!-- 输出为 Telegram 格式 -->
第一段
第二段

<!-- blockquote 内的段落也会被处理 -->
<blockquote expandable="true"><p>引用内容</p></blockquote>
<!-- 输出 -->
<blockquote expandable="true">引用内容</blockquote>

代码块语言保留:

html
<!-- 输入 -->
<pre><code class="language-python">code</code></pre>

<!-- 输出(保留 language-* class) -->
<pre><code class="language-python">code</code></pre>

Spoiler 标签转换:

html
<!-- 源码模式输入 -->
<tg-spoiler>隐藏内容</tg-spoiler>

<!-- 转换为编辑器内部格式 -->
<span class="tg-spoiler">隐藏内容</span>

<!-- 如果 useShorthandTags={true},输出时转回 -->
<tg-spoiler>隐藏内容</tg-spoiler>

引用标签保留:

html
<!-- 普通引用 -->
<blockquote>引用内容</blockquote>

<!-- 可展开引用 -->
<blockquote expandable>长引用内容</blockquote>

保留的特殊标签

以下标签会被完整保留,不做修改:

html
<!-- 自定义 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 会被移除:

html
<!-- 输入 -->
<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 变量来定制组件样式:

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)

自定义示例:

tsx
// 提高整体 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),可以通过调整基础值确保层级关系正确:

tsx
<MobilePage>
  <TelegramEditor
    // 确保编辑器层级低于页面固定按钮
    style={{ '--xc-editor-z-index-base': '10' } as React.CSSProperties}
  />
  {/* 固定按钮 z-index: 50 在编辑器之上 */}
</MobilePage>

使用固定定位

在移动端应用中使用固定定位(键盘上方固定):

tsx
<TelegramEditor
  style={{ '--xc-editor-position': 'fixed' } as React.CSSProperties}
  // ...
/>

在 Demo 中使用相对定位

在文档或 Demo 页面中,使用默认的绝对定位:

tsx
<TelegramEditor
  className="demo-editor"
  // 默认是 absolute,无需额外设置
  // ...
/>

暗黑模式

组件自动支持暗黑模式:

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. 定位模式 - 默认使用 absolute 定位,移动端应用可通过 CSS 变量改为 fixed
  4. iOS Safari - 已针对 iOS Safari 的选区和输入法问题进行优化
  5. 特殊标签 - <tg-emoji>tg:// 协议链接在编辑器中会被保留,但可能无法实时预览效果
  6. 代码语言 - 代码块的 language-* class 会被保留,但编辑器 UI 不提供语言选择器,需在源码模式手动添加
  7. 按钮限制 - 最多 7 行,每行最多 8 个按钮;按钮和快捷键互斥
  8. 后端格式 - 使用 onBackendDataChange 可自动获取后端格式,无需手动转换

导出函数

convertToBackendFormat

将编辑器格式转换为后端 API 格式。

typescript
function convertToBackendFormat(
  html: string,
  keyboard: KeyboardMarkup,
  buttonMode: 'button' | 'shortcut',
  mediaUrl: string
): BackendMessageTemplate

参数:

  • html: HTML 内容
  • keyboard: 按钮布局(二维数组)
  • buttonMode: 按钮模式
  • mediaUrl: 媒体地址

**返回:**后端消息模板格式

convertFromBackendFormat

将后端格式转换为编辑器格式。

typescript
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 中,无需额外安装。

相关资源

基于 MIT 许可发布