@remirror/extension-yjs 1.0.19 → 1.0.23

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.
@@ -1,5 +1,5 @@
1
1
  import type { Doc } from 'yjs';
2
- import { AcceptUndefined, EditorState, KeyBindingProps, NonChainableCommandFunction, OnSetOptionsProps, PlainExtension, ProsemirrorPlugin, Selection, Shape } from '@remirror/core';
2
+ import { AcceptUndefined, Dispose, EditorState, KeyBindingProps, NonChainableCommandFunction, OnSetOptionsProps, PlainExtension, ProsemirrorPlugin, Selection, Shape, Static } from '@remirror/core';
3
3
  export interface ColorDef {
4
4
  light: string;
5
5
  dark: string;
@@ -54,13 +54,14 @@ export interface YjsOptions<Provider extends YjsRealtimeProvider = YjsRealtimePr
54
54
  * @default `(state) => state.selection`
55
55
  */
56
56
  getSelection?: (state: EditorState) => Selection;
57
+ disableUndo?: Static<boolean>;
57
58
  /**
58
59
  * Names of nodes in the editor which should be protected.
59
60
  *
60
61
  * @default `new Set('paragraph')`
61
62
  */
62
- protectedNodes?: Set<string>;
63
- trackedOrigins?: any[];
63
+ protectedNodes?: Static<Set<string>>;
64
+ trackedOrigins?: Static<any[]>;
64
65
  }
65
66
  /**
66
67
  * The YJS extension is the recommended extension for creating a collaborative
@@ -73,7 +74,10 @@ export declare class YjsExtension extends PlainExtension<YjsOptions> {
73
74
  * The provider that is being used for the editor.
74
75
  */
75
76
  get provider(): YjsRealtimeProvider;
76
- onView(): void;
77
+ getBinding(): {
78
+ mapping: Map<any, any>;
79
+ } | undefined;
80
+ onView(): Dispose | void;
77
81
  /**
78
82
  * Create the yjs plugins.
79
83
  */
@@ -87,19 +91,17 @@ export declare class YjsExtension extends PlainExtension<YjsOptions> {
87
91
  */
88
92
  onDestroy(): void;
89
93
  /**
90
- * Undo within a collaborative editor.
91
- *
92
- * This should be used instead of the built in `undo` command.
94
+ * Undo that last Yjs transaction(s)
93
95
  *
94
96
  * This command does **not** support chaining.
97
+ * This command is a no-op and always returns `false` when the `disableUndo` option is set.
95
98
  */
96
99
  yUndo(): NonChainableCommandFunction;
97
100
  /**
98
- * Redo, within a collaborative editor.
99
- *
100
- * This should be used instead of the built in `redo` command.
101
+ * Redo the last transaction undone with a previous `yUndo` command.
101
102
  *
102
103
  * This command does **not** support chaining.
104
+ * This command is a no-op and always returns `false` when the `disableUndo` option is set.
103
105
  */
104
106
  yRedo(): NonChainableCommandFunction;
105
107
  /**
@@ -110,8 +112,6 @@ export declare class YjsExtension extends PlainExtension<YjsOptions> {
110
112
  * Handle the redo keybinding for the editor.
111
113
  */
112
114
  redoShortcut(props: KeyBindingProps): boolean;
113
- private absolutePositionToRelativePosition;
114
- private relativePositionToAbsolutePosition;
115
115
  }
116
116
  /**
117
117
  * The default destroy provider method.
@@ -3,6 +3,8 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var _applyDecoratedDescriptor = require('@babel/runtime/helpers/applyDecoratedDescriptor');
6
+ var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
7
+ var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties');
6
8
  var yProsemirror = require('y-prosemirror');
7
9
  var yjs = require('yjs');
8
10
  var core = require('@remirror/core');
@@ -10,6 +12,98 @@ var extensionAnnotation = require('@remirror/extension-annotation');
10
12
  var messages = require('@remirror/messages');
11
13
 
12
14
  var _dec, _dec2, _dec3, _dec4, _dec5, _class, _class2;
15
+
16
+ var _excluded = ["from", "to"],
17
+ _excluded2 = ["from", "to"];
18
+
19
+ class YjsAnnotationStore {
20
+ constructor(doc, pmName, mapName, getMapping) {
21
+ this.doc = doc;
22
+ this.getMapping = getMapping;
23
+ this.type = doc.getXmlFragment(pmName);
24
+ this.map = doc.getMap(mapName);
25
+ }
26
+
27
+ addAnnotation(_ref) {
28
+ var from = _ref.from,
29
+ to = _ref.to,
30
+ data = _objectWithoutProperties(_ref, _excluded);
31
+
32
+ // XXX: Why is this cast needed?
33
+ var storedData = _objectSpread(_objectSpread({}, data), {}, {
34
+ from: this.absolutePositionToRelativePosition(from),
35
+ to: this.absolutePositionToRelativePosition(to)
36
+ });
37
+
38
+ this.map.set(data.id, storedData);
39
+ }
40
+
41
+ updateAnnotation(id, updateData) {
42
+ var existing = this.map.get(id);
43
+
44
+ if (!existing) {
45
+ return;
46
+ }
47
+
48
+ this.map.set(id, _objectSpread(_objectSpread({}, updateData), {}, {
49
+ from: existing.from,
50
+ to: existing.to
51
+ }));
52
+ }
53
+
54
+ removeAnnotations(ids) {
55
+ yjs.transact(this.doc, () => {
56
+ ids.forEach(id => this.map.delete(id));
57
+ });
58
+ }
59
+
60
+ setAnnotations(annotations) {
61
+ yjs.transact(this.doc, () => {
62
+ this.map.clear();
63
+ annotations.forEach(annotation => this.addAnnotation(annotation));
64
+ });
65
+ }
66
+
67
+ formatAnnotations() {
68
+ var result = [];
69
+ this.map.forEach(_ref2 => {
70
+ var relFrom = _ref2.from,
71
+ relTo = _ref2.to,
72
+ data = _objectWithoutProperties(_ref2, _excluded2);
73
+
74
+ var from = this.relativePositionToAbsolutePosition(relFrom);
75
+ var to = this.relativePositionToAbsolutePosition(relTo);
76
+
77
+ if (!from || !to) {
78
+ return;
79
+ } // XXX: Why is this cast needed?
80
+
81
+
82
+ result.push(_objectSpread(_objectSpread({}, data), {}, {
83
+ from,
84
+ to
85
+ }));
86
+ });
87
+ return result;
88
+ }
89
+
90
+ absolutePositionToRelativePosition(pos) {
91
+ var mapping = this.getMapping();
92
+ return yProsemirror.absolutePositionToRelativePosition(pos, this.type, mapping);
93
+ }
94
+
95
+ relativePositionToAbsolutePosition(relPos) {
96
+ var mapping = this.getMapping();
97
+ return yProsemirror.relativePositionToAbsolutePosition(this.doc, this.type, relPos, mapping);
98
+ }
99
+
100
+ }
101
+ /**
102
+ * The YJS extension is the recommended extension for creating a collaborative
103
+ * editor.
104
+ */
105
+
106
+
13
107
  var YjsExtension = (_dec = core.extension({
14
108
  defaultOptions: {
15
109
  getProvider: () => {
@@ -23,29 +117,31 @@ var YjsExtension = (_dec = core.extension({
23
117
  cursorBuilder: yProsemirror.defaultCursorBuilder,
24
118
  cursorStateField: 'cursor',
25
119
  getSelection: state => state.selection,
120
+ disableUndo: false,
26
121
  protectedNodes: new Set('paragraph'),
27
122
  trackedOrigins: []
28
123
  },
124
+ staticKeys: ['disableUndo', 'protectedNodes', 'trackedOrigins'],
29
125
  defaultPriority: core.ExtensionPriority.High
30
126
  }), _dec2 = core.command({
31
127
  disableChaining: true,
32
- description: _ref => {
33
- var t = _ref.t;
128
+ description: _ref3 => {
129
+ var t = _ref3.t;
34
130
  return t(messages.ExtensionHistoryMessages.UNDO_DESCRIPTION);
35
131
  },
36
- label: _ref2 => {
37
- var t = _ref2.t;
132
+ label: _ref4 => {
133
+ var t = _ref4.t;
38
134
  return t(messages.ExtensionHistoryMessages.UNDO_LABEL);
39
135
  },
40
136
  icon: 'arrowGoBackFill'
41
137
  }), _dec3 = core.command({
42
138
  disableChaining: true,
43
- description: _ref3 => {
44
- var t = _ref3.t;
139
+ description: _ref5 => {
140
+ var t = _ref5.t;
45
141
  return t(messages.ExtensionHistoryMessages.REDO_DESCRIPTION);
46
142
  },
47
- label: _ref4 => {
48
- var t = _ref4.t;
143
+ label: _ref6 => {
144
+ var t = _ref6.t;
49
145
  return t(messages.ExtensionHistoryMessages.REDO_LABEL);
50
146
  },
51
147
  icon: 'arrowGoForwardFill'
@@ -70,14 +166,27 @@ var YjsExtension = (_dec = core.extension({
70
166
  return (_this$_provider = this._provider) !== null && _this$_provider !== void 0 ? _this$_provider : this._provider = getLazyValue(getProvider);
71
167
  }
72
168
 
169
+ getBinding() {
170
+ var state = this.store.getState();
171
+
172
+ var _ySyncPluginKey$getSt = yProsemirror.ySyncPluginKey.getState(state),
173
+ binding = _ySyncPluginKey$getSt.binding;
174
+
175
+ return binding;
176
+ }
177
+
73
178
  onView() {
74
179
  try {
180
+ var annotationStore = new YjsAnnotationStore(this.provider.doc, 'prosemirror', 'annotations', () => {
181
+ var _this$getBinding;
182
+
183
+ return (_this$getBinding = this.getBinding()) === null || _this$getBinding === void 0 ? void 0 : _this$getBinding.mapping;
184
+ });
75
185
  this.store.manager.getExtension(extensionAnnotation.AnnotationExtension).setOptions({
76
- getMap: () => this.provider.doc.getMap('annotations'),
77
- transformPosition: this.absolutePositionToRelativePosition.bind(this),
78
- transformPositionBeforeRender: this.relativePositionToAbsolutePosition.bind(this)
186
+ getStore: () => annotationStore
79
187
  });
80
- this.provider.doc.on('update', (_update, _origin, _doc, yjsTr) => {
188
+
189
+ var handler = (_update, _origin, _doc, yjsTr) => {
81
190
  var _this$store$commands$, _this$store$commands;
82
191
 
83
192
  // Ignore own changes
@@ -86,7 +195,12 @@ var YjsExtension = (_dec = core.extension({
86
195
  }
87
196
 
88
197
  (_this$store$commands$ = (_this$store$commands = this.store.commands).redrawAnnotations) === null || _this$store$commands$ === void 0 ? void 0 : _this$store$commands$.call(_this$store$commands);
89
- });
198
+ };
199
+
200
+ this.provider.doc.on('update', handler);
201
+ return () => {
202
+ this.provider.doc.off('update', handler);
203
+ };
90
204
  } catch (_unused) {// AnnotationExtension isn't present in editor
91
205
  }
92
206
  }
@@ -101,21 +215,28 @@ var YjsExtension = (_dec = core.extension({
101
215
  cursorBuilder = _this$options.cursorBuilder,
102
216
  getSelection = _this$options.getSelection,
103
217
  cursorStateField = _this$options.cursorStateField,
218
+ disableUndo = _this$options.disableUndo,
104
219
  protectedNodes = _this$options.protectedNodes,
105
220
  trackedOrigins = _this$options.trackedOrigins;
106
221
  var yDoc = this.provider.doc;
107
222
  var type = yDoc.getXmlFragment('prosemirror');
108
- var undoManager = new yjs.UndoManager(type, {
109
- trackedOrigins: new Set([yProsemirror.ySyncPluginKey, ...trackedOrigins]),
110
- deleteFilter: item => yProsemirror.defaultDeleteFilter(item, protectedNodes)
111
- });
112
- return [yProsemirror.ySyncPlugin(type, syncPluginOptions), yProsemirror.yCursorPlugin(this.provider.awareness, {
223
+ var plugins = [yProsemirror.ySyncPlugin(type, syncPluginOptions), yProsemirror.yCursorPlugin(this.provider.awareness, {
113
224
  cursorBuilder,
114
225
  cursorStateField,
115
226
  getSelection
116
- }, cursorStateField), yProsemirror.yUndoPlugin({
117
- undoManager
118
- })];
227
+ }, cursorStateField)];
228
+
229
+ if (!disableUndo) {
230
+ var undoManager = new yjs.UndoManager(type, {
231
+ trackedOrigins: new Set([yProsemirror.ySyncPluginKey, ...trackedOrigins]),
232
+ deleteFilter: item => yProsemirror.defaultDeleteFilter(item, protectedNodes)
233
+ });
234
+ plugins.push(yProsemirror.yUndoPlugin({
235
+ undoManager
236
+ }));
237
+ }
238
+
239
+ return plugins;
119
240
  }
120
241
  /**
121
242
  * This managers the updates of the collaboration provider.
@@ -125,14 +246,7 @@ var YjsExtension = (_dec = core.extension({
125
246
  onSetOptions(props) {
126
247
  var changes = props.changes,
127
248
  pickChanged = props.pickChanged;
128
- var changedPluginOptions = pickChanged(['cursorBuilder', 'cursorStateField', 'getProvider', 'getSelection', 'syncPluginOptions', 'protectedNodes', 'trackedOrigins']);
129
-
130
- if (changes.protectedNodes.changed || changes.trackedOrigins.changed) {
131
- // Cannot change these, as we would need a new undo manager instance, and for that
132
- // we would need to unregister the previous instance from the document to avoid
133
- // memory leaks.
134
- throw new Error("Cannot change \"protectedNodes\" or \"trackedOrigins\" options");
135
- }
249
+ var changedPluginOptions = pickChanged(['cursorBuilder', 'cursorStateField', 'getProvider', 'getSelection', 'syncPluginOptions']);
136
250
 
137
251
  if (changes.getProvider.changed) {
138
252
  this._provider = undefined;
@@ -165,16 +279,19 @@ var YjsExtension = (_dec = core.extension({
165
279
  this._provider = undefined;
166
280
  }
167
281
  /**
168
- * Undo within a collaborative editor.
169
- *
170
- * This should be used instead of the built in `undo` command.
282
+ * Undo that last Yjs transaction(s)
171
283
  *
172
284
  * This command does **not** support chaining.
285
+ * This command is a no-op and always returns `false` when the `disableUndo` option is set.
173
286
  */
174
287
 
175
288
 
176
289
  yUndo() {
177
290
  return core.nonChainable(props => {
291
+ if (this.options.disableUndo) {
292
+ return false;
293
+ }
294
+
178
295
  var state = props.state,
179
296
  dispatch = props.dispatch;
180
297
  var undoManager = yProsemirror.yUndoPluginKey.getState(state).undoManager;
@@ -191,16 +308,19 @@ var YjsExtension = (_dec = core.extension({
191
308
  });
192
309
  }
193
310
  /**
194
- * Redo, within a collaborative editor.
195
- *
196
- * This should be used instead of the built in `redo` command.
311
+ * Redo the last transaction undone with a previous `yUndo` command.
197
312
  *
198
313
  * This command does **not** support chaining.
314
+ * This command is a no-op and always returns `false` when the `disableUndo` option is set.
199
315
  */
200
316
 
201
317
 
202
318
  yRedo() {
203
319
  return core.nonChainable(props => {
320
+ if (this.options.disableUndo) {
321
+ return false;
322
+ }
323
+
204
324
  var state = props.state,
205
325
  dispatch = props.dispatch;
206
326
  var undoManager = yProsemirror.yUndoPluginKey.getState(state).undoManager;
@@ -233,26 +353,6 @@ var YjsExtension = (_dec = core.extension({
233
353
  return this.yRedo()(props);
234
354
  }
235
355
 
236
- absolutePositionToRelativePosition(pos) {
237
- var state = this.store.getState();
238
-
239
- var _ySyncPluginKey$getSt = yProsemirror.ySyncPluginKey.getState(state),
240
- type = _ySyncPluginKey$getSt.type,
241
- binding = _ySyncPluginKey$getSt.binding;
242
-
243
- return yProsemirror.absolutePositionToRelativePosition(pos, type, binding.mapping);
244
- }
245
-
246
- relativePositionToAbsolutePosition(relPos) {
247
- var state = this.store.getState();
248
-
249
- var _ySyncPluginKey$getSt2 = yProsemirror.ySyncPluginKey.getState(state),
250
- type = _ySyncPluginKey$getSt2.type,
251
- binding = _ySyncPluginKey$getSt2.binding;
252
-
253
- return yProsemirror.relativePositionToAbsolutePosition(this.provider.doc, type, relPos, binding.mapping);
254
- }
255
-
256
356
  }, (_applyDecoratedDescriptor(_class2.prototype, "yUndo", [_dec2], Object.getOwnPropertyDescriptor(_class2.prototype, "yUndo"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "yRedo", [_dec3], Object.getOwnPropertyDescriptor(_class2.prototype, "yRedo"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "undoShortcut", [_dec4], Object.getOwnPropertyDescriptor(_class2.prototype, "undoShortcut"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "redoShortcut", [_dec5], Object.getOwnPropertyDescriptor(_class2.prototype, "redoShortcut"), _class2.prototype)), _class2)) || _class);
257
357
  /**
258
358
  * The default destroy provider method.