or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdplugins.mdutilities.md

index.mddocs/

0

# Y-ProseMirror

1

2

Y-ProseMirror provides ProseMirror bindings for Yjs that enable real-time collaborative editing. It offers essential collaborative features including document synchronization, shared cursor visibility, and individual undo/redo history for each user. The library handles concurrent editing conflicts and integrates seamlessly with ProseMirror's plugin system.

3

4

## Package Information

5

6

- **Package Name**: y-prosemirror

7

- **Package Type**: npm

8

- **Language**: JavaScript with TypeScript definitions

9

- **Installation**: `npm install y-prosemirror`

10

11

## Core Imports

12

13

```javascript

14

import { ySyncPlugin, yCursorPlugin, yUndoPlugin } from "y-prosemirror";

15

```

16

17

For CommonJS:

18

19

```javascript

20

const { ySyncPlugin, yCursorPlugin, yUndoPlugin } = require("y-prosemirror");

21

```

22

23

Utility functions:

24

25

```javascript

26

import {

27

prosemirrorToYDoc,

28

yXmlFragmentToProseMirrorRootNode,

29

absolutePositionToRelativePosition

30

} from "y-prosemirror";

31

```

32

33

## Basic Usage

34

35

```javascript

36

import * as Y from "yjs";

37

import { EditorView } from "prosemirror-view";

38

import { EditorState } from "prosemirror-state";

39

import { DOMParser, Schema } from "prosemirror-model";

40

import { Awareness } from "y-protocols/awareness";

41

import {

42

ySyncPlugin,

43

yCursorPlugin,

44

yUndoPlugin,

45

undo,

46

redo,

47

initProseMirrorDoc

48

} from "y-prosemirror";

49

import { keymap } from "prosemirror-keymap";

50

51

// Define your ProseMirror schema

52

const schema = new Schema({

53

nodes: {

54

doc: { content: "paragraph+" },

55

paragraph: { content: "text*", toDOM: () => ["p", 0] },

56

text: {}

57

}

58

});

59

60

// Create Yjs document and awareness

61

const ydoc = new Y.Doc();

62

const yXmlFragment = ydoc.getXmlFragment("prosemirror");

63

const awareness = new Awareness(ydoc);

64

65

// Initialize document from Yjs content (or create empty)

66

const { doc, mapping } = initProseMirrorDoc(yXmlFragment, schema);

67

68

// Create ProseMirror editor with collaborative plugins

69

const view = new EditorView(document.querySelector("#editor"), {

70

state: EditorState.create({

71

doc,

72

schema,

73

plugins: [

74

ySyncPlugin(yXmlFragment, { mapping }),

75

yCursorPlugin(awareness),

76

yUndoPlugin(),

77

keymap({

78

'Mod-z': undo,

79

'Mod-y': redo,

80

'Mod-Shift-z': redo

81

})

82

]

83

})

84

});

85

86

// Set user information for collaborative cursors

87

awareness.setLocalStateField('user', {

88

name: 'User Name',

89

color: '#ff6b6b'

90

});

91

```

92

93

## Architecture

94

95

Y-ProseMirror is built around several key components:

96

97

- **Synchronization Plugin**: Maintains bidirectional sync between Yjs and ProseMirror documents

98

- **Cursor Plugin**: Displays real-time cursors and selections from other users via awareness protocol

99

- **Undo Plugin**: Provides collaborative undo/redo with per-user history tracking

100

- **Binding System**: Core `ProsemirrorBinding` class managing the synchronization lifecycle

101

- **Conversion Utilities**: Functions for converting between Yjs and ProseMirror data structures

102

- **Position Mapping**: Utilities for converting between absolute and relative positions

103

104

## Capabilities

105

106

### Core Plugins

107

108

Essential ProseMirror plugins that enable collaborative editing with synchronization, cursors, and undo functionality.

109

110

```javascript { .api }

111

function ySyncPlugin(yXmlFragment: Y.XmlFragment, opts?: {

112

colors?: Array<ColorDef>;

113

colorMapping?: Map<string, ColorDef>;

114

permanentUserData?: Y.PermanentUserData | null;

115

mapping?: ProsemirrorMapping;

116

onFirstRender?: () => void;

117

}): Plugin;

118

119

function yCursorPlugin(awareness: Awareness, opts?: {

120

awarenessStateFilter?: (currentClientId: number, userClientId: number, user: any) => boolean;

121

cursorBuilder?: (user: any, clientId: number) => HTMLElement;

122

selectionBuilder?: (user: any, clientId: number) => DecorationAttrs;

123

getSelection?: (state: EditorState) => Selection;

124

}, cursorStateField?: string): Plugin;

125

126

function yUndoPlugin(options?: {

127

protectedNodes?: Set<string>;

128

trackedOrigins?: any[];

129

undoManager?: UndoManager | null;

130

}): Plugin;

131

```

132

133

[Core Plugins](./plugins.md)

134

135

### Document Conversion

136

137

Utilities for converting between ProseMirror and Yjs document formats, enabling data migration and persistence.

138

139

```javascript { .api }

140

function prosemirrorToYDoc(doc: Node, xmlFragment?: string): Y.Doc;

141

function yXmlFragmentToProseMirrorRootNode(yXmlFragment: Y.XmlFragment, schema: Schema): Node;

142

function prosemirrorJSONToYDoc(schema: Schema, state: object, xmlFragment?: string): Y.Doc;

143

```

144

145

[Document Conversion](./utilities.md)

146

147

### Position and Selection Utilities

148

149

Functions for managing positions and selections in collaborative editing contexts with relative position support.

150

151

```javascript { .api }

152

function absolutePositionToRelativePosition(pos: number, type: Y.AbstractType, mapping: ProsemirrorMapping): Y.RelativePosition;

153

function relativePositionToAbsolutePosition(y: Y.Doc, documentType: Y.AbstractType, relPos: Y.RelativePosition, mapping: ProsemirrorMapping): number | null;

154

function getRelativeSelection(pmbinding: ProsemirrorBinding, state: EditorState): {

155

type: string;

156

anchor: Y.RelativePosition;

157

head: Y.RelativePosition;

158

};

159

```

160

161

[Position Utilities](./utilities.md)

162

163

### Plugin Key Constants

164

165

Plugin keys for accessing plugin state and configuration.

166

167

```javascript { .api }

168

const ySyncPluginKey: PluginKey;

169

const yCursorPluginKey: PluginKey;

170

const yUndoPluginKey: PluginKey;

171

```

172

173

## Types

174

175

```javascript { .api }

176

interface ColorDef {

177

light: string;

178

dark: string;

179

}

180

181

type ProsemirrorMapping = Map<Y.AbstractType<any>, PModel.Node | Array<PModel.Node>>;

182

183

interface BindingMetadata {

184

mapping: ProsemirrorMapping;

185

isOMark: Map<import('prosemirror-model').MarkType, boolean>;

186

}

187

188

interface UndoPluginState {

189

undoManager: import('yjs').UndoManager;

190

prevSel: ReturnType<typeof getRelativeSelection> | null;

191

hasUndoOps: boolean;

192

hasRedoOps: boolean;

193

}

194

195

interface YSyncOpts {

196

colors?: Array<ColorDef>;

197

colorMapping?: Map<string, ColorDef>;

198

permanentUserData?: Y.PermanentUserData | null;

199

mapping?: ProsemirrorMapping;

200

onFirstRender?: () => void;

201

}

202

203

class ProsemirrorBinding {

204

type: Y.XmlFragment;

205

prosemirrorView: EditorView | null;

206

mapping: ProsemirrorMapping;

207

doc: Y.Doc;

208

mux: any;

209

isOMark: Map<MarkType, boolean>;

210

isDestroyed: boolean;

211

beforeTransactionSelection: any;

212

213

constructor(yXmlFragment: Y.XmlFragment, mapping?: Map);

214

initView(prosemirrorView: EditorView): void;

215

destroy(): void;

216

renderSnapshot(snapshot: Snapshot, prevSnapshot?: Snapshot): void;

217

unrenderSnapshot(): void;

218

}

219

```