prosemirror-math 0.0.1 → 0.2.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/README.md +12 -32
- package/dist/prosemirror-math.d.ts +65 -8
- package/dist/prosemirror-math.js +145 -44
- package/package.json +7 -5
- package/src/create-element.spec.ts +1 -1
- package/src/cursor-inside-plugin.spec.ts +8 -8
- package/src/cursor-inside-plugin.ts +35 -8
- package/src/index.ts +7 -7
- package/src/katex.ts +9 -0
- package/src/math-block-enter-rule.spec.ts +2 -2
- package/src/math-block-enter-rule.ts +6 -0
- package/src/math-block-spec.spec.ts +2 -2
- package/src/math-block-spec.ts +12 -3
- package/src/math-block-view.spec.ts +146 -26
- package/src/math-block-view.ts +25 -20
- package/src/math-inline-input-rule.spec.ts +2 -2
- package/src/math-inline-input-rule.ts +8 -0
- package/src/math-inline-spec.spec.ts +2 -2
- package/src/math-inline-spec.ts +9 -3
- package/src/math-inline-view.spec.ts +133 -19
- package/src/math-inline-view.ts +31 -21
- package/src/math-view-render.ts +75 -0
- package/src/mathjax.ts +28 -0
- package/src/temml.ts +9 -0
- package/src/testing.ts +61 -27
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Node } from 'prosemirror-model'
|
|
2
|
+
import type { Decoration } from 'prosemirror-view'
|
|
3
|
+
|
|
4
|
+
import { hasCursorInsideDecoration } from './cursor-inside-plugin.ts'
|
|
5
|
+
|
|
6
|
+
type RenderMath = (text: string, element: HTMLElement) => void
|
|
7
|
+
|
|
8
|
+
export function createMathViewRender(
|
|
9
|
+
renderMath: RenderMath,
|
|
10
|
+
source: HTMLElement,
|
|
11
|
+
display: HTMLElement,
|
|
12
|
+
inline: boolean,
|
|
13
|
+
) {
|
|
14
|
+
let prevNode: Node | undefined
|
|
15
|
+
let prevText: string | undefined
|
|
16
|
+
let prevSelected: boolean | undefined
|
|
17
|
+
|
|
18
|
+
function updateDisplay(node: Node) {
|
|
19
|
+
if (node === prevNode) return
|
|
20
|
+
prevNode = node
|
|
21
|
+
|
|
22
|
+
const text = node.textContent
|
|
23
|
+
if (text === prevText) return
|
|
24
|
+
prevText = text
|
|
25
|
+
|
|
26
|
+
renderMath(text, display)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function updateStyle(decorations: readonly Decoration[]): void {
|
|
30
|
+
const selected = hasCursorInsideDecoration(decorations)
|
|
31
|
+
if (selected === prevSelected) return
|
|
32
|
+
prevSelected = selected
|
|
33
|
+
|
|
34
|
+
// When the math node is selected, show the source code.
|
|
35
|
+
// Otherwise, show the rendered result.
|
|
36
|
+
display.style.display = selected ? 'none' : ''
|
|
37
|
+
if (!inline) {
|
|
38
|
+
source.style.display = selected ? '' : 'none'
|
|
39
|
+
} else {
|
|
40
|
+
// For inline source code, we don't use `display: none` because we need
|
|
41
|
+
// the source text rendered in the DOM to ensure the text cursor can be
|
|
42
|
+
// placed correctly.
|
|
43
|
+
Object.assign(
|
|
44
|
+
source.style,
|
|
45
|
+
selected ? visibleInlineSourceStyle : hiddenInlineSourceStyle,
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return function updateMathView(
|
|
51
|
+
node: Node,
|
|
52
|
+
decorations: readonly Decoration[],
|
|
53
|
+
): void {
|
|
54
|
+
updateDisplay(node)
|
|
55
|
+
updateStyle(decorations)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const hiddenInlineSourceStyle: Partial<CSSStyleDeclaration> = {
|
|
60
|
+
display: 'inline-flex',
|
|
61
|
+
opacity: '0',
|
|
62
|
+
pointerEvents: 'none',
|
|
63
|
+
maxWidth: '0',
|
|
64
|
+
maxHeight: '0',
|
|
65
|
+
overflow: 'hidden',
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const visibleInlineSourceStyle: Partial<CSSStyleDeclaration> = {
|
|
69
|
+
display: 'inline-flex',
|
|
70
|
+
opacity: '1',
|
|
71
|
+
pointerEvents: '',
|
|
72
|
+
maxWidth: '',
|
|
73
|
+
maxHeight: '',
|
|
74
|
+
overflow: '',
|
|
75
|
+
}
|
package/src/mathjax.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import '@mathjax/src/js/input/tex/base/BaseConfiguration.js'
|
|
2
|
+
|
|
3
|
+
import { liteAdaptor } from '@mathjax/src/js/adaptors/liteAdaptor.js'
|
|
4
|
+
import type { MmlNode } from '@mathjax/src/js/core/MmlTree/MmlNode.js'
|
|
5
|
+
import { SerializedMmlVisitor } from '@mathjax/src/js/core/MmlTree/SerializedMmlVisitor.js'
|
|
6
|
+
import { RegisterHTMLHandler } from '@mathjax/src/js/handlers/html.js'
|
|
7
|
+
import { TeX } from '@mathjax/src/js/input/tex.js'
|
|
8
|
+
import { mathjax } from '@mathjax/src/js/mathjax.js'
|
|
9
|
+
|
|
10
|
+
const adaptor = liteAdaptor()
|
|
11
|
+
RegisterHTMLHandler(adaptor)
|
|
12
|
+
|
|
13
|
+
const tex = new TeX({ packages: ['base'] })
|
|
14
|
+
const htmlDocument = mathjax.document('', { InputJax: tex })
|
|
15
|
+
const visitor = new SerializedMmlVisitor()
|
|
16
|
+
|
|
17
|
+
function texToMathML(text: string, display: boolean): string {
|
|
18
|
+
const mathML = htmlDocument.convert(text, { display }) as MmlNode
|
|
19
|
+
return visitor.visitTree(mathML)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function renderMathJaxMathBlock(text: string, element: HTMLElement) {
|
|
23
|
+
element.innerHTML = texToMathML(text, true)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function renderMathJaxMathInline(text: string, element: HTMLElement) {
|
|
27
|
+
element.innerHTML = texToMathML(text, false)
|
|
28
|
+
}
|
package/src/temml.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Temml from 'temml'
|
|
2
|
+
|
|
3
|
+
export function renderTemmlMathBlock(text: string, element: HTMLElement) {
|
|
4
|
+
Temml.render(text, element, { displayMode: true, annotate: true, throwOnError: false })
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function renderTemmlMathInline(text: string, element: HTMLElement) {
|
|
8
|
+
Temml.render(text, element, { displayMode: false, annotate: true, throwOnError: false })
|
|
9
|
+
}
|
package/src/testing.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import '
|
|
1
|
+
import 'prosemirror-view/style/prosemirror.css'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
defineBaseCommands,
|
|
@@ -15,18 +15,48 @@ import {
|
|
|
15
15
|
type PlainExtension,
|
|
16
16
|
} from '@prosekit/core'
|
|
17
17
|
import { createTestEditor, type TestEditor } from '@prosekit/core/test'
|
|
18
|
-
import { inputRules } from '@prosekit/pm/inputrules'
|
|
19
|
-
import type { Attrs } from '@prosekit/pm/model'
|
|
20
18
|
import { createEnterRuleCommand, type EnterRule } from 'prosemirror-enter-rules'
|
|
21
|
-
import
|
|
19
|
+
import { inputRules } from 'prosemirror-inputrules'
|
|
20
|
+
import type { Attrs } from 'prosemirror-model'
|
|
21
|
+
|
|
22
|
+
import { createCursorInsidePlugin } from './cursor-inside-plugin.ts'
|
|
23
|
+
import { renderKaTeXMathBlock, renderKaTeXMathInline } from './katex.ts'
|
|
24
|
+
import { mathBlockEnterRule } from './math-block-enter-rule.ts'
|
|
25
|
+
import { mathBlockSpec } from './math-block-spec.ts'
|
|
26
|
+
import { createMathBlockView } from './math-block-view.ts'
|
|
27
|
+
import { createMathInlineInputRule } from './math-inline-input-rule.ts'
|
|
28
|
+
import { mathInlineSpec } from './math-inline-spec.ts'
|
|
29
|
+
import { createMathInlineView } from './math-inline-view.ts'
|
|
30
|
+
import { renderMathJaxMathBlock, renderMathJaxMathInline } from './mathjax.ts'
|
|
31
|
+
import { renderTemmlMathBlock, renderTemmlMathInline } from './temml.ts'
|
|
32
|
+
|
|
33
|
+
type RenderMath = (text: string, element: HTMLElement) => void
|
|
34
|
+
|
|
35
|
+
interface MathRenderer {
|
|
36
|
+
renderBlock: RenderMath
|
|
37
|
+
renderInline: RenderMath
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const temmlRenderer: MathRenderer = {
|
|
41
|
+
renderBlock: renderTemmlMathBlock,
|
|
42
|
+
renderInline: renderTemmlMathInline,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const katexRenderer: MathRenderer = {
|
|
46
|
+
renderBlock: renderKaTeXMathBlock,
|
|
47
|
+
renderInline: renderKaTeXMathInline,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const mathjaxRenderer: MathRenderer = {
|
|
51
|
+
renderBlock: renderMathJaxMathBlock,
|
|
52
|
+
renderInline: renderMathJaxMathInline,
|
|
53
|
+
}
|
|
22
54
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
import { mathInlineSpec } from './math-inline-spec'
|
|
29
|
-
import { createMathInlineView } from './math-inline-view'
|
|
55
|
+
export const renderers = {
|
|
56
|
+
temml: temmlRenderer,
|
|
57
|
+
katex: katexRenderer,
|
|
58
|
+
mathjax: mathjaxRenderer,
|
|
59
|
+
} as const
|
|
30
60
|
|
|
31
61
|
type DocExtension = Extension<{ Nodes: { doc: Attrs } }>
|
|
32
62
|
|
|
@@ -101,24 +131,28 @@ function defineMathInlineSpec(): MathInlineExtension {
|
|
|
101
131
|
})
|
|
102
132
|
}
|
|
103
133
|
|
|
104
|
-
function defineMathBlockView(): Extension {
|
|
134
|
+
function defineMathBlockView(renderer: MathRenderer): Extension {
|
|
105
135
|
return defineNodeView({
|
|
106
136
|
name: 'mathBlock',
|
|
107
|
-
constructor: (node) => {
|
|
108
|
-
return createMathBlockView(
|
|
109
|
-
|
|
110
|
-
|
|
137
|
+
constructor: (node, _view, _getPos, decorations) => {
|
|
138
|
+
return createMathBlockView(
|
|
139
|
+
renderer.renderBlock,
|
|
140
|
+
node,
|
|
141
|
+
decorations,
|
|
142
|
+
)
|
|
111
143
|
},
|
|
112
144
|
})
|
|
113
145
|
}
|
|
114
146
|
|
|
115
|
-
function defineMathInlineView(): Extension {
|
|
147
|
+
function defineMathInlineView(renderer: MathRenderer): Extension {
|
|
116
148
|
return defineNodeView({
|
|
117
149
|
name: 'mathInline',
|
|
118
|
-
constructor: (node) => {
|
|
119
|
-
return createMathInlineView(
|
|
120
|
-
|
|
121
|
-
|
|
150
|
+
constructor: (node, _view, _getPos, decorations) => {
|
|
151
|
+
return createMathInlineView(
|
|
152
|
+
renderer.renderInline,
|
|
153
|
+
node,
|
|
154
|
+
decorations,
|
|
155
|
+
)
|
|
122
156
|
},
|
|
123
157
|
})
|
|
124
158
|
}
|
|
@@ -128,7 +162,7 @@ function defineEnterRule(rules: EnterRule[]): PlainExtension {
|
|
|
128
162
|
return defineKeymap({ Enter: command })
|
|
129
163
|
}
|
|
130
164
|
|
|
131
|
-
function defineTestExtension() {
|
|
165
|
+
function defineTestExtension(renderer: MathRenderer) {
|
|
132
166
|
return union(
|
|
133
167
|
defineDoc(),
|
|
134
168
|
defineText(),
|
|
@@ -136,11 +170,11 @@ function defineTestExtension() {
|
|
|
136
170
|
defineCodeBlock(),
|
|
137
171
|
defineMathBlockSpec(),
|
|
138
172
|
defineMathInlineSpec(),
|
|
139
|
-
defineMathBlockView(),
|
|
140
|
-
defineMathInlineView(),
|
|
173
|
+
defineMathBlockView(renderer),
|
|
174
|
+
defineMathInlineView(renderer),
|
|
141
175
|
defineEnterRule([mathBlockEnterRule]),
|
|
142
176
|
definePlugin(inputRules({ rules: [createMathInlineInputRule('mathInline')] })),
|
|
143
|
-
definePlugin(createCursorInsidePlugin(
|
|
177
|
+
definePlugin(createCursorInsidePlugin()),
|
|
144
178
|
defineBaseCommands(),
|
|
145
179
|
defineBaseKeymap(),
|
|
146
180
|
)
|
|
@@ -164,8 +198,8 @@ function setupTestFromExtension<E extends Extension>(
|
|
|
164
198
|
return { editor, n }
|
|
165
199
|
}
|
|
166
200
|
|
|
167
|
-
export function setupTest() {
|
|
168
|
-
const { editor, n } = setupTestFromExtension(defineTestExtension())
|
|
201
|
+
export function setupTest(renderer: MathRenderer = temmlRenderer) {
|
|
202
|
+
const { editor, n } = setupTestFromExtension(defineTestExtension(renderer))
|
|
169
203
|
|
|
170
204
|
return {
|
|
171
205
|
editor,
|