smart-compose
v4.0.3
Published
Smart Compose 是一个轻量级的 JavaScript 库,可以将任何给定的 `textarea` 或 `contenteditable` 元素转换为具有智能补全功能的编辑器。
Downloads
118
Readme
Smart Compose
Smart Compose 是一个轻量级的 JavaScript 库,可以将任何给定的 textarea
或 contenteditable
元素转换为具有智能补全功能的编辑器。
功能特点
- 支持
textarea
和contenteditable
元素 - 实时文本补全建议
- 自定义 API 端点
- 可配置的防抖时间
- 自动调整文本区域高度
- 支持自定义样式和回调函数
- 响应式设计,支持窗口大小变化
- 焦点状态样式
- 占位符文本支持
项目架构
Smart Compose 采用模块化和面向对象的架构设计。以下是项目的整体结构概览:
| 文件/文件夹 | 描述 |
| ---------------------- | --------------------------------------------------- |
| src
/ | 源代码目录 |
| ├── SmartCompose
/ | Smart Compose 核心代码 |
| │ ├── index.ts
| 主入口文件,包含 SmartCompose
类和 enhance
方法 |
| │ ├── utils
/ | 工具函数目录 |
| │ │ ├── api.ts
| API
相关工具函数 |
| │ │ ├── domUtils.ts
| DOM
操作相关工具函数 |
| │ │ └── textUtils.ts
| 文本处理相关工具函数 |
| │ ├── constants.ts
| 全局常量 |
| │ ├── handlers.ts
| 元素处理器,处理不同类型可编辑元素的逻辑 |
| │ ├── styles.ts
| 样式定义和管理 |
| │ └── types.ts
| 类型定义文件 |
| ├── __tests__
/ | 测试文件目录 |
| ├── App.css
| 开发环境:应用程序样式文件 |
| ├── App.tsx
| 开发环境:主应用程序组件 |
| ├── index.ts
| 项目入口文件 |
| ├── main.tsx
| 开发环境:主渲染文件 |
| └── vite-env.d.ts
| Vite 环境声明文件 |
| .github
/ | GitHub 相关配置文件目录 |
| .husky
/ | Husky git hooks 配置目录 |
| dist
/ | 构建输出目录 |
| githubExtension
/ | GitHub 扩展测试相关代码 |
| node_modules
/ | 项目依赖包目录 |
| tiptapTest
/ | TipTap 编辑器测试相关代码 |
| .eslint.config.js
| ESLint 配置文件 |
| .gitignore
| Git 忽略文件配置 |
| .npmignore
| npm 发布忽略文件配置 |
| index.html
| 开发环境:项目 HTML 入口文件 |
| package.json
| 项目依赖和脚本配置 |
| pnpm-lock.yaml
| pnpm 依赖锁定文件 |
| README.md
| 项目说明文档 |
| tsconfig.dev.json
| 开发环境 TypeScript 配置 |
| tsconfig.json
| 生产环境 TypeScript 配置 |
| tsconfig.node.json
| Node.js 环境 TypeScript 配置 |
| tsconfig.tsbuildinfo
| TypeScript 构建信息文件 |
| vite.config.ts
| Vite 配置文件 |
| vite.dev.config.ts
| Vite 开发环境配置文件 |
实现思路
创建一个新的
div
:包裹层(wrapper
),包含原始的编辑器元素(textarea
或contenteditable
)和一个新创建的div
:的补全层(completion
)。补全层位于编辑器元素下方,用于显示补全建议。它的内容由用户输入的文本和智能补全的建议组成。
将编辑器元素的背景设置为透明,允许补全层的内容透过显示。
精确调整补全层的样式(字体、大小、行高等),使其与编辑器元素的文本完全对齐。
实时监听编辑器的输入事件,并相应更新补全层的内容:
- 用户输入的文本保持不变
- 根据 API 返回的建议更新补全部分
实现光标跟踪机制,确保补全建议始终出现在光标位置之后,而不仅仅是在文本末尾。
添加用户交互逻辑,如按 Tab 键接受补全建议。
优化渲染性能,使用防抖(
debounce
)技术减少API
调用频率,避免频繁的DOM
操作。实现响应式设计,确保在窗口大小变化时保持对齐。
数据流
用户输入 → 触发输入事件 → 防抖处理 → 调用 API
获取补全建议 → 更新补全层内容 → 用户接受建议 → 更新编辑器内容
待改进
- 如果在已输入内容中间输入,生成的联想还是会在末尾
- 输入和删除时会闪烁
安装
npm install smart-compose
yarn add smart-compose
pnpm add smart-compose
开发
克隆仓库并安装依赖:
git clone https://github.com/dadafawang/smart-compose
cd smart-compose
pnpm install
运行开发服务器:
pnpm dev
运行测试:
pnpm test
构建库:
pnpm build
使用方法
作为模块使用
import SmartCompose from 'smart-compose'
const textarea = document.querySelector('#myTextarea')
const apiEndpoint = 'https://your-api-endpoint.com/smart-compose'
const smartCompose = SmartCompose.enhance(textarea, apiEndpoint, {
debounceTime: 300,
placeholder: '在此处描述问题...',
onComplete: (result) => {
console.log('补全完成:', result)
},
onChange: (text) => {
console.log('内容变化:', text)
}
})
在 GitHub Issues 测试
因为 GitHub 有内容安全策略(Content Security Policy,CSP)设置,不允许向 http://localhost:8000 发送请求。 所以对于在 GitHub Issues 的测试,我使用 Chrome 扩展(Chrome 扩展可以绕过网站的 CSP 限制)。 当然,您可以自由选择测试的方法,比如像使用代理等。
- 进入当前项目根目录的
githubExtension
文件夹,安装依赖并构建扩展生成dist
文件夹(扩展的主要脚本内容写在src/content.js
文件中)
cd githubExtension/
pnpm install
pnpm build
打开 Chrome 浏览器,进入扩展管理页面(chrome://extensions/),启用 "开发者模式";点击 "加载已解压的扩展程序",选择
githubExtension
文件夹下构建后的dist
文件夹打开一个 GitHub 仓库的 Issues 页面,点击 "New issue" 创建新的 issue,扩展会自动激活
如果遇到问题,可以打开 Chrome 开发者工具查看控制台输出
如果需要卸载扩展,可以在 Chrome 扩展管理页面中找到该扩展并点击"删除"
作为浏览器脚本使用
<div contenteditable="true"></div>
<script src="https://unpkg.com/smart-compose@latest/dist/js/smart-compose.umd.js"></script>
<script>
const editor = document.querySelector('[contenteditable="true"]')
const apiEndpoint = 'https://your-api-endpoint.com/smart-compose'
const smartCompose = SmartCompose.enhance(editor, apiEndpoint, {
debounceTime: 300,
placeholder: '开始输入...',
onComplete: (result) => {
console.log('补全完成:', result)
},
onChange: (text) => {
console.log('内容变化:', text)
}
})
</script>
在 TipTap 测试
打开 https://tiptap.dev/docs/examples/basics/default-text-editor
打开浏览器开发者工具(F12),切换到 console 标签页
在根目录下运行:
pnpm build
构建当前项目,并复制打包后的dist/js/smart-compose.umd.js
到控制台运行复制以下测试代码粘贴到控制台运行(为了复制方便,以下测试代码也已备份到根目录下的
tiptapTest/index.js
内)
window.initTipTapSmartCompose = function () {
const apiEndpoint = 'http://localhost:8000/api/smartCompose'
function findEditor() {
let editor = document.querySelector('[contenteditable="true"]')
if (!editor) {
editor = document.getElementsByClassName('tiptap')[0]
}
return editor
}
const editor = findEditor()
if (editor) {
// 如果已存在实例,先销毁它
if (
window.TipTapSmartComposeInstance &&
typeof window.TipTapSmartComposeInstance.destroy === 'function'
) {
window.TipTapSmartComposeInstance.destroy()
console.log('已销毁旧的 GitHub SmartCompose 实例')
}
const smartCompose = SmartCompose.enhance(editor, apiEndpoint, {
debounceTime: 300,
placeholder: '开始输入...',
onComplete: (result) => {
console.log('补全完成:', result)
},
onChange: (text) => {
console.log('内容变化:', text)
}
})
// 在实例化后立即为 completion 元素添加 tiptap 类名
const completionElements = document.getElementsByClassName(
'smart-compose-completion'
)
Array.from(completionElements).forEach((element) => {
element.classList.add('tiptap')
})
console.log('新的 TipTap SmartCompose 实例已创建:', smartCompose)
// 在页面卸载时销毁 SmartCompose 实例
window.addEventListener('beforeunload', () => {
smartCompose.destroy()
console.log('TipTap SmartCompose 实例已销毁')
})
window.TipTapSmartComposeInstance = smartCompose
} else {
console.error('未找到合适的 TipTap 编辑器元素')
}
}
// 初始化SmartCompose
window.initTipTapSmartCompose()
- 如果页面刷新或需要重新初始化,在控制台中运行
window.initTipTapSmartCompose()
API
SmartCompose.enhance(element, apiEndpoint, options)
将给定的元素转换为智能补全编辑器。
参数:
element
:HTMLTextAreaElement | HTMLElement
- 要增强的textarea
或contenteditable
元素apiEndpoint
:string
- 用于获取补全建议的 API 端点options
:SmartComposeOptions
- 配置选项(可选)
返回值: SmartCompose
实例
SmartComposeOptions
| 选项 | 类型 | 默认值 | 是否必填 | 描述 |
| -------------- | ---------- | ------ | -------- | ----------------------------- |
| debounceTime
| number
| 300 | 可选 | 输入防抖时间(毫秒) |
| initialValue
| string
| - | 可选 | 编辑器的初始文本 |
| className
| string
| - | 可选 | 应用于编辑器的额外 CSS
类名 |
| placeholder
| string
| - | 可选 | 编辑器的占位符文本 |
| style
| object
| - | 可选 | 应用于容器的内联样式 |
| onComplete
| function
| - | 可选 | 应用补全建议时的回调函数 |
| onChange
| function
| - | 可选 | 输入文本变化时的回调函数 |
实例方法
onComplete(callback: (result: CompletionResult) => void)
: 设置应用补全建议时的回调函数onChange(callback: (value: string) => void)
: 设置输入文本变化时的回调函数destroy()
: 销毁SmartCompose
实例,移除所有事件监听器和DOM
修改
示例:
const smartCompose = SmartCompose.enhance(element, apiEndpoint)
// 设置补全回调
smartCompose.onComplete((result) => {
console.log('补全已应用:', result)
})
// 设置变更回调
smartCompose.onChange((value) => {
console.log('输入已更改:', value)
})
// 销毁实例
smartCompose.destroy()
这些方法允许你在实例创建后动态设置回调函数,或者在不再需要 SmartCompose
功能时清理资源。