@tiptap/extension-collaboration
Version:
collaboration extension for tiptap
93 lines (80 loc) • 2.69 kB
text/typescript
import {
type GetUpdatedPositionResult,
getUpdatedPosition as coreGetUpdatedPosition,
MappablePosition,
} from '@tiptap/core'
import type { EditorState, Transaction } from '@tiptap/pm/state'
import { isChangeOrigin } from './isChangeOrigin.js'
import {
type YRelativePosition,
getYAbsolutePosition,
getYRelativePosition,
} from './yRelativePosition.js'
/**
* A MappablePosition subclass that includes Y.js relative position information
* to track positions in collaborative transactions.
*/
export class CollaborationMappablePosition extends MappablePosition {
/**
* The Y.js relative position used for mapping positions in collaborative editing.
*/
public yRelativePosition: YRelativePosition
constructor(position: number, yRelativePosition: YRelativePosition) {
super(position)
this.yRelativePosition = yRelativePosition
}
/**
* Creates a CollaborationMappablePosition from a JSON object.
*/
static fromJSON(json: any): CollaborationMappablePosition {
return new CollaborationMappablePosition(json.position, json.yRelativePosition)
}
/**
* Converts the CollaborationMappablePosition to a JSON object.
*/
toJSON(): any {
return {
position: this.position,
yRelativePosition: this.yRelativePosition,
}
}
}
/**
* Creates a MappablePosition from a position number.
* This is the collaboration implementation that returns a CollaborationMappablePosition.
*/
export function createMappablePosition(
position: number,
state: EditorState,
): CollaborationMappablePosition {
const yRelativePosition = getYRelativePosition(state, position)
return new CollaborationMappablePosition(position, yRelativePosition)
}
/**
* Returns the new position after applying a transaction. Handles both Y.js
* transactions and regular transactions.
*/
export function getUpdatedPosition(
position: MappablePosition,
transaction: Transaction,
state: EditorState,
): GetUpdatedPositionResult {
const yRelativePosition =
position instanceof CollaborationMappablePosition ? position.yRelativePosition : null
if (isChangeOrigin(transaction) && yRelativePosition) {
const absolutePosition = getYAbsolutePosition(state, yRelativePosition)
return {
position: new CollaborationMappablePosition(absolutePosition, yRelativePosition),
mapResult: null,
}
}
const result = coreGetUpdatedPosition(position, transaction)
const absolutePosition = result.position.position
return {
position: new CollaborationMappablePosition(
absolutePosition,
yRelativePosition ?? getYRelativePosition(state, absolutePosition),
),
mapResult: result.mapResult,
}
}