@lax-wp/editor 0.4.15 → 0.4.16

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 (47) hide show
  1. package/dist/components/sidebar/content/TrackChangesContent.d.ts +8 -0
  2. package/dist/components/sidebar/content/anonymization-page/anonymizationUtils.d.ts +1 -0
  3. package/dist/components/trackChanges/TrackChangesCards.d.ts +1 -0
  4. package/dist/components/trackChanges/index.d.ts +2 -0
  5. package/dist/components/trackChanges/utils.d.ts +5 -0
  6. package/dist/config/EditorConfig.d.ts +1 -1
  7. package/dist/constants/Extensions.d.ts +12 -0
  8. package/dist/extensions/AnonymizedText.d.ts +11 -1
  9. package/dist/extensions/VariableText.d.ts +20 -0
  10. package/dist/extensions/index.d.ts +1 -1
  11. package/dist/extensions/redline/changeTypes.d.ts +70 -0
  12. package/dist/extensions/redline/constants.d.ts +25 -0
  13. package/dist/extensions/redline/engine/blockNodes.d.ts +31 -0
  14. package/dist/extensions/redline/engine/clipboard.d.ts +16 -0
  15. package/dist/extensions/redline/engine/deletion.d.ts +34 -0
  16. package/dist/extensions/redline/engine/formatSplit.d.ts +16 -0
  17. package/dist/extensions/redline/engine/insertion.d.ts +26 -0
  18. package/dist/extensions/redline/engine/predicates.d.ts +73 -0
  19. package/dist/extensions/redline/engine/textReplace.d.ts +19 -0
  20. package/dist/extensions/redline/id.d.ts +7 -0
  21. package/dist/extensions/redline/index.d.ts +36 -0
  22. package/dist/extensions/redline/plugin.d.ts +34 -0
  23. package/dist/extensions/redline/query/scan.d.ts +52 -0
  24. package/dist/extensions/redline/review/applyChange.d.ts +25 -0
  25. package/dist/extensions/redline/review/index.d.ts +1 -0
  26. package/dist/extensions/redline/review/nodeResolvers.d.ts +29 -0
  27. package/dist/extensions/redline/review/pairedNodes.d.ts +38 -0
  28. package/dist/extensions/redline/review/structuralRevert.d.ts +20 -0
  29. package/dist/extensions/redline/review/textResolver.d.ts +9 -0
  30. package/dist/extensions/redline/schema/marks.d.ts +65 -0
  31. package/dist/extensions/redline/schema/shared.d.ts +34 -0
  32. package/dist/extensions/redline/session.d.ts +71 -0
  33. package/dist/extensions/redline/types.d.ts +24 -0
  34. package/dist/extensions/trackedChanges/TrackedChanges.d.ts +64 -0
  35. package/dist/extensions/trackedChanges/constants.d.ts +34 -0
  36. package/dist/extensions/trackedChanges/engine.d.ts +32 -0
  37. package/dist/extensions/trackedChanges/index.d.ts +13 -0
  38. package/dist/extensions/trackedChanges/marks.d.ts +20 -0
  39. package/dist/extensions/trackedChanges/normalize.d.ts +2 -0
  40. package/dist/extensions/trackedChanges/plugin.d.ts +32 -0
  41. package/dist/extensions/trackedChanges/query.d.ts +3 -0
  42. package/dist/extensions/trackedChanges/review.d.ts +34 -0
  43. package/dist/extensions/trackedChanges/types.d.ts +72 -0
  44. package/dist/extensions/trackedChanges/utils.d.ts +20 -0
  45. package/dist/index.es.js +7675 -7498
  46. package/dist/index.umd.js +85 -85
  47. package/package.json +1 -1
@@ -0,0 +1,29 @@
1
+ import type { Editor } from '@tiptap/core';
2
+ import type { EditorState, Transaction } from '@tiptap/pm/state';
3
+ import type { RedlineChange } from '../changeTypes';
4
+ /**
5
+ * Per-node-type review resolvers (change-tracking.md M3 — accept/reject
6
+ * semantics per encoding).
7
+ *
8
+ * Each resolver receives the shared ResolveContext (one transaction per
9
+ * change) and returns:
10
+ * - `true` / `false` — the change was handled (dispatched or not),
11
+ * - `'fallthrough'` — the target node could not be located; control
12
+ * continues to later resolvers and ultimately the text path, exactly
13
+ * matching the legacy if-chain's fall-through behavior.
14
+ */
15
+ export interface ResolveContext {
16
+ editor: Editor;
17
+ state: EditorState;
18
+ tr: Transaction;
19
+ dispatchWithSkipMeta: () => void;
20
+ }
21
+ export type ResolveResult = boolean | 'fallthrough';
22
+ export declare const resolveImageChange: (ctx: ResolveContext, change: RedlineChange, operation: "accept" | "reject") => ResolveResult;
23
+ export declare const resolveDividerChange: (ctx: ResolveContext, change: RedlineChange, operation: "accept" | "reject") => ResolveResult;
24
+ export declare const resolveTableRowChange: (ctx: ResolveContext, change: RedlineChange, operation: "accept" | "reject") => ResolveResult;
25
+ export declare const resolveTableColumnChange: (ctx: ResolveContext, change: RedlineChange, operation: "accept" | "reject") => ResolveResult;
26
+ export declare const resolveTableChange: (ctx: ResolveContext, change: RedlineChange, operation: "accept" | "reject") => ResolveResult;
27
+ export declare const resolveSignatureChange: (ctx: ResolveContext, change: RedlineChange, operation: "accept" | "reject") => ResolveResult;
28
+ export declare const resolveBlockquoteChange: (ctx: ResolveContext, change: RedlineChange, operation: "accept" | "reject") => ResolveResult;
29
+ export declare const resolveVariableChange: (ctx: ResolveContext, change: RedlineChange, operation: "accept" | "reject") => ResolveResult;
@@ -0,0 +1,38 @@
1
+ import type { EditorState, Transaction } from '@tiptap/pm/state';
2
+ /**
3
+ * Paired-node resolution (change-tracking.md M3.6 — atomicity).
4
+ *
5
+ * When a gesture deletes/pastes block nodes together with text, the nodes
6
+ * share the text change's mark id (see engine/blockNodes and the paste
7
+ * batch). Resolving that text change must resolve the paired nodes in the
8
+ * SAME transaction, mapping positions through earlier edits.
9
+ *
10
+ * Four node kinds use the `redline*` attribute scheme and identical action
11
+ * semantics, differing only in their "insert" action name and which extra
12
+ * attrs get cleared — previously four copy-pasted blocks, now one function:
13
+ *
14
+ * | node | insert action | extra cleared attr |
15
+ * |----------------|---------------|----------------------|
16
+ * | horizontalRule | 'insert' | redlineGroupId |
17
+ * | image | 'insert' | redlinePriorAction |
18
+ * | signature | 'add' | redlinePriorAction |
19
+ * | variableText | 'add' | redlinePriorAction |
20
+ *
21
+ * Tables use the `data-redline-*` scheme with type-based (not action-based)
22
+ * semantics and keep their own resolver.
23
+ */
24
+ interface PlainAttrNodeSpec {
25
+ nodeName: string;
26
+ insertAction: 'insert' | 'add';
27
+ /** Extra attribute keys cleared alongside the shared redline* identity attrs. */
28
+ extraClearKeys: string[];
29
+ }
30
+ export declare const PAIRED_PLAIN_ATTR_NODES: PlainAttrNodeSpec[];
31
+ export declare function resolvePairedPlainAttrNodes(state: EditorState, tr: Transaction, targetMarkIds: Set<string>, operation: 'accept' | 'reject', spec: PlainAttrNodeSpec): void;
32
+ /**
33
+ * Tables deleted in the same selection as text share its mark id via
34
+ * `data-redline-id`; semantics are type-based (insertion vs deletion type)
35
+ * with `data-redline-prior-type` remembering an overlaid same-user insertion.
36
+ */
37
+ export declare function resolvePairedTables(state: EditorState, tr: Transaction, targetMarkIds: Set<string>, operation: 'accept' | 'reject'): void;
38
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { Editor } from '@tiptap/core';
2
+ /**
3
+ * Structural-revert helpers (change-tracking.md M3 — reject semantics for
4
+ * node-level formats).
5
+ *
6
+ * Rejecting a format-change suggestion must physically restore the previous
7
+ * structure, which for lists/headings/alignment/blockquotes/indent cannot be
8
+ * done with mark operations alone — the recorded editor commands are re-run
9
+ * with the skip meta so the revert itself is not tracked as a new change.
10
+ */
11
+ export type TrackedListState = 'none' | 'task' | `bullet:${string}` | `ordered:${string}`;
12
+ export type TrackedHeadingState = 'paragraph' | `h${1 | 2 | 3 | 4 | 5 | 6}`;
13
+ export type TrackedTextAlignState = 'left' | 'center' | 'right' | 'justify';
14
+ export type TrackedBlockquoteState = boolean;
15
+ export declare const applyTrackedListState: (editor: Editor, from: number, to: number, targetState: TrackedListState) => void;
16
+ export declare const applyTrackedHeadingState: (editor: Editor, from: number, to: number, targetState: TrackedHeadingState) => void;
17
+ export declare const applyTrackedTextAlignState: (editor: Editor, from: number, to: number, targetState: TrackedTextAlignState) => void;
18
+ export declare const applyTrackedMarkerFontSizeState: (editor: Editor, from: number, to: number, targetState: string | null) => void;
19
+ export declare const applyTrackedBlockquoteState: (editor: Editor, from: number, to: number, targetState: TrackedBlockquoteState) => void;
20
+ export declare const applyTrackedIndentState: (editor: Editor, from: number, to: number, targetIndent: number) => void;
@@ -0,0 +1,9 @@
1
+ import type { RedlineChange } from '../changeTypes';
2
+ import type { ResolveContext, ResolveResult } from './nodeResolvers';
3
+ export declare const resolveLinkChange: (ctx: ResolveContext, change: RedlineChange, operation: "accept" | "reject") => ResolveResult;
4
+ /**
5
+ * Handles format-change and plain insertion/deletion marks, then resolves
6
+ * paired block nodes sharing the same mark id. This is the final resolver —
7
+ * it always returns a boolean.
8
+ */
9
+ export declare const resolveTextChange: (ctx: ResolveContext, change: RedlineChange, operation: "accept" | "reject") => boolean;
@@ -0,0 +1,65 @@
1
+ import { Mark } from '@tiptap/core';
2
+ import { type RedlineBaseAttributes, type RedlineExtendedAttributes } from './shared';
3
+ /**
4
+ * Redline inline marks (change-tracking.md M0.1).
5
+ *
6
+ * Two shapes, one insertion/deletion pair per authoring mode:
7
+ *
8
+ * - insertion marks carry the extended attribute set (formatChanges,
9
+ * linkData, groupId) and derive their class/tooltip via
10
+ * getRedlineInsertionPresentation,
11
+ * - deletion marks carry only the base identity attributes and a static
12
+ * class; all visual treatment (strikethrough/colors) comes from the
13
+ * decoration CSS, never inline styles.
14
+ *
15
+ * All marks are `inclusive: false`: typing at a mark edge must not silently
16
+ * extend someone's suggestion — extension is an explicit engine decision
17
+ * (adjacency/typing-session grouping in the tracking engine).
18
+ */
19
+ export interface RedlineMarkOptions {
20
+ HTMLAttributes: Record<string, string>;
21
+ }
22
+ export type UserInsertionAttributes = RedlineExtendedAttributes;
23
+ export type AIInsertionAttributes = RedlineExtendedAttributes;
24
+ export type UserDeletionAttributes = RedlineBaseAttributes;
25
+ export type AIDeletionAttributes = RedlineBaseAttributes;
26
+ declare module '@tiptap/core' {
27
+ interface Commands<ReturnType> {
28
+ userInsertion: {
29
+ /** Set user insertion mark */
30
+ setUserInsertion: (attributes: UserInsertionAttributes) => ReturnType;
31
+ /** Toggle user insertion mark */
32
+ toggleUserInsertion: (attributes: UserInsertionAttributes) => ReturnType;
33
+ /** Unset user insertion mark */
34
+ unsetUserInsertion: () => ReturnType;
35
+ };
36
+ userDeletion: {
37
+ /** Set user deletion mark */
38
+ setUserDeletion: (attributes: UserDeletionAttributes) => ReturnType;
39
+ /** Toggle user deletion mark */
40
+ toggleUserDeletion: (attributes: UserDeletionAttributes) => ReturnType;
41
+ /** Unset user deletion mark */
42
+ unsetUserDeletion: () => ReturnType;
43
+ };
44
+ aiInsertion: {
45
+ /** Set AI insertion mark */
46
+ setAIInsertion: (attributes: AIInsertionAttributes) => ReturnType;
47
+ /** Toggle AI insertion mark */
48
+ toggleAIInsertion: (attributes: AIInsertionAttributes) => ReturnType;
49
+ /** Unset AI insertion mark */
50
+ unsetAIInsertion: () => ReturnType;
51
+ };
52
+ aiDeletion: {
53
+ /** Set AI deletion mark */
54
+ setAIDeletion: (attributes: AIDeletionAttributes) => ReturnType;
55
+ /** Toggle AI deletion mark */
56
+ toggleAIDeletion: (attributes: AIDeletionAttributes) => ReturnType;
57
+ /** Unset AI deletion mark */
58
+ unsetAIDeletion: () => ReturnType;
59
+ };
60
+ }
61
+ }
62
+ export declare const UserInsertion: Mark<RedlineMarkOptions, any>;
63
+ export declare const AIInsertion: Mark<RedlineMarkOptions, any>;
64
+ export declare const UserDeletion: Mark<RedlineMarkOptions, any>;
65
+ export declare const AIDeletion: Mark<RedlineMarkOptions, any>;
@@ -0,0 +1,34 @@
1
+ import type { Attribute } from '@tiptap/core';
2
+ export interface RedlineBaseAttributes {
3
+ id: string;
4
+ userId: string;
5
+ userName: string;
6
+ timestamp: string;
7
+ }
8
+ export interface RedlineExtendedAttributes extends RedlineBaseAttributes {
9
+ formatChanges?: string;
10
+ linkData?: string;
11
+ }
12
+ export declare const createRedlineBaseAttributes: (includeExtendedFields?: boolean) => Record<string, Attribute>;
13
+ export declare const getRedlineInsertionPresentation: (htmlAttributes: Record<string, unknown>, baseClassName: string, regularColor: string) => {
14
+ title?: string | undefined;
15
+ style: string;
16
+ className: string;
17
+ };
18
+ export declare const createRedlineMarkCommands: <TAttributes>(markName: string) => {
19
+ setMarkCommand: (attributes: TAttributes) => ({ commands }: {
20
+ commands: {
21
+ setMark: (name: string, attrs: TAttributes) => boolean;
22
+ };
23
+ }) => boolean;
24
+ toggleMarkCommand: (attributes: TAttributes) => ({ commands }: {
25
+ commands: {
26
+ toggleMark: (name: string, attrs: TAttributes) => boolean;
27
+ };
28
+ }) => boolean;
29
+ unsetMarkCommand: () => ({ commands }: {
30
+ commands: {
31
+ unsetMark: (name: string) => boolean;
32
+ };
33
+ }) => boolean;
34
+ };
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Redline session state (change-tracking.md M1/M2 — engine context).
3
+ *
4
+ * The tracking engine spans several cooperating ProseMirror plugins (keymap,
5
+ * input props, appendTransaction trackers) that must agree on batch identity
6
+ * within one synchronous editing gesture:
7
+ *
8
+ * - paste batch — one mark id per paste so text + dividers + images pasted
9
+ * together appear as a single panel card,
10
+ * - deletion batch — one mark id per Backspace/Delete gesture so dividers
11
+ * removed together with text share the text's card,
12
+ * - typing session — cross-block grouping (Docs model): typing + Enter +
13
+ * typing stays one card until the cursor navigates away,
14
+ * - pending list format — a list toggled on an EMPTY paragraph has no text
15
+ * range to mark yet; the intent is parked here and merged
16
+ * into the next insertion so the panel shows
17
+ * "Add List Item" instead of plain "Add".
18
+ *
19
+ * Batches are deliberately cleared on the next macrotask (setTimeout 0):
20
+ * every appendTransaction triggered by the same gesture runs synchronously,
21
+ * so "this tick" is exactly the batch boundary.
22
+ *
23
+ * Previously this state was spread across module-level singletons
24
+ * (redlineSharedMeta.ts) and factory closures; it is now one object owned by
25
+ * the Redline extension and passed explicitly to the engine functions.
26
+ */
27
+ export interface BatchState {
28
+ activeMarkId: string | null;
29
+ activeTimestamp: string | null;
30
+ }
31
+ export interface PendingListFormat {
32
+ listOld: string | null;
33
+ listNew: string | null;
34
+ userId: string | null;
35
+ userName: string | null;
36
+ mode: 'user' | 'ai' | null;
37
+ }
38
+ export declare class RedlineSession {
39
+ /** Shared mark identity for the current paste gesture. */
40
+ readonly pasteBatch: BatchState;
41
+ /** Shared mark identity for the current keyboard-deletion gesture. */
42
+ readonly deletionBatch: BatchState;
43
+ /** Cross-block typing session (cleared on pure cursor navigation). */
44
+ typingSessionMarkId: string | null;
45
+ typingSessionUserId: string | null;
46
+ /** List activation on an empty paragraph, awaiting the first insertion. */
47
+ readonly pendingListFormat: PendingListFormat;
48
+ private pasteTimeout;
49
+ /** Opens a paste batch for the current tick; auto-clears next macrotask. */
50
+ beginPasteBatch(markId: string, timestamp: string): void;
51
+ /** Opens a deletion batch for the current tick; auto-clears next macrotask. */
52
+ beginDeletionBatch(markId: string, timestamp: string): void;
53
+ setTypingSession(markId: string, userId: string): void;
54
+ /** Called by the view plugin on pure cursor navigation (selection moved,
55
+ * doc unchanged): ends the cross-block typing session and abandons any
56
+ * pending list format the user navigated away from. */
57
+ endTypingSession(): void;
58
+ setPendingListFormat(update: PendingListFormat): void;
59
+ clearPendingListFormat(): void;
60
+ }
61
+ /**
62
+ * The shared session instance.
63
+ *
64
+ * A single module-level instance (not per-extension) mirrors the legacy
65
+ * contract exactly: tracker plugins constructed in different factories must
66
+ * observe the same batch state within a gesture. The editor is a singleton
67
+ * per package consumer, so this is safe in practice; tests that need
68
+ * isolation can call `resetRedlineSession()`.
69
+ */
70
+ export declare const redlineSession: RedlineSession;
71
+ export declare const resetRedlineSession: () => void;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Shared types for the redline (track changes) system.
3
+ */
4
+ /** Entity performing the change (user or AI). */
5
+ export interface RedlineEntity {
6
+ id: string;
7
+ name: string;
8
+ }
9
+ export type RedlineMode = 'user' | 'ai';
10
+ /** Configuration options for the Redline extension. */
11
+ export interface RedlineOptions {
12
+ isActive: boolean;
13
+ mode: RedlineMode;
14
+ currentEntity: RedlineEntity;
15
+ }
16
+ /**
17
+ * Runtime tracking context resolved per keystroke/transaction: the live
18
+ * enabled/mode toggle plus the identity to attribute changes to.
19
+ */
20
+ export interface RedlineContext {
21
+ isActive: boolean;
22
+ mode: RedlineMode;
23
+ entity: RedlineEntity;
24
+ }
@@ -0,0 +1,64 @@
1
+ import { Extension } from '@tiptap/core';
2
+ import { type TrackedChangesShared } from './plugin';
3
+ import type { Suggestion, SuggestionEventHandler, SuggestionFilter, SuggestionUserMetadata, UntrackedOperationHandler } from './types';
4
+ export interface TrackedChangesOptions {
5
+ /** Start with suggest mode on. */
6
+ enabled: boolean;
7
+ /** Author attributed on new suggestions (M9 identity binding). */
8
+ userId: string;
9
+ /** Display metadata stored with every mark (name, color…). */
10
+ userMetadata: SuggestionUserMetadata;
11
+ /** Fired on suggestion create/update/accept/reject, local and remote (M4.3). */
12
+ onSuggestionEvent?: SuggestionEventHandler;
13
+ /** Fired with the full suggestion list whenever it changes (feeds the M7 store). */
14
+ onSuggestionsChange?: (suggestions: Suggestion[]) => void;
15
+ /** Fired when an operation is blocked or passes through untracked (5.3/5.8) — show a toast. */
16
+ onUntrackedOperation?: UntrackedOperationHandler;
17
+ }
18
+ export interface TrackedChangesStorage {
19
+ enabled: boolean;
20
+ userId: string;
21
+ userMetadata: SuggestionUserMetadata;
22
+ shared: TrackedChangesShared;
23
+ /** Query API over the plugin-state index (M4). */
24
+ getSuggestions: () => Suggestion[];
25
+ on: (handler: SuggestionEventHandler) => void;
26
+ off: (handler: SuggestionEventHandler) => void;
27
+ /** @internal */
28
+ handlers: Set<SuggestionEventHandler>;
29
+ }
30
+ declare module '@tiptap/core' {
31
+ interface Commands<ReturnType> {
32
+ trackedChanges: {
33
+ /** Turn suggest mode on (M4.4). */
34
+ enableSuggesting: () => ReturnType;
35
+ /** Turn suggest mode off. */
36
+ disableSuggesting: () => ReturnType;
37
+ toggleSuggesting: () => ReturnType;
38
+ /** Bind the identity attributed on new suggestions (M5: call on auth changes). */
39
+ setSuggestionUser: (user: {
40
+ userId: string;
41
+ userMetadata?: SuggestionUserMetadata;
42
+ }) => ReturnType;
43
+ /** Accept one suggestion by id ("acceptSuggestion" is taken by AI autocompletion). */
44
+ acceptTrackedChange: (id: string) => ReturnType;
45
+ /** Reject one suggestion by id. */
46
+ rejectTrackedChange: (id: string) => ReturnType;
47
+ /** Accept every suggestion, optionally filtered by user or ids (M3.5). */
48
+ acceptAllTrackedChanges: (filter?: SuggestionFilter) => ReturnType;
49
+ /** Reject every suggestion, optionally filtered by user or ids (M3.5). */
50
+ rejectAllTrackedChanges: (filter?: SuggestionFilter) => ReturnType;
51
+ /** Move the selection to a suggestion and scroll it into view. */
52
+ goToSuggestion: (id: string) => ReturnType;
53
+ };
54
+ }
55
+ }
56
+ /**
57
+ * Tracked Changes — our own suggest-mode extension (change-tracking.md v2).
58
+ *
59
+ * Packages M0 (schema marks), M1 (tracking engine), M2 (input behavior),
60
+ * M3 (review engine) and M4 (query/events/commands) as one Tiptap extension.
61
+ * Suggestions live entirely inside the document as marks, so Yjs sync and
62
+ * persistence handle replication and storage for free (D1).
63
+ */
64
+ export declare const TrackedChanges: Extension<TrackedChangesOptions, TrackedChangesStorage>;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Tracked Changes — shared constants (see change-tracking.md, M0/M1).
3
+ */
4
+ /** Mark names (M0.1). */
5
+ export declare const INSERTION_MARK_NAME = "insertion";
6
+ export declare const DELETION_MARK_NAME = "deletion";
7
+ export declare const MODIFICATION_MARK_NAME = "modification";
8
+ export declare const SUGGESTION_MARK_NAMES: readonly ["insertion", "deletion", "modification"];
9
+ /**
10
+ * Transaction meta key. Values:
11
+ * - 'track' — a transaction the engine rewrote (never re-process)
12
+ * - 'normalize' — merge/cleanup pass from appendTransaction
13
+ * - 'resolve' — an accept/reject transaction from the review engine
14
+ */
15
+ export declare const TRACKED_CHANGES_META = "trackedChanges$";
16
+ /** Current encoding version, stamped on every mark (M0, edge case 5.7). */
17
+ export declare const SUGGESTION_SCHEMA_VERSION = 1;
18
+ /** DOM data attributes emitted by renderHTML (M0.1). */
19
+ export declare const DATA_SUGGESTION_ID = "data-suggestion-id";
20
+ export declare const DATA_SUGGESTION_USER = "data-suggestion-user";
21
+ export declare const DATA_SUGGESTION_TYPE = "data-type";
22
+ export declare const DATA_SUGGESTION_CREATED_AT = "data-suggestion-created-at";
23
+ export declare const DATA_SUGGESTION_USER_METADATA = "data-suggestion-user-metadata";
24
+ export declare const DATA_SUGGESTION_SCHEMA_VERSION = "data-suggestion-schema-version";
25
+ /** Extra attributes for the `modification` mark (M0.1). */
26
+ export declare const DATA_MODIFICATION_MARK_NAME = "data-modification-mark-name";
27
+ export declare const DATA_MODIFICATION_ACTION = "data-modification-action";
28
+ export declare const DATA_MODIFICATION_PREVIOUS_ATTRS = "data-modification-previous-attrs";
29
+ export declare const DATA_MODIFICATION_NEW_ATTRS = "data-modification-new-attrs";
30
+ /** Metas of other plugins whose transactions must never be rewritten (M1.3). */
31
+ export declare const YJS_SYNC_META = "y-sync$";
32
+ export declare const YJS_UNDO_META = "y-undo$";
33
+ export declare const PM_HISTORY_META = "history$";
34
+ export declare const COMPOSITION_META = "composition";
@@ -0,0 +1,32 @@
1
+ import type { EditorState, Transaction } from '@tiptap/pm/state';
2
+ import type { SuggestionUserMetadata, UntrackedOperationHandler } from './types';
3
+ /**
4
+ * M1 — Tracking Engine.
5
+ *
6
+ * `rewriteTransaction` receives a would-be-dispatched local transaction and
7
+ * rebuilds it per the step-rewriting semantics table in change-tracking.md so
8
+ * that nothing is ever really deleted and everything added is attributed.
9
+ * It is a pure function over (state, tr) so it is unit-testable without a view.
10
+ */
11
+ export interface TrackContext {
12
+ userId: string;
13
+ userMetadata: SuggestionUserMetadata;
14
+ /** Timestamp stamped on new suggestion marks. */
15
+ now: number;
16
+ /** Which way the caret should walk after a rewritten deletion (M2.2). */
17
+ deleteDirection?: 'backward' | 'forward';
18
+ /** Notified when an operation is blocked or passed through untracked (5.3/5.8). */
19
+ onUntracked?: UntrackedOperationHandler;
20
+ }
21
+ /**
22
+ * M1.3 — exemption guards. Transactions that must pass through untouched:
23
+ * remote Yjs sync, undo/redo, history-excluded, our own rewrites, IME
24
+ * composition (rewriting mid-composition corrupts IME input — edge case 5.1).
25
+ */
26
+ export declare function isExemptTransaction(tr: Transaction, composing?: boolean): boolean;
27
+ /**
28
+ * Rebuild `tr` as a tracked transaction. Every step's coordinates are mapped
29
+ * from its own doc into the rebuilt transaction's doc via the inverted
30
+ * original mapping composed with our own mapping (M1.5).
31
+ */
32
+ export declare function rewriteTransaction(state: EditorState, tr: Transaction, ctx: TrackContext): Transaction;
@@ -0,0 +1,13 @@
1
+ export { TrackedChanges } from './TrackedChanges';
2
+ export type { TrackedChangesOptions, TrackedChangesStorage } from './TrackedChanges';
3
+ export { InsertionMark, DeletionMark, ModificationMark } from './marks';
4
+ export { findSuggestions } from './query';
5
+ export { resolveSuggestions } from './review';
6
+ export type { ResolveAction } from './review';
7
+ export { rewriteTransaction, isExemptTransaction } from './engine';
8
+ export type { TrackContext } from './engine';
9
+ export { trackedChangesPluginKey } from './plugin';
10
+ export type { TrackedChangesPluginState } from './plugin';
11
+ export * from './types';
12
+ export { INSERTION_MARK_NAME, DELETION_MARK_NAME, MODIFICATION_MARK_NAME, TRACKED_CHANGES_META, SUGGESTION_SCHEMA_VERSION, } from './constants';
13
+ export { suggestionColorForUser } from './utils';
@@ -0,0 +1,20 @@
1
+ import { Mark } from '@tiptap/core';
2
+ /**
3
+ * `insertion` — proposed new content (M0.1).
4
+ * `inclusive: true` so continued typing at the edge extends the author's own
5
+ * insertion (edge case 5.5); the engine re-attributes other users' typing.
6
+ */
7
+ export declare const InsertionMark: Mark<any, any>;
8
+ /**
9
+ * `deletion` — content proposed for removal; it stays in the document with a
10
+ * strikethrough (M0.1). `inclusive: false` so typing at the edge never silently
11
+ * extends someone's deletion (edge case 5.5).
12
+ */
13
+ export declare const DeletionMark: Mark<any, any>;
14
+ /**
15
+ * `modification` — a proposed formatting change (Tier 2, M0.1). The real
16
+ * formatting is *not* applied until accept; the mark records exactly what to
17
+ * apply (`markName`, `action`, `previousAttrs`, `newAttrs`).
18
+ * `excludes: ''` lets several pending format changes stack on the same text.
19
+ */
20
+ export declare const ModificationMark: Mark<any, any>;
@@ -0,0 +1,2 @@
1
+ import type { EditorState, Transaction } from '@tiptap/pm/state';
2
+ export declare function createNormalizeTransaction(state: EditorState): Transaction | null;
@@ -0,0 +1,32 @@
1
+ import { Plugin, PluginKey } from '@tiptap/pm/state';
2
+ import type { ResolveMeta } from './review';
3
+ import type { Suggestion, SuggestionEvent } from './types';
4
+ /**
5
+ * M2 (input behavior) + M4.2/M4.3 (plugin-state suggestion index + events),
6
+ * as one ProseMirror plugin owned by the TrackedChanges extension.
7
+ */
8
+ export interface TrackedChangesPluginState {
9
+ suggestions: Map<string, Suggestion>;
10
+ /** Present when the last transaction was an accept/reject (M3.7). */
11
+ lastResolve: ResolveMeta | null;
12
+ /** True when the last doc change arrived via Yjs sync. */
13
+ lastChangeWasRemote: boolean;
14
+ }
15
+ export interface TrackedChangesShared {
16
+ /** Set by handleKeyDown so the engine knows which way the caret walks (M2.2). */
17
+ deleteDirection: 'backward' | 'forward' | null;
18
+ /** Selection anchor recorded at compositionstart for IME reconciliation (M2.4). */
19
+ compositionStart: number | null;
20
+ }
21
+ export interface TrackedChangesPluginDeps {
22
+ isEnabled: () => boolean;
23
+ getUser: () => {
24
+ userId: string;
25
+ userMetadata: Record<string, unknown> | null;
26
+ };
27
+ emit: (event: SuggestionEvent) => void;
28
+ onSuggestionsChange?: (suggestions: Suggestion[]) => void;
29
+ shared: TrackedChangesShared;
30
+ }
31
+ export declare const trackedChangesPluginKey: PluginKey<TrackedChangesPluginState>;
32
+ export declare function createTrackedChangesPlugin(deps: TrackedChangesPluginDeps): Plugin;
@@ -0,0 +1,3 @@
1
+ import type { Node as PMNode } from '@tiptap/pm/model';
2
+ import type { Suggestion } from './types';
3
+ export declare function findSuggestions(doc: PMNode): Suggestion[];
@@ -0,0 +1,34 @@
1
+ import type { EditorState, Transaction } from '@tiptap/pm/state';
2
+ import type { SuggestionFilter } from './types';
3
+ /**
4
+ * M3 — Review Engine. Accept/reject as pure document transforms.
5
+ *
6
+ * Accept: insertion → unmark (content becomes real); deletion → really delete;
7
+ * modification → apply the recorded change, drop the mark.
8
+ * Reject: exact inverse — insertion → delete the content; deletion → unmark;
9
+ * modification → discard (the change was never applied, so the text
10
+ * already carries `previousAttrs`).
11
+ *
12
+ * Nested/stacked truth table (M3.4) falls out of op ordering below:
13
+ * - Reject an insertion carrying a stacked deletion → the content is deleted,
14
+ * so both vanish (the substrate is gone).
15
+ * - Accept an insertion carrying a stacked deletion → only the insertion mark
16
+ * is removed; the deletion suggestion survives on now-real content.
17
+ * - Accept a deletion stacked on someone's insertion → the content is deleted;
18
+ * the insertion suggestion is consumed with it.
19
+ */
20
+ export type ResolveAction = 'accept' | 'reject';
21
+ export interface ResolveMeta {
22
+ kind: 'resolve';
23
+ action: ResolveAction;
24
+ ids: string[];
25
+ }
26
+ export interface ResolveTarget extends SuggestionFilter {
27
+ all?: boolean;
28
+ }
29
+ /**
30
+ * Resolve every suggestion matched by `target` into the provided transaction
31
+ * (M3.5: bulk operations are one transaction — one undo step, one Yjs update).
32
+ * Returns false when nothing matched.
33
+ */
34
+ export declare function resolveSuggestions(state: EditorState, tr: Transaction, target: ResolveTarget, action: ResolveAction): boolean;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Tracked Changes — public types (change-tracking.md M4).
3
+ */
4
+ /** Suggestion type surfaced by the query API (M4.1). */
5
+ export type SuggestionType = 'add' | 'delete' | 'replace' | 'markChange';
6
+ export type SuggestionMarkKind = 'insertion' | 'deletion' | 'modification';
7
+ /** Arbitrary per-user display metadata carried on every mark (name, color, avatar…). */
8
+ export type SuggestionUserMetadata = Record<string, unknown> | null;
9
+ /** Attributes shared by all three suggestion marks (M0.1). */
10
+ export interface SuggestionMarkAttrs {
11
+ id: string | null;
12
+ userId: string | null;
13
+ createdAt: number | null;
14
+ userMetadata: SuggestionUserMetadata;
15
+ schemaVersion: number;
16
+ }
17
+ /** Extra attributes carried by the `modification` mark (M0.1). */
18
+ export interface ModificationMarkAttrs extends SuggestionMarkAttrs {
19
+ /** The formatting mark this suggestion proposes to add/remove (e.g. 'bold', 'link'). */
20
+ markName: string | null;
21
+ action: 'add' | 'remove' | null;
22
+ /** Attrs of the pre-existing same-type mark (so reject/accept can restore an exact href). */
23
+ previousAttrs: Record<string, unknown> | null;
24
+ newAttrs: Record<string, unknown> | null;
25
+ }
26
+ /** One contiguous document range carrying a suggestion mark. */
27
+ export interface SuggestionRange {
28
+ from: number;
29
+ to: number;
30
+ markKind: SuggestionMarkKind;
31
+ }
32
+ /** A suggestion as returned by the query API (M4.1). */
33
+ export interface Suggestion {
34
+ id: string;
35
+ type: SuggestionType;
36
+ userId: string | null;
37
+ userMetadata: SuggestionUserMetadata;
38
+ createdAt: number | null;
39
+ ranges: SuggestionRange[];
40
+ /** Text excluding content contributed by *nested* suggestions of other users. */
41
+ text: string;
42
+ /** The literal text of every range. */
43
+ fullText: string;
44
+ /** Present for `markChange` suggestions. */
45
+ modification?: {
46
+ markName: string | null;
47
+ action: 'add' | 'remove' | null;
48
+ previousAttrs: Record<string, unknown> | null;
49
+ newAttrs: Record<string, unknown> | null;
50
+ };
51
+ }
52
+ /** Event names emitted on the tracked-changes emitter (M4.3). */
53
+ export type SuggestionEventName = 'suggestion:create' | 'suggestion:update' | 'suggestion:accept' | 'suggestion:reject';
54
+ export interface SuggestionEvent {
55
+ name: SuggestionEventName;
56
+ suggestion: Suggestion;
57
+ /** True when the change arrived via collaboration rather than local editing. */
58
+ remote: boolean;
59
+ }
60
+ export type SuggestionEventHandler = (event: SuggestionEvent) => void;
61
+ /**
62
+ * Operations the engine cannot represent yet (Tier 2/3).
63
+ * 'block-structure' — Enter / paragraph join / block paste, blocked in suggest mode (edge case 5.3).
64
+ * 'untracked-step' — wrap/unwrap, node attrs… passed through untracked with this notice (edge case 5.8).
65
+ */
66
+ export type UntrackedOperationKind = 'block-structure' | 'untracked-step';
67
+ export type UntrackedOperationHandler = (kind: UntrackedOperationKind, detail?: string) => void;
68
+ /** Filter accepted by bulk accept/reject commands (M3.5). */
69
+ export interface SuggestionFilter {
70
+ userId?: string;
71
+ ids?: string[];
72
+ }
@@ -0,0 +1,20 @@
1
+ import type { Mark, Node as PMNode } from '@tiptap/pm/model';
2
+ /**
3
+ * UUIDv4 suggestion ids (M0.5) — counters would collide across concurrent
4
+ * offline clients and Yjs would happily merge them into one corrupted suggestion.
5
+ */
6
+ export declare function createSuggestionId(): string;
7
+ export declare function isSuggestionMark(mark: Mark): boolean;
8
+ export declare function getInsertionMark(node: PMNode): Mark | undefined;
9
+ export declare function getDeletionMark(node: PMNode): Mark | undefined;
10
+ export declare function getModificationMarks(node: PMNode): Mark[];
11
+ /** Serialize an attrs object into a DOM data attribute. */
12
+ export declare function jsonAttrToDom(value: unknown): string | null;
13
+ /** Parse a DOM data attribute back into an attrs object. */
14
+ export declare function jsonAttrFromDom(value: string | null): Record<string, unknown> | null;
15
+ /**
16
+ * Deterministic per-user hue so mark colors match across clients without
17
+ * coordination. An explicit `userMetadata.color` always wins (M8: colors are
18
+ * derived from userId, matching awareness cursors).
19
+ */
20
+ export declare function suggestionColorForUser(userId: string | null, userMetadata: Record<string, unknown> | null): string;