@pilotiq/tiptap 3.10.8 → 3.11.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/CHANGELOG.md +6 -0
- package/dist/markdownExtension.js +2 -2
- package/dist/react/CollabTextRenderer.js +47 -24
- package/dist/test/setup.js +12 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @pilotiq/tiptap
|
|
2
2
|
|
|
3
|
+
## 3.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 30a802e: `CollabTextRenderer` (the Tiptap surface behind collab/AI `TextField` / `TextareaField`) now renders whole-field AI suggestions through `AiInlineDiffExtension` + `AiSuggestionBanner` — the same red/green inline diff and amber Accept/Reject banner `RichTextField` uses — instead of the legacy green-pill chip with ✓/✕. One review surface across every text shape. The chip bridge stays mounted for producer-supplied `editorRange` suggestions; `onApplyWholeField` remains the fallback when a suggestion can't parse.
|
|
8
|
+
|
|
3
9
|
## 3.10.8
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -129,7 +129,7 @@ var require_markdown_it_task_lists = __commonJS({
|
|
|
129
129
|
}
|
|
130
130
|
});
|
|
131
131
|
|
|
132
|
-
// ../../node_modules/.pnpm/tiptap-markdown@0.9.0_@tiptap+core@3.
|
|
132
|
+
// ../../node_modules/.pnpm/tiptap-markdown@0.9.0_@tiptap+core@3.26.0_@tiptap+pm@3.26.0_/node_modules/tiptap-markdown/dist/tiptap-markdown.es.js
|
|
133
133
|
import { Extension, Mark as Mark2, getHTMLFromFragment, Node as Node$1, extensions } from "@tiptap/core";
|
|
134
134
|
|
|
135
135
|
// ../../node_modules/.pnpm/orderedmap@2.1.1/node_modules/orderedmap/dist/index.js
|
|
@@ -8859,7 +8859,7 @@ var MarkdownSerializerState = class {
|
|
|
8859
8859
|
}
|
|
8860
8860
|
};
|
|
8861
8861
|
|
|
8862
|
-
// ../../node_modules/.pnpm/tiptap-markdown@0.9.0_@tiptap+core@3.
|
|
8862
|
+
// ../../node_modules/.pnpm/tiptap-markdown@0.9.0_@tiptap+core@3.26.0_@tiptap+pm@3.26.0_/node_modules/tiptap-markdown/dist/tiptap-markdown.es.js
|
|
8863
8863
|
var import_markdown_it_task_lists = __toESM(require_markdown_it_task_lists(), 1);
|
|
8864
8864
|
import { Fragment as Fragment2, DOMParser } from "@tiptap/pm/model";
|
|
8865
8865
|
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useRef } from 'react';
|
|
3
3
|
import { useEditor, EditorContent } from '@tiptap/react';
|
|
4
|
+
import { Slice } from '@tiptap/pm/model';
|
|
4
5
|
import { useCollabRoom, getCollabExtensions, } from '@pilotiq/pilotiq/react';
|
|
5
6
|
import { useCollabSeed } from '@rudderjs/sync/react';
|
|
6
7
|
import { createPlainTextEditor, plainTextOf, plainTextToDoc } from '../PlainTextEditor.js';
|
|
7
8
|
import { AiSuggestionExtension } from '../extensions/AiSuggestionExtension.js';
|
|
9
|
+
import { AiInlineDiffExtension } from '../extensions/AiInlineDiffExtension.js';
|
|
8
10
|
import { useAiSuggestionBridge } from './useAiSuggestionBridge.js';
|
|
11
|
+
import { useAiInlineDiff, useIsAiInlineDiffActive } from './useAiInlineDiff.js';
|
|
12
|
+
import { AiSuggestionBanner } from './AiSuggestionBanner.js';
|
|
9
13
|
/**
|
|
10
14
|
* Tiptap-backed plain-text editor for pilotiq's `TextField` / `TextareaField`
|
|
11
15
|
* / similar single-line / multi-line text fields when collab is on.
|
|
@@ -93,12 +97,14 @@ export function CollabTextRenderer({ name, fragmentKey, multiline, defaultValue,
|
|
|
93
97
|
// seeds the fragment on first connect when it's still empty. When
|
|
94
98
|
// collab is off, seed from defaultValue directly.
|
|
95
99
|
content: collabActive ? '' : defaultValue,
|
|
96
|
-
// AI suggestions —
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
+
// AI suggestions — chip extension (producer-supplied range
|
|
101
|
+
// suggestions) + inline-diff extension (whole-field suggestions:
|
|
102
|
+
// red strikethrough on removed runs, green on inserted, with the
|
|
103
|
+
// `<AiSuggestionBanner>` Accept / Reject below). Both idle until
|
|
104
|
+
// a suggestion arrives via the bridges below. Matches the
|
|
105
|
+
// `TiptapEditor` wiring so the review surface reads identically
|
|
100
106
|
// across RichTextField / MarkdownField / TextField+TextareaField.
|
|
101
|
-
extensions: [...collabExtensions, AiSuggestionExtension],
|
|
107
|
+
extensions: [...collabExtensions, AiSuggestionExtension, AiInlineDiffExtension],
|
|
102
108
|
onUpdate: (text) => onChange(text),
|
|
103
109
|
...(onSubmit ? { onSubmit: () => { onSubmit(); return false; } } : {}),
|
|
104
110
|
...(className || editorAttributes
|
|
@@ -125,26 +131,35 @@ export function CollabTextRenderer({ name, fragmentKey, multiline, defaultValue,
|
|
|
125
131
|
// `<PendingSuggestionsContext>` queue with the editor's `AiSuggestion`
|
|
126
132
|
// extension. No-op when no provider is mounted (default no-op context).
|
|
127
133
|
//
|
|
128
|
-
// Whole-field
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
// Whole-field suggestions do NOT synthesize a chip range anymore —
|
|
135
|
+
// they render through `useAiInlineDiff` below (same red/green inline
|
|
136
|
+
// diff + banner as `TiptapEditor`), replacing the old green-pill chip
|
|
137
|
+
// that read differently from the rich-text surface. The bridge stays
|
|
138
|
+
// mounted for producer-supplied `meta.editorRange` suggestions (precise
|
|
139
|
+
// anchors worth visualizing in place) and as the `onApplyWholeField`
|
|
140
|
+
// fallback when the diff path can't parse a suggestion.
|
|
141
|
+
const applyWholeField = (value) => {
|
|
142
|
+
if (!editor || editor.isDestroyed)
|
|
143
|
+
return;
|
|
144
|
+
editor.commands.setContent(plainTextToDoc(value, !!multiline));
|
|
145
|
+
};
|
|
137
146
|
useAiSuggestionBridge(editor ?? null, name, {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
onApplyWholeField: applyWholeField,
|
|
148
|
+
});
|
|
149
|
+
// Inline diff for whole-field suggestions — plain-text shape: each
|
|
150
|
+
// line wraps in a `paragraph` node, mirroring `plainTextToDoc`.
|
|
151
|
+
useAiInlineDiff(editor ?? null, name, {
|
|
152
|
+
parseSuggestion: (ed, value) => {
|
|
153
|
+
try {
|
|
154
|
+
const node = ed.schema.nodeFromJSON(plainTextToDoc(value, !!multiline));
|
|
155
|
+
return new Slice(node.content, 0, 0);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
146
160
|
},
|
|
147
161
|
});
|
|
162
|
+
const isDiffActive = useIsAiInlineDiffActive(editor ?? null);
|
|
148
163
|
// First-load seed when collab is active. Collaboration starts the editor
|
|
149
164
|
// empty regardless of `defaultValue`; once the room's first sync
|
|
150
165
|
// resolves, `useCollabSeed` runs the callback inside `ydoc.transact`.
|
|
@@ -197,5 +212,13 @@ export function CollabTextRenderer({ name, fragmentKey, multiline, defaultValue,
|
|
|
197
212
|
onChange(plainTextOf(editor));
|
|
198
213
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
199
214
|
}, [editor]);
|
|
200
|
-
|
|
215
|
+
// Banner mounts below the editor exactly like `TiptapEditor`'s — it
|
|
216
|
+
// renders nothing while no suggestion is pending for this field, so
|
|
217
|
+
// the single-line text surface keeps its normal footprint.
|
|
218
|
+
return (_jsxs(_Fragment, { children: [_jsx(EditorContent, { editor: editor }), _jsx(AiSuggestionBanner, { fieldName: name, onApplyWholeField: applyWholeField, ...(isDiffActive && editor
|
|
219
|
+
? {
|
|
220
|
+
onAcceptViaEditor: () => editor.commands.acceptAiInlineDiff(),
|
|
221
|
+
onRejectViaEditor: () => editor.commands.rejectAiInlineDiff(),
|
|
222
|
+
}
|
|
223
|
+
: {}) })] }));
|
|
201
224
|
}
|
package/dist/test/setup.js
CHANGED
|
@@ -40,6 +40,9 @@ const globals = {
|
|
|
40
40
|
KeyboardEvent: window.KeyboardEvent,
|
|
41
41
|
CustomEvent: window.CustomEvent,
|
|
42
42
|
DocumentFragment: window.DocumentFragment,
|
|
43
|
+
// prosemirror-view ≥1.41 probes `root instanceof ShadowRoot` while
|
|
44
|
+
// resolving the editor's event root.
|
|
45
|
+
ShadowRoot: window.ShadowRoot,
|
|
43
46
|
Range: window.Range,
|
|
44
47
|
Selection: window.Selection,
|
|
45
48
|
MutationObserver: window.MutationObserver,
|
|
@@ -57,6 +60,15 @@ const globals = {
|
|
|
57
60
|
for (const [k, v] of Object.entries(globals)) {
|
|
58
61
|
Object.defineProperty(globalThis, k, { value: v, writable: true, configurable: true });
|
|
59
62
|
}
|
|
63
|
+
// jsdom has no layout engine and never implements elementFromPoint;
|
|
64
|
+
// prosemirror-view ≥1.41 calls it during view initialization.
|
|
65
|
+
if (typeof window.document.elementFromPoint !== 'function') {
|
|
66
|
+
Object.defineProperty(window.document, 'elementFromPoint', {
|
|
67
|
+
value: () => null,
|
|
68
|
+
writable: true,
|
|
69
|
+
configurable: true,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
60
72
|
// React 19 + RTL require `IS_REACT_ACT_ENVIRONMENT` so `act()` warnings
|
|
61
73
|
// don't fire on every render. Without it, Tiptap's mount cascade
|
|
62
74
|
// produces dozens of warnings that swamp real test failures.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pilotiq/tiptap",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.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": {
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"react-dom": "^19",
|
|
92
92
|
"tiptap-markdown": "^0.9",
|
|
93
93
|
"typescript": "^5",
|
|
94
|
-
"@pilotiq/pilotiq": "^0.
|
|
94
|
+
"@pilotiq/pilotiq": "^0.37.0"
|
|
95
95
|
},
|
|
96
96
|
"author": "Suleiman Shahbari",
|
|
97
97
|
"scripts": {
|