@slexkit/tiptap 0.3.3 → 0.4.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 +88 -88
- package/dist/index.js +114 -3
- package/package.json +68 -66
package/README.md
CHANGED
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
# @slexkit/tiptap
|
|
2
|
-
|
|
3
|
-
Tiptap extension for explicit `slex` fenced UI blocks.
|
|
4
|
-
|
|
5
|
-
```sh
|
|
6
|
-
npm install slexkit @slexkit/theme-shadcn @slexkit/tiptap @tiptap/core @tiptap/pm @tiptap/starter-kit @tiptap/extension-code-block @tiptap/markdown
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Import the SlexKit theme once in
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
import "@slexkit/theme-shadcn/style.css";
|
|
13
|
-
import "@slexkit/tiptap/style.css";
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## Minimal setup
|
|
17
|
-
|
|
18
|
-
```ts
|
|
19
|
-
import { Editor } from "@tiptap/core";
|
|
20
|
-
import StarterKit from "@tiptap/starter-kit";
|
|
21
|
-
import { createSlexKitTiptapExtension } from "@slexkit/tiptap";
|
|
22
|
-
|
|
23
|
-
const editor = new Editor({
|
|
24
|
-
element: document.querySelector("#editor"),
|
|
25
|
-
extensions: [
|
|
26
|
-
StarterKit.configure({ codeBlock: false }),
|
|
27
|
-
createSlexKitTiptapExtension({
|
|
28
|
-
artifactId: "note-42",
|
|
29
|
-
}),
|
|
30
|
-
],
|
|
31
|
-
});
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Only code blocks whose language is exactly `slex` are rendered by SlexKit. Other code blocks stay ordinary Tiptap code blocks.
|
|
35
|
-
|
|
36
|
-
## Markdown roundtrip
|
|
37
|
-
|
|
38
|
-
Add Tiptap's Markdown extension when loading or exporting Markdown:
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
import { Markdown } from "@tiptap/markdown";
|
|
42
|
-
|
|
43
|
-
const editor = new Editor({
|
|
44
|
-
extensions: [
|
|
45
|
-
StarterKit.configure({ codeBlock: false }),
|
|
46
|
-
Markdown,
|
|
47
|
-
createSlexKitTiptapExtension({ artifactId: "doc" }),
|
|
48
|
-
],
|
|
49
|
-
content: markdown,
|
|
50
|
-
contentType: "markdown",
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const nextMarkdown = editor.getMarkdown();
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
The adapter uses normal fenced code blocks instead of a custom tokenizer, so ` ```slex ` blocks remain readable in plain Markdown hosts.
|
|
57
|
-
|
|
58
|
-
## Shared state across fences
|
|
59
|
-
|
|
60
|
-
All `slex` blocks in one editor share the same artifact runtime by default. A state-only fence can seed later renderable fences:
|
|
61
|
-
|
|
62
|
-
````md
|
|
63
|
-
```slex
|
|
64
|
-
{
|
|
65
|
-
namespace: "calc",
|
|
66
|
-
g: { value: 21 }
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
```slex
|
|
71
|
-
{
|
|
72
|
-
namespace: "calc",
|
|
73
|
-
layout: {
|
|
74
|
-
"text:answer": { "$text": "'answer: ' + (g.value * 2)" }
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
````
|
|
79
|
-
|
|
80
|
-
## Runtime boundary
|
|
81
|
-
|
|
82
|
-
This adapter defaults to trusted runtime mode, intended for application-authored content, repository-maintained snippets, reviewed examples, and local document workflows. Use SlexKit secure runtime APIs for untrusted user Markdown or direct agent output.
|
|
83
|
-
|
|
84
|
-
## Documentation
|
|
85
|
-
|
|
86
|
-
- [Official Tiptap editor example](https://slexkit.app.simgor.cn/examples/tiptap-host)
|
|
87
|
-
- [Runnable example source](https://github.com/slexkit/slexkit/tree/main/examples/tiptap)
|
|
88
|
-
- [SlexKit Host integration](https://github.com/slexkit/slexkit/blob/main/site/content/reference/integration/en-US.md)
|
|
1
|
+
# @slexkit/tiptap
|
|
2
|
+
|
|
3
|
+
Tiptap extension for explicit `slex` fenced UI blocks.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install slexkit @slexkit/theme-shadcn @slexkit/tiptap @tiptap/core @tiptap/pm @tiptap/starter-kit @tiptap/extension-code-block @tiptap/markdown
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Import the SlexKit theme once in the app entry:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import "@slexkit/theme-shadcn/style.css";
|
|
13
|
+
import "@slexkit/tiptap/style.css";
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Minimal setup
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { Editor } from "@tiptap/core";
|
|
20
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
21
|
+
import { createSlexKitTiptapExtension } from "@slexkit/tiptap";
|
|
22
|
+
|
|
23
|
+
const editor = new Editor({
|
|
24
|
+
element: document.querySelector("#editor"),
|
|
25
|
+
extensions: [
|
|
26
|
+
StarterKit.configure({ codeBlock: false }),
|
|
27
|
+
createSlexKitTiptapExtension({
|
|
28
|
+
artifactId: "note-42",
|
|
29
|
+
}),
|
|
30
|
+
],
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Only code blocks whose language is exactly `slex` are rendered by SlexKit. Other code blocks stay ordinary Tiptap code blocks.
|
|
35
|
+
|
|
36
|
+
## Markdown roundtrip
|
|
37
|
+
|
|
38
|
+
Add Tiptap's Markdown extension when loading or exporting Markdown:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { Markdown } from "@tiptap/markdown";
|
|
42
|
+
|
|
43
|
+
const editor = new Editor({
|
|
44
|
+
extensions: [
|
|
45
|
+
StarterKit.configure({ codeBlock: false }),
|
|
46
|
+
Markdown,
|
|
47
|
+
createSlexKitTiptapExtension({ artifactId: "doc" }),
|
|
48
|
+
],
|
|
49
|
+
content: markdown,
|
|
50
|
+
contentType: "markdown",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const nextMarkdown = editor.getMarkdown();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The adapter uses normal fenced code blocks instead of a custom tokenizer, so ` ```slex ` blocks remain readable in plain Markdown hosts.
|
|
57
|
+
|
|
58
|
+
## Shared state across fences
|
|
59
|
+
|
|
60
|
+
All `slex` blocks in one editor share the same artifact runtime by default. A state-only fence can seed later renderable fences:
|
|
61
|
+
|
|
62
|
+
````md
|
|
63
|
+
```slex
|
|
64
|
+
{
|
|
65
|
+
namespace: "calc",
|
|
66
|
+
g: { value: 21 }
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```slex
|
|
71
|
+
{
|
|
72
|
+
namespace: "calc",
|
|
73
|
+
layout: {
|
|
74
|
+
"text:answer": { "$text": "'answer: ' + (g.value * 2)" }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
````
|
|
79
|
+
|
|
80
|
+
## Runtime boundary
|
|
81
|
+
|
|
82
|
+
This adapter defaults to trusted runtime mode, intended for application-authored content, repository-maintained snippets, reviewed examples, and local document workflows. Use SlexKit secure runtime APIs for untrusted user Markdown or direct agent output.
|
|
83
|
+
|
|
84
|
+
## Documentation
|
|
85
|
+
|
|
86
|
+
- [Official Tiptap editor example](https://slexkit.app.simgor.cn/examples/tiptap-host)
|
|
87
|
+
- [Runnable example source](https://github.com/slexkit/slexkit/tree/main/examples/tiptap)
|
|
88
|
+
- [SlexKit Host integration](https://github.com/slexkit/slexkit/blob/main/site/content/reference/integration/en-US.md)
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,23 @@ const PREVIEW_INTERACTIVE_SELECTOR = [
|
|
|
20
20
|
"[role='tab']",
|
|
21
21
|
"[role='textbox']",
|
|
22
22
|
].join(",");
|
|
23
|
+
const TRANSIENT_POINTER_INTERACTIVE_SELECTOR = [
|
|
24
|
+
"a[href]",
|
|
25
|
+
"button",
|
|
26
|
+
"input[type='button']",
|
|
27
|
+
"input[type='checkbox']",
|
|
28
|
+
"input[type='image']",
|
|
29
|
+
"input[type='radio']",
|
|
30
|
+
"input[type='range']",
|
|
31
|
+
"input[type='reset']",
|
|
32
|
+
"input[type='submit']",
|
|
33
|
+
"[role='button']",
|
|
34
|
+
"[role='checkbox']",
|
|
35
|
+
"[role='radio']",
|
|
36
|
+
"[role='slider']",
|
|
37
|
+
"[role='switch']",
|
|
38
|
+
"[role='tab']",
|
|
39
|
+
].join(",");
|
|
23
40
|
const editorArtifactIds = new WeakMap();
|
|
24
41
|
let nextArtifactId = 0;
|
|
25
42
|
const sourceOpenStates = new Map();
|
|
@@ -125,8 +142,17 @@ function focusPreviewInteractiveTarget(event) {
|
|
|
125
142
|
const target = event.target;
|
|
126
143
|
const targetElement = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
127
144
|
const interactive = targetElement?.closest(PREVIEW_INTERACTIVE_SELECTOR);
|
|
128
|
-
if (interactive instanceof HTMLElement)
|
|
129
|
-
|
|
145
|
+
if (!(interactive instanceof HTMLElement))
|
|
146
|
+
return null;
|
|
147
|
+
interactive.focus({ preventScroll: true });
|
|
148
|
+
return interactive;
|
|
149
|
+
}
|
|
150
|
+
function shouldRestorePreviewFocusAfterPointer(element) {
|
|
151
|
+
return !!element.closest(TRANSIENT_POINTER_INTERACTIVE_SELECTOR);
|
|
152
|
+
}
|
|
153
|
+
function pointerIdFromEvent(event) {
|
|
154
|
+
const pointerEvent = event;
|
|
155
|
+
return typeof pointerEvent?.pointerId === "number" ? pointerEvent.pointerId : undefined;
|
|
130
156
|
}
|
|
131
157
|
function markPreviewInteractive(preview, force = false) {
|
|
132
158
|
if (preview.getAttribute("contenteditable") !== "false") {
|
|
@@ -194,7 +220,77 @@ class SlexKitCodeBlockNodeView {
|
|
|
194
220
|
preview;
|
|
195
221
|
runtime;
|
|
196
222
|
interactiveObserver;
|
|
223
|
+
pendingFocusRestore;
|
|
224
|
+
pointerFocusContext;
|
|
197
225
|
renderToken = 0;
|
|
226
|
+
focusPreviewPointerTarget = (event) => {
|
|
227
|
+
const restoreEditor = this.editor.isFocused;
|
|
228
|
+
this.pointerFocusContext = { restoreEditor, expiresAt: Date.now() + 500 };
|
|
229
|
+
const interactive = focusPreviewInteractiveTarget(event);
|
|
230
|
+
if (!interactive || !shouldRestorePreviewFocusAfterPointer(interactive))
|
|
231
|
+
return;
|
|
232
|
+
this.pendingFocusRestore = {
|
|
233
|
+
target: interactive,
|
|
234
|
+
restoreEditor,
|
|
235
|
+
pointerId: typeof event.pointerId === "number" ? event.pointerId : null,
|
|
236
|
+
};
|
|
237
|
+
this.addFocusRestoreListeners();
|
|
238
|
+
};
|
|
239
|
+
clearPointerFocusedPreviewTarget = (event) => {
|
|
240
|
+
const context = this.pointerFocusContext;
|
|
241
|
+
if (!context || Date.now() > context.expiresAt)
|
|
242
|
+
return;
|
|
243
|
+
const target = event.target;
|
|
244
|
+
const targetElement = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
245
|
+
const interactive = targetElement?.closest(TRANSIENT_POINTER_INTERACTIVE_SELECTOR);
|
|
246
|
+
if (!(interactive instanceof HTMLElement))
|
|
247
|
+
return;
|
|
248
|
+
if (this.pendingFocusRestore?.target === interactive)
|
|
249
|
+
return;
|
|
250
|
+
this.queuePreviewFocusCleanup({
|
|
251
|
+
target: interactive,
|
|
252
|
+
restoreEditor: context.restoreEditor,
|
|
253
|
+
});
|
|
254
|
+
};
|
|
255
|
+
finishPreviewPointerFocus = (event) => {
|
|
256
|
+
const pending = this.pendingFocusRestore;
|
|
257
|
+
if (!pending)
|
|
258
|
+
return;
|
|
259
|
+
const pointerId = pointerIdFromEvent(event);
|
|
260
|
+
if (pointerId !== undefined
|
|
261
|
+
&& pending.pointerId !== null
|
|
262
|
+
&& pointerId !== pending.pointerId) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
this.pendingFocusRestore = undefined;
|
|
266
|
+
this.removeFocusRestoreListeners();
|
|
267
|
+
this.queuePreviewFocusCleanup(pending);
|
|
268
|
+
};
|
|
269
|
+
queuePreviewFocusCleanup(pending) {
|
|
270
|
+
const doc = this.preview.ownerDocument || document;
|
|
271
|
+
const win = doc.defaultView;
|
|
272
|
+
const cleanupFocus = () => {
|
|
273
|
+
if (!this.dom.isConnected)
|
|
274
|
+
return;
|
|
275
|
+
const active = doc.activeElement;
|
|
276
|
+
const clearedTarget = active === pending.target;
|
|
277
|
+
if (clearedTarget)
|
|
278
|
+
pending.target.blur();
|
|
279
|
+
const nextActive = doc.activeElement;
|
|
280
|
+
const canRestoreEditor = pending.restoreEditor
|
|
281
|
+
&& !this.editor.isDestroyed
|
|
282
|
+
&& (clearedTarget || nextActive === doc.body || nextActive === doc.documentElement);
|
|
283
|
+
if (canRestoreEditor) {
|
|
284
|
+
this.editor.commands.focus(undefined, { scrollIntoView: false });
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
win?.setTimeout(cleanupFocus, 0);
|
|
288
|
+
win?.requestAnimationFrame(cleanupFocus);
|
|
289
|
+
win?.setTimeout(cleanupFocus, 50);
|
|
290
|
+
}
|
|
291
|
+
cancelPreviewPointerFocus = (event) => {
|
|
292
|
+
this.finishPreviewPointerFocus(event);
|
|
293
|
+
};
|
|
198
294
|
constructor(node, props, options) {
|
|
199
295
|
this.node = node;
|
|
200
296
|
this.options = options;
|
|
@@ -211,7 +307,8 @@ class SlexKitCodeBlockNodeView {
|
|
|
211
307
|
label.textContent = options.previewLabel;
|
|
212
308
|
this.preview = createElement(doc, "div", "slex-tiptap-preview");
|
|
213
309
|
this.preview.setAttribute("contenteditable", "false");
|
|
214
|
-
this.preview.addEventListener("pointerdown",
|
|
310
|
+
this.preview.addEventListener("pointerdown", this.focusPreviewPointerTarget, { capture: true });
|
|
311
|
+
this.preview.addEventListener("focusin", this.clearPointerFocusedPreviewTarget, { capture: true });
|
|
215
312
|
this.preview.addEventListener("mousedown", focusPreviewInteractiveTarget, { capture: true });
|
|
216
313
|
this.preview.addEventListener("click", focusPreviewInteractiveTarget, { capture: true });
|
|
217
314
|
if (typeof MutationObserver !== "undefined") {
|
|
@@ -278,6 +375,8 @@ class SlexKitCodeBlockNodeView {
|
|
|
278
375
|
}
|
|
279
376
|
destroy() {
|
|
280
377
|
this.interactiveObserver?.disconnect();
|
|
378
|
+
this.removeFocusRestoreListeners();
|
|
379
|
+
this.preview.removeEventListener("focusin", this.clearPointerFocusedPreviewTarget, { capture: true });
|
|
281
380
|
this.preview.replaceChildren();
|
|
282
381
|
unregisterArtifactRuntime(this.editor, this.runtime, this);
|
|
283
382
|
}
|
|
@@ -315,6 +414,18 @@ class SlexKitCodeBlockNodeView {
|
|
|
315
414
|
scheduleArtifactRender(this.runtime);
|
|
316
415
|
});
|
|
317
416
|
}
|
|
417
|
+
addFocusRestoreListeners() {
|
|
418
|
+
const doc = this.preview.ownerDocument || document;
|
|
419
|
+
doc.addEventListener("pointerup", this.finishPreviewPointerFocus, { capture: true });
|
|
420
|
+
doc.addEventListener("pointercancel", this.cancelPreviewPointerFocus, { capture: true });
|
|
421
|
+
doc.defaultView?.addEventListener("blur", this.cancelPreviewPointerFocus);
|
|
422
|
+
}
|
|
423
|
+
removeFocusRestoreListeners() {
|
|
424
|
+
const doc = this.preview.ownerDocument || document;
|
|
425
|
+
doc.removeEventListener("pointerup", this.finishPreviewPointerFocus, { capture: true });
|
|
426
|
+
doc.removeEventListener("pointercancel", this.cancelPreviewPointerFocus, { capture: true });
|
|
427
|
+
doc.defaultView?.removeEventListener("blur", this.cancelPreviewPointerFocus);
|
|
428
|
+
}
|
|
318
429
|
renderWithRuntime(runtimeHost) {
|
|
319
430
|
const source = this.source();
|
|
320
431
|
this.dom.hidden = false;
|
package/package.json
CHANGED
|
@@ -1,66 +1,68 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@slexkit/tiptap",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Tiptap extension for SlexKit fenced UI blocks.",
|
|
5
|
-
"author": "SlexKit contributors",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/slexkit/slexkit.git",
|
|
10
|
-
"directory": "packages/tiptap"
|
|
11
|
-
},
|
|
12
|
-
"homepage": "https://github.com/slexkit/slexkit/tree/main/packages/tiptap#readme",
|
|
13
|
-
"bugs": {
|
|
14
|
-
"url": "https://github.com/slexkit/slexkit/issues"
|
|
15
|
-
},
|
|
16
|
-
"main": "./dist/index.js",
|
|
17
|
-
"module": "./dist/index.js",
|
|
18
|
-
"types": "./dist/index.d.ts",
|
|
19
|
-
"exports": {
|
|
20
|
-
".": {
|
|
21
|
-
"types": "./dist/index.d.ts",
|
|
22
|
-
"import": "./dist/index.js"
|
|
23
|
-
},
|
|
24
|
-
"./style.css": "./style.css"
|
|
25
|
-
},
|
|
26
|
-
"files": [
|
|
27
|
-
"dist/",
|
|
28
|
-
"style.css",
|
|
29
|
-
"README.md",
|
|
30
|
-
"LICENSE"
|
|
31
|
-
],
|
|
32
|
-
"scripts": {
|
|
33
|
-
"build": "bun run scripts/build.ts"
|
|
34
|
-
},
|
|
35
|
-
"keywords": [
|
|
36
|
-
"slexkit",
|
|
37
|
-
"tiptap",
|
|
38
|
-
"prosemirror",
|
|
39
|
-
"markdown",
|
|
40
|
-
"editor"
|
|
41
|
-
],
|
|
42
|
-
"license": "MIT",
|
|
43
|
-
"publishConfig": {
|
|
44
|
-
"access": "public"
|
|
45
|
-
},
|
|
46
|
-
"peerDependencies": {
|
|
47
|
-
"@tiptap/core": "^3.0.0",
|
|
48
|
-
"@tiptap/extension-code-block": "^3.0.0",
|
|
49
|
-
"@tiptap/markdown": "^3.0.0",
|
|
50
|
-
"@tiptap/pm": "^3.0.0",
|
|
51
|
-
"slexkit": "^0.
|
|
52
|
-
},
|
|
53
|
-
"peerDependenciesMeta": {
|
|
54
|
-
"
|
|
55
|
-
"optional": true
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"@tiptap/
|
|
63
|
-
"@tiptap/
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@slexkit/tiptap",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Tiptap extension for SlexKit fenced UI blocks.",
|
|
5
|
+
"author": "SlexKit contributors",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/slexkit/slexkit.git",
|
|
10
|
+
"directory": "packages/tiptap"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/slexkit/slexkit/tree/main/packages/tiptap#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/slexkit/slexkit/issues"
|
|
15
|
+
},
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"module": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./style.css": "./style.css"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/",
|
|
28
|
+
"style.css",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "bun run scripts/build.ts"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"slexkit",
|
|
37
|
+
"tiptap",
|
|
38
|
+
"prosemirror",
|
|
39
|
+
"markdown",
|
|
40
|
+
"editor"
|
|
41
|
+
],
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@tiptap/core": "^3.0.0",
|
|
48
|
+
"@tiptap/extension-code-block": "^3.0.0",
|
|
49
|
+
"@tiptap/markdown": "^3.0.0",
|
|
50
|
+
"@tiptap/pm": "^3.0.0",
|
|
51
|
+
"slexkit": "^0.4.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"slexkit": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"@tiptap/markdown": {
|
|
58
|
+
"optional": true
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@tiptap/core": "^3.27.1",
|
|
63
|
+
"@tiptap/extension-code-block": "^3.27.1",
|
|
64
|
+
"@tiptap/markdown": "^3.27.1",
|
|
65
|
+
"@tiptap/pm": "^3.27.1",
|
|
66
|
+
"@tiptap/starter-kit": "^3.27.1"
|
|
67
|
+
}
|
|
68
|
+
}
|