@pilotiq/tiptap 3.19.2 → 4.0.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 (29) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/extensions/BlockNodeExtension.d.ts +0 -9
  3. package/dist/extensions/BlockNodeExtension.js +0 -20
  4. package/dist/extensions/{AiInlineDiffExtension.d.ts → InlineDiffExtension.d.ts} +23 -23
  5. package/dist/extensions/{AiInlineDiffExtension.js → InlineDiffExtension.js} +33 -33
  6. package/dist/extensions/{AiSuggestionExtension.d.ts → SuggestionChipExtension.d.ts} +29 -29
  7. package/dist/extensions/{AiSuggestionExtension.js → SuggestionChipExtension.js} +52 -52
  8. package/dist/index.d.ts +4 -4
  9. package/dist/index.js +4 -4
  10. package/dist/react/BlockNodeView.d.ts +23 -12
  11. package/dist/react/BlockNodeView.js +55 -21
  12. package/dist/react/CollabTextRenderer.js +16 -16
  13. package/dist/react/MarkdownEditor.js +17 -17
  14. package/dist/react/{AiSuggestionBanner.d.ts → SuggestionBanner.d.ts} +6 -6
  15. package/dist/react/{AiSuggestionBanner.js → SuggestionBanner.js} +5 -5
  16. package/dist/react/TiptapEditor.js +24 -59
  17. package/dist/react/blockValues.d.ts +54 -0
  18. package/dist/react/blockValues.js +161 -0
  19. package/dist/react/floatingToolbarVisibility.d.ts +9 -2
  20. package/dist/react/floatingToolbarVisibility.js +12 -3
  21. package/dist/react/{useAiInlineDiff.d.ts → useInlineDiff.d.ts} +13 -13
  22. package/dist/react/{useAiInlineDiff.js → useInlineDiff.js} +36 -19
  23. package/dist/react/{useAiSuggestionBridge.d.ts → useSuggestionBridge.d.ts} +7 -7
  24. package/dist/react/{useAiSuggestionBridge.js → useSuggestionBridge.js} +10 -10
  25. package/dist/surgicalOps.d.ts +15 -2
  26. package/dist/surgicalOps.js +50 -3
  27. package/package.json +1 -1
  28. package/dist/react/BlockSidePanel.d.ts +0 -105
  29. package/dist/react/BlockSidePanel.js +0 -338
package/CHANGELOG.md CHANGED
@@ -1,5 +1,61 @@
1
1
  # @pilotiq/tiptap
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 58794c1: Rename the AI suggestion/diff primitives to provider-neutral names. These are generic inline-diff machinery the package exposes — they contain no AI logic and can be driven by any producer (the actual AI lives in `@pilotiq-pro/ai`), so the `Ai*` prefix oversold them.
8
+
9
+ **Renamed exports** (no aliases — direct importers must update):
10
+
11
+ | Old | New |
12
+ | ---------------------------------------------------------------------- | ---------------------------------------------------------------- |
13
+ | `AiSuggestionExtension` | `SuggestionChipExtension` |
14
+ | `AiSuggestion` | `InlineSuggestion` |
15
+ | `AiSuggestionExtensionOptions` | `SuggestionChipExtensionOptions` |
16
+ | `aiSuggestionPluginKey` | `suggestionChipPluginKey` |
17
+ | `useAiSuggestionBridge` | `useSuggestionBridge` |
18
+ | `AiInlineDiffExtension` | `InlineDiffExtension` |
19
+ | `AiInlineDiffExtensionOptions` | `InlineDiffExtensionOptions` |
20
+ | `aiInlineDiffPluginKey` | `inlineDiffPluginKey` |
21
+ | `getAiInlineDiffState` | `getInlineDiffState` |
22
+ | `AiDiffDisplayMode` | `DiffDisplayMode` |
23
+ | `useAiInlineDiff` / `useIsAiInlineDiffActive` / `readAiDiffViewMarker` | `useInlineDiff` / `useIsInlineDiffActive` / `readDiffViewMarker` |
24
+ | `AiSuggestionBanner` / `useAiSuggestionBanner` | `SuggestionBanner` / `useSuggestionBanner` |
25
+
26
+ **Renamed editor commands**: `addAiSuggestion` → `addSuggestion`, `approveAiSuggestion` → `approveSuggestion`, `rejectAiSuggestion` → `rejectSuggestion`, `approveAllAiSuggestions` → `approveAllSuggestions`, `rejectAllAiSuggestions` → `rejectAllSuggestions`, `clearAiSuggestions` → `clearSuggestions`; `startAiInlineDiff` → `startInlineDiff`, `applySurgicalAiInlineDiff` → `applySurgicalInlineDiff`, `acceptAiInlineDiff` → `acceptInlineDiff`, `rejectAiInlineDiff` → `rejectInlineDiff`.
27
+
28
+ **Renamed CSS classes / DOM markers** (consumers with custom stylesheets must update; the injected defaults follow the new names automatically): `pilotiq-ai-suggestion-*` → `pilotiq-suggestion-*`, `pilotiq-ai-banner-*` → `pilotiq-suggestion-banner-*`, `pilotiq-ai-diff-*` → `pilotiq-diff-*`, and the matching `data-pilotiq-ai-*` attributes → `data-pilotiq-*`.
29
+
30
+ **Deliberately unchanged**: the cross-package field-config markers `data-ai-suggestions-mode` / `data-ai-diff-view` (written by `@pilotiq-pro/ai`'s `.aiSuggestionsMode()` / `.aiDiffView()` field API) stay `ai`-prefixed — they configure genuinely AI-specific behavior, not provider-neutral primitives.
31
+
32
+ ### Minor Changes
33
+
34
+ - 0096a7f: Add an in-block text find→replace surgical op — `planReplaceText` plus a `replace_text` case in the inline-diff dispatch.
35
+
36
+ It swaps the first occurrence of a `search` string with `replace`, preserving the surrounding node structure. This lets a producer (e.g. `@pilotiq-pro/ai`) fix a word, number, or typo **inside** a custom block (alert / prosCons / faq / keyTakeaways) or a table cell without rebuilding the block as HTML — which `replace_block` would force, flattening the block. The op is index-free: the match position resolves at apply time, so it composes safely after the index-based block ops in a batch. Returns `null` when `search` isn't present, so a stale or guessed search string changes nothing rather than corrupting the doc.
37
+
38
+ New export: `planReplaceText`. Surgical meta op: `{ op: 'replace_text', search, replace }`.
39
+
40
+ ## 3.20.0
41
+
42
+ ### Minor Changes
43
+
44
+ - 47c8187: Custom blocks now edit inline (accordion) instead of in a right-docked side panel.
45
+
46
+ Clicking **Edit** on an inserted custom block (`Block.make().schema([...])`) expands the block in place and renders its schema as a `FormFields` form; edits write straight back onto the node via `updateAttributes({ blockData })` on every change — no popup, no save button.
47
+
48
+ This replaces the `BlockSidePanel` and removes the machinery that existed only to host the form outside the NodeView: the `onEdit` bridge + `Mod-e` shortcut on `BlockNodeExtension`, and the host-side `selectedBlock` state / position-remapping in `TiptapEditor`. The form lives in a `contentEditable=false` region with event guards so ProseMirror never treats the inputs as document content. Pure `coerceBlockValues` / `readBlockFieldValue` helpers moved to `react/blockValues.ts`.
49
+
50
+ ### Patch Changes
51
+
52
+ - 1a1026d: Inline format toolbar visibility fixed for block nodes (#155).
53
+
54
+ Two adjustments to `shouldShowFloatingToolbar`:
55
+
56
+ - **Hidden on a whole-node block selection.** Clicking a schema-form custom block card (`pilotiqBlock`), an image, an hr, or picking a whole Alert via the drag handle produces a `NodeSelection` with no inline text to format — the bold/italic/link toolbar no longer appears for any of these. Previously only the built-in `alert` block was special-cased, so custom block cards still surfaced the toolbar.
57
+ - **Shown inside the Alert block's editable text.** The Alert block has an editable title and body; the mark toolbar now works there like anywhere else. An earlier fix over-suppressed the entire Alert (including its editable text) — that suppression is reversed; only the whole-node pick is hidden now.
58
+
3
59
  ## 3.19.2
4
60
 
5
61
  ### Patch Changes
@@ -17,15 +17,6 @@ export interface BlockNodeOptions {
17
17
  * registry data via React context.
18
18
  */
19
19
  blocks: BlockMeta[];
20
- /**
21
- * Bridge from the NodeView's separate React tree back to the editor's
22
- * own tree, where the side panel lives. Set by `TiptapEditor` so the
23
- * "Edit" button on each block can request the panel open against this
24
- * specific node. `undefined` means no host is listening — the NodeView
25
- * falls back to a no-op (does not render an Edit affordance, or does
26
- * so disabled, depending on the consumer's chrome).
27
- */
28
- onEdit?: (pos: number) => void;
29
20
  }
30
21
  /**
31
22
  * Single ProseMirror node type that represents every custom block. The
@@ -25,9 +25,6 @@ export const BlockNodeExtension = Node.create({
25
25
  // dispatch — even before any block was inserted.
26
26
  draggable: true,
27
27
  addOptions() {
28
- // `onEdit` intentionally omitted — `exactOptionalPropertyTypes` makes
29
- // an explicit `undefined` non-assignable to the optional field, and
30
- // the host wires it via `BlockNodeExtension.configure({ onEdit })`.
31
28
  return { blocks: [] };
32
29
  },
33
30
  addAttributes() {
@@ -82,21 +79,4 @@ export const BlockNodeExtension = Node.create({
82
79
  }),
83
80
  };
84
81
  },
85
- // `Mod-e` opens the side panel for the currently NodeSelected block.
86
- // Returns false when no block is selected so the browser's default
87
- // (Safari "Use Selection for Find", etc.) still applies in plain text.
88
- addKeyboardShortcuts() {
89
- return {
90
- 'Mod-e': () => {
91
- const onEdit = this.options.onEdit;
92
- if (!onEdit)
93
- return false;
94
- const sel = this.editor.state.selection;
95
- if (sel.node?.type.name !== this.name)
96
- return false;
97
- onEdit(sel.from);
98
- return true;
99
- },
100
- };
101
- },
102
82
  });
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * Inline-diff visualization for whole-field AI suggestions.
3
3
  *
4
- * Sibling to `AiSuggestionExtension`, which handles producer-supplied
4
+ * Sibling to `SuggestionChipExtension`, which handles producer-supplied
5
5
  * range suggestions (surgical edits with `meta.editorRange`) via the
6
6
  * inline chip widget. This extension handles the *whole-field* case:
7
7
  * the AI proposes a new document and the user reviews the structural
8
8
  * delta (added paragraphs, deleted text, mark changes, etc.) before
9
- * accepting or rejecting via the host-mounted `<AiSuggestionBanner>`.
9
+ * accepting or rejecting via the host-mounted `<SuggestionBanner>`.
10
10
  *
11
11
  * Architecture:
12
- * 1. `startAiInlineDiff(id, newDoc)` captures the current doc as the
12
+ * 1. `startInlineDiff(id, newDoc)` captures the current doc as the
13
13
  * baseline, replaces the doc body with `newDoc`'s content (so the
14
14
  * editor surface IS the proposed state), and initializes a
15
15
  * `prosemirror-changeset` tracking the original-to-current
@@ -24,9 +24,9 @@
24
24
  * through next to the insert point (the deleted content
25
25
  * isn't in the current doc, so a widget is the only way to
26
26
  * surface it)
27
- * 4. `acceptAiInlineDiff()` clears the plugin state — the current
27
+ * 4. `acceptInlineDiff()` clears the plugin state — the current
28
28
  * doc is the accepted state.
29
- * 5. `rejectAiInlineDiff()` replaces the doc back to the baseline
29
+ * 5. `rejectInlineDiff()` replaces the doc back to the baseline
30
30
  * via a single transaction and clears state.
31
31
  *
32
32
  * For Tiptap Pro parity. See `[[project_pilotiq_text_field_tiptap_rules]]`.
@@ -38,7 +38,7 @@ import type { Node as ProseMirrorNode, Slice } from '@tiptap/pm/model';
38
38
  import { ChangeSet } from 'prosemirror-changeset';
39
39
  declare module '@tiptap/core' {
40
40
  interface Commands<ReturnType> {
41
- aiInlineDiff: {
41
+ inlineDiff: {
42
42
  /**
43
43
  * Start the inline-diff review session. Snapshots the current
44
44
  * doc as the baseline, replaces the doc with `newDocSlice`'s
@@ -48,7 +48,7 @@ declare module '@tiptap/core' {
48
48
  * banner / approve handlers can correlate the editor state with
49
49
  * the queue entry.
50
50
  */
51
- startAiInlineDiff: (id: string, newDocSlice: Slice, displayMode?: AiDiffDisplayMode) => ReturnType;
51
+ startInlineDiff: (id: string, newDocSlice: Slice, displayMode?: DiffDisplayMode) => ReturnType;
52
52
  /**
53
53
  * Start the inline-diff review session for a surgical edit.
54
54
  * Snapshots the current doc as the baseline, then runs
@@ -62,11 +62,11 @@ declare module '@tiptap/core' {
62
62
  * `delete_block` / `update_block_mark` AI ops. Returns false (no
63
63
  * dispatch) when `applyFn` produced no doc change.
64
64
  */
65
- applySurgicalAiInlineDiff: (id: string, applyFn: (tr: Transaction) => void, displayMode?: AiDiffDisplayMode) => ReturnType;
65
+ applySurgicalInlineDiff: (id: string, applyFn: (tr: Transaction) => void, displayMode?: DiffDisplayMode) => ReturnType;
66
66
  /** Clear diff state. Current doc IS the accepted state. */
67
- acceptAiInlineDiff: () => ReturnType;
67
+ acceptInlineDiff: () => ReturnType;
68
68
  /** Revert doc to the captured baseline and clear diff state. */
69
- rejectAiInlineDiff: () => ReturnType;
69
+ rejectInlineDiff: () => ReturnType;
70
70
  };
71
71
  }
72
72
  }
@@ -79,30 +79,30 @@ declare module '@tiptap/core' {
79
79
  * full-width red row (`−` gutter) above the change. Suits markdown
80
80
  * sources / structured text where lines are the meaningful unit.
81
81
  */
82
- export type AiDiffDisplayMode = 'inline' | 'lines';
82
+ export type DiffDisplayMode = 'inline' | 'lines';
83
83
  interface DiffState {
84
84
  id: string;
85
- /** Original doc captured at `startAiInlineDiff` time — used for revert. */
85
+ /** Original doc captured at `startInlineDiff` time — used for revert. */
86
86
  baseline: ProseMirrorNode;
87
87
  /** ChangeSet accumulating diffs since baseline. */
88
88
  changeset: ChangeSet;
89
- /** Rendering mode for the decorations — see `AiDiffDisplayMode`. */
90
- displayMode: AiDiffDisplayMode;
89
+ /** Rendering mode for the decorations — see `DiffDisplayMode`. */
90
+ displayMode: DiffDisplayMode;
91
91
  }
92
- export declare const aiInlineDiffPluginKey: PluginKey<DiffState | null>;
92
+ export declare const inlineDiffPluginKey: PluginKey<DiffState | null>;
93
93
  /** Read the active diff state, if any. Public for hosts that want to
94
94
  * branch their banner UI on "diff active" vs "diff inactive". */
95
- export declare function getAiInlineDiffState(state: EditorState): DiffState | null;
96
- export interface AiInlineDiffExtensionOptions {
95
+ export declare function getInlineDiffState(state: EditorState): DiffState | null;
96
+ export interface InlineDiffExtensionOptions {
97
97
  /**
98
98
  * Class prefix for inline-diff decorations. Defaults to
99
- * `'pilotiq-ai-diff'`, producing:
100
- * - `pilotiq-ai-diff-inserted` (green-background span on new ranges)
101
- * - `pilotiq-ai-diff-deleted` (widget DOM root for deleted text)
102
- * - `pilotiq-ai-diff-deleted-text` (the strikethrough span inside)
99
+ * `'pilotiq-diff'`, producing:
100
+ * - `pilotiq-diff-inserted` (green-background span on new ranges)
101
+ * - `pilotiq-diff-deleted` (widget DOM root for deleted text)
102
+ * - `pilotiq-diff-deleted-text` (the strikethrough span inside)
103
103
  */
104
104
  classPrefix?: string;
105
105
  }
106
- export declare const AiInlineDiffExtension: Extension<AiInlineDiffExtensionOptions, any>;
106
+ export declare const InlineDiffExtension: Extension<InlineDiffExtensionOptions, any>;
107
107
  export {};
108
- //# sourceMappingURL=AiInlineDiffExtension.d.ts.map
108
+ //# sourceMappingURL=InlineDiffExtension.d.ts.map
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * Inline-diff visualization for whole-field AI suggestions.
3
3
  *
4
- * Sibling to `AiSuggestionExtension`, which handles producer-supplied
4
+ * Sibling to `SuggestionChipExtension`, which handles producer-supplied
5
5
  * range suggestions (surgical edits with `meta.editorRange`) via the
6
6
  * inline chip widget. This extension handles the *whole-field* case:
7
7
  * the AI proposes a new document and the user reviews the structural
8
8
  * delta (added paragraphs, deleted text, mark changes, etc.) before
9
- * accepting or rejecting via the host-mounted `<AiSuggestionBanner>`.
9
+ * accepting or rejecting via the host-mounted `<SuggestionBanner>`.
10
10
  *
11
11
  * Architecture:
12
- * 1. `startAiInlineDiff(id, newDoc)` captures the current doc as the
12
+ * 1. `startInlineDiff(id, newDoc)` captures the current doc as the
13
13
  * baseline, replaces the doc body with `newDoc`'s content (so the
14
14
  * editor surface IS the proposed state), and initializes a
15
15
  * `prosemirror-changeset` tracking the original-to-current
@@ -24,9 +24,9 @@
24
24
  * through next to the insert point (the deleted content
25
25
  * isn't in the current doc, so a widget is the only way to
26
26
  * surface it)
27
- * 4. `acceptAiInlineDiff()` clears the plugin state — the current
27
+ * 4. `acceptInlineDiff()` clears the plugin state — the current
28
28
  * doc is the accepted state.
29
- * 5. `rejectAiInlineDiff()` replaces the doc back to the baseline
29
+ * 5. `rejectInlineDiff()` replaces the doc back to the baseline
30
30
  * via a single transaction and clears state.
31
31
  *
32
32
  * For Tiptap Pro parity. See `[[project_pilotiq_text_field_tiptap_rules]]`.
@@ -36,22 +36,22 @@ import { Plugin, PluginKey } from '@tiptap/pm/state';
36
36
  import { Decoration, DecorationSet } from '@tiptap/pm/view';
37
37
  import { DOMSerializer, Fragment } from '@tiptap/pm/model';
38
38
  import { ChangeSet } from 'prosemirror-changeset';
39
- export const aiInlineDiffPluginKey = new PluginKey('pilotiqAiInlineDiff');
39
+ export const inlineDiffPluginKey = new PluginKey('pilotiqInlineDiff');
40
40
  /** Read the active diff state, if any. Public for hosts that want to
41
41
  * branch their banner UI on "diff active" vs "diff inactive". */
42
- export function getAiInlineDiffState(state) {
43
- return aiInlineDiffPluginKey.getState(state) ?? null;
42
+ export function getInlineDiffState(state) {
43
+ return inlineDiffPluginKey.getState(state) ?? null;
44
44
  }
45
- export const AiInlineDiffExtension = Extension.create({
46
- name: 'pilotiqAiInlineDiff',
45
+ export const InlineDiffExtension = Extension.create({
46
+ name: 'pilotiqInlineDiff',
47
47
  addOptions() {
48
- return { classPrefix: 'pilotiq-ai-diff' };
48
+ return { classPrefix: 'pilotiq-diff' };
49
49
  },
50
50
  onCreate() {
51
51
  // Mirror the chip CSS injection pattern. Idempotent via sentinel.
52
52
  if (typeof document === 'undefined')
53
53
  return;
54
- const SENTINEL = 'data-pilotiq-ai-diff-styles';
54
+ const SENTINEL = 'data-pilotiq-diff-styles';
55
55
  if (document.head.querySelector(`style[${SENTINEL}]`))
56
56
  return;
57
57
  const prefix = this.options.classPrefix;
@@ -129,7 +129,7 @@ export const AiInlineDiffExtension = Extension.create({
129
129
  },
130
130
  addCommands() {
131
131
  return {
132
- startAiInlineDiff: (id, newDocSlice, displayMode) => ({ tr, state, dispatch }) => {
132
+ startInlineDiff: (id, newDocSlice, displayMode) => ({ tr, state, dispatch }) => {
133
133
  const baseline = state.doc;
134
134
  const docEnd = state.doc.content.size;
135
135
  // Replace the whole doc body with the proposed content. The
@@ -137,31 +137,31 @@ export const AiInlineDiffExtension = Extension.create({
137
137
  // throws (callers should pre-validate via `editor.schema`).
138
138
  tr.replaceRange(0, docEnd, newDocSlice);
139
139
  const meta = { type: 'start', id, baseline, ...(displayMode ? { displayMode } : {}) };
140
- tr.setMeta(aiInlineDiffPluginKey, meta);
140
+ tr.setMeta(inlineDiffPluginKey, meta);
141
141
  if (dispatch)
142
142
  dispatch(tr);
143
143
  return true;
144
144
  },
145
- applySurgicalAiInlineDiff: (id, applyFn, displayMode) => ({ tr, state, dispatch }) => {
145
+ applySurgicalInlineDiff: (id, applyFn, displayMode) => ({ tr, state, dispatch }) => {
146
146
  const baseline = state.doc;
147
147
  applyFn(tr);
148
148
  if (!tr.docChanged)
149
149
  return false;
150
150
  const meta = { type: 'start', id, baseline, ...(displayMode ? { displayMode } : {}) };
151
- tr.setMeta(aiInlineDiffPluginKey, meta);
151
+ tr.setMeta(inlineDiffPluginKey, meta);
152
152
  if (dispatch)
153
153
  dispatch(tr);
154
154
  return true;
155
155
  },
156
- acceptAiInlineDiff: () => ({ tr, dispatch }) => {
156
+ acceptInlineDiff: () => ({ tr, dispatch }) => {
157
157
  const meta = { type: 'clear' };
158
- tr.setMeta(aiInlineDiffPluginKey, meta);
158
+ tr.setMeta(inlineDiffPluginKey, meta);
159
159
  if (dispatch)
160
160
  dispatch(tr);
161
161
  return true;
162
162
  },
163
- rejectAiInlineDiff: () => ({ tr, state, dispatch }) => {
164
- const ds = aiInlineDiffPluginKey.getState(state);
163
+ rejectInlineDiff: () => ({ tr, state, dispatch }) => {
164
+ const ds = inlineDiffPluginKey.getState(state);
165
165
  if (!ds)
166
166
  return false;
167
167
  const docEnd = state.doc.content.size;
@@ -170,7 +170,7 @@ export const AiInlineDiffExtension = Extension.create({
170
170
  // doc replace).
171
171
  tr.replaceWith(0, docEnd, ds.baseline.content);
172
172
  const meta = { type: 'clear' };
173
- tr.setMeta(aiInlineDiffPluginKey, meta);
173
+ tr.setMeta(inlineDiffPluginKey, meta);
174
174
  if (dispatch)
175
175
  dispatch(tr);
176
176
  return true;
@@ -181,11 +181,11 @@ export const AiInlineDiffExtension = Extension.create({
181
181
  const ext = this;
182
182
  return [
183
183
  new Plugin({
184
- key: aiInlineDiffPluginKey,
184
+ key: inlineDiffPluginKey,
185
185
  state: {
186
186
  init() { return null; },
187
187
  apply(tr, value) {
188
- const meta = tr.getMeta(aiInlineDiffPluginKey);
188
+ const meta = tr.getMeta(inlineDiffPluginKey);
189
189
  if (meta?.type === 'start') {
190
190
  // Baseline captured BEFORE the replaceRange step in this
191
191
  // same transaction. The changeset's `addSteps` consumes
@@ -210,10 +210,10 @@ export const AiInlineDiffExtension = Extension.create({
210
210
  },
211
211
  props: {
212
212
  decorations(state) {
213
- const ds = aiInlineDiffPluginKey.getState(state);
213
+ const ds = inlineDiffPluginKey.getState(state);
214
214
  if (!ds)
215
215
  return DecorationSet.empty;
216
- return buildDiffDecorations(state, ds, ext.options.classPrefix ?? 'pilotiq-ai-diff');
216
+ return buildDiffDecorations(state, ds, ext.options.classPrefix ?? 'pilotiq-diff');
217
217
  },
218
218
  // While a LINES-mode diff is active, force the editor root to
219
219
  // block layout. Some text surfaces style the root as a flex row
@@ -221,9 +221,9 @@ export const AiInlineDiffExtension = Extension.create({
221
221
  // rows lay out as overflowing columns. Drops automatically on
222
222
  // accept / reject.
223
223
  attributes(state) {
224
- const ds = aiInlineDiffPluginKey.getState(state);
224
+ const ds = inlineDiffPluginKey.getState(state);
225
225
  return ds?.displayMode === 'lines'
226
- ? { class: `${ext.options.classPrefix ?? 'pilotiq-ai-diff'}-lines-active` }
226
+ ? { class: `${ext.options.classPrefix ?? 'pilotiq-diff'}-lines-active` }
227
227
  : {};
228
228
  },
229
229
  },
@@ -246,7 +246,7 @@ function buildDiffDecorations(state, ds, prefix) {
246
246
  if (toB > fromB) {
247
247
  decos.push(Decoration.inline(fromB, toB, {
248
248
  class: `${prefix}-inserted`,
249
- 'data-pilotiq-ai-diff-id': ds.id,
249
+ 'data-pilotiq-diff-id': ds.id,
250
250
  }));
251
251
  }
252
252
  // Deleted content — pull from the baseline using the `fromA..toA`
@@ -257,7 +257,7 @@ function buildDiffDecorations(state, ds, prefix) {
257
257
  decos.push(Decoration.widget(fromB, () => buildDeletedWidget(ds.baseline, change.fromA, change.toA, prefix, ds.id), {
258
258
  side: -1,
259
259
  ignoreSelection: true,
260
- key: `pilotiq-ai-diff:deleted:${change.fromA}:${change.toA}`,
260
+ key: `pilotiq-diff:deleted:${change.fromA}:${change.toA}`,
261
261
  }));
262
262
  }
263
263
  }
@@ -281,7 +281,7 @@ function buildDiffDecorations(state, ds, prefix) {
281
281
  function buildDeletedWidget(baseline, fromA, toA, prefix, id) {
282
282
  const root = document.createElement('span');
283
283
  root.className = `${prefix}-deleted`;
284
- root.setAttribute('data-pilotiq-ai-diff-id', id);
284
+ root.setAttribute('data-pilotiq-diff-id', id);
285
285
  root.contentEditable = 'false';
286
286
  // Walk the baseline's top-level blocks; for each one the deleted range
287
287
  // touches, keep the whole node when fully covered, else cut it to the
@@ -356,7 +356,7 @@ function buildLineDiffDecorations(state, ds, prefix) {
356
356
  decos.push(Decoration.widget(anchor, () => buildDeletedLinesWidget(nodes, schema, prefix, ds.id), {
357
357
  side: -1,
358
358
  ignoreSelection: true,
359
- key: `pilotiq-ai-diff:deleted-lines:${anchor}:${nodes.length}`,
359
+ key: `pilotiq-diff:deleted-lines:${anchor}:${nodes.length}`,
360
360
  }));
361
361
  };
362
362
  for (const tok of lcsBlockDiffTokens(baseBlocks.map(b => b.text), current.map(c => c.text))) {
@@ -370,7 +370,7 @@ function buildLineDiffDecorations(state, ds, prefix) {
370
370
  flushRemoved(current[j].pos);
371
371
  decos.push(Decoration.node(current[j].pos, current[j].pos + current[j].nodeSize, {
372
372
  class: `${prefix}-inserted-line`,
373
- 'data-pilotiq-ai-diff-id': ds.id,
373
+ 'data-pilotiq-diff-id': ds.id,
374
374
  }));
375
375
  j++;
376
376
  continue;
@@ -435,7 +435,7 @@ function lcsBlockDiffTokens(a, b) {
435
435
  function buildDeletedLinesWidget(nodes, schema, prefix, id) {
436
436
  const root = document.createElement('div');
437
437
  root.className = `${prefix}-deleted-lines`;
438
- root.setAttribute('data-pilotiq-ai-diff-id', id);
438
+ root.setAttribute('data-pilotiq-diff-id', id);
439
439
  root.contentEditable = 'false';
440
440
  const serializer = DOMSerializer.fromSchema(schema);
441
441
  for (const node of nodes) {
@@ -8,7 +8,7 @@ import { PluginKey } from '@tiptap/pm/state';
8
8
  * editor as-is when the suggestion is approved (the original range's marks
9
9
  * are preserved on the inserted text node by ProseMirror).
10
10
  */
11
- export interface AiSuggestion {
11
+ export interface InlineSuggestion {
12
12
  /** Stable id; consumer-provided. Re-adding with the same id replaces the prior entry. */
13
13
  id: string;
14
14
  /** Inclusive document position the original range starts at. */
@@ -23,16 +23,16 @@ export interface AiSuggestion {
23
23
  agentLabel?: string;
24
24
  };
25
25
  }
26
- export interface AiSuggestionExtensionOptions {
26
+ export interface SuggestionChipExtensionOptions {
27
27
  /**
28
28
  * Class prefix for both decoration spans and chip widgets. The package
29
29
  * stays CSS-free — consumers ship the matching styles. Default
30
- * `'pilotiq-ai-suggestion'` produces classes:
31
- * - `pilotiq-ai-suggestion-original` (strikethrough on the original range)
32
- * - `pilotiq-ai-suggestion-chip` (root of the inline widget)
33
- * - `pilotiq-ai-suggestion-replacement` (the suggested-text preview span)
34
- * - `pilotiq-ai-suggestion-accept` (Approve button)
35
- * - `pilotiq-ai-suggestion-reject` (Reject button)
30
+ * `'pilotiq-suggestion'` produces classes:
31
+ * - `pilotiq-suggestion-original` (strikethrough on the original range)
32
+ * - `pilotiq-suggestion-chip` (root of the inline widget)
33
+ * - `pilotiq-suggestion-replacement` (the suggested-text preview span)
34
+ * - `pilotiq-suggestion-accept` (Approve button)
35
+ * - `pilotiq-suggestion-reject` (Reject button)
36
36
  */
37
37
  classPrefix: string;
38
38
  /**
@@ -40,52 +40,52 @@ export interface AiSuggestionExtensionOptions {
40
40
  * `reject*`, `clear*`, or after a doc edit collapses a range. Lets the host
41
41
  * mirror state into a React context (e.g. `PendingSuggestionsApi`).
42
42
  */
43
- onChange?: (suggestions: AiSuggestion[]) => void;
43
+ onChange?: (suggestions: InlineSuggestion[]) => void;
44
44
  }
45
45
  declare module '@tiptap/core' {
46
46
  interface Commands<ReturnType> {
47
- aiSuggestion: {
47
+ suggestionChip: {
48
48
  /** Add or replace a suggestion (matched by id). */
49
- addAiSuggestion: (suggestion: AiSuggestion) => ReturnType;
49
+ addSuggestion: (suggestion: InlineSuggestion) => ReturnType;
50
50
  /** Add or replace many suggestions in one transaction. */
51
- addAiSuggestions: (suggestions: AiSuggestion[]) => ReturnType;
51
+ addSuggestions: (suggestions: InlineSuggestion[]) => ReturnType;
52
52
  /** Apply the replacement to the doc and drop the suggestion. */
53
- approveAiSuggestion: (id: string) => ReturnType;
53
+ approveSuggestion: (id: string) => ReturnType;
54
54
  /** Drop the suggestion without touching the doc. */
55
- rejectAiSuggestion: (id: string) => ReturnType;
55
+ rejectSuggestion: (id: string) => ReturnType;
56
56
  /** Apply every replacement in highest-`from`-first order. */
57
- approveAllAiSuggestions: () => ReturnType;
57
+ approveAllSuggestions: () => ReturnType;
58
58
  /** Drop every suggestion. */
59
- rejectAllAiSuggestions: () => ReturnType;
60
- /** Alias for `rejectAllAiSuggestions`. */
61
- clearAiSuggestions: () => ReturnType;
59
+ rejectAllSuggestions: () => ReturnType;
60
+ /** Alias for `rejectAllSuggestions`. */
61
+ clearSuggestions: () => ReturnType;
62
62
  };
63
63
  }
64
64
  }
65
65
  interface PluginState {
66
- suggestions: readonly AiSuggestion[];
66
+ suggestions: readonly InlineSuggestion[];
67
67
  }
68
- export declare const aiSuggestionPluginKey: PluginKey<PluginState>;
68
+ export declare const suggestionChipPluginKey: PluginKey<PluginState>;
69
69
  /**
70
70
  * Append or replace by id. Pure — exported for tests and so the same dedupe
71
71
  * shape can drive consumer-side mirror state.
72
72
  */
73
- export declare function upsertSuggestion(current: readonly AiSuggestion[], next: AiSuggestion): AiSuggestion[];
73
+ export declare function upsertSuggestion(current: readonly InlineSuggestion[], next: InlineSuggestion): InlineSuggestion[];
74
74
  /** Append or replace many — semantically equivalent to a fold over `upsertSuggestion`. */
75
- export declare function upsertSuggestions(current: readonly AiSuggestion[], nexts: readonly AiSuggestion[]): AiSuggestion[];
75
+ export declare function upsertSuggestions(current: readonly InlineSuggestion[], nexts: readonly InlineSuggestion[]): InlineSuggestion[];
76
76
  /** Remove by id. */
77
- export declare function removeSuggestion(current: readonly AiSuggestion[], id: string): AiSuggestion[];
77
+ export declare function removeSuggestion(current: readonly InlineSuggestion[], id: string): InlineSuggestion[];
78
78
  /**
79
79
  * Remap survivors through a PM mapping; drop ranges that collapsed past
80
80
  * each other (`to < from` after remap). Pure — exported for tests.
81
81
  */
82
- export declare function remapSuggestions(suggestions: readonly AiSuggestion[], map: (pos: number, side: -1 | 1) => number): AiSuggestion[];
82
+ export declare function remapSuggestions(suggestions: readonly InlineSuggestion[], map: (pos: number, side: -1 | 1) => number): InlineSuggestion[];
83
83
  /**
84
84
  * Order suggestions for `approveAll` so the highest-`from` runs first;
85
85
  * earlier-in-doc replacements then can't shift positions of later ones.
86
86
  * Pure — exported for tests.
87
87
  */
88
- export declare function sortForApproveAll(suggestions: readonly AiSuggestion[]): AiSuggestion[];
88
+ export declare function sortForApproveAll(suggestions: readonly InlineSuggestion[]): InlineSuggestion[];
89
89
  /**
90
90
  * Editor extension that tracks AI-suggested edits as inline decorations with
91
91
  * per-hunk Approve/Reject chips. The package is CSS-free — consumers wire
@@ -93,7 +93,7 @@ export declare function sortForApproveAll(suggestions: readonly AiSuggestion[]):
93
93
  *
94
94
  * Usage:
95
95
  * ```ts
96
- * editor.commands.addAiSuggestion({
96
+ * editor.commands.addSuggestion({
97
97
  * id: 'seo-1',
98
98
  * from: 12,
99
99
  * to: 18,
@@ -101,14 +101,14 @@ export declare function sortForApproveAll(suggestions: readonly AiSuggestion[]):
101
101
  * source: { agentLabel: 'SEO' },
102
102
  * })
103
103
  * // …user clicks ✓ on the chip, or:
104
- * editor.commands.approveAiSuggestion('seo-1')
104
+ * editor.commands.approveSuggestion('seo-1')
105
105
  * ```
106
106
  *
107
107
  * Mounted by default inside `TiptapEditor`; consumer code reaches it through
108
108
  * the editor's command surface.
109
109
  */
110
- export declare const AiSuggestionExtension: Extension<AiSuggestionExtensionOptions, any>;
110
+ export declare const SuggestionChipExtension: Extension<SuggestionChipExtensionOptions, any>;
111
111
  /** Bound `pos` into `[0, max]`; non-finite or negative input collapses to 0. */
112
112
  export declare function clampPos(pos: number, max: number): number;
113
113
  export {};
114
- //# sourceMappingURL=AiSuggestionExtension.d.ts.map
114
+ //# sourceMappingURL=SuggestionChipExtension.d.ts.map