@tiptap/extension-mathematics 3.0.0-beta.16 → 3.0.0-beta.17
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/dist/index.cjs +266 -149
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -17
- package/dist/index.d.ts +118 -17
- package/dist/index.js +262 -146
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/extensions/BlockMath.ts +210 -0
- package/src/extensions/InlineMath.ts +210 -0
- package/src/extensions/index.ts +2 -0
- package/src/index.ts +3 -3
- package/src/mathematics.ts +9 -16
- package/src/types.ts +4 -4
- package/src/MathematicsPlugin.ts +0 -205
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiptap/extension-mathematics",
|
|
3
3
|
"description": "latex math extension for tiptap",
|
|
4
|
-
"version": "3.0.0-beta.
|
|
4
|
+
"version": "3.0.0-beta.17",
|
|
5
5
|
"homepage": "https://tiptap.dev/api/extensions/mathematics",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"tiptap",
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
],
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/katex": "^0.16.7",
|
|
40
|
-
"@tiptap/core": "3.0.0-beta.
|
|
41
|
-
"@tiptap/pm": "3.0.0-beta.
|
|
40
|
+
"@tiptap/core": "3.0.0-beta.17",
|
|
41
|
+
"@tiptap/pm": "3.0.0-beta.17"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"katex": "^0.16.4",
|
|
45
|
-
"@tiptap/core": "3.0.0-beta.
|
|
46
|
-
"@tiptap/pm": "3.0.0-beta.
|
|
45
|
+
"@tiptap/core": "3.0.0-beta.17",
|
|
46
|
+
"@tiptap/pm": "3.0.0-beta.17"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "tsup",
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { InputRule, mergeAttributes, Node } from '@tiptap/core'
|
|
2
|
+
import type { Node as PMNode } from '@tiptap/pm/model'
|
|
3
|
+
import katex from 'katex'
|
|
4
|
+
|
|
5
|
+
export type BlockMathOptions = {
|
|
6
|
+
onClick?: (node: PMNode, pos: number) => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
declare module '@tiptap/core' {
|
|
10
|
+
interface Commands<ReturnType> {
|
|
11
|
+
blockMath: {
|
|
12
|
+
/**
|
|
13
|
+
* Set block math node with LaTeX string.
|
|
14
|
+
* @param options - Options for setting block math.
|
|
15
|
+
* @returns ReturnType
|
|
16
|
+
*/
|
|
17
|
+
setBlockMath: (options: { latex: string; pos?: number }) => ReturnType
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Unset block math node.
|
|
21
|
+
* @returns ReturnType
|
|
22
|
+
*/
|
|
23
|
+
unsetBlockMath: (options?: { pos?: number }) => ReturnType
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Update block math node with optional LaTeX string.
|
|
27
|
+
* @param options - Options for updating block math.
|
|
28
|
+
* @returns ReturnType
|
|
29
|
+
*/
|
|
30
|
+
updateBlockMath: (options?: { latex?: string; pos?: number }) => ReturnType
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* BlockMath is a Tiptap extension for rendering block mathematical expressions using KaTeX.
|
|
37
|
+
* It allows users to insert LaTeX formatted math expressions block within text.
|
|
38
|
+
* It supports rendering, input rules for LaTeX syntax, and click handling for interaction.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```javascript
|
|
42
|
+
* import { BlockMath } from 'your-extension-path'
|
|
43
|
+
* import { Editor } from '@tiptap/core'
|
|
44
|
+
*
|
|
45
|
+
* const editor = new Editor({
|
|
46
|
+
* extensions: [
|
|
47
|
+
* BlockMath.configure({
|
|
48
|
+
* onClick: (node, pos) => {
|
|
49
|
+
* console.log('Block math clicked:', node.attrs.latex, 'at position:', pos)
|
|
50
|
+
* },
|
|
51
|
+
* }),
|
|
52
|
+
* ],
|
|
53
|
+
* })
|
|
54
|
+
*/
|
|
55
|
+
export const BlockMath = Node.create({
|
|
56
|
+
name: 'blockMath',
|
|
57
|
+
|
|
58
|
+
group: 'block',
|
|
59
|
+
|
|
60
|
+
atom: true,
|
|
61
|
+
|
|
62
|
+
addOptions() {
|
|
63
|
+
return {
|
|
64
|
+
onClick: undefined,
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
addAttributes() {
|
|
69
|
+
return {
|
|
70
|
+
latex: {
|
|
71
|
+
default: '',
|
|
72
|
+
parseHTML: element => element.getAttribute('data-latex'),
|
|
73
|
+
renderHTML: attributes => {
|
|
74
|
+
return {
|
|
75
|
+
'data-latex': attributes.latex,
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
addCommands() {
|
|
83
|
+
return {
|
|
84
|
+
setBlockMath:
|
|
85
|
+
options =>
|
|
86
|
+
({ commands, editor }) => {
|
|
87
|
+
const { latex, pos } = options
|
|
88
|
+
return commands.insertContentAt(pos ?? editor.state.selection.from, {
|
|
89
|
+
type: this.name,
|
|
90
|
+
attrs: { latex },
|
|
91
|
+
})
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
unsetBlockMath:
|
|
95
|
+
options =>
|
|
96
|
+
({ editor, tr }) => {
|
|
97
|
+
const pos = options?.pos ?? editor.state.selection.$from.pos
|
|
98
|
+
const node = editor.state.doc.nodeAt(pos)
|
|
99
|
+
|
|
100
|
+
if (!node || node.type.name !== this.name) {
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
tr.delete(pos, pos + node.nodeSize)
|
|
105
|
+
return true
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
updateBlockMath:
|
|
109
|
+
options =>
|
|
110
|
+
({ editor, tr }) => {
|
|
111
|
+
const latex = options?.latex
|
|
112
|
+
let pos = options?.pos
|
|
113
|
+
|
|
114
|
+
if (pos === undefined) {
|
|
115
|
+
pos = editor.state.selection.$from.pos
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const node = editor.state.doc.nodeAt(pos)
|
|
119
|
+
|
|
120
|
+
if (!node || node.type.name !== this.name) {
|
|
121
|
+
return false
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
tr.setNodeMarkup(pos, this.type, {
|
|
125
|
+
...node.attrs,
|
|
126
|
+
latex: latex || node.attrs.latex,
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
return true
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
parseHTML() {
|
|
135
|
+
return [
|
|
136
|
+
{
|
|
137
|
+
tag: 'div[data-type="block-math"]',
|
|
138
|
+
},
|
|
139
|
+
]
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
renderHTML({ HTMLAttributes }) {
|
|
143
|
+
return ['div', mergeAttributes(HTMLAttributes, { 'data-type': 'block-math' })]
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
addInputRules() {
|
|
147
|
+
return [
|
|
148
|
+
new InputRule({
|
|
149
|
+
find: /^\$\$\$([^$]+)\$\$\$$/,
|
|
150
|
+
handler: ({ state, range, match }) => {
|
|
151
|
+
const [, latex] = match
|
|
152
|
+
const { tr } = state
|
|
153
|
+
const start = range.from
|
|
154
|
+
const end = range.to
|
|
155
|
+
|
|
156
|
+
tr.replaceWith(start, end, this.type.create({ latex }))
|
|
157
|
+
},
|
|
158
|
+
}),
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
addNodeView() {
|
|
163
|
+
return ({ node, getPos }) => {
|
|
164
|
+
const wrapper = document.createElement('div')
|
|
165
|
+
const innerWrapper = document.createElement('div')
|
|
166
|
+
wrapper.className = 'Tiptap-mathematics-render Tiptap-mathematics-render--editable'
|
|
167
|
+
innerWrapper.className = 'block-math-inner'
|
|
168
|
+
wrapper.dataset.type = 'block-math'
|
|
169
|
+
wrapper.setAttribute('data-latex', node.attrs.latex)
|
|
170
|
+
wrapper.appendChild(innerWrapper)
|
|
171
|
+
|
|
172
|
+
function renderMath() {
|
|
173
|
+
try {
|
|
174
|
+
katex.render(node.attrs.latex, innerWrapper)
|
|
175
|
+
wrapper.classList.remove('block-math-error')
|
|
176
|
+
} catch {
|
|
177
|
+
wrapper.textContent = node.attrs.latex
|
|
178
|
+
wrapper.classList.add('block-math-error')
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const handleClick = (event: MouseEvent) => {
|
|
183
|
+
event.preventDefault()
|
|
184
|
+
event.stopPropagation()
|
|
185
|
+
const pos = getPos()
|
|
186
|
+
|
|
187
|
+
if (pos == null) {
|
|
188
|
+
return
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (this.options.onClick) {
|
|
192
|
+
this.options.onClick(node, pos)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (this.options.onClick) {
|
|
197
|
+
wrapper.addEventListener('click', handleClick)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
renderMath()
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
dom: wrapper,
|
|
204
|
+
destroy() {
|
|
205
|
+
wrapper.removeEventListener('click', handleClick)
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
})
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { InputRule, mergeAttributes, Node } from '@tiptap/core'
|
|
2
|
+
import type { Node as PMNode } from '@tiptap/pm/model'
|
|
3
|
+
import katex from 'katex'
|
|
4
|
+
|
|
5
|
+
export type InlineMathOptions = {
|
|
6
|
+
onClick?: (node: PMNode, pos: number) => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
declare module '@tiptap/core' {
|
|
10
|
+
interface Commands<ReturnType> {
|
|
11
|
+
inlineMath: {
|
|
12
|
+
/**
|
|
13
|
+
* Set inline math node with LaTeX string.
|
|
14
|
+
* @param options - Options for setting inline math.
|
|
15
|
+
* @returns ReturnType
|
|
16
|
+
*/
|
|
17
|
+
setInlineMath: (options: { latex: string; pos?: number }) => ReturnType
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Unset inline math node.
|
|
21
|
+
* @returns ReturnType
|
|
22
|
+
*/
|
|
23
|
+
unsetInlineMath: (options?: { pos?: number }) => ReturnType
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Update inline math node with optional LaTeX string.
|
|
27
|
+
* @param options - Options for updating inline math.
|
|
28
|
+
* @returns ReturnType
|
|
29
|
+
*/
|
|
30
|
+
updateInlineMath: (options?: { latex?: string; pos?: number }) => ReturnType
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* InlineMath is a Tiptap extension for rendering inline mathematical expressions using KaTeX.
|
|
37
|
+
* It allows users to insert LaTeX formatted math expressions inline within text.
|
|
38
|
+
* It supports rendering, input rules for LaTeX syntax, and click handling for interaction.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```javascript
|
|
42
|
+
* import { InlineMath } from 'your-extension-path'
|
|
43
|
+
* import { Editor } from '@tiptap/core'
|
|
44
|
+
*
|
|
45
|
+
* const editor = new Editor({
|
|
46
|
+
* extensions: [
|
|
47
|
+
* InlineMath.configure({
|
|
48
|
+
* onClick: (node, pos) => {
|
|
49
|
+
* console.log('Inline math clicked:', node.attrs.latex, 'at position:', pos)
|
|
50
|
+
* },
|
|
51
|
+
* }),
|
|
52
|
+
* ],
|
|
53
|
+
* })
|
|
54
|
+
*/
|
|
55
|
+
export const InlineMath = Node.create<InlineMathOptions>({
|
|
56
|
+
name: 'inlineMath',
|
|
57
|
+
|
|
58
|
+
group: 'inline',
|
|
59
|
+
|
|
60
|
+
inline: true,
|
|
61
|
+
|
|
62
|
+
atom: true,
|
|
63
|
+
|
|
64
|
+
addOptions() {
|
|
65
|
+
return {
|
|
66
|
+
onClick: undefined,
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
addAttributes() {
|
|
71
|
+
return {
|
|
72
|
+
latex: {
|
|
73
|
+
default: '',
|
|
74
|
+
parseHTML: element => element.getAttribute('data-latex'),
|
|
75
|
+
renderHTML: attributes => {
|
|
76
|
+
return {
|
|
77
|
+
'data-latex': attributes.latex,
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
addCommands() {
|
|
85
|
+
return {
|
|
86
|
+
setInlineMath:
|
|
87
|
+
options =>
|
|
88
|
+
({ editor, tr }) => {
|
|
89
|
+
const latex = options?.latex
|
|
90
|
+
const pos = options?.pos ?? editor.state.selection.$from.pos
|
|
91
|
+
|
|
92
|
+
if (!latex) {
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
tr.replaceWith(pos, pos, this.type.create({ latex }))
|
|
97
|
+
return true
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
unsetInlineMath:
|
|
101
|
+
options =>
|
|
102
|
+
({ editor, tr }) => {
|
|
103
|
+
const pos = options?.pos ?? editor.state.selection.$from.pos
|
|
104
|
+
const node = editor.state.doc.nodeAt(pos)
|
|
105
|
+
|
|
106
|
+
if (!node || node.type.name !== this.name) {
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
tr.delete(pos, pos + node.nodeSize)
|
|
111
|
+
return true
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
updateInlineMath:
|
|
115
|
+
options =>
|
|
116
|
+
({ editor, tr }) => {
|
|
117
|
+
const latex = options?.latex
|
|
118
|
+
let pos = options?.pos
|
|
119
|
+
|
|
120
|
+
if (pos === undefined) {
|
|
121
|
+
pos = editor.state.selection.$from.pos
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const node = editor.state.doc.nodeAt(pos)
|
|
125
|
+
|
|
126
|
+
if (!node || node.type.name !== this.name) {
|
|
127
|
+
return false
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
tr.setNodeMarkup(pos, this.type, { ...node.attrs, latex })
|
|
131
|
+
|
|
132
|
+
return true
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
parseHTML() {
|
|
138
|
+
return [
|
|
139
|
+
{
|
|
140
|
+
tag: 'span[data-type="inline-math"]',
|
|
141
|
+
},
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
renderHTML({ HTMLAttributes }) {
|
|
146
|
+
return ['span', mergeAttributes(HTMLAttributes, { 'data-type': 'inline-math' })]
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
addInputRules() {
|
|
150
|
+
return [
|
|
151
|
+
new InputRule({
|
|
152
|
+
find: /(?<!\$)\$\$([^$\n]+)\$\$(?!\$)$/,
|
|
153
|
+
handler: ({ state, range, match }) => {
|
|
154
|
+
const [, latex] = match
|
|
155
|
+
const { tr } = state
|
|
156
|
+
const start = range.from
|
|
157
|
+
const end = range.to
|
|
158
|
+
|
|
159
|
+
tr.replaceWith(start, end, this.type.create({ latex }))
|
|
160
|
+
},
|
|
161
|
+
}),
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
addNodeView() {
|
|
166
|
+
return ({ node, getPos }) => {
|
|
167
|
+
const wrapper = document.createElement('span')
|
|
168
|
+
wrapper.className = 'Tiptap-mathematics-render Tiptap-mathematics-render--editable'
|
|
169
|
+
wrapper.dataset.type = 'inline-math'
|
|
170
|
+
wrapper.setAttribute('data-latex', node.attrs.latex)
|
|
171
|
+
|
|
172
|
+
function renderMath() {
|
|
173
|
+
try {
|
|
174
|
+
katex.render(node.attrs.latex, wrapper)
|
|
175
|
+
wrapper.classList.remove('inline-math-error')
|
|
176
|
+
} catch {
|
|
177
|
+
wrapper.textContent = node.attrs.latex
|
|
178
|
+
wrapper.classList.add('inline-math-error')
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const handleClick = (event: MouseEvent) => {
|
|
183
|
+
event.preventDefault()
|
|
184
|
+
event.stopPropagation()
|
|
185
|
+
const pos = getPos()
|
|
186
|
+
|
|
187
|
+
if (pos == null) {
|
|
188
|
+
return
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (this.options.onClick) {
|
|
192
|
+
this.options.onClick(node, pos)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (this.options.onClick) {
|
|
197
|
+
wrapper.addEventListener('click', handleClick)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
renderMath()
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
dom: wrapper,
|
|
204
|
+
destroy() {
|
|
205
|
+
wrapper.removeEventListener('click', handleClick)
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
})
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Math } from './mathematics.js'
|
|
2
2
|
|
|
3
|
+
export * from './extensions/index.js'
|
|
3
4
|
export * from './mathematics.js'
|
|
4
|
-
export * from './MathematicsPlugin.js'
|
|
5
5
|
export * from './types.js'
|
|
6
6
|
|
|
7
|
-
export default
|
|
7
|
+
export default Math
|
package/src/mathematics.ts
CHANGED
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
import { Extension } from '@tiptap/core'
|
|
2
|
-
import type { EditorState } from '@tiptap/pm/state'
|
|
3
2
|
|
|
4
|
-
import {
|
|
3
|
+
import { BlockMath, InlineMath } from './extensions/index.js'
|
|
5
4
|
import type { MathematicsOptions } from './types.js'
|
|
6
5
|
|
|
7
|
-
export const
|
|
8
|
-
const $pos = state.doc.resolve(pos)
|
|
9
|
-
const isInCodeBlock = $pos.parent.type.name === 'codeBlock'
|
|
10
|
-
|
|
11
|
-
return !isInCodeBlock
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const Mathematics = Extension.create<MathematicsOptions>({
|
|
6
|
+
export const Math = Extension.create<MathematicsOptions>({
|
|
15
7
|
name: 'Mathematics',
|
|
16
8
|
|
|
17
9
|
addOptions() {
|
|
18
10
|
return {
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
inlineOptions: undefined,
|
|
12
|
+
blockOptions: undefined,
|
|
21
13
|
katexOptions: undefined,
|
|
22
|
-
shouldRender: defaultShouldRender,
|
|
23
14
|
}
|
|
24
15
|
},
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
return [
|
|
17
|
+
addExtensions() {
|
|
18
|
+
return [BlockMath.configure(this.options.blockOptions), InlineMath.configure(this.options.inlineOptions)]
|
|
28
19
|
},
|
|
29
20
|
})
|
|
30
21
|
|
|
31
|
-
export
|
|
22
|
+
export const Mathematics = Math
|
|
23
|
+
|
|
24
|
+
export default Math
|
package/src/types.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Editor } from '@tiptap/core'
|
|
2
|
-
import type { Node } from '@tiptap/pm/model'
|
|
3
|
-
import type { EditorState } from '@tiptap/pm/state'
|
|
4
2
|
import type { KatexOptions } from 'katex'
|
|
5
3
|
|
|
4
|
+
import type { BlockMathOptions, InlineMathOptions } from './extensions'
|
|
5
|
+
|
|
6
6
|
export type MathematicsOptions = {
|
|
7
|
-
|
|
7
|
+
inlineOptions?: InlineMathOptions
|
|
8
|
+
blockOptions?: BlockMathOptions
|
|
8
9
|
katexOptions?: KatexOptions
|
|
9
|
-
shouldRender: (state: EditorState, pos: number, node: Node) => boolean
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export type MathematicsOptionsWithEditor = MathematicsOptions & { editor: Editor }
|