tiptap-extension-shiki 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish_npm.yml +32 -0
- package/README.md +146 -0
- package/README_CN.md +146 -0
- package/dist/ShikiLightPlugin.d.ts +19 -0
- package/dist/index.cjs.css +1 -0
- package/dist/index.cjs.js +412 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +407 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
- package/rollup.config.js +71 -0
- package/src/ShikiLightPlugin.ts +221 -0
- package/src/index.css +41 -0
- package/src/index.ts +340 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
# 触发ci/cd的代码分支
|
|
7
|
+
- master
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build_and_publish:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
# 必须添加这个权限,否则无法获取临时身份证明
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
id-token: write
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: '20'
|
|
22
|
+
# 注意:这里不再需要配置 registry-url 或 NODE_AUTH_TOKEN
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: npm install
|
|
26
|
+
|
|
27
|
+
- name: Build package
|
|
28
|
+
run: npm run build
|
|
29
|
+
|
|
30
|
+
- name: Publish to NPM
|
|
31
|
+
# 使用专用 Action,它会自动识别 OIDC 身份并完成发布
|
|
32
|
+
run: npm publish --provenance --access public
|
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Tiptap Extension Shiki
|
|
2
|
+
|
|
3
|
+
[📖 View Chinese Version](./README_CN.md)
|
|
4
|
+
|
|
5
|
+
### Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install shiki tiptap-extension-shiki
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
new Editor({
|
|
15
|
+
content: "",
|
|
16
|
+
extensions: [
|
|
17
|
+
TiptapShiki.configure({
|
|
18
|
+
// Must have a default theme for fallback
|
|
19
|
+
defaultTheme: "dracula",
|
|
20
|
+
// Must have a default language for fallback
|
|
21
|
+
defaultLanguage: "javascript",
|
|
22
|
+
// Since the renderer is asynchronous, the highlighter instance must be passed in the extension configuration
|
|
23
|
+
highlighter: await createHighlighter({
|
|
24
|
+
// You can only use the themes and languages loaded by your highlighter, otherwise it will throw an error
|
|
25
|
+
// Since the main purpose is to provide it for background editor usage, I won't consider asynchronously loading additional languages and themes
|
|
26
|
+
themes: ["dracula", "dark-plus"],
|
|
27
|
+
langs: ["javascript", "typescript", "html", "css", "python", "json"],
|
|
28
|
+
}),
|
|
29
|
+
}),
|
|
30
|
+
StarterKit.configure({
|
|
31
|
+
codeBlock: false,
|
|
32
|
+
}),
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Tiptap getHTML Returns Highlighted HTML
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
TiptapShiki.configure({
|
|
41
|
+
// After passing the configuration, using tiptap's getHTML will return highlighted HTML
|
|
42
|
+
// Note: If getHighlighHTML is enabled, the returned HTML cannot be used for setContent backfill, so please store getJSON for editing, and use HTML only for frontend display
|
|
43
|
+
getHighlighHTML: true,
|
|
44
|
+
}),
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Custom Toolbar
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// You can import the built-in stylesheet or write your own styles
|
|
51
|
+
import "tiptap-extension-shiki/dist/style.css";
|
|
52
|
+
|
|
53
|
+
TiptapShiki.configure({
|
|
54
|
+
renderToolbar: ({ language, theme, toolbarDOM, setTheme, setLanguage }) => {
|
|
55
|
+
// Here, you can insert DOM elements into toolbarDOM in your own way (React/VUE).
|
|
56
|
+
// For example, you can use renderer(VNode,toolbarDOM)
|
|
57
|
+
|
|
58
|
+
// Example: Create toolbar using native DOM
|
|
59
|
+
// Create language selection dropdown
|
|
60
|
+
const languageSelect = document.createElement("select");
|
|
61
|
+
languageSelect.style.cssText =
|
|
62
|
+
"width: 200px; padding: 4px 8px; margin-right: 8px;";
|
|
63
|
+
languageSelect.innerHTML = `
|
|
64
|
+
<option value="javascript">JavaScript</option>
|
|
65
|
+
<option value="typescript">TypeScript</option>
|
|
66
|
+
<option value="html">HTML</option>
|
|
67
|
+
<option value="css">CSS</option>
|
|
68
|
+
<option value="python">Python</option>
|
|
69
|
+
<option value="json">JSON</option>
|
|
70
|
+
<option value="c++">C++</option>
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
// Create theme selection dropdown
|
|
74
|
+
const themeSelect = document.createElement("select");
|
|
75
|
+
themeSelect.style.cssText = "width: 200px; padding: 4px 8px;";
|
|
76
|
+
themeSelect.innerHTML = `
|
|
77
|
+
<option value="dracula">Dracula</option>
|
|
78
|
+
<option value="dark-plus">DarkPlus</option>
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
// Add language change event listener
|
|
82
|
+
languageSelect.addEventListener("change", (event) => {
|
|
83
|
+
// Set selected language
|
|
84
|
+
setLanguage((event.target as HTMLSelectElement).value);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Add theme change event listener
|
|
88
|
+
themeSelect.addEventListener("change", (event) => {
|
|
89
|
+
// Set selected theme
|
|
90
|
+
setTheme((event.target as HTMLSelectElement).value);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Add DOM elements to toolbar container
|
|
94
|
+
toolbarDOM.appendChild(languageSelect);
|
|
95
|
+
toolbarDOM.appendChild(themeSelect);
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Features
|
|
101
|
+
|
|
102
|
+
- ✨ Support for multiple programming languages
|
|
103
|
+
- 🎨 Support for multiple theme switching
|
|
104
|
+
- 🛠️ Customizable toolbar interface
|
|
105
|
+
- 🚀 Real-time syntax highlighting rendering
|
|
106
|
+
- 🔧 High-performance syntax highlighting engine based on Shiki
|
|
107
|
+
|
|
108
|
+
### Configuration Options
|
|
109
|
+
|
|
110
|
+
| Option | Type | Default | Description |
|
|
111
|
+
| ----------------- | ------------- | -------------- | ------------------------------------ |
|
|
112
|
+
| `defaultTheme` | `string` | `'dracula'` | Default syntax highlighting theme (Required) |
|
|
113
|
+
| `defaultLanguage` | `string` | `'javascript'` | Default programming language (Required) |
|
|
114
|
+
| `highlighter` | `Highlighter` | `undefined` | Shiki highlighter instance (Required) |
|
|
115
|
+
| `getHighlighHTML` | `boolean` | `false` | Whether to generate static highlighted HTML |
|
|
116
|
+
| `renderToolbar` | `function` | `undefined` | Custom toolbar rendering function |
|
|
117
|
+
|
|
118
|
+
### Custom Styling
|
|
119
|
+
|
|
120
|
+
You can customize the appearance of code blocks through CSS:
|
|
121
|
+
|
|
122
|
+
```css
|
|
123
|
+
.tiptap-shiki--container {
|
|
124
|
+
border-radius: 8px;
|
|
125
|
+
font-family: "Fira Code", monospace;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.tiptap-shiki--toolbar {
|
|
129
|
+
background: rgba(0, 0, 0, 0.05);
|
|
130
|
+
border-radius: 6px 6px 0 0;
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Contributing
|
|
135
|
+
This plugin references the original highlighting plugin
|
|
136
|
+
[extension-code-block-lowlight](https://github.com/ueberdosis/tiptap/tree/main/packages/extension-code-block-lowlight)
|
|
137
|
+
|
|
138
|
+
### Notes
|
|
139
|
+
|
|
140
|
+
1. You must create and configure a Shiki highlighter instance before use
|
|
141
|
+
2. DOM operations in custom toolbar functions are safe, the editor will handle conflicts
|
|
142
|
+
3. Make sure to install all dependencies before use
|
|
143
|
+
|
|
144
|
+
### License
|
|
145
|
+
|
|
146
|
+
MIT License
|
package/README_CN.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Tiptap Shiki 语法高亮扩展
|
|
2
|
+
|
|
3
|
+
[📖 View English Version](./README.md)
|
|
4
|
+
|
|
5
|
+
### 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install shiki tiptap-extension-shiki
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### 使用方法
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
new Editor({
|
|
15
|
+
content: "",
|
|
16
|
+
extensions: [
|
|
17
|
+
TiptapShiki.configure({
|
|
18
|
+
// 必须有一个默认主题来进行回退
|
|
19
|
+
defaultTheme: "dracula",
|
|
20
|
+
// 必须有一个默认语言来进行回退
|
|
21
|
+
defaultLanguage: "javascript",
|
|
22
|
+
// 由于渲染器是异步的,所以必须在扩展配置中传递高亮器实例
|
|
23
|
+
highlighter: await createHighlighter({
|
|
24
|
+
// 你只能使用你高亮器加载的主题和语言,否则会报错
|
|
25
|
+
// 因为主要目的是提供给后台的编辑器使用所以我不会考虑异步去加载额外的语言和主题
|
|
26
|
+
themes: ["dracula", "dark-plus"],
|
|
27
|
+
langs: ["javascript", "typescript", "html", "css", "python", "json"],
|
|
28
|
+
}),
|
|
29
|
+
}),
|
|
30
|
+
StarterKit.configure({
|
|
31
|
+
codeBlock: false,
|
|
32
|
+
}),
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Tiptap getHTML 返回高亮后的 html
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
TiptapShiki.configure({
|
|
41
|
+
// 传递配置项之后 使用tiptap的 getHTML将会返回高亮后的 html
|
|
42
|
+
// 注意:如果启用了 getHighlighHTML,返回的 HTML 不能用于setContent 回填,所以请储存getJSON用来编辑,而 html 只用来做前台展示
|
|
43
|
+
getHighlighHTML: true,
|
|
44
|
+
}),
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 自定义工具栏
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// 你可以导入预制的样式文件来使用,也可以自行编写样式
|
|
51
|
+
import "tiptap-extension-shiki/dist/style.css";
|
|
52
|
+
|
|
53
|
+
TiptapShiki.configure({
|
|
54
|
+
renderToolbar: ({ language, theme, toolbarDOM, setTheme, setLanguage }) => {
|
|
55
|
+
// 在这里,您可以按照自己的方式(React/VUE)插入 DOM 到 toolbarDOM 中。
|
|
56
|
+
// 例如,您可以使用 renderer(VNode,toolbarDOM)
|
|
57
|
+
|
|
58
|
+
// 示例用原生 dom 来创建工具栏
|
|
59
|
+
// Create language selection dropdown
|
|
60
|
+
const languageSelect = document.createElement("select");
|
|
61
|
+
languageSelect.style.cssText =
|
|
62
|
+
"width: 200px; padding: 4px 8px; margin-right: 8px;";
|
|
63
|
+
languageSelect.innerHTML = `
|
|
64
|
+
<option value="javascript">JavaScript</option>
|
|
65
|
+
<option value="typescript">TypeScript</option>
|
|
66
|
+
<option value="html">HTML</option>
|
|
67
|
+
<option value="css">CSS</option>
|
|
68
|
+
<option value="python">Python</option>
|
|
69
|
+
<option value="json">JSON</option>
|
|
70
|
+
<option value="c++">C++</option>
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
// Create theme selection dropdown
|
|
74
|
+
const themeSelect = document.createElement("select");
|
|
75
|
+
themeSelect.style.cssText = "width: 200px; padding: 4px 8px;";
|
|
76
|
+
themeSelect.innerHTML = `
|
|
77
|
+
<option value="dracula">Dracula</option>
|
|
78
|
+
<option value="dark-plus">DarkPlus</option>
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
// Add language change event listener
|
|
82
|
+
languageSelect.addEventListener("change", (event) => {
|
|
83
|
+
// 设置选中的语言
|
|
84
|
+
setLanguage((event.target as HTMLSelectElement).value);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Add theme change event listener
|
|
88
|
+
themeSelect.addEventListener("change", (event) => {
|
|
89
|
+
// 设置选中的主题
|
|
90
|
+
setTheme((event.target as HTMLSelectElement).value);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// 在工具栏容器中添加DOM
|
|
94
|
+
toolbarDOM.appendChild(languageSelect);
|
|
95
|
+
toolbarDOM.appendChild(themeSelect);
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 功能特性
|
|
101
|
+
|
|
102
|
+
- ✨ 支持多种编程语言切换
|
|
103
|
+
- 🎨 支持多种主题切换
|
|
104
|
+
- 🛠️ 可自定义工具栏界面
|
|
105
|
+
- 🚀 实时语法高亮渲染
|
|
106
|
+
- 🔧 基于 Shiki 的高性能语法高亮引擎
|
|
107
|
+
|
|
108
|
+
### 配置选项
|
|
109
|
+
|
|
110
|
+
| 选项 | 类型 | 默认值 | 描述 |
|
|
111
|
+
| ----------------- | ------------- | -------------- | ------------------------- |
|
|
112
|
+
| `defaultTheme` | `string` | `'dracula'` | 默认语法高亮主题 (必需) |
|
|
113
|
+
| `defaultLanguage` | `string` | `'javascript'` | 默认编程语言 (必需) |
|
|
114
|
+
| `highlighter` | `Highlighter` | `undefined` | Shiki 高亮器实例(必需) |
|
|
115
|
+
| `getHighlighHTML` | `boolean` | `false` | 是否生成静态高亮 HTML |
|
|
116
|
+
| `renderToolbar` | `function` | `undefined` | 自定义工具栏渲染函数 |
|
|
117
|
+
|
|
118
|
+
### 自定义样式
|
|
119
|
+
|
|
120
|
+
你可以通过 CSS 自定义代码块的外观:
|
|
121
|
+
|
|
122
|
+
```css
|
|
123
|
+
.tiptap-shiki--container {
|
|
124
|
+
border-radius: 8px;
|
|
125
|
+
font-family: "Fira Code", monospace;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.tiptap-shiki--toolbar {
|
|
129
|
+
background: rgba(0, 0, 0, 0.05);
|
|
130
|
+
border-radius: 6px 6px 0 0;
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 贡献
|
|
135
|
+
这个插件参考了原有的高亮插件
|
|
136
|
+
[extension-code-block-lowlight](https://github.com/ueberdosis/tiptap/tree/main/packages/extension-code-block-lowlight)
|
|
137
|
+
|
|
138
|
+
### 注意事项
|
|
139
|
+
|
|
140
|
+
1. 使用前必须创建并配置 Shiki 高亮器实例
|
|
141
|
+
2. 自定义工具栏函数中的 DOM 操作是安全的,编辑器会处理冲突
|
|
142
|
+
3. 确保在使用前安装所有依赖包
|
|
143
|
+
|
|
144
|
+
### 许可证
|
|
145
|
+
|
|
146
|
+
MIT License
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Plugin } from "@tiptap/pm/state";
|
|
2
|
+
import type { BundledLanguage, BundledTheme, HighlighterGeneric, SpecialLanguage, StringLiteralUnion, ThemeRegistrationAny } from "shiki";
|
|
3
|
+
/**
|
|
4
|
+
* 创建Shiki轻量级语法高亮插件
|
|
5
|
+
* 该插件负责在ProseMirror编辑器中为代码块提供实时的语法高亮显示
|
|
6
|
+
* 通过ProseMirror的装饰器系统实现高性能的语法高亮渲染
|
|
7
|
+
*
|
|
8
|
+
* @param name - 插件名称
|
|
9
|
+
* @param highlighter - Shiki语法高亮器实例
|
|
10
|
+
* @param defaultTheme - 默认主题
|
|
11
|
+
* @param defaultLanguage - 默认编程语言
|
|
12
|
+
* @returns ProseMirror插件实例
|
|
13
|
+
*/
|
|
14
|
+
export declare function ShikiLightPlugin({ name, highlighter, defaultTheme, defaultLanguage, }: {
|
|
15
|
+
name: string;
|
|
16
|
+
highlighter: HighlighterGeneric<BundledLanguage, BundledTheme>;
|
|
17
|
+
defaultTheme: ThemeRegistrationAny | StringLiteralUnion<string>;
|
|
18
|
+
defaultLanguage: StringLiteralUnion<SpecialLanguage>;
|
|
19
|
+
}): Plugin<any>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.tiptap-shiki--container{border-radius:.4rem;font-size:.875em;pre{max-height:400px;overflow:auto;padding:20px}}.tiptap-shiki--toolbar{align-items:center;display:flex;padding:10px}
|