@pilotiq/tiptap 3.5.0 → 3.7.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/dist/extensions/AiInlineDiffExtension.d.ts +96 -0
- package/dist/extensions/AiInlineDiffExtension.d.ts.map +1 -0
- package/dist/extensions/AiInlineDiffExtension.js +216 -0
- package/dist/extensions/AiInlineDiffExtension.js.map +1 -0
- package/dist/extensions/AiSuggestionExtension.d.ts.map +1 -1
- package/dist/extensions/AiSuggestionExtension.js +51 -0
- package/dist/extensions/AiSuggestionExtension.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/react/AiSuggestionBanner.d.ts +72 -0
- package/dist/react/AiSuggestionBanner.d.ts.map +1 -0
- package/dist/react/AiSuggestionBanner.js +72 -0
- package/dist/react/AiSuggestionBanner.js.map +1 -0
- package/dist/react/MarkdownEditor.d.ts.map +1 -1
- package/dist/react/MarkdownEditor.js +58 -20
- package/dist/react/MarkdownEditor.js.map +1 -1
- package/dist/react/TiptapEditor.d.ts.map +1 -1
- package/dist/react/TiptapEditor.js +43 -18
- package/dist/react/TiptapEditor.js.map +1 -1
- package/dist/react/useAiInlineDiff.d.ts +57 -0
- package/dist/react/useAiInlineDiff.d.ts.map +1 -0
- package/dist/react/useAiInlineDiff.js +218 -0
- package/dist/react/useAiInlineDiff.js.map +1 -0
- package/dist/surgicalOps.d.ts +72 -0
- package/dist/surgicalOps.d.ts.map +1 -0
- package/dist/surgicalOps.js +160 -0
- package/dist/surgicalOps.js.map +1 -0
- package/package.json +24 -22
- package/src/extensions/AiInlineDiffExtension.ts +286 -0
- package/src/extensions/AiSuggestionExtension.ts +51 -0
- package/src/index.ts +15 -0
- package/src/react/AiSuggestionBanner.tsx +184 -0
- package/src/react/MarkdownEditor.tsx +58 -19
- package/src/react/TiptapEditor.tsx +44 -16
- package/src/react/useAiInlineDiff.ts +267 -0
- package/src/surgicalOps.ts +186 -0
|
@@ -0,0 +1,218 @@
|
|
|
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 { useEditorState } from '@tiptap/react';
|
|
34
|
+
import { registerPendingSuggestionApplier, usePendingSuggestionsForField, } from '@pilotiq/pilotiq/react';
|
|
35
|
+
import { aiInlineDiffPluginKey } from '../extensions/AiInlineDiffExtension.js';
|
|
36
|
+
import { planReplaceBlock, planInsertBlockBefore, planDeleteBlock, planUpdateBlockMark, } from '../surgicalOps.js';
|
|
37
|
+
/**
|
|
38
|
+
* Returns whether a diff is currently active in the editor. Hosts use
|
|
39
|
+
* this to gate the banner's UI between the legacy `onApplyWholeField`
|
|
40
|
+
* mode and the diff-aware mode (Reject routes through
|
|
41
|
+
* `rejectAiInlineDiff` to revert the doc).
|
|
42
|
+
*/
|
|
43
|
+
export function useIsAiInlineDiffActive(editor) {
|
|
44
|
+
const active = useEditorState({
|
|
45
|
+
editor,
|
|
46
|
+
selector: ({ editor: ed }) => !!ed && aiInlineDiffPluginKey.getState(ed.state) !== null,
|
|
47
|
+
});
|
|
48
|
+
return active ?? false;
|
|
49
|
+
}
|
|
50
|
+
export function useAiInlineDiff(editor, fieldName, options) {
|
|
51
|
+
const { list } = usePendingSuggestionsForField(fieldName);
|
|
52
|
+
const parseRef = useRef(options.parseSuggestion);
|
|
53
|
+
useEffect(() => { parseRef.current = options.parseSuggestion; }, [options.parseSuggestion]);
|
|
54
|
+
// Track which ids we've handed off to the editor's diff extension
|
|
55
|
+
// so we don't re-start the diff every render or for already-active
|
|
56
|
+
// suggestions.
|
|
57
|
+
const startedRef = useRef(new Set());
|
|
58
|
+
// Context → editor: start the diff for each new whole-field /
|
|
59
|
+
// surgical-block suggestion. `meta.surgical` (if present) routes to a
|
|
60
|
+
// precise PM transaction; otherwise we treat the suggested value as a
|
|
61
|
+
// whole-field replacement. `meta.editorRange` (chip path) is filtered
|
|
62
|
+
// out — handled by AiSuggestionExtension elsewhere.
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (!editor)
|
|
65
|
+
return;
|
|
66
|
+
const diffable = list.filter(s => !hasEditorRange(s));
|
|
67
|
+
for (const s of diffable) {
|
|
68
|
+
if (startedRef.current.has(s.id))
|
|
69
|
+
continue;
|
|
70
|
+
// Bail when a different diff is already showing — one at a time.
|
|
71
|
+
// Producer should serialize calls; if not, the second suggestion
|
|
72
|
+
// sits in the queue until the first is approved/rejected.
|
|
73
|
+
if (aiInlineDiffPluginKey.getState(editor.state) !== null)
|
|
74
|
+
continue;
|
|
75
|
+
const surgical = readSurgicalMeta(s);
|
|
76
|
+
if (surgical) {
|
|
77
|
+
const modifier = planSurgicalModifier(editor, surgical);
|
|
78
|
+
if (!modifier)
|
|
79
|
+
continue;
|
|
80
|
+
editor.commands.applySurgicalAiInlineDiff(s.id, modifier);
|
|
81
|
+
startedRef.current.add(s.id);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (typeof s.suggestedValue !== 'string')
|
|
85
|
+
continue;
|
|
86
|
+
const slice = parseRef.current(editor, s.suggestedValue);
|
|
87
|
+
if (!slice)
|
|
88
|
+
continue;
|
|
89
|
+
editor.commands.startAiInlineDiff(s.id, slice);
|
|
90
|
+
startedRef.current.add(s.id);
|
|
91
|
+
}
|
|
92
|
+
// Cleanup: when a suggestion leaves the context AND we previously
|
|
93
|
+
// started a diff for it, the editor should drop the diff state too.
|
|
94
|
+
// Approve dismisses via context → here we drop from startedRef.
|
|
95
|
+
const contextIds = new Set(list.map(s => s.id));
|
|
96
|
+
for (const id of Array.from(startedRef.current)) {
|
|
97
|
+
if (!contextIds.has(id))
|
|
98
|
+
startedRef.current.delete(id);
|
|
99
|
+
}
|
|
100
|
+
}, [editor, list]);
|
|
101
|
+
// Cross-tree applier — when the banner / chat-sidebar pill calls
|
|
102
|
+
// `pendingSuggestions.approve(id)` for one of our tracked suggestions,
|
|
103
|
+
// accept the diff. Editor is the source of truth for the new doc.
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!editor)
|
|
106
|
+
return;
|
|
107
|
+
const applier = (suggestion) => {
|
|
108
|
+
if (!startedRef.current.has(suggestion.id))
|
|
109
|
+
return;
|
|
110
|
+
editor.commands.acceptAiInlineDiff();
|
|
111
|
+
};
|
|
112
|
+
return registerPendingSuggestionApplier(undefined, fieldName, applier);
|
|
113
|
+
}, [editor, fieldName]);
|
|
114
|
+
}
|
|
115
|
+
function hasEditorRange(s) {
|
|
116
|
+
const meta = (s.meta ?? {});
|
|
117
|
+
const range = meta['editorRange'];
|
|
118
|
+
return !!(range && typeof range.from === 'number' && typeof range.to === 'number');
|
|
119
|
+
}
|
|
120
|
+
function parseSurgicalOp(obj) {
|
|
121
|
+
const op = obj['op'];
|
|
122
|
+
const blockIndex = obj['blockIndex'];
|
|
123
|
+
if (typeof blockIndex !== 'number')
|
|
124
|
+
return null;
|
|
125
|
+
switch (op) {
|
|
126
|
+
case 'replace_block':
|
|
127
|
+
case 'insert_block_before': {
|
|
128
|
+
const content = obj['content'];
|
|
129
|
+
if (typeof content !== 'string')
|
|
130
|
+
return null;
|
|
131
|
+
return { op, blockIndex, content };
|
|
132
|
+
}
|
|
133
|
+
case 'delete_block':
|
|
134
|
+
return { op, blockIndex };
|
|
135
|
+
case 'update_block_mark': {
|
|
136
|
+
const mark = obj['mark'];
|
|
137
|
+
const range = obj['range'];
|
|
138
|
+
const apply = obj['apply'];
|
|
139
|
+
const attrs = obj['attrs'];
|
|
140
|
+
if (typeof mark !== 'string')
|
|
141
|
+
return null;
|
|
142
|
+
if (!range || typeof range.from !== 'number' || typeof range.to !== 'number')
|
|
143
|
+
return null;
|
|
144
|
+
if (typeof apply !== 'boolean')
|
|
145
|
+
return null;
|
|
146
|
+
return {
|
|
147
|
+
op,
|
|
148
|
+
blockIndex,
|
|
149
|
+
mark,
|
|
150
|
+
range: { from: range.from, to: range.to },
|
|
151
|
+
apply,
|
|
152
|
+
...(attrs && typeof attrs === 'object' ? { attrs: attrs } : {}),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
default:
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function readSurgicalMeta(s) {
|
|
160
|
+
const meta = (s.meta ?? {});
|
|
161
|
+
const raw = meta['surgical'];
|
|
162
|
+
if (!raw || typeof raw !== 'object')
|
|
163
|
+
return null;
|
|
164
|
+
const obj = raw;
|
|
165
|
+
// Batch form: { ops: [SurgicalOp, ...] }
|
|
166
|
+
if (Array.isArray(obj['ops'])) {
|
|
167
|
+
const parsed = [];
|
|
168
|
+
for (const entry of obj['ops']) {
|
|
169
|
+
if (!entry || typeof entry !== 'object')
|
|
170
|
+
continue;
|
|
171
|
+
const op = parseSurgicalOp(entry);
|
|
172
|
+
if (op)
|
|
173
|
+
parsed.push(op);
|
|
174
|
+
}
|
|
175
|
+
if (parsed.length === 0)
|
|
176
|
+
return null;
|
|
177
|
+
return { ops: parsed };
|
|
178
|
+
}
|
|
179
|
+
return parseSurgicalOp(obj);
|
|
180
|
+
}
|
|
181
|
+
function planOp(editor, op) {
|
|
182
|
+
switch (op.op) {
|
|
183
|
+
case 'replace_block': return planReplaceBlock(editor, op.blockIndex, op.content);
|
|
184
|
+
case 'insert_block_before': return planInsertBlockBefore(editor, op.blockIndex, op.content);
|
|
185
|
+
case 'delete_block': return planDeleteBlock(editor, op.blockIndex);
|
|
186
|
+
case 'update_block_mark': return planUpdateBlockMark(editor, op.blockIndex, op.mark, op.range, op.apply, op.attrs);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Translate a surgical meta into a single TransactionModifier the diff
|
|
191
|
+
* extension can wrap with a snapshot. For batches, modifiers are
|
|
192
|
+
* computed against the original (pre-transaction) doc and then applied
|
|
193
|
+
* in DESC `blockIndex` order — each subsequent modifier touches earlier
|
|
194
|
+
* positions, so the prior modifiers' edits (at higher positions) don't
|
|
195
|
+
* shift the absolute positions the later modifiers were planned with.
|
|
196
|
+
*
|
|
197
|
+
* Returns null when the batch has no plannable ops (all out-of-range /
|
|
198
|
+
* unparseable). Drops individual non-plannable ops from a batch but
|
|
199
|
+
* still runs whatever did plan, so a single bad op doesn't kill the
|
|
200
|
+
* whole batch.
|
|
201
|
+
*/
|
|
202
|
+
function planSurgicalModifier(editor, surgical) {
|
|
203
|
+
if ('ops' in surgical) {
|
|
204
|
+
const sorted = [...surgical.ops].sort((a, b) => b.blockIndex - a.blockIndex);
|
|
205
|
+
const modifiers = [];
|
|
206
|
+
for (const op of sorted) {
|
|
207
|
+
const mod = planOp(editor, op);
|
|
208
|
+
if (mod)
|
|
209
|
+
modifiers.push(mod);
|
|
210
|
+
}
|
|
211
|
+
if (modifiers.length === 0)
|
|
212
|
+
return null;
|
|
213
|
+
return (tr) => { for (const mod of modifiers)
|
|
214
|
+
mod(tr); };
|
|
215
|
+
}
|
|
216
|
+
return planOp(editor, surgical);
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=useAiInlineDiff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAiInlineDiff.js","sourceRoot":"","sources":["../../src/react/useAiInlineDiff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAGzC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EACL,gCAAgC,EAChC,6BAA6B,GAG9B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAA;AAC9E,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,GAGpB,MAAM,mBAAmB,CAAA;AAkB1B;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAqB;IAC3D,MAAM,MAAM,GAAG,cAAc,CAAC;QAC5B,MAAM;QACN,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI;KACxF,CAAC,CAAA;IACF,OAAO,MAAM,IAAI,KAAK,CAAA;AACxB,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,MAAqB,EACrB,SAAiB,EACjB,OAA+B;IAE/B,MAAM,EAAE,IAAI,EAAE,GAAG,6BAA6B,CAAC,SAAS,CAAC,CAAA;IAEzD,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;IAChD,SAAS,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC,eAAe,CAAA,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAA;IAE1F,kEAAkE;IAClE,mEAAmE;IACnE,eAAe;IACf,MAAM,UAAU,GAAG,MAAM,CAAc,IAAI,GAAG,EAAE,CAAC,CAAA;IAEjD,8DAA8D;IAC9D,sEAAsE;IACtE,sEAAsE;IACtE,sEAAsE;IACtE,oDAAoD;IACpD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAA;QACrD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAAE,SAAQ;YAC1C,iEAAiE;YACjE,iEAAiE;YACjE,0DAA0D;YAC1D,IAAI,qBAAqB,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI;gBAAE,SAAQ;YAEnE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAA;YACpC,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;gBACvD,IAAI,CAAC,QAAQ;oBAAE,SAAQ;gBACvB,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAA;gBACzD,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;gBAC5B,SAAQ;YACV,CAAC;YAED,IAAI,OAAO,CAAC,CAAC,cAAc,KAAK,QAAQ;gBAAE,SAAQ;YAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,cAAc,CAAC,CAAA;YACxD,IAAI,CAAC,KAAK;gBAAE,SAAQ;YACpB,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;YAC9C,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAC9B,CAAC;QACD,kEAAkE;QAClE,oEAAoE;QACpE,gEAAgE;QAChE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC/C,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACxD,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;IAElB,iEAAiE;IACjE,uEAAuE;IACvE,kEAAkE;IAClE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,OAAO,GAA6B,CAAC,UAAU,EAAE,EAAE;YACvD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAAE,OAAM;YAClD,MAAM,CAAC,QAAQ,CAAC,kBAAkB,EAAE,CAAA;QACtC,CAAC,CAAA;QACD,OAAO,gCAAgC,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAA;IACxE,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;AACzB,CAAC;AAED,SAAS,cAAc,CAAC,CAAoB;IAC1C,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAA;IACtD,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAiD,CAAA;IACjF,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAA;AACpF,CAAC;AAyBD,SAAS,eAAe,CAAC,GAA4B;IACnD,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;IACpB,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,CAAA;IACpC,IAAI,OAAO,UAAU,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IAC/C,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,eAAe,CAAC;QACrB,KAAK,qBAAqB,CAAC,CAAC,CAAC;YAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,CAAA;YAC9B,IAAI,OAAO,OAAO,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAA;YAC5C,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,CAAA;QACpC,CAAC;QACD,KAAK,cAAc;YACjB,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,CAAA;QAC3B,KAAK,mBAAmB,CAAC,CAAC,CAAC;YACzB,MAAM,IAAI,GAAI,GAAG,CAAC,MAAM,CAAC,CAAA;YACzB,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAiD,CAAA;YAC1E,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;YAC1B,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;YAC1B,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAA;YACzC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAA;YACzF,IAAI,OAAO,KAAK,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAA;YAC3C,OAAO;gBACL,EAAE;gBACF,UAAU;gBACV,IAAI;gBACJ,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE;gBACzC,KAAK;gBACL,GAAG,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAgC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC3F,CAAA;QACH,CAAC;QACD;YACE,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAoB;IAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAA;IACtD,MAAM,GAAG,GAAI,IAAI,CAAC,UAAU,CAAC,CAAA;IAC7B,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IAChD,MAAM,GAAG,GAAG,GAA8B,CAAA;IAC1C,yCAAyC;IACzC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAiB,EAAE,CAAA;QAC/B,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,KAAK,CAAc,EAAE,CAAC;YAC5C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,SAAQ;YACjD,MAAM,EAAE,GAAG,eAAe,CAAC,KAAgC,CAAC,CAAA;YAC5D,IAAI,EAAE;gBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACzB,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;QACpC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAA;IACxB,CAAC;IACD,OAAO,eAAe,CAAC,GAAG,CAAC,CAAA;AAC7B,CAAC;AAED,SAAS,MAAM,CAAC,MAAc,EAAE,EAAc;IAC5C,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QACd,KAAK,eAAe,CAAC,CAAO,OAAO,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,OAAO,CAAC,CAAA;QACtF,KAAK,qBAAqB,CAAC,CAAC,OAAO,qBAAqB,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,OAAO,CAAC,CAAA;QAC3F,KAAK,cAAc,CAAC,CAAQ,OAAO,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,CAAA;QACzE,KAAK,mBAAmB,CAAC,CAAG,OAAO,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAA;IACtH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAS,oBAAoB,CAAC,MAAc,EAAE,QAAsB;IAClE,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAA;QAC5E,MAAM,SAAS,GAA0B,EAAE,CAAA;QAC3C,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;YAC9B,IAAI,GAAG;gBAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC9B,CAAC;QACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;QACvC,OAAO,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,MAAM,GAAG,IAAI,SAAS;YAAE,GAAG,CAAC,EAAE,CAAC,CAAA,CAAC,CAAC,CAAA;IACzD,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AACjC,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surgical block-op planners for AI-driven precise edits.
|
|
3
|
+
*
|
|
4
|
+
* Each planner takes the editor + a logical block index + a payload and
|
|
5
|
+
* returns a `TransactionModifier` — a function the caller (typically
|
|
6
|
+
* `useAiInlineDiff`) feeds into
|
|
7
|
+
* `editor.commands.applySurgicalAiInlineDiff(id, modifier)`. The diff
|
|
8
|
+
* extension wraps the modifier in a snapshot-then-apply step so the
|
|
9
|
+
* inline-diff overlay renders against the precise changed range.
|
|
10
|
+
*
|
|
11
|
+
* "Block index" refers to a 0-based position across the doc's top-level
|
|
12
|
+
* children — what the AI agent sees as a numbered structural summary.
|
|
13
|
+
* Planners translate that to absolute ProseMirror positions internally.
|
|
14
|
+
*
|
|
15
|
+
* Planners return `null` when the request can't be satisfied (out-of-
|
|
16
|
+
* range index, unparseable HTML, unknown mark). Callers should treat
|
|
17
|
+
* `null` as "abort the surgical op" and surface a clear error to the
|
|
18
|
+
* agent so it can retry with a different plan.
|
|
19
|
+
*/
|
|
20
|
+
import type { Editor } from '@tiptap/core';
|
|
21
|
+
import type { Transaction } from '@tiptap/pm/state';
|
|
22
|
+
import type { Node as ProseMirrorNode } from '@tiptap/pm/model';
|
|
23
|
+
export type TransactionModifier = (tr: Transaction) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Replace the top-level block at `blockIndex` with the parsed content.
|
|
26
|
+
* Caller-supplied `content` is HTML — multiple top-level nodes are
|
|
27
|
+
* allowed and will all land where the original block was.
|
|
28
|
+
*/
|
|
29
|
+
export declare function planReplaceBlock(editor: Editor, blockIndex: number, content: string): TransactionModifier | null;
|
|
30
|
+
/**
|
|
31
|
+
* Insert one or more top-level nodes (parsed from `content` HTML)
|
|
32
|
+
* before the block at `blockIndex`. `blockIndex === doc.childCount`
|
|
33
|
+
* appends at the end.
|
|
34
|
+
*/
|
|
35
|
+
export declare function planInsertBlockBefore(editor: Editor, blockIndex: number, content: string): TransactionModifier | null;
|
|
36
|
+
/**
|
|
37
|
+
* Delete the top-level block at `blockIndex`. Doc must retain at least
|
|
38
|
+
* one child after the delete (most schemas require this) — refuses to
|
|
39
|
+
* delete the last remaining block.
|
|
40
|
+
*/
|
|
41
|
+
export declare function planDeleteBlock(editor: Editor, blockIndex: number): TransactionModifier | null;
|
|
42
|
+
export interface BlockMarkRange {
|
|
43
|
+
/** 0-based text offset from the start of the block's content. */
|
|
44
|
+
from: number;
|
|
45
|
+
/** Exclusive end offset. */
|
|
46
|
+
to: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Apply or remove an inline mark on a range *within* the block at
|
|
50
|
+
* `blockIndex`. `range.from` / `range.to` are text offsets relative to
|
|
51
|
+
* the start of the block's content (so `0` is the first character of
|
|
52
|
+
* the block, not the start of the doc).
|
|
53
|
+
*
|
|
54
|
+
* `apply = true` sets the mark (with optional `attrs`); `apply = false`
|
|
55
|
+
* removes it. Unknown marks (not in the editor's schema) return `null`
|
|
56
|
+
* so the caller can surface a clean error to the agent.
|
|
57
|
+
*/
|
|
58
|
+
export declare function planUpdateBlockMark(editor: Editor, blockIndex: number, mark: string, range: BlockMarkRange, apply: boolean, attrs?: Record<string, unknown>): TransactionModifier | null;
|
|
59
|
+
/**
|
|
60
|
+
* Summarize a doc's top-level structure as a numbered list the AI can
|
|
61
|
+
* cite by index when proposing surgical ops. Each entry includes the
|
|
62
|
+
* block index, node type, and a truncated text preview — enough for the
|
|
63
|
+
* model to identify which block it wants to modify without sending the
|
|
64
|
+
* whole HTML/markdown back through token-priced channels.
|
|
65
|
+
*
|
|
66
|
+
* Returns one line per top-level child:
|
|
67
|
+
* `[0] heading: Welcome to the docs`
|
|
68
|
+
* `[1] paragraph: Lorem ipsum dolor sit amet…`
|
|
69
|
+
* `[2] bulletList: 3 items`
|
|
70
|
+
*/
|
|
71
|
+
export declare function summarizeBlockStructure(doc: ProseMirrorNode, maxChars?: number): string;
|
|
72
|
+
//# sourceMappingURL=surgicalOps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surgicalOps.d.ts","sourceRoot":"","sources":["../src/surgicalOps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAkB,IAAI,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAG/E,MAAM,MAAM,mBAAmB,GAAG,CAAC,EAAE,EAAE,WAAW,KAAK,IAAI,CAAA;AAyB3D;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAM,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAK,MAAM,GACjB,mBAAmB,GAAG,IAAI,CAQ5B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAM,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAK,MAAM,GACjB,mBAAmB,GAAG,IAAI,CAQ5B;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAM,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,mBAAmB,GAAG,IAAI,CAO5B;AAED,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAA;IACZ,4BAA4B;IAC5B,EAAE,EAAI,MAAM,CAAA;CACb;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAM,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAQ,MAAM,EAClB,KAAK,EAAO,cAAc,EAC1B,KAAK,EAAO,OAAO,EACnB,KAAK,CAAC,EAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,mBAAmB,GAAG,IAAI,CAwB5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,eAAe,EAAE,QAAQ,SAAK,GAAG,MAAM,CAWnF"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surgical block-op planners for AI-driven precise edits.
|
|
3
|
+
*
|
|
4
|
+
* Each planner takes the editor + a logical block index + a payload and
|
|
5
|
+
* returns a `TransactionModifier` — a function the caller (typically
|
|
6
|
+
* `useAiInlineDiff`) feeds into
|
|
7
|
+
* `editor.commands.applySurgicalAiInlineDiff(id, modifier)`. The diff
|
|
8
|
+
* extension wraps the modifier in a snapshot-then-apply step so the
|
|
9
|
+
* inline-diff overlay renders against the precise changed range.
|
|
10
|
+
*
|
|
11
|
+
* "Block index" refers to a 0-based position across the doc's top-level
|
|
12
|
+
* children — what the AI agent sees as a numbered structural summary.
|
|
13
|
+
* Planners translate that to absolute ProseMirror positions internally.
|
|
14
|
+
*
|
|
15
|
+
* Planners return `null` when the request can't be satisfied (out-of-
|
|
16
|
+
* range index, unparseable HTML, unknown mark). Callers should treat
|
|
17
|
+
* `null` as "abort the surgical op" and surface a clear error to the
|
|
18
|
+
* agent so it can retry with a different plan.
|
|
19
|
+
*/
|
|
20
|
+
import { DOMParser as PMDOMParser } from '@tiptap/pm/model';
|
|
21
|
+
/** Resolve the start position of the top-level child at `blockIndex`. */
|
|
22
|
+
function blockStartPos(doc, blockIndex) {
|
|
23
|
+
if (!Number.isInteger(blockIndex) || blockIndex < 0 || blockIndex >= doc.childCount)
|
|
24
|
+
return null;
|
|
25
|
+
let pos = 0;
|
|
26
|
+
for (let i = 0; i < blockIndex; i++)
|
|
27
|
+
pos += doc.child(i).nodeSize;
|
|
28
|
+
return pos;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Parse an HTML fragment into a doc-replaceable Slice. Uses the
|
|
32
|
+
* editor's own schema so block types unknown to the schema fail loudly
|
|
33
|
+
* rather than silently degrading.
|
|
34
|
+
*
|
|
35
|
+
* Returns `null` when DOM isn't available (SSR — shouldn't happen here,
|
|
36
|
+
* but keeps the planner safe).
|
|
37
|
+
*/
|
|
38
|
+
function parseHtmlToSlice(editor, html) {
|
|
39
|
+
if (typeof document === 'undefined')
|
|
40
|
+
return null;
|
|
41
|
+
const container = document.createElement('div');
|
|
42
|
+
container.innerHTML = html;
|
|
43
|
+
return PMDOMParser.fromSchema(editor.schema).parseSlice(container);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Replace the top-level block at `blockIndex` with the parsed content.
|
|
47
|
+
* Caller-supplied `content` is HTML — multiple top-level nodes are
|
|
48
|
+
* allowed and will all land where the original block was.
|
|
49
|
+
*/
|
|
50
|
+
export function planReplaceBlock(editor, blockIndex, content) {
|
|
51
|
+
const doc = editor.state.doc;
|
|
52
|
+
const start = blockStartPos(doc, blockIndex);
|
|
53
|
+
if (start === null)
|
|
54
|
+
return null;
|
|
55
|
+
const slice = parseHtmlToSlice(editor, content);
|
|
56
|
+
if (!slice)
|
|
57
|
+
return null;
|
|
58
|
+
const end = start + doc.child(blockIndex).nodeSize;
|
|
59
|
+
return (tr) => { tr.replace(start, end, slice); };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Insert one or more top-level nodes (parsed from `content` HTML)
|
|
63
|
+
* before the block at `blockIndex`. `blockIndex === doc.childCount`
|
|
64
|
+
* appends at the end.
|
|
65
|
+
*/
|
|
66
|
+
export function planInsertBlockBefore(editor, blockIndex, content) {
|
|
67
|
+
const doc = editor.state.doc;
|
|
68
|
+
if (!Number.isInteger(blockIndex) || blockIndex < 0 || blockIndex > doc.childCount)
|
|
69
|
+
return null;
|
|
70
|
+
const slice = parseHtmlToSlice(editor, content);
|
|
71
|
+
if (!slice)
|
|
72
|
+
return null;
|
|
73
|
+
let pos = 0;
|
|
74
|
+
for (let i = 0; i < blockIndex; i++)
|
|
75
|
+
pos += doc.child(i).nodeSize;
|
|
76
|
+
return (tr) => { tr.replace(pos, pos, slice); };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Delete the top-level block at `blockIndex`. Doc must retain at least
|
|
80
|
+
* one child after the delete (most schemas require this) — refuses to
|
|
81
|
+
* delete the last remaining block.
|
|
82
|
+
*/
|
|
83
|
+
export function planDeleteBlock(editor, blockIndex) {
|
|
84
|
+
const doc = editor.state.doc;
|
|
85
|
+
const start = blockStartPos(doc, blockIndex);
|
|
86
|
+
if (start === null)
|
|
87
|
+
return null;
|
|
88
|
+
if (doc.childCount <= 1)
|
|
89
|
+
return null;
|
|
90
|
+
const end = start + doc.child(blockIndex).nodeSize;
|
|
91
|
+
return (tr) => { tr.delete(start, end); };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Apply or remove an inline mark on a range *within* the block at
|
|
95
|
+
* `blockIndex`. `range.from` / `range.to` are text offsets relative to
|
|
96
|
+
* the start of the block's content (so `0` is the first character of
|
|
97
|
+
* the block, not the start of the doc).
|
|
98
|
+
*
|
|
99
|
+
* `apply = true` sets the mark (with optional `attrs`); `apply = false`
|
|
100
|
+
* removes it. Unknown marks (not in the editor's schema) return `null`
|
|
101
|
+
* so the caller can surface a clean error to the agent.
|
|
102
|
+
*/
|
|
103
|
+
export function planUpdateBlockMark(editor, blockIndex, mark, range, apply, attrs) {
|
|
104
|
+
const doc = editor.state.doc;
|
|
105
|
+
const start = blockStartPos(doc, blockIndex);
|
|
106
|
+
if (start === null)
|
|
107
|
+
return null;
|
|
108
|
+
const markType = editor.schema.marks[mark];
|
|
109
|
+
if (!markType)
|
|
110
|
+
return null;
|
|
111
|
+
const block = doc.child(blockIndex);
|
|
112
|
+
const blockInner = start + 1; // step inside the block's opening token
|
|
113
|
+
const contentMax = block.content.size;
|
|
114
|
+
if (!Number.isInteger(range.from) || !Number.isInteger(range.to))
|
|
115
|
+
return null;
|
|
116
|
+
const clampedFrom = Math.max(0, Math.min(range.from, contentMax));
|
|
117
|
+
const clampedTo = Math.max(clampedFrom, Math.min(range.to, contentMax));
|
|
118
|
+
if (clampedTo === clampedFrom)
|
|
119
|
+
return null;
|
|
120
|
+
const from = blockInner + clampedFrom;
|
|
121
|
+
const to = blockInner + clampedTo;
|
|
122
|
+
if (apply) {
|
|
123
|
+
const m = markType.create(attrs ?? null);
|
|
124
|
+
return (tr) => { tr.addMark(from, to, m); };
|
|
125
|
+
}
|
|
126
|
+
return (tr) => { tr.removeMark(from, to, markType); };
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Summarize a doc's top-level structure as a numbered list the AI can
|
|
130
|
+
* cite by index when proposing surgical ops. Each entry includes the
|
|
131
|
+
* block index, node type, and a truncated text preview — enough for the
|
|
132
|
+
* model to identify which block it wants to modify without sending the
|
|
133
|
+
* whole HTML/markdown back through token-priced channels.
|
|
134
|
+
*
|
|
135
|
+
* Returns one line per top-level child:
|
|
136
|
+
* `[0] heading: Welcome to the docs`
|
|
137
|
+
* `[1] paragraph: Lorem ipsum dolor sit amet…`
|
|
138
|
+
* `[2] bulletList: 3 items`
|
|
139
|
+
*/
|
|
140
|
+
export function summarizeBlockStructure(doc, maxChars = 80) {
|
|
141
|
+
const lines = [];
|
|
142
|
+
for (let i = 0; i < doc.childCount; i++) {
|
|
143
|
+
const node = doc.child(i);
|
|
144
|
+
const text = node.textContent.trim().replace(/\s+/g, ' ');
|
|
145
|
+
const preview = text.length === 0
|
|
146
|
+
? describeStructuralNode(node)
|
|
147
|
+
: text.length > maxChars ? `${text.slice(0, maxChars)}…` : text;
|
|
148
|
+
lines.push(`[${i}] ${node.type.name}: ${preview}`);
|
|
149
|
+
}
|
|
150
|
+
return lines.join('\n');
|
|
151
|
+
}
|
|
152
|
+
function describeStructuralNode(node) {
|
|
153
|
+
const kids = node.childCount;
|
|
154
|
+
if (kids === 0)
|
|
155
|
+
return '(empty)';
|
|
156
|
+
if (kids === 1)
|
|
157
|
+
return `1 ${node.firstChild?.type.name ?? 'child'}`;
|
|
158
|
+
return `${kids} children`;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=surgicalOps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surgicalOps.js","sourceRoot":"","sources":["../src/surgicalOps.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.
|
|
3
|
+
"version": "3.7.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/
|
|
39
|
-
"@tiptap/
|
|
40
|
-
"@tiptap/
|
|
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-
|
|
49
|
-
"@tiptap/
|
|
50
|
-
"@tiptap/
|
|
51
|
-
"@tiptap/
|
|
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,29 +59,29 @@
|
|
|
57
59
|
"devDependencies": {
|
|
58
60
|
"@base-ui/react": "^1",
|
|
59
61
|
"@tiptap/core": "^3",
|
|
60
|
-
"@tiptap/
|
|
61
|
-
"@tiptap/
|
|
62
|
-
"@tiptap/
|
|
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-
|
|
71
|
-
"@tiptap/
|
|
72
|
-
"@tiptap/
|
|
73
|
-
"@tiptap/
|
|
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
86
|
"@pilotiq/pilotiq": "^0.19.0"
|
|
85
87
|
},
|