prosemirror-math 0.1.0 → 0.2.2

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 ocavue
3
+ Copyright (c) 2026 ocavue
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # prosemirror-math
2
2
 
3
- Math editing extensions for [ProseMirror](https://prosemirror.net/). Provides node specs, node views, input rules, and plugins for inline and block math.
3
+ [![NPM version](https://img.shields.io/npm/v/prosemirror-math?color=a1b858&label=)](https://www.npmjs.com/package/prosemirror-math)
4
+
5
+ Rendering math expressions in [ProseMirror](https://prosemirror.net/).
4
6
 
5
7
  ## Installation
6
8
 
@@ -23,7 +25,12 @@ import { Schema } from 'prosemirror-model'
23
25
  const schema = new Schema({
24
26
  nodes: {
25
27
  doc: { content: 'block+' },
26
- paragraph: { content: 'inline*', group: 'block', parseDOM: [{ tag: 'p' }], toDOM: () => ['p', 0] },
28
+ paragraph: {
29
+ content: 'inline*',
30
+ group: 'block',
31
+ parseDOM: [{ tag: 'p' }],
32
+ toDOM: () => ['p', 0],
33
+ },
27
34
  text: { group: 'inline' },
28
35
  mathBlock: { ...mathBlockSpec },
29
36
  mathInline: { ...mathInlineSpec },
@@ -43,12 +50,22 @@ import Temml from 'temml'
43
50
  const view = new EditorView(document.body, {
44
51
  state,
45
52
  nodeViews: {
46
- mathBlock: (node, view, getPos, decorations) => createMathBlockView((text, element) => {
47
- Temml.render(text, element, { displayMode: true })
48
- }, node, decorations),
49
- mathInline: (node, view, getPos, decorations) => createMathInlineView((text, element) => {
50
- Temml.render(text, element, { displayMode: false })
51
- }, node, decorations),
53
+ mathBlock: (node, view, getPos, decorations) =>
54
+ createMathBlockView(
55
+ (text, element) => {
56
+ Temml.render(text, element, { displayMode: true })
57
+ },
58
+ node,
59
+ decorations,
60
+ ),
61
+ mathInline: (node, view, getPos, decorations) =>
62
+ createMathInlineView(
63
+ (text, element) => {
64
+ Temml.render(text, element, { displayMode: false })
65
+ },
66
+ node,
67
+ decorations,
68
+ ),
52
69
  },
53
70
  })
54
71
  ```
@@ -91,29 +108,7 @@ const plugin = createCursorInsidePlugin()
91
108
 
92
109
  ## API
93
110
 
94
- ### Node specs
95
-
96
- - **`mathBlockSpec`** — NodeSpec for block math (`div.prosekit-math-block > pre > code`)
97
- - **`mathInlineSpec`** — NodeSpec for inline math (`span.prosekit-math-inline > code`)
98
-
99
- ### Node views
100
-
101
- - **`createMathBlockView(renderMath, node, decorations)`** — Creates a block math NodeView
102
- - **`createMathInlineView(renderMath, node, decorations)`** — Creates an inline math NodeView
103
-
104
- The `renderMath` callback receives `(text: string, element: HTMLElement)` and should render the math into the element.
105
-
106
- ### Input rules
107
-
108
- - **`createMathInlineInputRule(nodeType)`** — Creates an InputRule for inline math
109
-
110
- ### Enter rules
111
-
112
- - **`mathBlockEnterRule`** — EnterRule for converting `$$` into a math block
113
-
114
- ### Plugins
115
-
116
- - **`createCursorInsidePlugin()`** — Plugin that decorates math nodes containing the cursor
111
+ [API Reference](https://npmx.dev/package-docs/prosemirror-math)
117
112
 
118
113
  ## License
119
114
 
@@ -17,9 +17,20 @@ import { Node, NodeSpec } from "prosemirror-model";
17
17
  declare function createCursorInsidePlugin(): Plugin;
18
18
  //#endregion
19
19
  //#region src/math-block-enter-rule.d.ts
20
+ /**
21
+ * An {@link EnterRule} that converts a textblock node that only contains `$$` into a math
22
+ * block node when Enter is pressed.
23
+ *
24
+ * @public
25
+ */
20
26
  declare const mathBlockEnterRule: EnterRule;
21
27
  //#endregion
22
28
  //#region src/math-block-spec.d.ts
29
+ /**
30
+ * A {@link NodeSpec} for a block-level math node.
31
+ *
32
+ * @public
33
+ */
23
34
  declare const mathBlockSpec: NodeSpec;
24
35
  //#endregion
25
36
  //#region src/math-block-view.d.ts
@@ -30,12 +41,37 @@ declare const mathBlockSpec: NodeSpec;
30
41
  * @param element - A `<div>` element to render the math block.
31
42
  */
32
43
  type RenderMathBlock = (text: string, element: HTMLElement) => void;
44
+ /**
45
+ * Creates a {@link NodeView} for a block-level math node. The view will show a
46
+ * source editor or a rendered display area based on the text cursor position.
47
+ *
48
+ * @param renderMathBlock - A function that renders math text (e.g. TeX) into
49
+ * the display element. You can use libraries like
50
+ * [Temml](https://temml.org/) or [KaTeX](https://katex.org/).
51
+ * @param node - The ProseMirror node to render.
52
+ * @param decorations - The decorations applied to the node.
53
+ *
54
+ * @public
55
+ */
33
56
  declare function createMathBlockView(renderMathBlock: RenderMathBlock, node: Node, decorations: readonly Decoration[]): NodeView;
34
57
  //#endregion
35
58
  //#region src/math-inline-input-rule.d.ts
59
+ /**
60
+ * Creates a ProseMirror {@link InputRule} that converts text wrapped in `$` or
61
+ * `$$` (e.g. `$x^2$`) into an inline math node.
62
+ *
63
+ * @param nodeType - The name of the inline math node type in your schema.
64
+ *
65
+ * @public
66
+ */
36
67
  declare function createMathInlineInputRule(nodeType: string): InputRule;
37
68
  //#endregion
38
69
  //#region src/math-inline-spec.d.ts
70
+ /**
71
+ * A {@link NodeSpec} for an inline math node.
72
+ *
73
+ * @public
74
+ */
39
75
  declare const mathInlineSpec: NodeSpec;
40
76
  //#endregion
41
77
  //#region src/math-inline-view.d.ts
@@ -46,6 +82,19 @@ declare const mathInlineSpec: NodeSpec;
46
82
  * @param element - A `<span>` element to render the math inline.
47
83
  */
48
84
  type RenderMathInline = (text: string, element: HTMLElement) => void;
85
+ /**
86
+ * Creates a {@link NodeView} for an inline math node. The view will show a
87
+ * source editor or a rendered display area based on the text cursor position.
88
+ *
89
+ * @param renderMathInline - A function that renders math text (e.g. TeX) into
90
+ * the display element. You can use libraries like [Temml](https://temml.org/)
91
+ * or [KaTeX](https://katex.org/).
92
+ * @param node - The ProseMirror node to render.
93
+ * @param decorations - The decorations applied to the node.
94
+ *
95
+ * @public
96
+ */
49
97
  declare function createMathInlineView(renderMathInline: RenderMathInline, node: Node, decorations: readonly Decoration[]): NodeView;
50
98
  //#endregion
51
- export { type RenderMathBlock, type RenderMathInline, createCursorInsidePlugin, createMathBlockView, createMathInlineInputRule, createMathInlineView, mathBlockEnterRule, mathBlockSpec, mathInlineSpec };
99
+ export { type RenderMathBlock, type RenderMathInline, createCursorInsidePlugin, createMathBlockView, createMathInlineInputRule, createMathInlineView, mathBlockEnterRule, mathBlockSpec, mathInlineSpec };
100
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/cursor-inside-plugin.ts","../src/math-block-enter-rule.ts","../src/math-block-spec.ts","../src/math-block-view.ts","../src/math-inline-input-rule.ts","../src/math-inline-spec.ts","../src/math-inline-view.ts"],"mappings":";;;;;;;;AA2CA;;;;;;;;iBAAgB,wBAAA,CAAA,GAA4B,MAAA;;;;;;;;AAA5C;cC9Ba,kBAAA,EAAoB,SAAA;;;;;;;;cCNpB,aAAA,EAAe,QAAA;;;;;;;;AFoC5B;KG/BY,eAAA,IAAmB,IAAA,UAAc,OAAA,EAAS,WAAA;;;;;;;AFCtD;;;;;;iBEagB,mBAAA,CACd,eAAA,EAAiB,eAAA,EACjB,IAAA,EAAM,IAAA,EACN,WAAA,WAAsB,UAAA,KACrB,QAAA;;;;;;;;AHaH;;;iBIfgB,yBAAA,CAA0B,QAAA,WAAmB,SAAA;;;;;;;;cCrBhD,cAAA,EAAgB,QAAA;;;;;;;;ALoC7B;KM/BY,gBAAA,IAAoB,IAAA,UAAc,OAAA,EAAS,WAAA;;;;;;;ALCvD;;;;;;iBKagB,oBAAA,CACd,gBAAA,EAAkB,gBAAA,EAClB,IAAA,EAAM,IAAA,EACN,WAAA,WAAsB,UAAA,KACrB,QAAA"}
@@ -49,6 +49,12 @@ function createCursorInsidePlugin() {
49
49
  //#endregion
50
50
  //#region src/math-block-enter-rule.ts
51
51
  const MATH_BLOCK_ENTER_REGEXP = /^\$\$$/;
52
+ /**
53
+ * An {@link EnterRule} that converts a textblock node that only contains `$$` into a math
54
+ * block node when Enter is pressed.
55
+ *
56
+ * @public
57
+ */
52
58
  const mathBlockEnterRule = /* @__PURE__ */ createTextBlockEnterRule({
53
59
  regex: MATH_BLOCK_ENTER_REGEXP,
54
60
  type: "mathBlock"
@@ -56,6 +62,11 @@ const mathBlockEnterRule = /* @__PURE__ */ createTextBlockEnterRule({
56
62
 
57
63
  //#endregion
58
64
  //#region src/math-block-spec.ts
65
+ /**
66
+ * A {@link NodeSpec} for a block-level math node.
67
+ *
68
+ * @public
69
+ */
59
70
  const mathBlockSpec = {
60
71
  atom: false,
61
72
  group: "block math",
@@ -64,12 +75,12 @@ const mathBlockSpec = {
64
75
  toDOM() {
65
76
  return [
66
77
  "div",
67
- { class: "prosekit-math-block" },
78
+ { class: "prosemirror-math-block" },
68
79
  ["pre", ["code", 0]]
69
80
  ];
70
81
  },
71
82
  parseDOM: [{
72
- tag: "div.prosekit-math-block",
83
+ tag: "div.prosemirror-math-block",
73
84
  contentElement: "code"
74
85
  }]
75
86
  };
@@ -85,7 +96,7 @@ function createElement(tag, className, ...children) {
85
96
 
86
97
  //#endregion
87
98
  //#region src/math-view-render.ts
88
- function createMathViewRender(renderMath, source, display) {
99
+ function createMathViewRender(renderMath, source, display, inline) {
89
100
  let prevNode;
90
101
  let prevText;
91
102
  let prevSelected;
@@ -101,23 +112,52 @@ function createMathViewRender(renderMath, source, display) {
101
112
  const selected = hasCursorInsideDecoration(decorations);
102
113
  if (selected === prevSelected) return;
103
114
  prevSelected = selected;
104
- source.style.display = selected ? "" : "none";
105
115
  display.style.display = selected ? "none" : "";
116
+ if (!inline) source.style.display = selected ? "" : "none";
117
+ else Object.assign(source.style, selected ? visibleInlineSourceStyle : hiddenInlineSourceStyle);
106
118
  }
107
119
  return function updateMathView(node, decorations) {
108
120
  updateDisplay(node);
109
121
  updateStyle(decorations);
110
122
  };
111
123
  }
124
+ const hiddenInlineSourceStyle = {
125
+ display: "inline-flex",
126
+ opacity: "0",
127
+ pointerEvents: "none",
128
+ maxWidth: "0",
129
+ maxHeight: "0",
130
+ overflow: "hidden"
131
+ };
132
+ const visibleInlineSourceStyle = {
133
+ display: "inline-flex",
134
+ opacity: "1",
135
+ pointerEvents: "",
136
+ maxWidth: "",
137
+ maxHeight: "",
138
+ overflow: ""
139
+ };
112
140
 
113
141
  //#endregion
114
142
  //#region src/math-block-view.ts
143
+ /**
144
+ * Creates a {@link NodeView} for a block-level math node. The view will show a
145
+ * source editor or a rendered display area based on the text cursor position.
146
+ *
147
+ * @param renderMathBlock - A function that renders math text (e.g. TeX) into
148
+ * the display element. You can use libraries like
149
+ * [Temml](https://temml.org/) or [KaTeX](https://katex.org/).
150
+ * @param node - The ProseMirror node to render.
151
+ * @param decorations - The decorations applied to the node.
152
+ *
153
+ * @public
154
+ */
115
155
  function createMathBlockView(renderMathBlock, node, decorations) {
116
156
  const code = createElement("code");
117
- const source = createElement("pre", "prosekit-math-source", code);
118
- const display = createElement("div", "prosekit-math-display");
119
- const dom = createElement("div", "prosekit-math-block", source, display);
120
- const render = createMathViewRender(renderMathBlock, source, display);
157
+ const source = createElement("pre", "prosemirror-math-source", code);
158
+ const display = createElement("div", "prosemirror-math-display");
159
+ const dom = createElement("div", "prosemirror-math-block", source, display);
160
+ const render = createMathViewRender(renderMathBlock, source, display, false);
121
161
  render(node, decorations);
122
162
  return {
123
163
  dom,
@@ -132,6 +172,14 @@ function createMathBlockView(renderMathBlock, node, decorations) {
132
172
  //#endregion
133
173
  //#region src/math-inline-input-rule.ts
134
174
  const MATH_INPUT_REGEXP = (supportsRegexLookbehind() ? "(?<!\\$)" : "") + "(\\$\\$?)([^\\s$](?:[^$]*[^\\s$])?)\\1$";
175
+ /**
176
+ * Creates a ProseMirror {@link InputRule} that converts text wrapped in `$` or
177
+ * `$$` (e.g. `$x^2$`) into an inline math node.
178
+ *
179
+ * @param nodeType - The name of the inline math node type in your schema.
180
+ *
181
+ * @public
182
+ */
135
183
  function createMathInlineInputRule(nodeType) {
136
184
  return new InputRule(new RegExp(MATH_INPUT_REGEXP), (state, match, start, end) => {
137
185
  const { tr, schema } = state;
@@ -147,6 +195,11 @@ function createMathInlineInputRule(nodeType) {
147
195
 
148
196
  //#endregion
149
197
  //#region src/math-inline-spec.ts
198
+ /**
199
+ * A {@link NodeSpec} for an inline math node.
200
+ *
201
+ * @public
202
+ */
150
203
  const mathInlineSpec = {
151
204
  atom: false,
152
205
  inline: true,
@@ -157,27 +210,40 @@ const mathInlineSpec = {
157
210
  toDOM() {
158
211
  return [
159
212
  "span",
160
- { class: "prosekit-math-inline" },
213
+ { class: "prosemirror-math-inline" },
161
214
  ["code", 0]
162
215
  ];
163
216
  },
164
217
  parseDOM: [{
165
- tag: "span.prosekit-math-inline",
218
+ tag: "span.prosemirror-math-inline",
166
219
  contentElement: "code"
167
220
  }]
168
221
  };
169
222
 
170
223
  //#endregion
171
224
  //#region src/math-inline-view.ts
225
+ /**
226
+ * Creates a {@link NodeView} for an inline math node. The view will show a
227
+ * source editor or a rendered display area based on the text cursor position.
228
+ *
229
+ * @param renderMathInline - A function that renders math text (e.g. TeX) into
230
+ * the display element. You can use libraries like [Temml](https://temml.org/)
231
+ * or [KaTeX](https://katex.org/).
232
+ * @param node - The ProseMirror node to render.
233
+ * @param decorations - The decorations applied to the node.
234
+ *
235
+ * @public
236
+ */
172
237
  function createMathInlineView(renderMathInline, node, decorations) {
173
- const source = createElement("code", "prosekit-math-source");
174
- const display = createElement("span", "prosekit-math-display");
175
- const dom = createElement("span", "prosekit-math-inline", source, display);
176
- const render = createMathViewRender(renderMathInline, source, display);
238
+ const code = createElement("code");
239
+ const source = createElement("span", "prosemirror-math-source", code);
240
+ const display = createElement("span", "prosemirror-math-display");
241
+ const dom = createElement("span", "prosemirror-math-inline", source, display);
242
+ const render = createMathViewRender(renderMathInline, source, display, true);
177
243
  render(node, decorations);
178
244
  return {
179
245
  dom,
180
- contentDOM: source,
246
+ contentDOM: code,
181
247
  update: (node, decorations) => {
182
248
  render(node, decorations);
183
249
  return true;
@@ -186,4 +252,5 @@ function createMathInlineView(renderMathInline, node, decorations) {
186
252
  }
187
253
 
188
254
  //#endregion
189
- export { createCursorInsidePlugin, createMathBlockView, createMathInlineInputRule, createMathInlineView, mathBlockEnterRule, mathBlockSpec, mathInlineSpec };
255
+ export { createCursorInsidePlugin, createMathBlockView, createMathInlineInputRule, createMathInlineView, mathBlockEnterRule, mathBlockSpec, mathInlineSpec };
256
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/cursor-inside-plugin.ts","../src/math-block-enter-rule.ts","../src/math-block-spec.ts","../src/create-element.ts","../src/math-view-render.ts","../src/math-block-view.ts","../src/math-inline-input-rule.ts","../src/math-inline-spec.ts","../src/math-inline-view.ts"],"sourcesContent":["import { Plugin, PluginKey, type EditorState } from 'prosemirror-state'\nimport { Decoration, DecorationSet } from 'prosemirror-view'\n\nconst DECORATION_SPEC = 'MATH_CURSOR_INSIDE'\n\nfunction createCursorInsideDecoration(\n state: EditorState,\n): DecorationSet | undefined {\n const { $head } = state.selection\n const node = $head.parent\n\n if (!node.type.isInGroup('math')) return\n\n const before = $head.before()\n const deco = Decoration.node(\n before,\n before + node.nodeSize,\n { class: 'prosemirror-math-head-inside' },\n DECORATION_SPEC,\n )\n return DecorationSet.create(state.doc, [deco])\n}\n\n/**\n * @internal\n */\nexport function hasCursorInsideDecoration(\n decorations: readonly Decoration[],\n): boolean {\n return decorations.some((deco) => deco.spec === DECORATION_SPEC)\n}\n\ntype PluginState = DecorationSet | undefined\n\n/**\n * Creates a plugin that adds a `prosemirror-math-head-inside` CSS class to math\n * nodes when the text selection head is inside them. This is useful for styling\n * math nodes differently while they are being edited.\n *\n * The plugin automatically detects nodes in the `math` group.\n *\n * @public\n */\nexport function createCursorInsidePlugin(): Plugin {\n const key = new PluginKey<PluginState>('prosemirror-math-cursor-inside')\n return new Plugin<PluginState>({\n key,\n state: {\n init(): PluginState {\n return undefined\n },\n apply(tr, oldValue, oldState, newState): PluginState {\n if (\n oldState.selection.head === newState.selection.head &&\n !tr.docChanged\n ) {\n return oldValue\n }\n return createCursorInsideDecoration(newState)\n },\n },\n props: {\n decorations(state: EditorState): PluginState | undefined {\n return key.getState(state)\n },\n },\n })\n}\n","import {\n createTextBlockEnterRule,\n type EnterRule,\n} from 'prosemirror-enter-rules'\n\nexport const MATH_BLOCK_ENTER_REGEXP: RegExp = /^\\$\\$$/\n\n/**\n * An {@link EnterRule} that converts a textblock node that only contains `$$` into a math\n * block node when Enter is pressed.\n *\n * @public\n */\nexport const mathBlockEnterRule: EnterRule =\n /* @__PURE__ */ createTextBlockEnterRule({\n regex: MATH_BLOCK_ENTER_REGEXP,\n type: 'mathBlock',\n })\n","import type { NodeSpec } from 'prosemirror-model'\n\n/**\n * A {@link NodeSpec} for a block-level math node.\n *\n * @public\n */\nexport const mathBlockSpec: NodeSpec = {\n atom: false,\n group: 'block math',\n content: 'text*',\n code: true,\n toDOM() {\n return [\n 'div',\n {\n class: 'prosemirror-math-block',\n },\n ['pre', ['code', 0]],\n ]\n },\n parseDOM: [\n {\n tag: 'div.prosemirror-math-block',\n\n // skip the `<pre>` wrapper so that the node `codeBlock` won't match the content.\n // TODO: add test to verify it\n contentElement: 'code',\n },\n ],\n}\n","export function createElement<Tag extends keyof HTMLElementTagNameMap>(\n tag: Tag,\n className?: string,\n ...children: HTMLElement[]\n): HTMLElementTagNameMap[Tag] {\n const element: HTMLElementTagNameMap[Tag] = document.createElement(tag)\n if (className) {\n element.className = className\n }\n if (children.length > 0) {\n element.append(...children)\n }\n return element\n}\n","import type { Node } from 'prosemirror-model'\nimport type { Decoration } from 'prosemirror-view'\n\nimport { hasCursorInsideDecoration } from './cursor-inside-plugin.ts'\n\ntype RenderMath = (text: string, element: HTMLElement) => void\n\nexport function createMathViewRender(\n renderMath: RenderMath,\n source: HTMLElement,\n display: HTMLElement,\n inline: boolean,\n) {\n let prevNode: Node | undefined\n let prevText: string | undefined\n let prevSelected: boolean | undefined\n\n function updateDisplay(node: Node) {\n if (node === prevNode) return\n prevNode = node\n\n const text = node.textContent\n if (text === prevText) return\n prevText = text\n\n renderMath(text, display)\n }\n\n function updateStyle(decorations: readonly Decoration[]): void {\n const selected = hasCursorInsideDecoration(decorations)\n if (selected === prevSelected) return\n prevSelected = selected\n\n // When the math node is selected, show the source code.\n // Otherwise, show the rendered result.\n display.style.display = selected ? 'none' : ''\n if (!inline) {\n source.style.display = selected ? '' : 'none'\n } else {\n // For inline source code, we don't use `display: none` because we need\n // the source text rendered in the DOM to ensure the text cursor can be\n // placed correctly.\n Object.assign(\n source.style,\n selected ? visibleInlineSourceStyle : hiddenInlineSourceStyle,\n )\n }\n }\n\n return function updateMathView(\n node: Node,\n decorations: readonly Decoration[],\n ): void {\n updateDisplay(node)\n updateStyle(decorations)\n }\n}\n\nconst hiddenInlineSourceStyle: Partial<CSSStyleDeclaration> = {\n display: 'inline-flex',\n opacity: '0',\n pointerEvents: 'none',\n maxWidth: '0',\n maxHeight: '0',\n overflow: 'hidden',\n}\n\nconst visibleInlineSourceStyle: Partial<CSSStyleDeclaration> = {\n display: 'inline-flex',\n opacity: '1',\n pointerEvents: '',\n maxWidth: '',\n maxHeight: '',\n overflow: '',\n}\n","import type { Node as ProseMirrorNode } from 'prosemirror-model'\nimport type { Decoration, NodeView } from 'prosemirror-view'\n\nimport { createElement } from './create-element.ts'\nimport { createMathViewRender } from './math-view-render.ts'\n\n/**\n * The function to render a math block.\n *\n * @param text - The text of the math block. For example, a TeX expression.\n * @param element - A `<div>` element to render the math block.\n */\nexport type RenderMathBlock = (text: string, element: HTMLElement) => void\n\n/**\n * Creates a {@link NodeView} for a block-level math node. The view will show a\n * source editor or a rendered display area based on the text cursor position.\n *\n * @param renderMathBlock - A function that renders math text (e.g. TeX) into\n * the display element. You can use libraries like\n * [Temml](https://temml.org/) or [KaTeX](https://katex.org/).\n * @param node - The ProseMirror node to render.\n * @param decorations - The decorations applied to the node.\n *\n * @public\n */\nexport function createMathBlockView(\n renderMathBlock: RenderMathBlock,\n node: ProseMirrorNode,\n decorations: readonly Decoration[],\n): NodeView {\n const code = createElement('code')\n const source = createElement('pre', 'prosemirror-math-source', code)\n const display = createElement('div', 'prosemirror-math-display')\n const dom = createElement('div', 'prosemirror-math-block', source, display)\n\n const render = createMathViewRender(renderMathBlock, source, display, false)\n\n render(node, decorations)\n\n return {\n dom,\n contentDOM: code,\n update: (node, decorations) => {\n render(node, decorations)\n return true\n },\n }\n}\n","/* eslint-disable unicorn/prefer-string-raw -- Don't use String.raw here for better bundler minification */\n\nimport { supportsRegexLookbehind } from '@ocavue/utils'\nimport { InputRule } from 'prosemirror-inputrules'\n\n// Matches text wrapped in `$` or `$$`, e.g. `$x^2$` or `$$x^2$$`.\nexport const MATH_INPUT_REGEXP: string =\n // Don't allow $ before the opening delimiter\n (supportsRegexLookbehind() ? '(?<!\\\\$)' : '') +\n // capture group 1: opening delimiter (`$` or `$$`)\n '(\\\\$\\\\$?)' +\n // capture group 2: the math content\n // - a single non-whitespace, non-`$` character\n // - optionally followed by any non-`$` characters and a final non-whitespace, non-`$` character\n '([^\\\\s$](?:[^$]*[^\\\\s$])?)' +\n // backreference: closing delimiter must match the opening\n '\\\\1' +\n // end of input (required by ProseMirror InputRule)\n '$'\n\n/**\n * Creates a ProseMirror {@link InputRule} that converts text wrapped in `$` or\n * `$$` (e.g. `$x^2$`) into an inline math node.\n *\n * @param nodeType - The name of the inline math node type in your schema.\n *\n * @public\n */\nexport function createMathInlineInputRule(nodeType: string): InputRule {\n return new InputRule(\n new RegExp(MATH_INPUT_REGEXP),\n (state, match, start, end) => {\n const { tr, schema } = state\n const mathText = match[2]\n if (!mathText) return null\n\n const type = schema.nodes[nodeType]\n if (!type) return null\n\n const node = type.create(null, schema.text(mathText))\n tr.replaceWith(start, end, node)\n return tr\n },\n )\n}\n","import type { NodeSpec } from 'prosemirror-model'\n\n/**\n * A {@link NodeSpec} for an inline math node.\n *\n * @public\n */\nexport const mathInlineSpec: NodeSpec = {\n atom: false,\n inline: true,\n group: 'inline math',\n content: 'text*',\n selectable: false,\n code: true,\n toDOM() {\n return [\n 'span',\n {\n class: 'prosemirror-math-inline',\n },\n ['code', 0],\n ]\n },\n parseDOM: [\n {\n tag: 'span.prosemirror-math-inline',\n contentElement: 'code',\n },\n ],\n}\n","import type { Node as ProseMirrorNode } from 'prosemirror-model'\nimport type { Decoration, NodeView } from 'prosemirror-view'\n\nimport { createElement } from './create-element.ts'\nimport { createMathViewRender } from './math-view-render.ts'\n\n/**\n * The function to render a math inline.\n *\n * @param text - The text of the math inline. For example, a TeX expression.\n * @param element - A `<span>` element to render the math inline.\n */\nexport type RenderMathInline = (text: string, element: HTMLElement) => void\n\n/**\n * Creates a {@link NodeView} for an inline math node. The view will show a\n * source editor or a rendered display area based on the text cursor position.\n *\n * @param renderMathInline - A function that renders math text (e.g. TeX) into\n * the display element. You can use libraries like [Temml](https://temml.org/)\n * or [KaTeX](https://katex.org/).\n * @param node - The ProseMirror node to render.\n * @param decorations - The decorations applied to the node.\n *\n * @public\n */\nexport function createMathInlineView(\n renderMathInline: RenderMathInline,\n node: ProseMirrorNode,\n decorations: readonly Decoration[],\n): NodeView {\n const code = createElement('code')\n const source = createElement('span', 'prosemirror-math-source', code)\n const display = createElement('span', 'prosemirror-math-display')\n const dom = createElement('span', 'prosemirror-math-inline', source, display)\n\n const render = createMathViewRender(renderMathInline, source, display, true)\n\n render(node, decorations)\n\n return {\n dom,\n contentDOM: code,\n update: (node, decorations) => {\n render(node, decorations)\n return true\n },\n }\n}\n"],"mappings":";;;;;;;AAGA,MAAM,kBAAkB;AAExB,SAAS,6BACP,OAC2B;CAC3B,MAAM,EAAE,UAAU,MAAM;CACxB,MAAM,OAAO,MAAM;AAEnB,KAAI,CAAC,KAAK,KAAK,UAAU,OAAO,CAAE;CAElC,MAAM,SAAS,MAAM,QAAQ;CAC7B,MAAM,OAAO,WAAW,KACtB,QACA,SAAS,KAAK,UACd,EAAE,OAAO,gCAAgC,EACzC,gBACD;AACD,QAAO,cAAc,OAAO,MAAM,KAAK,CAAC,KAAK,CAAC;;;;;AAMhD,SAAgB,0BACd,aACS;AACT,QAAO,YAAY,MAAM,SAAS,KAAK,SAAS,gBAAgB;;;;;;;;;;;AAclE,SAAgB,2BAAmC;CACjD,MAAM,MAAM,IAAI,UAAuB,iCAAiC;AACxE,QAAO,IAAI,OAAoB;EAC7B;EACA,OAAO;GACL,OAAoB;GAGpB,MAAM,IAAI,UAAU,UAAU,UAAuB;AACnD,QACE,SAAS,UAAU,SAAS,SAAS,UAAU,QAC/C,CAAC,GAAG,WAEJ,QAAO;AAET,WAAO,6BAA6B,SAAS;;GAEhD;EACD,OAAO,EACL,YAAY,OAA6C;AACvD,UAAO,IAAI,SAAS,MAAM;KAE7B;EACF,CAAC;;;;;AC7DJ,MAAa,0BAAkC;;;;;;;AAQ/C,MAAa,qBACK,yCAAyB;CACvC,OAAO;CACP,MAAM;CACP,CAAC;;;;;;;;;ACVJ,MAAa,gBAA0B;CACrC,MAAM;CACN,OAAO;CACP,SAAS;CACT,MAAM;CACN,QAAQ;AACN,SAAO;GACL;GACA,EACE,OAAO,0BACR;GACD,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;GACrB;;CAEH,UAAU,CACR;EACE,KAAK;EAIL,gBAAgB;EACjB,CACF;CACF;;;;AC9BD,SAAgB,cACd,KACA,WACA,GAAG,UACyB;CAC5B,MAAM,UAAsC,SAAS,cAAc,IAAI;AACvE,KAAI,UACF,SAAQ,YAAY;AAEtB,KAAI,SAAS,SAAS,EACpB,SAAQ,OAAO,GAAG,SAAS;AAE7B,QAAO;;;;;ACLT,SAAgB,qBACd,YACA,QACA,SACA,QACA;CACA,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,SAAS,cAAc,MAAY;AACjC,MAAI,SAAS,SAAU;AACvB,aAAW;EAEX,MAAM,OAAO,KAAK;AAClB,MAAI,SAAS,SAAU;AACvB,aAAW;AAEX,aAAW,MAAM,QAAQ;;CAG3B,SAAS,YAAY,aAA0C;EAC7D,MAAM,WAAW,0BAA0B,YAAY;AACvD,MAAI,aAAa,aAAc;AAC/B,iBAAe;AAIf,UAAQ,MAAM,UAAU,WAAW,SAAS;AAC5C,MAAI,CAAC,OACH,QAAO,MAAM,UAAU,WAAW,KAAK;MAKvC,QAAO,OACL,OAAO,OACP,WAAW,2BAA2B,wBACvC;;AAIL,QAAO,SAAS,eACd,MACA,aACM;AACN,gBAAc,KAAK;AACnB,cAAY,YAAY;;;AAI5B,MAAM,0BAAwD;CAC5D,SAAS;CACT,SAAS;CACT,eAAe;CACf,UAAU;CACV,WAAW;CACX,UAAU;CACX;AAED,MAAM,2BAAyD;CAC7D,SAAS;CACT,SAAS;CACT,eAAe;CACf,UAAU;CACV,WAAW;CACX,UAAU;CACX;;;;;;;;;;;;;;;;AChDD,SAAgB,oBACd,iBACA,MACA,aACU;CACV,MAAM,OAAO,cAAc,OAAO;CAClC,MAAM,SAAS,cAAc,OAAO,2BAA2B,KAAK;CACpE,MAAM,UAAU,cAAc,OAAO,2BAA2B;CAChE,MAAM,MAAM,cAAc,OAAO,0BAA0B,QAAQ,QAAQ;CAE3E,MAAM,SAAS,qBAAqB,iBAAiB,QAAQ,SAAS,MAAM;AAE5E,QAAO,MAAM,YAAY;AAEzB,QAAO;EACL;EACA,YAAY;EACZ,SAAS,MAAM,gBAAgB;AAC7B,UAAO,MAAM,YAAY;AACzB,UAAO;;EAEV;;;;;ACzCH,MAAa,qBAEV,yBAAyB,GAAG,aAAa,MAE1C;;;;;;;;;AAkBF,SAAgB,0BAA0B,UAA6B;AACrE,QAAO,IAAI,UACT,IAAI,OAAO,kBAAkB,GAC5B,OAAO,OAAO,OAAO,QAAQ;EAC5B,MAAM,EAAE,IAAI,WAAW;EACvB,MAAM,WAAW,MAAM;AACvB,MAAI,CAAC,SAAU,QAAO;EAEtB,MAAM,OAAO,OAAO,MAAM;AAC1B,MAAI,CAAC,KAAM,QAAO;EAElB,MAAM,OAAO,KAAK,OAAO,MAAM,OAAO,KAAK,SAAS,CAAC;AACrD,KAAG,YAAY,OAAO,KAAK,KAAK;AAChC,SAAO;GAEV;;;;;;;;;;ACpCH,MAAa,iBAA2B;CACtC,MAAM;CACN,QAAQ;CACR,OAAO;CACP,SAAS;CACT,YAAY;CACZ,MAAM;CACN,QAAQ;AACN,SAAO;GACL;GACA,EACE,OAAO,2BACR;GACD,CAAC,QAAQ,EAAE;GACZ;;CAEH,UAAU,CACR;EACE,KAAK;EACL,gBAAgB;EACjB,CACF;CACF;;;;;;;;;;;;;;;;ACHD,SAAgB,qBACd,kBACA,MACA,aACU;CACV,MAAM,OAAO,cAAc,OAAO;CAClC,MAAM,SAAS,cAAc,QAAQ,2BAA2B,KAAK;CACrE,MAAM,UAAU,cAAc,QAAQ,2BAA2B;CACjE,MAAM,MAAM,cAAc,QAAQ,2BAA2B,QAAQ,QAAQ;CAE7E,MAAM,SAAS,qBAAqB,kBAAkB,QAAQ,SAAS,KAAK;AAE5E,QAAO,MAAM,YAAY;AAEzB,QAAO;EACL;EACA,YAAY;EACZ,SAAS,MAAM,gBAAgB;AAC7B,UAAO,MAAM,YAAY;AACzB,UAAO;;EAEV"}
package/package.json CHANGED
@@ -1,34 +1,36 @@
1
1
  {
2
2
  "name": "prosemirror-math",
3
3
  "type": "module",
4
- "version": "0.1.0",
5
- "private": false,
6
- "description": "Math extensions for ProseMirror",
7
- "author": {
8
- "name": "ocavue",
9
- "email": "ocavue@gmail.com"
10
- },
4
+ "version": "0.2.2",
5
+ "description": "Rendering math expressions in ProseMirror",
6
+ "author": "ocavue <ocavue@gmail.com>",
11
7
  "license": "MIT",
12
8
  "funding": "https://github.com/sponsors/ocavue",
13
- "homepage": "https://github.com/prosekit/prosekit#readme",
9
+ "homepage": "https://github.com/ocavue/prosemirror-math#readme",
14
10
  "repository": {
15
11
  "type": "git",
16
- "url": "git+https://github.com/prosekit/prosekit.git",
17
- "directory": "packages/prosemirror-math"
18
- },
19
- "bugs": {
20
- "url": "https://github.com/prosekit/prosekit/issues"
12
+ "url": "https://github.com/ocavue/prosemirror-math.git"
21
13
  },
14
+ "bugs": "https://github.com/ocavue/prosemirror-math/issues",
22
15
  "keywords": [
23
16
  "ProseMirror"
24
17
  ],
25
18
  "sideEffects": false,
26
- "main": "./dist/prosemirror-math.js",
27
- "module": "./dist/prosemirror-math.js",
19
+ "main": "./dist/index.js",
20
+ "module": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
28
22
  "exports": {
29
23
  ".": {
30
- "types": "./dist/prosemirror-math.d.ts",
31
- "default": "./dist/prosemirror-math.js"
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ }
27
+ },
28
+ "typesVersions": {
29
+ "*": {
30
+ "*": [
31
+ "./dist/*",
32
+ "./dist/index.d.ts"
33
+ ]
32
34
  }
33
35
  },
34
36
  "files": [
@@ -37,42 +39,39 @@
37
39
  ],
38
40
  "dependencies": {
39
41
  "@ocavue/utils": "^1.5.0",
40
- "prosemirror-inputrules": "^1.5.1",
41
- "prosemirror-model": "^1.25.4",
42
- "prosemirror-state": "^1.4.4",
43
- "prosemirror-view": "^1.41.6",
44
- "prosemirror-enter-rules": "^0.1.3"
42
+ "prosemirror-enter-rules": "^0.1.5",
43
+ "prosemirror-inputrules": "^1.0.0",
44
+ "prosemirror-model": "^1.0.0",
45
+ "prosemirror-state": "^1.0.0",
46
+ "prosemirror-view": "^1.0.0"
45
47
  },
46
48
  "devDependencies": {
47
49
  "@mathjax/src": "^4.1.0",
50
+ "@ocavue/eslint-config": "^4.1.0",
51
+ "@ocavue/tsconfig": "^0.6.3",
52
+ "@prosekit/core": "^0.10.0",
53
+ "@types/node": "^20.19.10",
54
+ "@vitest/browser": "^4.0.18",
55
+ "@vitest/browser-playwright": "^4.0.18",
48
56
  "diffable-html-snapshot": "^0.2.0",
57
+ "eslint": "^10.0.1",
49
58
  "katex": "^0.16.28",
59
+ "playwright": "^1.58.2",
60
+ "prettier": "^3.8.1",
50
61
  "temml": "^0.13.1",
51
62
  "tsdown": "^0.20.3",
52
- "typescript": "~5.9.3",
63
+ "typescript": "^5.9.3",
64
+ "vite": "^7.3.1",
53
65
  "vitest": "^4.0.18",
54
- "vitest-browser-commands": "^0.2.0",
55
- "@prosekit/core": "^0.10.0",
56
- "@prosekit/config-vitest": "0.0.0"
57
- },
58
- "publishConfig": {
59
- "dev": {}
60
- },
61
- "dev": {
62
- "entry": {
63
- "prosemirror-math": "./src/index.ts"
64
- }
66
+ "vitest-browser-commands": "^0.2.0"
65
67
  },
66
68
  "scripts": {
67
- "build:tsc": "tsc -b tsconfig.json",
68
- "build:tsdown": "tsdown"
69
- },
70
- "types": "./dist/prosemirror-math.d.ts",
71
- "typesVersions": {
72
- "*": {
73
- ".": [
74
- "./dist/prosemirror-math.d.ts"
75
- ]
76
- }
69
+ "build": "tsdown",
70
+ "dev": "tsdown --watch",
71
+ "lint": "eslint .",
72
+ "fix": "eslint --fix . && prettier --write .",
73
+ "test:install": "playwright install chromium",
74
+ "test": "vitest",
75
+ "typecheck": "tsc -b"
77
76
  }
78
77
  }
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
 
3
- import { createElement } from './create-element'
3
+ import { createElement } from './create-element.ts'
4
4
 
5
5
  describe('createElement', () => {
6
6
  it('creates an element with the given tag', () => {
@@ -1,7 +1,7 @@
1
1
  import { TextSelection } from 'prosemirror-state'
2
2
  import { describe, expect, it } from 'vitest'
3
3
 
4
- import { setupTest } from './testing'
4
+ import { setupTest } from './testing.ts'
5
5
 
6
6
  describe('cursorInsidePlugin', () => {
7
7
  it('applies decoration when cursor is inside mathBlock', () => {
@@ -10,13 +10,13 @@ describe('cursorInsidePlugin', () => {
10
10
 
11
11
  // Place cursor inside the math block
12
12
  const { state } = editor.view
13
- const tr = state.tr.setSelection(
14
- TextSelection.near(state.doc.resolve(2)),
15
- )
13
+ const tr = state.tr.setSelection(TextSelection.near(state.doc.resolve(2)))
16
14
  editor.view.dispatch(tr)
17
15
 
18
- const mathBlock = editor.view.dom.querySelector('.prosekit-math-block')
19
- expect(mathBlock?.classList.contains('prosemirror-math-head-inside')).toBe(true)
16
+ const mathBlock = editor.view.dom.querySelector('.prosemirror-math-block')
17
+ expect(mathBlock?.classList.contains('prosemirror-math-head-inside')).toBe(
18
+ true,
19
+ )
20
20
  })
21
21
 
22
22
  it('applies decoration when cursor is inside mathInline', () => {
@@ -25,13 +25,13 @@ describe('cursorInsidePlugin', () => {
25
25
 
26
26
  // Place cursor inside the math inline node
27
27
  const { state } = editor.view
28
- const tr = state.tr.setSelection(
29
- TextSelection.near(state.doc.resolve(2)),
30
- )
28
+ const tr = state.tr.setSelection(TextSelection.near(state.doc.resolve(2)))
31
29
  editor.view.dispatch(tr)
32
30
 
33
- const mathInline = editor.view.dom.querySelector('.prosekit-math-inline')
34
- expect(mathInline?.classList.contains('prosemirror-math-head-inside')).toBe(true)
31
+ const mathInline = editor.view.dom.querySelector('.prosemirror-math-inline')
32
+ expect(mathInline?.classList.contains('prosemirror-math-head-inside')).toBe(
33
+ true,
34
+ )
35
35
  })
36
36
 
37
37
  it('does not apply decoration when cursor is outside math nodes', () => {
@@ -40,12 +40,12 @@ describe('cursorInsidePlugin', () => {
40
40
 
41
41
  // Place cursor inside the paragraph (position 2 should be inside "hello")
42
42
  const { state } = editor.view
43
- const tr = state.tr.setSelection(
44
- TextSelection.near(state.doc.resolve(2)),
45
- )
43
+ const tr = state.tr.setSelection(TextSelection.near(state.doc.resolve(2)))
46
44
  editor.view.dispatch(tr)
47
45
 
48
- const mathBlock = editor.view.dom.querySelector('.prosekit-math-block')
49
- expect(mathBlock?.classList.contains('prosemirror-math-head-inside')).toBe(false)
46
+ const mathBlock = editor.view.dom.querySelector('.prosemirror-math-block')
47
+ expect(mathBlock?.classList.contains('prosemirror-math-head-inside')).toBe(
48
+ false,
49
+ )
50
50
  })
51
51
  })
@@ -24,8 +24,10 @@ function createCursorInsideDecoration(
24
24
  /**
25
25
  * @internal
26
26
  */
27
- export function hasCursorInsideDecoration(decorations: readonly Decoration[]): boolean {
28
- return decorations.some(deco => deco.spec === DECORATION_SPEC)
27
+ export function hasCursorInsideDecoration(
28
+ decorations: readonly Decoration[],
29
+ ): boolean {
30
+ return decorations.some((deco) => deco.spec === DECORATION_SPEC)
29
31
  }
30
32
 
31
33
  type PluginState = DecorationSet | undefined
@@ -49,8 +51,8 @@ export function createCursorInsidePlugin(): Plugin {
49
51
  },
50
52
  apply(tr, oldValue, oldState, newState): PluginState {
51
53
  if (
52
- oldState.selection.head === newState.selection.head
53
- && !tr.docChanged
54
+ oldState.selection.head === newState.selection.head &&
55
+ !tr.docChanged
54
56
  ) {
55
57
  return oldValue
56
58
  }
package/src/index.ts CHANGED
@@ -1,7 +1,10 @@
1
- export { createCursorInsidePlugin } from './cursor-inside-plugin'
2
- export { mathBlockEnterRule } from './math-block-enter-rule'
3
- export { mathBlockSpec } from './math-block-spec'
4
- export { createMathBlockView, type RenderMathBlock } from './math-block-view'
5
- export { createMathInlineInputRule } from './math-inline-input-rule'
6
- export { mathInlineSpec } from './math-inline-spec'
7
- export { createMathInlineView, type RenderMathInline } from './math-inline-view'
1
+ export { createCursorInsidePlugin } from './cursor-inside-plugin.ts'
2
+ export { mathBlockEnterRule } from './math-block-enter-rule.ts'
3
+ export { mathBlockSpec } from './math-block-spec.ts'
4
+ export { createMathBlockView, type RenderMathBlock } from './math-block-view.ts'
5
+ export { createMathInlineInputRule } from './math-inline-input-rule.ts'
6
+ export { mathInlineSpec } from './math-inline-spec.ts'
7
+ export {
8
+ createMathInlineView,
9
+ type RenderMathInline,
10
+ } from './math-inline-view.ts'
@@ -1,8 +1,8 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
  import { userEvent } from 'vitest/browser'
3
3
 
4
- import { MATH_BLOCK_ENTER_REGEXP } from './math-block-enter-rule'
5
- import { setupTest } from './testing'
4
+ import { MATH_BLOCK_ENTER_REGEXP } from './math-block-enter-rule.ts'
5
+ import { setupTest } from './testing.ts'
6
6
 
7
7
  describe('MATH_BLOCK_ENTER_REGEXP', () => {
8
8
  const cases: Array<[input: string, matched: boolean]> = [
@@ -26,9 +26,7 @@ describe('defineMathBlockEnterRule', () => {
26
26
  editor.set(n.doc(n.p('<a>')))
27
27
 
28
28
  await userEvent.keyboard('$$')
29
- expect(editor.view.state.doc.toJSON()).toEqual(
30
- n.doc(n.p('$$')).toJSON(),
31
- )
29
+ expect(editor.view.state.doc.toJSON()).toEqual(n.doc(n.p('$$')).toJSON())
32
30
 
33
31
  await userEvent.keyboard('{Enter}')
34
32
  expect(editor.view.state.doc.toJSON()).toEqual(
@@ -1,8 +1,18 @@
1
- import { createTextBlockEnterRule, type EnterRule } from 'prosemirror-enter-rules'
1
+ import {
2
+ createTextBlockEnterRule,
3
+ type EnterRule,
4
+ } from 'prosemirror-enter-rules'
2
5
 
3
6
  export const MATH_BLOCK_ENTER_REGEXP: RegExp = /^\$\$$/
4
7
 
5
- export const mathBlockEnterRule: EnterRule = /* @__PURE__ */ createTextBlockEnterRule({
6
- regex: MATH_BLOCK_ENTER_REGEXP,
7
- type: 'mathBlock',
8
- })
8
+ /**
9
+ * An {@link EnterRule} that converts a textblock node that only contains `$$` into a math
10
+ * block node when Enter is pressed.
11
+ *
12
+ * @public
13
+ */
14
+ export const mathBlockEnterRule: EnterRule =
15
+ /* @__PURE__ */ createTextBlockEnterRule({
16
+ regex: MATH_BLOCK_ENTER_REGEXP,
17
+ type: 'mathBlock',
18
+ })
@@ -1,7 +1,7 @@
1
1
  import { formatHTML } from 'diffable-html-snapshot'
2
2
  import { describe, expect, it } from 'vitest'
3
3
 
4
- import { setupTest } from './testing'
4
+ import { setupTest } from './testing.ts'
5
5
 
6
6
  describe('mathBlockSpec', () => {
7
7
  it('can serialize to HTML', () => {
@@ -12,7 +12,7 @@ describe('mathBlockSpec', () => {
12
12
  `
13
13
  "
14
14
  <div>
15
- <div class="prosekit-math-block">
15
+ <div class="prosemirror-math-block">
16
16
  <pre>
17
17
  <code>
18
18
  E = mc^2
@@ -1,5 +1,10 @@
1
1
  import type { NodeSpec } from 'prosemirror-model'
2
2
 
3
+ /**
4
+ * A {@link NodeSpec} for a block-level math node.
5
+ *
6
+ * @public
7
+ */
3
8
  export const mathBlockSpec: NodeSpec = {
4
9
  atom: false,
5
10
  group: 'block math',
@@ -9,14 +14,14 @@ export const mathBlockSpec: NodeSpec = {
9
14
  return [
10
15
  'div',
11
16
  {
12
- class: 'prosekit-math-block',
17
+ class: 'prosemirror-math-block',
13
18
  },
14
19
  ['pre', ['code', 0]],
15
20
  ]
16
21
  },
17
22
  parseDOM: [
18
23
  {
19
- tag: 'div.prosekit-math-block',
24
+ tag: 'div.prosemirror-math-block',
20
25
 
21
26
  // skip the `<pre>` wrapper so that the node `codeBlock` won't match the content.
22
27
  // TODO: add test to verify it
@@ -1,7 +1,13 @@
1
1
  import { formatHTML } from 'diffable-html-snapshot'
2
2
  import { describe, expect, it } from 'vitest'
3
3
 
4
- import { katexRenderer, mathjaxRenderer, renderers, setupTest, temmlRenderer } from './testing'
4
+ import {
5
+ katexRenderer,
6
+ mathjaxRenderer,
7
+ renderers,
8
+ setupTest,
9
+ temmlRenderer,
10
+ } from './testing.ts'
5
11
 
6
12
  describe.each(Object.keys(renderers))('createMathBlockView (%s)', (name) => {
7
13
  const renderer = renderers[name as keyof typeof renderers]
@@ -11,17 +17,17 @@ describe.each(Object.keys(renderers))('createMathBlockView (%s)', (name) => {
11
17
  editor.set(n.doc(n.mathBlock('x^2')))
12
18
 
13
19
  const dom = editor.view.dom
14
- const mathBlock = dom.querySelector('.prosekit-math-block')
20
+ const mathBlock = dom.querySelector('.prosemirror-math-block')
15
21
  expect(mathBlock).toBeTruthy()
16
- expect(mathBlock?.querySelector('.prosekit-math-source')).toBeTruthy()
17
- expect(mathBlock?.querySelector('.prosekit-math-display')).toBeTruthy()
22
+ expect(mathBlock?.querySelector('.prosemirror-math-source')).toBeTruthy()
23
+ expect(mathBlock?.querySelector('.prosemirror-math-display')).toBeTruthy()
18
24
  })
19
25
 
20
26
  it('updates display when content changes', () => {
21
27
  const { editor, n } = setupTest(renderer)
22
28
  editor.set(n.doc(n.mathBlock('x^2')))
23
29
 
24
- const display = editor.view.dom.querySelector('.prosekit-math-display')
30
+ const display = editor.view.dom.querySelector('.prosemirror-math-display')
25
31
  const initialHTML = display?.innerHTML
26
32
 
27
33
  // Dispatch a transaction to change content
@@ -39,7 +45,7 @@ describe('createMathBlockView (temml snapshot)', () => {
39
45
  const { editor, n } = setupTest(temmlRenderer)
40
46
  editor.set(n.doc(n.mathBlock('x^2')))
41
47
 
42
- const display = editor.view.dom.querySelector('.prosekit-math-display')
48
+ const display = editor.view.dom.querySelector('.prosemirror-math-display')
43
49
  const html = formatHTML(display?.innerHTML || '')
44
50
  expect(html).toMatchInlineSnapshot(`
45
51
  "
@@ -72,7 +78,7 @@ describe('createMathBlockView (katex snapshot)', () => {
72
78
  const { editor, n } = setupTest(katexRenderer)
73
79
  editor.set(n.doc(n.mathBlock('x^2')))
74
80
 
75
- const display = editor.view.dom.querySelector('.prosekit-math-display')
81
+ const display = editor.view.dom.querySelector('.prosemirror-math-display')
76
82
  const html = formatHTML(display?.innerHTML || '')
77
83
  expect(html).toMatchInlineSnapshot(`
78
84
  "
@@ -155,7 +161,7 @@ describe('createMathBlockView (mathjax snapshot)', () => {
155
161
  const { editor, n } = setupTest(mathjaxRenderer)
156
162
  editor.set(n.doc(n.mathBlock('x^2')))
157
163
 
158
- const display = editor.view.dom.querySelector('.prosekit-math-display')
164
+ const display = editor.view.dom.querySelector('.prosemirror-math-display')
159
165
  const html = formatHTML(display?.innerHTML || '')
160
166
  expect(html).toMatchInlineSnapshot(`
161
167
  "
@@ -1,8 +1,8 @@
1
1
  import type { Node as ProseMirrorNode } from 'prosemirror-model'
2
2
  import type { Decoration, NodeView } from 'prosemirror-view'
3
3
 
4
- import { createElement } from './create-element'
5
- import { createMathViewRender } from './math-view-render'
4
+ import { createElement } from './create-element.ts'
5
+ import { createMathViewRender } from './math-view-render.ts'
6
6
 
7
7
  /**
8
8
  * The function to render a math block.
@@ -12,13 +12,29 @@ import { createMathViewRender } from './math-view-render'
12
12
  */
13
13
  export type RenderMathBlock = (text: string, element: HTMLElement) => void
14
14
 
15
- export function createMathBlockView(renderMathBlock: RenderMathBlock, node: ProseMirrorNode, decorations: readonly Decoration[]): NodeView {
15
+ /**
16
+ * Creates a {@link NodeView} for a block-level math node. The view will show a
17
+ * source editor or a rendered display area based on the text cursor position.
18
+ *
19
+ * @param renderMathBlock - A function that renders math text (e.g. TeX) into
20
+ * the display element. You can use libraries like
21
+ * [Temml](https://temml.org/) or [KaTeX](https://katex.org/).
22
+ * @param node - The ProseMirror node to render.
23
+ * @param decorations - The decorations applied to the node.
24
+ *
25
+ * @public
26
+ */
27
+ export function createMathBlockView(
28
+ renderMathBlock: RenderMathBlock,
29
+ node: ProseMirrorNode,
30
+ decorations: readonly Decoration[],
31
+ ): NodeView {
16
32
  const code = createElement('code')
17
- const source = createElement('pre', 'prosekit-math-source', code)
18
- const display = createElement('div', 'prosekit-math-display')
19
- const dom = createElement('div', 'prosekit-math-block', source, display)
33
+ const source = createElement('pre', 'prosemirror-math-source', code)
34
+ const display = createElement('div', 'prosemirror-math-display')
35
+ const dom = createElement('div', 'prosemirror-math-block', source, display)
20
36
 
21
- const render = createMathViewRender(renderMathBlock, source, display)
37
+ const render = createMathViewRender(renderMathBlock, source, display, false)
22
38
 
23
39
  render(node, decorations)
24
40
 
@@ -1,13 +1,15 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
  import { userEvent } from 'vitest/browser'
3
3
 
4
- import { MATH_INPUT_REGEXP } from './math-inline-input-rule'
5
- import { setupTest } from './testing'
4
+ import { MATH_INPUT_REGEXP } from './math-inline-input-rule.ts'
5
+ import { setupTest } from './testing.ts'
6
6
 
7
7
  describe('MATH_INPUT_REGEXP', () => {
8
8
  const regexp = new RegExp(MATH_INPUT_REGEXP)
9
9
 
10
- const cases: Array<[input: string, delimiter: string | null, captured: string | null]> = [
10
+ const cases: Array<
11
+ [input: string, delimiter: string | null, captured: string | null]
12
+ > = [
11
13
  // Single dollar: inline math
12
14
  ['$x$', '$', 'x'],
13
15
  ['$x^2$', '$', 'x^2'],
@@ -46,13 +48,16 @@ describe('MATH_INPUT_REGEXP', () => {
46
48
  ['hello', null, null],
47
49
  ]
48
50
 
49
- it.each(cases)('should handle %s', (input, expectedDelimiter, expectedContent) => {
50
- const match = regexp.exec(input)
51
- const delimiter = match?.[1] ?? null
52
- const captured = match?.[2] ?? null
53
- expect(delimiter).toEqual(expectedDelimiter)
54
- expect(captured).toEqual(expectedContent)
55
- })
51
+ it.each(cases)(
52
+ 'should handle %s',
53
+ (input, expectedDelimiter, expectedContent) => {
54
+ const match = regexp.exec(input)
55
+ const delimiter = match?.[1] ?? null
56
+ const captured = match?.[2] ?? null
57
+ expect(delimiter).toEqual(expectedDelimiter)
58
+ expect(captured).toEqual(expectedContent)
59
+ },
60
+ )
56
61
  })
57
62
 
58
63
  describe('defineMathInlineInputRule', () => {
@@ -62,9 +67,7 @@ describe('defineMathInlineInputRule', () => {
62
67
  editor.set(n.doc(n.p('<a>')))
63
68
 
64
69
  await userEvent.keyboard('$x^2')
65
- expect(editor.view.state.doc.toJSON()).toEqual(
66
- n.doc(n.p('$x^2')).toJSON(),
67
- )
70
+ expect(editor.view.state.doc.toJSON()).toEqual(n.doc(n.p('$x^2')).toJSON())
68
71
 
69
72
  await userEvent.keyboard('$')
70
73
  expect(editor.view.state.doc.toJSON()).toEqual(
@@ -99,9 +102,7 @@ describe('defineMathInlineInputRule', () => {
99
102
  editor.set(n.doc(n.p('<a>')))
100
103
 
101
104
  await userEvent.keyboard('$$')
102
- expect(editor.view.state.doc.toJSON()).toEqual(
103
- n.doc(n.p('$$')).toJSON(),
104
- )
105
+ expect(editor.view.state.doc.toJSON()).toEqual(n.doc(n.p('$$')).toJSON())
105
106
  })
106
107
 
107
108
  it('should not trigger with spaces at boundaries', async () => {
@@ -4,34 +4,42 @@ import { supportsRegexLookbehind } from '@ocavue/utils'
4
4
  import { InputRule } from 'prosemirror-inputrules'
5
5
 
6
6
  // Matches text wrapped in `$` or `$$`, e.g. `$x^2$` or `$$x^2$$`.
7
- export const MATH_INPUT_REGEXP: string = (
7
+ export const MATH_INPUT_REGEXP: string =
8
8
  // Don't allow $ before the opening delimiter
9
- (supportsRegexLookbehind() ? '(?<!\\$)' : '')
9
+ (supportsRegexLookbehind() ? '(?<!\\$)' : '') +
10
10
  // capture group 1: opening delimiter (`$` or `$$`)
11
- + '(\\$\\$?)'
11
+ '(\\$\\$?)' +
12
12
  // capture group 2: the math content
13
13
  // - a single non-whitespace, non-`$` character
14
14
  // - optionally followed by any non-`$` characters and a final non-whitespace, non-`$` character
15
- + '([^\\s$](?:[^$]*[^\\s$])?)'
15
+ '([^\\s$](?:[^$]*[^\\s$])?)' +
16
16
  // backreference: closing delimiter must match the opening
17
- + '\\1'
17
+ '\\1' +
18
18
  // end of input (required by ProseMirror InputRule)
19
- + '$'
20
- )
19
+ '$'
21
20
 
22
- export function createMathInlineInputRule(
23
- nodeType: string,
24
- ): InputRule {
25
- return new InputRule(new RegExp(MATH_INPUT_REGEXP), (state, match, start, end) => {
26
- const { tr, schema } = state
27
- const mathText = match[2]
28
- if (!mathText) return null
21
+ /**
22
+ * Creates a ProseMirror {@link InputRule} that converts text wrapped in `$` or
23
+ * `$$` (e.g. `$x^2$`) into an inline math node.
24
+ *
25
+ * @param nodeType - The name of the inline math node type in your schema.
26
+ *
27
+ * @public
28
+ */
29
+ export function createMathInlineInputRule(nodeType: string): InputRule {
30
+ return new InputRule(
31
+ new RegExp(MATH_INPUT_REGEXP),
32
+ (state, match, start, end) => {
33
+ const { tr, schema } = state
34
+ const mathText = match[2]
35
+ if (!mathText) return null
29
36
 
30
- const type = schema.nodes[nodeType]
31
- if (!type) return null
37
+ const type = schema.nodes[nodeType]
38
+ if (!type) return null
32
39
 
33
- const node = type.create(null, schema.text(mathText))
34
- tr.replaceWith(start, end, node)
35
- return tr
36
- })
40
+ const node = type.create(null, schema.text(mathText))
41
+ tr.replaceWith(start, end, node)
42
+ return tr
43
+ },
44
+ )
37
45
  }
@@ -1,7 +1,7 @@
1
1
  import { formatHTML } from 'diffable-html-snapshot'
2
2
  import { describe, expect, it } from 'vitest'
3
3
 
4
- import { setupTest } from './testing'
4
+ import { setupTest } from './testing.ts'
5
5
 
6
6
  describe('mathInlineSpec', () => {
7
7
  it('can serialize to HTML', () => {
@@ -13,7 +13,7 @@ describe('mathInlineSpec', () => {
13
13
  "
14
14
  <div>
15
15
  <p>
16
- <span class="prosekit-math-inline">
16
+ <span class="prosemirror-math-inline">
17
17
  <code>
18
18
  x^2
19
19
  </code>
@@ -75,7 +75,9 @@ describe('mathInlineSpec', () => {
75
75
 
76
76
  it('can be mixed with regular text', () => {
77
77
  const { editor, n } = setupTest()
78
- editor.set(n.doc(n.paragraph('The formula ', n.mathInline('E=mc^2'), ' is famous.')))
78
+ editor.set(
79
+ n.doc(n.paragraph('The formula ', n.mathInline('E=mc^2'), ' is famous.')),
80
+ )
79
81
  const json = editor.getDocJSON()
80
82
  expect(json).toMatchInlineSnapshot(`
81
83
  {
@@ -1,5 +1,10 @@
1
1
  import type { NodeSpec } from 'prosemirror-model'
2
2
 
3
+ /**
4
+ * A {@link NodeSpec} for an inline math node.
5
+ *
6
+ * @public
7
+ */
3
8
  export const mathInlineSpec: NodeSpec = {
4
9
  atom: false,
5
10
  inline: true,
@@ -11,14 +16,14 @@ export const mathInlineSpec: NodeSpec = {
11
16
  return [
12
17
  'span',
13
18
  {
14
- class: 'prosekit-math-inline',
19
+ class: 'prosemirror-math-inline',
15
20
  },
16
21
  ['code', 0],
17
22
  ]
18
23
  },
19
24
  parseDOM: [
20
25
  {
21
- tag: 'span.prosekit-math-inline',
26
+ tag: 'span.prosemirror-math-inline',
22
27
  contentElement: 'code',
23
28
  },
24
29
  ],
@@ -1,7 +1,13 @@
1
1
  import { formatHTML } from 'diffable-html-snapshot'
2
2
  import { describe, expect, it } from 'vitest'
3
3
 
4
- import { katexRenderer, mathjaxRenderer, renderers, setupTest, temmlRenderer } from './testing'
4
+ import {
5
+ katexRenderer,
6
+ mathjaxRenderer,
7
+ renderers,
8
+ setupTest,
9
+ temmlRenderer,
10
+ } from './testing.ts'
5
11
 
6
12
  describe.each(Object.keys(renderers))('createMathInlineView (%s)', (name) => {
7
13
  const renderer = renderers[name as keyof typeof renderers]
@@ -11,17 +17,17 @@ describe.each(Object.keys(renderers))('createMathInlineView (%s)', (name) => {
11
17
  editor.set(n.doc(n.paragraph(n.mathInline('x^2'))))
12
18
 
13
19
  const dom = editor.view.dom
14
- const mathInline = dom.querySelector('.prosekit-math-inline')
20
+ const mathInline = dom.querySelector('.prosemirror-math-inline')
15
21
  expect(mathInline).toBeTruthy()
16
- expect(mathInline?.querySelector('.prosekit-math-source')).toBeTruthy()
17
- expect(mathInline?.querySelector('.prosekit-math-display')).toBeTruthy()
22
+ expect(mathInline?.querySelector('.prosemirror-math-source')).toBeTruthy()
23
+ expect(mathInline?.querySelector('.prosemirror-math-display')).toBeTruthy()
18
24
  })
19
25
 
20
26
  it('uses span elements for inline math', () => {
21
27
  const { editor, n } = setupTest(renderer)
22
28
  editor.set(n.doc(n.paragraph(n.mathInline('x'))))
23
29
 
24
- const mathInline = editor.view.dom.querySelector('.prosekit-math-inline')
30
+ const mathInline = editor.view.dom.querySelector('.prosemirror-math-inline')
25
31
  expect(mathInline?.tagName).toBe('SPAN')
26
32
  })
27
33
  })
@@ -31,7 +37,7 @@ describe('createMathInlineView (temml snapshot)', () => {
31
37
  const { editor, n } = setupTest(temmlRenderer)
32
38
  editor.set(n.doc(n.paragraph(n.mathInline('x^2'))))
33
39
 
34
- const display = editor.view.dom.querySelector('.prosekit-math-display')
40
+ const display = editor.view.dom.querySelector('.prosemirror-math-display')
35
41
  const html = formatHTML(display?.innerHTML || '')
36
42
  expect(html).toMatchInlineSnapshot(`
37
43
  "
@@ -60,7 +66,7 @@ describe('createMathInlineView (katex snapshot)', () => {
60
66
  const { editor, n } = setupTest(katexRenderer)
61
67
  editor.set(n.doc(n.paragraph(n.mathInline('x^2'))))
62
68
 
63
- const display = editor.view.dom.querySelector('.prosekit-math-display')
69
+ const display = editor.view.dom.querySelector('.prosemirror-math-display')
64
70
  const html = formatHTML(display?.innerHTML || '')
65
71
  expect(html).toMatchInlineSnapshot(`
66
72
  "
@@ -138,7 +144,7 @@ describe('createMathInlineView (mathjax snapshot)', () => {
138
144
  const { editor, n } = setupTest(mathjaxRenderer)
139
145
  editor.set(n.doc(n.paragraph(n.mathInline('x^2'))))
140
146
 
141
- const display = editor.view.dom.querySelector('.prosekit-math-display')
147
+ const display = editor.view.dom.querySelector('.prosemirror-math-display')
142
148
  const html = formatHTML(display?.innerHTML || '')
143
149
  expect(html).toMatchInlineSnapshot(`
144
150
  "
@@ -1,8 +1,8 @@
1
1
  import type { Node as ProseMirrorNode } from 'prosemirror-model'
2
2
  import type { Decoration, NodeView } from 'prosemirror-view'
3
3
 
4
- import { createElement } from './create-element'
5
- import { createMathViewRender } from './math-view-render'
4
+ import { createElement } from './create-element.ts'
5
+ import { createMathViewRender } from './math-view-render.ts'
6
6
 
7
7
  /**
8
8
  * The function to render a math inline.
@@ -12,22 +12,35 @@ import { createMathViewRender } from './math-view-render'
12
12
  */
13
13
  export type RenderMathInline = (text: string, element: HTMLElement) => void
14
14
 
15
+ /**
16
+ * Creates a {@link NodeView} for an inline math node. The view will show a
17
+ * source editor or a rendered display area based on the text cursor position.
18
+ *
19
+ * @param renderMathInline - A function that renders math text (e.g. TeX) into
20
+ * the display element. You can use libraries like [Temml](https://temml.org/)
21
+ * or [KaTeX](https://katex.org/).
22
+ * @param node - The ProseMirror node to render.
23
+ * @param decorations - The decorations applied to the node.
24
+ *
25
+ * @public
26
+ */
15
27
  export function createMathInlineView(
16
28
  renderMathInline: RenderMathInline,
17
29
  node: ProseMirrorNode,
18
30
  decorations: readonly Decoration[],
19
31
  ): NodeView {
20
- const source = createElement('code', 'prosekit-math-source')
21
- const display = createElement('span', 'prosekit-math-display')
22
- const dom = createElement('span', 'prosekit-math-inline', source, display)
32
+ const code = createElement('code')
33
+ const source = createElement('span', 'prosemirror-math-source', code)
34
+ const display = createElement('span', 'prosemirror-math-display')
35
+ const dom = createElement('span', 'prosemirror-math-inline', source, display)
23
36
 
24
- const render = createMathViewRender(renderMathInline, source, display)
37
+ const render = createMathViewRender(renderMathInline, source, display, true)
25
38
 
26
39
  render(node, decorations)
27
40
 
28
41
  return {
29
42
  dom,
30
- contentDOM: source,
43
+ contentDOM: code,
31
44
  update: (node, decorations) => {
32
45
  render(node, decorations)
33
46
  return true
@@ -1,7 +1,7 @@
1
1
  import type { Node } from 'prosemirror-model'
2
2
  import type { Decoration } from 'prosemirror-view'
3
3
 
4
- import { hasCursorInsideDecoration } from './cursor-inside-plugin'
4
+ import { hasCursorInsideDecoration } from './cursor-inside-plugin.ts'
5
5
 
6
6
  type RenderMath = (text: string, element: HTMLElement) => void
7
7
 
@@ -9,6 +9,7 @@ export function createMathViewRender(
9
9
  renderMath: RenderMath,
10
10
  source: HTMLElement,
11
11
  display: HTMLElement,
12
+ inline: boolean,
12
13
  ) {
13
14
  let prevNode: Node | undefined
14
15
  let prevText: string | undefined
@@ -32,8 +33,18 @@ export function createMathViewRender(
32
33
 
33
34
  // When the math node is selected, show the source code.
34
35
  // Otherwise, show the rendered result.
35
- source.style.display = selected ? '' : 'none'
36
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
+ }
37
48
  }
38
49
 
39
50
  return function updateMathView(
@@ -44,3 +55,21 @@ export function createMathViewRender(
44
55
  updateStyle(decorations)
45
56
  }
46
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/temml.ts CHANGED
@@ -1,9 +1,17 @@
1
1
  import Temml from 'temml'
2
2
 
3
3
  export function renderTemmlMathBlock(text: string, element: HTMLElement) {
4
- Temml.render(text, element, { displayMode: true, annotate: true, throwOnError: false })
4
+ Temml.render(text, element, {
5
+ displayMode: true,
6
+ annotate: true,
7
+ throwOnError: false,
8
+ })
5
9
  }
6
10
 
7
11
  export function renderTemmlMathInline(text: string, element: HTMLElement) {
8
- Temml.render(text, element, { displayMode: false, annotate: true, throwOnError: false })
12
+ Temml.render(text, element, {
13
+ displayMode: false,
14
+ annotate: true,
15
+ throwOnError: false,
16
+ })
9
17
  }
package/src/testing.ts CHANGED
@@ -19,16 +19,16 @@ import { createEnterRuleCommand, type EnterRule } from 'prosemirror-enter-rules'
19
19
  import { inputRules } from 'prosemirror-inputrules'
20
20
  import type { Attrs } from 'prosemirror-model'
21
21
 
22
- import { createCursorInsidePlugin } from './cursor-inside-plugin'
23
- import { renderKaTeXMathBlock, renderKaTeXMathInline } from './katex'
24
- import { mathBlockEnterRule } from './math-block-enter-rule'
25
- import { mathBlockSpec } from './math-block-spec'
26
- import { createMathBlockView } from './math-block-view'
27
- import { createMathInlineInputRule } from './math-inline-input-rule'
28
- import { mathInlineSpec } from './math-inline-spec'
29
- import { createMathInlineView } from './math-inline-view'
30
- import { renderMathJaxMathBlock, renderMathJaxMathInline } from './mathjax'
31
- import { renderTemmlMathBlock, renderTemmlMathInline } from './temml'
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
32
 
33
33
  type RenderMath = (text: string, element: HTMLElement) => void
34
34
 
@@ -135,11 +135,7 @@ function defineMathBlockView(renderer: MathRenderer): Extension {
135
135
  return defineNodeView({
136
136
  name: 'mathBlock',
137
137
  constructor: (node, _view, _getPos, decorations) => {
138
- return createMathBlockView(
139
- renderer.renderBlock,
140
- node,
141
- decorations,
142
- )
138
+ return createMathBlockView(renderer.renderBlock, node, decorations)
143
139
  },
144
140
  })
145
141
  }
@@ -148,11 +144,7 @@ function defineMathInlineView(renderer: MathRenderer): Extension {
148
144
  return defineNodeView({
149
145
  name: 'mathInline',
150
146
  constructor: (node, _view, _getPos, decorations) => {
151
- return createMathInlineView(
152
- renderer.renderInline,
153
- node,
154
- decorations,
155
- )
147
+ return createMathInlineView(renderer.renderInline, node, decorations)
156
148
  },
157
149
  })
158
150
  }
@@ -173,7 +165,9 @@ function defineTestExtension(renderer: MathRenderer) {
173
165
  defineMathBlockView(renderer),
174
166
  defineMathInlineView(renderer),
175
167
  defineEnterRule([mathBlockEnterRule]),
176
- definePlugin(inputRules({ rules: [createMathInlineInputRule('mathInline')] })),
168
+ definePlugin(
169
+ inputRules({ rules: [createMathInlineInputRule('mathInline')] }),
170
+ ),
177
171
  definePlugin(createCursorInsidePlugin()),
178
172
  defineBaseCommands(),
179
173
  defineBaseKeymap(),