@pilotiq/tiptap 3.4.0 → 3.6.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.
Files changed (39) hide show
  1. package/dist/extensions/AiInlineDiffExtension.d.ts +82 -0
  2. package/dist/extensions/AiInlineDiffExtension.d.ts.map +1 -0
  3. package/dist/extensions/AiInlineDiffExtension.js +205 -0
  4. package/dist/extensions/AiInlineDiffExtension.js.map +1 -0
  5. package/dist/extensions/AiSuggestionExtension.d.ts.map +1 -1
  6. package/dist/extensions/AiSuggestionExtension.js +108 -0
  7. package/dist/extensions/AiSuggestionExtension.js.map +1 -1
  8. package/dist/markdownExtension.js +0 -1
  9. package/dist/react/AiSuggestionBanner.d.ts +72 -0
  10. package/dist/react/AiSuggestionBanner.d.ts.map +1 -0
  11. package/dist/react/AiSuggestionBanner.js +72 -0
  12. package/dist/react/AiSuggestionBanner.js.map +1 -0
  13. package/dist/react/CollabTextRenderer.d.ts.map +1 -1
  14. package/dist/react/CollabTextRenderer.js +62 -27
  15. package/dist/react/CollabTextRenderer.js.map +1 -1
  16. package/dist/react/MarkdownEditor.d.ts.map +1 -1
  17. package/dist/react/MarkdownEditor.js +62 -7
  18. package/dist/react/MarkdownEditor.js.map +1 -1
  19. package/dist/react/TiptapEditor.d.ts.map +1 -1
  20. package/dist/react/TiptapEditor.js +47 -5
  21. package/dist/react/TiptapEditor.js.map +1 -1
  22. package/dist/react/useAiInlineDiff.d.ts +57 -0
  23. package/dist/react/useAiInlineDiff.d.ts.map +1 -0
  24. package/dist/react/useAiInlineDiff.js +121 -0
  25. package/dist/react/useAiInlineDiff.js.map +1 -0
  26. package/dist/react/useAiSuggestionBridge.d.ts +37 -1
  27. package/dist/react/useAiSuggestionBridge.d.ts.map +1 -1
  28. package/dist/react/useAiSuggestionBridge.js +63 -32
  29. package/dist/react/useAiSuggestionBridge.js.map +1 -1
  30. package/package.json +26 -24
  31. package/src/extensions/AiInlineDiffExtension.ts +263 -0
  32. package/src/extensions/AiSuggestionExtension.ts +107 -0
  33. package/src/react/AiSuggestionBanner.tsx +184 -0
  34. package/src/react/CollabTextRenderer.tsx +61 -27
  35. package/src/react/MarkdownEditor.tsx +62 -6
  36. package/src/react/TiptapEditor.tsx +48 -4
  37. package/src/react/useAiInlineDiff.ts +146 -0
  38. package/src/react/useAiSuggestionBridge.ts +105 -9
  39. package/dist/markdownExtension.js.map +0 -7
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Bridge between the host's `<PendingSuggestionsContext>` queue and the
3
+ * editor's `AiInlineDiffExtension`. When a whole-field suggestion arrives
4
+ * for the field, the hook:
5
+ *
6
+ * 1. Parses the suggested value into a ProseMirror `Slice` via the
7
+ * renderer-supplied parser. Each Tiptap surface owns its own
8
+ * content shape — markdown source for `MarkdownEditor`, HTML / JSON
9
+ * for `TiptapEditor`, plain text for `CollabTextRenderer`.
10
+ * 2. Calls `editor.commands.startAiInlineDiff(id, slice)` — the
11
+ * extension snapshots the current doc as the baseline, replaces
12
+ * the doc content with the proposed slice, and starts a
13
+ * `prosemirror-changeset` tracking the diff.
14
+ * 3. Registers an applier on the cross-tree pending-suggestion
15
+ * registry so the host's `<AiSuggestionBanner>` Accept button (and
16
+ * any other surface calling `pendingSuggestions.approve(id)`) runs
17
+ * `acceptAiInlineDiff()` instead of the legacy `onApplyWholeField`
18
+ * callback. The current doc IS the accepted state — no extra
19
+ * content swap needed.
20
+ *
21
+ * Reject handling: not registered on the applier (the registry only
22
+ * tracks Approve). Renderers wire Reject through the banner's
23
+ * `onRejectWithEditor` prop, which calls `rejectAiInlineDiff()` to revert
24
+ * the doc to the baseline before dismissing the suggestion.
25
+ *
26
+ * Defensive: only one inline diff active at a time per editor. If a new
27
+ * synthesized suggestion arrives while one is still pending review, the
28
+ * hook drops it (the producer should have waited). This matches
29
+ * `AiSuggestionExtension`'s chip path which also allows only one
30
+ * suggestion at a time per id.
31
+ */
32
+ import { useEffect, useRef } from 'react';
33
+ import { registerPendingSuggestionApplier, usePendingSuggestionsForField, } from '@pilotiq/pilotiq/react';
34
+ import { aiInlineDiffPluginKey } from '../extensions/AiInlineDiffExtension.js';
35
+ /**
36
+ * Returns whether a diff is currently active in the editor. Hosts use
37
+ * this to gate the banner's UI between the legacy `onApplyWholeField`
38
+ * mode and the diff-aware mode (Reject routes through
39
+ * `rejectAiInlineDiff` to revert the doc).
40
+ */
41
+ export function useIsAiInlineDiffActive(editor) {
42
+ // Re-render on every editor transaction so the hook tracks state
43
+ // changes (start / accept / reject). useEditorState would be the
44
+ // idiomatic way; we read directly here to keep the dep surface tiny.
45
+ const [, force] = useReducerForceUpdate();
46
+ useEffect(() => {
47
+ if (!editor)
48
+ return;
49
+ const handler = () => force();
50
+ editor.on('transaction', handler);
51
+ return () => { editor.off('transaction', handler); };
52
+ }, [editor, force]);
53
+ if (!editor)
54
+ return false;
55
+ return aiInlineDiffPluginKey.getState(editor.state) !== null;
56
+ }
57
+ export function useAiInlineDiff(editor, fieldName, options) {
58
+ const { list } = usePendingSuggestionsForField(fieldName);
59
+ const parseRef = useRef(options.parseSuggestion);
60
+ useEffect(() => { parseRef.current = options.parseSuggestion; }, [options.parseSuggestion]);
61
+ // Track which ids we've handed off to the editor's diff extension
62
+ // so we don't re-start the diff every render or for already-active
63
+ // suggestions.
64
+ const startedRef = useRef(new Set());
65
+ // Context → editor: start the diff for each new whole-field suggestion.
66
+ useEffect(() => {
67
+ if (!editor)
68
+ return;
69
+ const wholeField = list.filter(s => !hasEditorRange(s));
70
+ for (const s of wholeField) {
71
+ if (startedRef.current.has(s.id))
72
+ continue;
73
+ if (typeof s.suggestedValue !== 'string')
74
+ continue;
75
+ // Bail when a different diff is already showing — one at a time.
76
+ // Producer should serialize calls; if not, the second suggestion
77
+ // sits in the queue until the first is approved/rejected.
78
+ if (aiInlineDiffPluginKey.getState(editor.state) !== null)
79
+ continue;
80
+ const slice = parseRef.current(editor, s.suggestedValue);
81
+ if (!slice)
82
+ continue;
83
+ editor.commands.startAiInlineDiff(s.id, slice);
84
+ startedRef.current.add(s.id);
85
+ }
86
+ // Cleanup: when a suggestion leaves the context AND we previously
87
+ // started a diff for it, the editor should drop the diff state too.
88
+ // Approve dismisses via context → here we drop from startedRef.
89
+ const contextIds = new Set(list.map(s => s.id));
90
+ for (const id of Array.from(startedRef.current)) {
91
+ if (!contextIds.has(id))
92
+ startedRef.current.delete(id);
93
+ }
94
+ }, [editor, list]);
95
+ // Cross-tree applier — when the banner / chat-sidebar pill calls
96
+ // `pendingSuggestions.approve(id)` for one of our tracked suggestions,
97
+ // accept the diff. Editor is the source of truth for the new doc.
98
+ useEffect(() => {
99
+ if (!editor)
100
+ return;
101
+ const applier = (suggestion) => {
102
+ if (!startedRef.current.has(suggestion.id))
103
+ return;
104
+ editor.commands.acceptAiInlineDiff();
105
+ };
106
+ return registerPendingSuggestionApplier(undefined, fieldName, applier);
107
+ }, [editor, fieldName]);
108
+ }
109
+ function hasEditorRange(s) {
110
+ const meta = (s.meta ?? {});
111
+ const range = meta['editorRange'];
112
+ return !!(range && typeof range.from === 'number' && typeof range.to === 'number');
113
+ }
114
+ // useReducer + dispatch is the smallest-API force-update primitive React
115
+ // ships. Hoisted into a helper so the call site stays one line.
116
+ import { useReducer } from 'react';
117
+ function useReducerForceUpdate() {
118
+ const [n, inc] = useReducer((x) => (x + 1) | 0, 0);
119
+ return [n, () => inc()];
120
+ }
121
+ //# sourceMappingURL=useAiInlineDiff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAiInlineDiff.js","sourceRoot":"","sources":["../../src/react/useAiInlineDiff.ts"],"names":[],"mappings":"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"}
@@ -21,7 +21,43 @@ import { type PendingSuggestion } from '@pilotiq/pilotiq/react';
21
21
  * hook had previously pushed (so an id added directly by host code via
22
22
  * `editor.commands.addAiSuggestion(...)` doesn't get reflected back through
23
23
  * a context that never knew about it).
24
+ *
25
+ * **Whole-field fallback** (chat-driven suggestions). Producers like
26
+ * `@pilotiq-pro/ai`'s `update_form_state` tool push suggestions that target
27
+ * the whole field — no `meta.editorRange`, just `suggestedValue` as a string.
28
+ * Without `editorRange` the bridge can't render the inline-diff chip widget
29
+ * (it has nowhere to anchor), so the host renderer passes an
30
+ * `onApplyWholeField(value)` callback. When the chat-sidebar Approve fires
31
+ * for a non-bridge-pushed id, the registered applier calls this callback
32
+ * instead of no-op'ing — letting each renderer apply the suggestion the
33
+ * right way for its shape (plain text → `plainTextToDoc`, markdown → set
34
+ * markdown source, richtext → setContent with HTML/JSON). The host is also
35
+ * responsible for the Approve UI — FieldShell hides its legacy overlay
36
+ * whenever a Tiptap renderer is mounted (richtext / markdown / collab text).
24
37
  */
25
- export declare function useAiSuggestionBridge(editor: Editor | null, fieldName: string): void;
38
+ export interface UseAiSuggestionBridgeOptions {
39
+ /**
40
+ * Apply a whole-field suggestion that lacks `meta.editorRange`. Each
41
+ * Tiptap renderer passes its own implementation (different content
42
+ * shapes — plain text, markdown source, HTML/JSON). Omit for editors
43
+ * that should ignore whole-field suggestions entirely.
44
+ */
45
+ onApplyWholeField?: (suggestedValue: string) => void;
46
+ /**
47
+ * Synthesize a `{ from, to }` range for whole-field suggestions so the
48
+ * inline-diff chip widget can render BEFORE the user approves. The
49
+ * extension's `applyApprove` inserts a plain text node spanning the
50
+ * synthesized range — safe only for editors whose schema accepts a
51
+ * text-node replacement covering the whole doc (CollabTextRenderer's
52
+ * plain-text schema fits; richtext / markdown lose formatting if
53
+ * approved that way). Return `undefined` to skip synthesis and fall
54
+ * through to the legacy `onApplyWholeField` callback (silent swap).
55
+ */
56
+ synthesizeWholeFieldRange?: (editor: Editor, suggestion: PendingSuggestion) => {
57
+ from: number;
58
+ to: number;
59
+ } | undefined;
60
+ }
61
+ export declare function useAiSuggestionBridge(editor: Editor | null, fieldName: string, options?: UseAiSuggestionBridgeOptions): void;
26
62
  export type { PendingSuggestion };
27
63
  //# sourceMappingURL=useAiSuggestionBridge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAiSuggestionBridge.d.ts","sourceRoot":"","sources":["../../src/react/useAiSuggestionBridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAGL,KAAK,iBAAiB,EAEvB,MAAM,wBAAwB,CAAA;AAG/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAiFpF;AAKD,YAAY,EAAE,iBAAiB,EAAE,CAAA"}
1
+ {"version":3,"file":"useAiSuggestionBridge.d.ts","sourceRoot":"","sources":["../../src/react/useAiSuggestionBridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAGL,KAAK,iBAAiB,EAEvB,MAAM,wBAAwB,CAAA;AAG/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAA;IAEpD;;;;;;;;;OASG;IACH,yBAAyB,CAAC,EAAE,CAC1B,MAAM,EAAM,MAAM,EAClB,UAAU,EAAE,iBAAiB,KAC1B;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;CAC9C;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,4BAAiC,GACzC,IAAI,CAuIN;AAKD,YAAY,EAAE,iBAAiB,EAAE,CAAA"}
@@ -1,36 +1,29 @@
1
1
  import { useEffect, useRef } from 'react';
2
2
  import { registerPendingSuggestionApplier, usePendingSuggestionsForField, } from '@pilotiq/pilotiq/react';
3
3
  import { aiSuggestionPluginKey } from '../extensions/AiSuggestionExtension.js';
4
- /**
5
- * Two-way sync between the cross-package `<PendingSuggestionsContext>`
6
- * queue and this editor's `AiSuggestionExtension` state.
7
- *
8
- * - **Context → editor**: every entry whose `meta.editorRange = { from, to }`
9
- * is present and whose `suggestedValue` is a string gets pushed into the
10
- * editor as an inline-diff hunk via `addAiSuggestion`. Entries leaving the
11
- * queue are removed from the editor via `rejectAiSuggestion` (no doc edit).
12
- *
13
- * - **Editor → context**: when a chip's Approve / Reject button removes a
14
- * hunk from the editor's plugin state, the matching id is dismissed from
15
- * the queue (`dismiss(id)`) so other surfaces (e.g. the chat-sidebar pill,
16
- * a future FieldShell overlay) clear in lock-step. The doc mutation
17
- * itself happens inside the editor — context is just a notification.
18
- *
19
- * Cycle protection: the hook tracks which ids it has personally pushed to
20
- * the editor (`pushed`). The Context→editor pass never re-pushes an id that's
21
- * already there, and the Editor→context pass only dismisses ids that this
22
- * hook had previously pushed (so an id added directly by host code via
23
- * `editor.commands.addAiSuggestion(...)` doesn't get reflected back through
24
- * a context that never knew about it).
25
- */
26
- export function useAiSuggestionBridge(editor, fieldName) {
4
+ export function useAiSuggestionBridge(editor, fieldName, options = {}) {
27
5
  const { list, dismiss } = usePendingSuggestionsForField(fieldName);
28
6
  // Hold the latest `dismiss` in a ref so the editor-side listener — which
29
7
  // installs once per editor — always reaches the up-to-date context API.
30
8
  const dismissRef = useRef(dismiss);
31
9
  useEffect(() => { dismissRef.current = dismiss; }, [dismiss]);
10
+ // Same ref pattern for the whole-field applier — captured here so the
11
+ // applier closure registered below stays stable across re-renders without
12
+ // re-registering on every option change.
13
+ const onApplyWholeFieldRef = useRef(options.onApplyWholeField);
14
+ useEffect(() => { onApplyWholeFieldRef.current = options.onApplyWholeField; }, [options.onApplyWholeField]);
15
+ const synthesizeRangeRef = useRef(options.synthesizeWholeFieldRange);
16
+ useEffect(() => { synthesizeRangeRef.current = options.synthesizeWholeFieldRange; }, [options.synthesizeWholeFieldRange]);
32
17
  // Set of ids this hook pushed; used by both directions for cycle control.
33
18
  const pushedRef = useRef(new Set());
19
+ // Subset of `pushedRef` whose range was synthesized (no producer-supplied
20
+ // `meta.editorRange`). Approving these must NOT route through the chip's
21
+ // plain-text replace — that would clobber HTML / markdown formatting on
22
+ // rich editors. Instead the applier delegates to `onApplyWholeField`,
23
+ // which sets content via the renderer's content-shape-aware command
24
+ // (`setContent(plainTextToDoc(...))` / `setContent(markdownSrc)` /
25
+ // `setContent(html)`), then clears the chip without a doc edit.
26
+ const synthesizedRef = useRef(new Set());
34
27
  // Context → editor.
35
28
  useEffect(() => {
36
29
  if (!editor)
@@ -40,9 +33,25 @@ export function useAiSuggestionBridge(editor, fieldName) {
40
33
  if (pushedRef.current.has(s.id))
41
34
  continue;
42
35
  const meta = (s.meta ?? {});
43
- const range = meta['editorRange'];
44
- if (!range || typeof range.from !== 'number' || typeof range.to !== 'number')
45
- continue;
36
+ const rawRange = meta['editorRange'];
37
+ let range;
38
+ let isSynthesized = false;
39
+ if (rawRange && typeof rawRange.from === 'number' && typeof rawRange.to === 'number') {
40
+ range = { from: rawRange.from, to: rawRange.to };
41
+ }
42
+ else {
43
+ // Producer didn't supply a range — let the renderer synthesize one
44
+ // so the inline-diff chip widget can still render. Renderers that
45
+ // can't safely round-trip a plain-text replace (richtext/markdown
46
+ // losing formatting on approve) STILL benefit by synthesizing for
47
+ // visualization — the applier below routes Approve through
48
+ // `onApplyWholeField` for synthesized ids instead of the chip's
49
+ // text-node replace.
50
+ range = synthesizeRangeRef.current?.(editor, s);
51
+ if (!range)
52
+ continue;
53
+ isSynthesized = true;
54
+ }
46
55
  const replacement = typeof s.suggestedValue === 'string' ? s.suggestedValue : '';
47
56
  editor.commands.addAiSuggestion({
48
57
  id: s.id,
@@ -52,6 +61,8 @@ export function useAiSuggestionBridge(editor, fieldName) {
52
61
  ...(s.source ? { source: s.source } : {}),
53
62
  });
54
63
  pushedRef.current.add(s.id);
64
+ if (isSynthesized)
65
+ synthesizedRef.current.add(s.id);
55
66
  }
56
67
  for (const id of Array.from(pushedRef.current)) {
57
68
  if (contextIds.has(id))
@@ -60,6 +71,7 @@ export function useAiSuggestionBridge(editor, fieldName) {
60
71
  // mutating the doc (rejectAiSuggestion drops state only).
61
72
  editor.commands.rejectAiSuggestion(id);
62
73
  pushedRef.current.delete(id);
74
+ synthesizedRef.current.delete(id);
63
75
  }
64
76
  }, [editor, list]);
65
77
  // Editor → context.
@@ -92,13 +104,32 @@ export function useAiSuggestionBridge(editor, fieldName) {
92
104
  if (!editor)
93
105
  return;
94
106
  const applier = (suggestion) => {
95
- // Bail when the suggestion isn't one of ours (no editor range or
96
- // bridge-pushed entry). Pro provider falls back to plain dismiss.
97
- if (!pushedRef.current.has(suggestion.id))
107
+ const apply = onApplyWholeFieldRef.current;
108
+ const hasSynthesized = synthesizedRef.current.has(suggestion.id);
109
+ const hasPushed = pushedRef.current.has(suggestion.id);
110
+ // Synthesized whole-field range — the chip rendered for visualization,
111
+ // but routing Approve through the editor's `approveAiSuggestion` would
112
+ // do a plain-text replace and clobber HTML / markdown formatting.
113
+ // Delegate to the renderer-supplied applier (content-shape-aware)
114
+ // and clear the chip state without a doc edit.
115
+ if (hasSynthesized && apply && typeof suggestion.suggestedValue === 'string') {
116
+ apply(suggestion.suggestedValue);
117
+ editor.commands.rejectAiSuggestion(suggestion.id);
98
118
  return;
99
- editor.chain().focus().approveAiSuggestion(suggestion.id).run();
100
- // The transaction listener above sees the editor state drop the id
101
- // and calls `dismiss(id)` on its own no manual mirror needed.
119
+ }
120
+ // Producer-supplied editor range surgical edit. Forward Approve to
121
+ // the editor command; the transaction listener above mirrors the
122
+ // dismiss back into context.
123
+ if (hasPushed) {
124
+ editor.chain().focus().approveAiSuggestion(suggestion.id).run();
125
+ return;
126
+ }
127
+ // Whole-field path WITHOUT visualization — producer skipped the range
128
+ // and the renderer didn't synthesize. Same applier as above, no chip
129
+ // to clear. Context's `approve()` dismisses the queue entry.
130
+ if (apply && typeof suggestion.suggestedValue === 'string') {
131
+ apply(suggestion.suggestedValue);
132
+ }
102
133
  };
103
134
  // Editor renderers don't currently have access to a `formId` here;
104
135
  // pass `undefined` so the wildcard form scope resolves. Phase 8.5+
@@ -1 +1 @@
1
- {"version":3,"file":"useAiSuggestionBridge.js","sourceRoot":"","sources":["../../src/react/useAiSuggestionBridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useAiSuggestionBridge.js","sourceRoot":"","sources":["../../src/react/useAiSuggestionBridge.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pilotiq/tiptap",
3
- "version": "3.4.0",
3
+ "version": "3.6.0",
4
4
  "description": "Tiptap rich-text editor adapter for @pilotiq/pilotiq — slash menu, draggable blocks, custom-block API",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -30,26 +30,28 @@
30
30
  "types": "./dist/render.d.ts"
31
31
  }
32
32
  },
33
- "dependencies": {},
33
+ "dependencies": {
34
+ "prosemirror-changeset": "^2.4.1"
35
+ },
34
36
  "peerDependencies": {
35
- "@pilotiq/pilotiq": ">=0.6.0 <1.0.0",
36
37
  "@base-ui/react": "^1",
38
+ "@pilotiq/pilotiq": ">=0.6.0 <1.0.0",
37
39
  "@tiptap/core": "^3",
38
- "@tiptap/pm": "^3",
39
- "@tiptap/react": "^3",
40
- "@tiptap/starter-kit": "^3",
40
+ "@tiptap/extension-color": "3.22.4",
41
+ "@tiptap/extension-details": "3.22.4",
42
+ "@tiptap/extension-highlight": "3.22.4",
43
+ "@tiptap/extension-image": "3.22.4",
41
44
  "@tiptap/extension-link": "^3",
42
45
  "@tiptap/extension-placeholder": "^3",
43
- "@tiptap/extension-underline": "3.22.4",
44
46
  "@tiptap/extension-subscript": "3.22.4",
45
47
  "@tiptap/extension-superscript": "3.22.4",
48
+ "@tiptap/extension-table": "3.22.4",
46
49
  "@tiptap/extension-text-align": "3.22.4",
47
50
  "@tiptap/extension-text-style": "3.22.4",
48
- "@tiptap/extension-color": "3.22.4",
49
- "@tiptap/extension-highlight": "3.22.4",
50
- "@tiptap/extension-image": "3.22.4",
51
- "@tiptap/extension-table": "3.22.4",
52
- "@tiptap/extension-details": "3.22.4",
51
+ "@tiptap/extension-underline": "3.22.4",
52
+ "@tiptap/pm": "^3",
53
+ "@tiptap/react": "^3",
54
+ "@tiptap/starter-kit": "^3",
53
55
  "@tiptap/suggestion": "^3",
54
56
  "react": "^18 || ^19",
55
57
  "react-dom": "^18 || ^19"
@@ -57,36 +59,36 @@
57
59
  "devDependencies": {
58
60
  "@base-ui/react": "^1",
59
61
  "@tiptap/core": "^3",
60
- "@tiptap/pm": "^3",
61
- "@tiptap/react": "^3",
62
- "@tiptap/starter-kit": "^3",
62
+ "@tiptap/extension-color": "3.22.4",
63
+ "@tiptap/extension-details": "3.22.4",
64
+ "@tiptap/extension-highlight": "3.22.4",
65
+ "@tiptap/extension-image": "3.22.4",
63
66
  "@tiptap/extension-link": "^3",
64
67
  "@tiptap/extension-placeholder": "^3",
65
- "@tiptap/extension-underline": "3.22.4",
66
68
  "@tiptap/extension-subscript": "3.22.4",
67
69
  "@tiptap/extension-superscript": "3.22.4",
70
+ "@tiptap/extension-table": "3.22.4",
68
71
  "@tiptap/extension-text-align": "3.22.4",
69
72
  "@tiptap/extension-text-style": "3.22.4",
70
- "@tiptap/extension-color": "3.22.4",
71
- "@tiptap/extension-highlight": "3.22.4",
72
- "@tiptap/extension-image": "3.22.4",
73
- "@tiptap/extension-table": "3.22.4",
74
- "@tiptap/extension-details": "3.22.4",
73
+ "@tiptap/extension-underline": "3.22.4",
74
+ "@tiptap/pm": "^3",
75
+ "@tiptap/react": "^3",
76
+ "@tiptap/starter-kit": "^3",
75
77
  "@tiptap/suggestion": "^3",
76
- "tiptap-markdown": "^0.9",
77
78
  "@types/node": "^20",
78
79
  "@types/react": "^19",
79
80
  "@types/react-dom": "^19",
80
81
  "esbuild": "^0.27",
81
82
  "react": "^19",
82
83
  "react-dom": "^19",
84
+ "tiptap-markdown": "^0.9",
83
85
  "typescript": "^5",
84
- "@pilotiq/pilotiq": "^0.18.0"
86
+ "@pilotiq/pilotiq": "^0.19.0"
85
87
  },
86
88
  "author": "Suleiman Shahbari",
87
89
  "scripts": {
88
90
  "build": "tsc -p tsconfig.build.json && pnpm run bundle:markdown",
89
- "bundle:markdown": "esbuild src/markdownExtension.ts --bundle --format=esm --outfile=dist/markdownExtension.js --external:@tiptap/* --sourcemap",
91
+ "bundle:markdown": "esbuild src/markdownExtension.ts --bundle --format=esm --outfile=dist/markdownExtension.js --external:@tiptap/* && rm -f dist/markdownExtension.js.map",
90
92
  "dev": "tsc -p tsconfig.build.json --watch",
91
93
  "typecheck": "tsc --noEmit",
92
94
  "lint": "eslint src",