@pluv/crdt-yjs 0.11.1 → 0.12.1

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
 
2
- > @pluv/crdt-yjs@0.11.1 build /home/runner/work/pluv/pluv/packages/crdt-yjs
2
+ > @pluv/crdt-yjs@0.12.1 build /home/runner/work/pluv/pluv/packages/crdt-yjs
3
3
  > tsup src/index.ts --format esm,cjs --dts
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -8,11 +8,11 @@
8
8
  CLI Target: es6
9
9
  ESM Build start
10
10
  CJS Build start
11
- CJS dist/index.js 4.87 KB
12
- CJS ⚡️ Build success in 81ms
13
- ESM dist/index.mjs 3.68 KB
14
- ESM ⚡️ Build success in 81ms
11
+ CJS dist/index.js 5.88 KB
12
+ CJS ⚡️ Build success in 34ms
13
+ ESM dist/index.mjs 4.70 KB
14
+ ESM ⚡️ Build success in 43ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 1101ms
17
- DTS dist/index.d.mts 3.11 KB
18
- DTS dist/index.d.ts 3.11 KB
16
+ DTS ⚡️ Build success in 1262ms
17
+ DTS dist/index.d.mts 3.41 KB
18
+ DTS dist/index.d.ts 3.41 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,255 @@
1
1
  # @pluv/crdt-yjs
2
2
 
3
+ ## 0.12.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @pluv/types@0.12.1
8
+
9
+ ## 0.12.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 436040b: Added ability to undo and redo changes to storage.
14
+
15
+ ## @pluv/crdt-yjs
16
+
17
+ `@pluv/crdt-yjs` now exposes 5 new methods: `canRedo`, `canUndo`, `redo`, `undo` and `trackOrigins`.
18
+
19
+ Refer to the code-example below to better understand how to undo and redo with your doc.
20
+
21
+ ```ts
22
+ // Example
23
+ import { array, doc } from "@pluv/crdt-yjs";
24
+
25
+ // Create your doc with your shared-types
26
+ const myDoc = doc({
27
+ messages: array<string>([]),
28
+ });
29
+
30
+ /**
31
+ * @description Track origins to enable undos and redos for your document.
32
+ * trackOrigins must be called before any storage mutations, to enable those
33
+ * mutations to be undone/redone.
34
+ */
35
+ myDoc.trackOrigins({
36
+ /**
37
+ * @description This is the same `captureTimeout` option from yjs's UndoManager.
38
+ * This specifies a number in ms, during which edits are merged together to be
39
+ * undone together. Set this to 0, to track each transacted change individually.
40
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
41
+ * @default 500
42
+ */
43
+ captureTimeout: 500,
44
+ /**
45
+ * @desription This is the same `trackedOrigins` option from yjs's UndoManager.
46
+ * This specifies transaction origins (strings only) to filter which transactions
47
+ * can be undone.
48
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
49
+ * @default undefined
50
+ */
51
+ trackedOrigins: ["user-123"],
52
+ });
53
+
54
+ /**
55
+ * @description Check whether calling undo will mutate storage
56
+ * @returns boolean
57
+ */
58
+ myDoc.canUndo();
59
+ /**
60
+ * @description Check whether calling redo will mutate storage
61
+ * @returns boolean
62
+ */
63
+ myDoc.canRedo();
64
+
65
+ // Perform a storage mutation within a transaction so that it can be affected
66
+ // by undo/redo operations.
67
+ myDoc.transact(() => {
68
+ myDoc.get("messages").push(["hello world!"]);
69
+ }, "user-123");
70
+
71
+ /**
72
+ * @description Undoes the last valid mutation to storage
73
+ */
74
+ myDoc.undo();
75
+
76
+ /**
77
+ * @description Re-applies the last undone mutation to storage
78
+ */
79
+ myDoc.redo();
80
+ ```
81
+
82
+ ## @pluv/client
83
+
84
+ `@pluv/client`'s `PluvRoom` and `MockedRoom` now exposes 5 new methods: `canRedo`, `canUndo`, `redo`, `undo` and `transact`.
85
+
86
+ Refer to the code-example below to better understand how to undo and redo with your `PluvRoom`.
87
+
88
+ ```ts
89
+ import { createClient, y } from "@pluv/client";
90
+
91
+ const client = createClient({});
92
+
93
+ /**
94
+ * @description When a room is created, undo/redo will automatically
95
+ * be configured to filter for changes made by the connected user
96
+ * (so that users only undo/redo their changes).
97
+ */
98
+ const room = client.createRoom("my-room", {
99
+ initialStorage: () => ({
100
+ messages: y.array<string>([]),
101
+ }),
102
+ /**
103
+ * @description This is the same `captureTimeout` option from yjs's UndoManager.
104
+ * This specifies a number in ms, during which edits are merged together to be
105
+ * undone together. Set this to 0, to track each transacted change individually.
106
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
107
+ * @default 500
108
+ */
109
+ captureTimeout: 500,
110
+ /**
111
+ * @desription This is the same `trackedOrigins` option from yjs's UndoManager.
112
+ * This specifies transaction origins (strings only) to filter which transactions
113
+ * can be undone.
114
+ * When omitted, the user's connection id will be tracked. When provided,
115
+ * specifies additional tracked origins besides the user's connection id.
116
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
117
+ * @default undefined
118
+ */
119
+ trackedOrigins: ["user-123"],
120
+ });
121
+
122
+ /**
123
+ * @description Check whether calling undo will mutate storage
124
+ * @returns boolean
125
+ */
126
+ room.canUndo();
127
+ /**
128
+ * @description Check whether calling redo will mutate storage
129
+ * @returns boolean
130
+ */
131
+ room.canRedo();
132
+
133
+ /**
134
+ * @description Calling transact will enable a storage mutation to be undone/redone.
135
+ * When called without an origin, the origin will default to the user's connection
136
+ * id.
137
+ *
138
+ * You can specify a 2nd parameter to transact with a different transaction origin.
139
+ */
140
+ room.transact(() => {
141
+ room.get("messages").push(["hello world!"]);
142
+ });
143
+
144
+ // This will also be undoable because `"user-123"` is a tracked origin.
145
+ room.transact(() => {
146
+ room.get("messages").push(["hello world!"]);
147
+ }, "user-123");
148
+
149
+ /**
150
+ * @description Undoes the last valid mutation to storage
151
+ */
152
+ room.undo();
153
+
154
+ /**
155
+ * @description Re-applies the last undone mutation to storage
156
+ */
157
+ room.redo();
158
+ ```
159
+
160
+ ## @pluv/react
161
+
162
+ `@pluv/react`'s `createRoomBundle` now exposes 5 new react hooks: `usePluvCanRedo`, `usePluvCanUndo`, `usePluvRedo`, `usePluvUndo` and `usePluvTransact`.
163
+
164
+ Refer to the code-example below to better understand how to undo and redo with your `createRoomBundle`.
165
+
166
+ ```tsx
167
+ import { createBundle, createClient, y } from "@pluv/react";
168
+ import { type io } from "./io";
169
+
170
+ const client = createClient<typeof io>();
171
+
172
+ const { createRoomBundle } = createBundle(client);
173
+
174
+ const {
175
+ usePluvCanRedo,
176
+ usePluvCanUndo,
177
+ usePluvRedo,
178
+ usePluvStorage,
179
+ usePluvTransact,
180
+ usePluvUndo,
181
+ } = createRoomBundle({
182
+ initialStorage: () => ({
183
+ messages: y.array<string>([]),
184
+ }),
185
+ /**
186
+ * @description This is the same `captureTimeout` option from yjs's UndoManager.
187
+ * This specifies a number in ms, during which edits are merged together to be
188
+ * undone together. Set this to 0, to track each transacted change individually.
189
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
190
+ * @default 500
191
+ */
192
+ captureTimeout: 500,
193
+ /**
194
+ * @desription This is the same `trackedOrigins` option from yjs's UndoManager.
195
+ * This specifies transaction origins (strings only) to filter which transactions
196
+ * can be undone.
197
+ * When omitted, the user's connection id will be tracked. When provided,
198
+ * specifies additional tracked origins besides the user's connection id.
199
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
200
+ * @default undefined
201
+ */
202
+ trackedOrigins: ["user-123"],
203
+ });
204
+
205
+ /**
206
+ * @description Check whether calling undo will mutate storage
207
+ */
208
+ const canUndo: boolean = usePluvCanUndo();
209
+ /**
210
+ * @description Check whether calling redo will mutate storage
211
+ */
212
+ const canRedo: boolean = usePluvCanRedo();
213
+
214
+ const [messages, sharedType] = usePluvStorage("messages");
215
+
216
+ /**
217
+ * @description Calling transact will enable a storage mutation to be undone/redone.
218
+ * When called without an origin, the origin will default to the user's connection
219
+ * id.
220
+ *
221
+ * You can specify a 2nd parameter to transact with a different transaction origin.
222
+ */
223
+ const transact = usePluvTransact();
224
+
225
+ transact(() => {
226
+ sharedType?.push(["hello world!"]);
227
+ });
228
+
229
+ // This will also be undoable because `"user-123"` is a tracked origin.
230
+ transact(() => {
231
+ sharedType?.push(["hello world!"]);
232
+ }, "user-123");
233
+
234
+ /**
235
+ * @description Undoes the last valid mutation to storage
236
+ */
237
+ const undo = usePluvUndo();
238
+
239
+ undo();
240
+
241
+ /**
242
+ * @description Re-applies the last undone mutation to storage
243
+ */
244
+ const redo = usePluvRedo();
245
+
246
+ redo();
247
+ ```
248
+
249
+ ### Patch Changes
250
+
251
+ - @pluv/types@0.12.0
252
+
3
253
  ## 0.11.1
4
254
 
5
255
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -20,20 +20,31 @@ type InferYjsSharedTypeJson<TShared extends unknown> = TShared extends AbstractT
20
20
  [P in keyof IObject]: InferYjsSharedTypeJson<IObject[P]>;
21
21
  } : TShared extends Map<infer IItem> ? Record<string, InferYjsSharedTypeJson<IItem>> : TShared extends Text | XmlElement | XmlFragment | XmlText ? string : never : TShared;
22
22
 
23
+ interface TrackOriginOptions {
24
+ captureTimeout?: number;
25
+ trackedOrigins?: readonly string[];
26
+ }
23
27
  declare class YjsDoc<T extends Record<string, AbstractType<any>> = {}> {
24
28
  value: Doc;
29
+ private _undoManager;
30
+ get storage(): T;
25
31
  private get _storage();
26
32
  constructor(value?: T);
27
33
  applyUpdate(update?: string | Uint8Array | null, origin?: string): this;
34
+ canRedo(): boolean;
35
+ canUndo(): boolean;
28
36
  destroy(): void;
29
37
  encodeStateAsUpdate(): string;
30
38
  get<TKey extends keyof T>(key: TKey): T[TKey];
31
39
  getSharedTypes(): T;
40
+ redo(): void;
32
41
  subscribe(fn: (update: string, origin: any, doc: Doc, transaction: Transaction) => void): () => void;
33
42
  toJSON(): InferYjsDocJson<this>;
43
+ trackOrigins(options: TrackOriginOptions): void;
34
44
  transact(fn: (transaction: Transaction) => void, origin?: any): void;
35
45
  static fromUint8Array(u8a: Uint8Array): string;
36
46
  static toUint8Array(str: string): Uint8Array;
47
+ undo(): void;
37
48
  }
38
49
  declare const doc: <T extends Record<string, AbstractType<any>> = {}>(value?: T | undefined) => YjsDoc<T>;
39
50
 
@@ -53,4 +64,4 @@ declare const xmlFragment: (params?: XmlFragmentParams) => XmlFragment;
53
64
 
54
65
  declare const xmlText: (value?: string) => XmlText;
55
66
 
56
- export { InferYjsDocJson, InferYjsDocSharedType, InferYjsDocSharedTypeJson, InferYjsDocSharedTypes, InferYjsSharedTypeJson, XmlElementParams, XmlFragmentParams, YObject, YObjectValue, YjsDoc, array, doc, map, object, text, xmlElement, xmlFragment, xmlText };
67
+ export { InferYjsDocJson, InferYjsDocSharedType, InferYjsDocSharedTypeJson, InferYjsDocSharedTypes, InferYjsSharedTypeJson, TrackOriginOptions, XmlElementParams, XmlFragmentParams, YObject, YObjectValue, YjsDoc, array, doc, map, object, text, xmlElement, xmlFragment, xmlText };
package/dist/index.d.ts CHANGED
@@ -20,20 +20,31 @@ type InferYjsSharedTypeJson<TShared extends unknown> = TShared extends AbstractT
20
20
  [P in keyof IObject]: InferYjsSharedTypeJson<IObject[P]>;
21
21
  } : TShared extends Map<infer IItem> ? Record<string, InferYjsSharedTypeJson<IItem>> : TShared extends Text | XmlElement | XmlFragment | XmlText ? string : never : TShared;
22
22
 
23
+ interface TrackOriginOptions {
24
+ captureTimeout?: number;
25
+ trackedOrigins?: readonly string[];
26
+ }
23
27
  declare class YjsDoc<T extends Record<string, AbstractType<any>> = {}> {
24
28
  value: Doc;
29
+ private _undoManager;
30
+ get storage(): T;
25
31
  private get _storage();
26
32
  constructor(value?: T);
27
33
  applyUpdate(update?: string | Uint8Array | null, origin?: string): this;
34
+ canRedo(): boolean;
35
+ canUndo(): boolean;
28
36
  destroy(): void;
29
37
  encodeStateAsUpdate(): string;
30
38
  get<TKey extends keyof T>(key: TKey): T[TKey];
31
39
  getSharedTypes(): T;
40
+ redo(): void;
32
41
  subscribe(fn: (update: string, origin: any, doc: Doc, transaction: Transaction) => void): () => void;
33
42
  toJSON(): InferYjsDocJson<this>;
43
+ trackOrigins(options: TrackOriginOptions): void;
34
44
  transact(fn: (transaction: Transaction) => void, origin?: any): void;
35
45
  static fromUint8Array(u8a: Uint8Array): string;
36
46
  static toUint8Array(str: string): Uint8Array;
47
+ undo(): void;
37
48
  }
38
49
  declare const doc: <T extends Record<string, AbstractType<any>> = {}>(value?: T | undefined) => YjsDoc<T>;
39
50
 
@@ -53,4 +64,4 @@ declare const xmlFragment: (params?: XmlFragmentParams) => XmlFragment;
53
64
 
54
65
  declare const xmlText: (value?: string) => XmlText;
55
66
 
56
- export { InferYjsDocJson, InferYjsDocSharedType, InferYjsDocSharedTypeJson, InferYjsDocSharedTypes, InferYjsSharedTypeJson, XmlElementParams, XmlFragmentParams, YObject, YObjectValue, YjsDoc, array, doc, map, object, text, xmlElement, xmlFragment, xmlText };
67
+ export { InferYjsDocJson, InferYjsDocSharedType, InferYjsDocSharedTypeJson, InferYjsDocSharedTypes, InferYjsSharedTypeJson, TrackOriginOptions, XmlElementParams, XmlFragmentParams, YObject, YObjectValue, YjsDoc, array, doc, map, object, text, xmlElement, xmlFragment, xmlText };
package/dist/index.js CHANGED
@@ -63,6 +63,7 @@ var import_yjs2 = require("yjs");
63
63
  var YjsDoc = class _YjsDoc {
64
64
  constructor(value) {
65
65
  this.value = new import_yjs2.Doc();
66
+ this._undoManager = null;
66
67
  if (!value)
67
68
  return;
68
69
  const storage = this.value.getMap("storage");
@@ -70,6 +71,14 @@ var YjsDoc = class _YjsDoc {
70
71
  storage.set(key, node);
71
72
  });
72
73
  }
74
+ get storage() {
75
+ const storage = this._storage;
76
+ const keys = Array.from(storage.keys());
77
+ return keys.reduce(
78
+ (acc, key) => __spreadProps(__spreadValues({}, acc), { [key]: storage.get(key) }),
79
+ {}
80
+ );
81
+ }
73
82
  get _storage() {
74
83
  return this.value.getMap("storage");
75
84
  }
@@ -80,7 +89,17 @@ var YjsDoc = class _YjsDoc {
80
89
  (0, import_yjs2.applyUpdate)(this.value, uint8Update, origin);
81
90
  return this;
82
91
  }
92
+ canRedo() {
93
+ var _a;
94
+ return !!((_a = this._undoManager) == null ? void 0 : _a.canRedo());
95
+ }
96
+ canUndo() {
97
+ var _a;
98
+ return !!((_a = this._undoManager) == null ? void 0 : _a.canUndo());
99
+ }
83
100
  destroy() {
101
+ var _a;
102
+ (_a = this._undoManager) == null ? void 0 : _a.destroy();
84
103
  this.value.destroy();
85
104
  }
86
105
  encodeStateAsUpdate() {
@@ -95,6 +114,10 @@ var YjsDoc = class _YjsDoc {
95
114
  {}
96
115
  );
97
116
  }
117
+ redo() {
118
+ var _a;
119
+ (_a = this._undoManager) == null ? void 0 : _a.redo();
120
+ }
98
121
  subscribe(fn) {
99
122
  const _fn = (update, origin, doc2, transaction) => fn(_YjsDoc.fromUint8Array(update), origin, doc2, transaction);
100
123
  this.value.on("update", _fn);
@@ -105,6 +128,16 @@ var YjsDoc = class _YjsDoc {
105
128
  toJSON() {
106
129
  return this._storage.toJSON();
107
130
  }
131
+ trackOrigins(options) {
132
+ const { captureTimeout, trackedOrigins } = options;
133
+ if (this._undoManager) {
134
+ this._undoManager.destroy();
135
+ }
136
+ this._undoManager = new import_yjs2.UndoManager(this._storage, {
137
+ captureTimeout,
138
+ trackedOrigins: trackedOrigins ? new Set(trackedOrigins) : void 0
139
+ });
140
+ }
108
141
  transact(fn, origin) {
109
142
  this.value.transact((tx) => {
110
143
  fn(tx);
@@ -116,6 +149,10 @@ var YjsDoc = class _YjsDoc {
116
149
  static toUint8Array(str) {
117
150
  return (0, import_js_base64.toUint8Array)(str);
118
151
  }
152
+ undo() {
153
+ var _a;
154
+ (_a = this._undoManager) == null ? void 0 : _a.undo();
155
+ }
119
156
  };
120
157
  var doc = (value) => {
121
158
  return new YjsDoc(value);
package/dist/index.mjs CHANGED
@@ -29,6 +29,7 @@ var array = (value = []) => {
29
29
  // src/doc.ts
30
30
  import { fromUint8Array, toUint8Array } from "js-base64";
31
31
  import {
32
+ UndoManager,
32
33
  Doc as YDoc,
33
34
  applyUpdate,
34
35
  encodeStateAsUpdate
@@ -36,6 +37,7 @@ import {
36
37
  var YjsDoc = class _YjsDoc {
37
38
  constructor(value) {
38
39
  this.value = new YDoc();
40
+ this._undoManager = null;
39
41
  if (!value)
40
42
  return;
41
43
  const storage = this.value.getMap("storage");
@@ -43,6 +45,14 @@ var YjsDoc = class _YjsDoc {
43
45
  storage.set(key, node);
44
46
  });
45
47
  }
48
+ get storage() {
49
+ const storage = this._storage;
50
+ const keys = Array.from(storage.keys());
51
+ return keys.reduce(
52
+ (acc, key) => __spreadProps(__spreadValues({}, acc), { [key]: storage.get(key) }),
53
+ {}
54
+ );
55
+ }
46
56
  get _storage() {
47
57
  return this.value.getMap("storage");
48
58
  }
@@ -53,7 +63,17 @@ var YjsDoc = class _YjsDoc {
53
63
  applyUpdate(this.value, uint8Update, origin);
54
64
  return this;
55
65
  }
66
+ canRedo() {
67
+ var _a;
68
+ return !!((_a = this._undoManager) == null ? void 0 : _a.canRedo());
69
+ }
70
+ canUndo() {
71
+ var _a;
72
+ return !!((_a = this._undoManager) == null ? void 0 : _a.canUndo());
73
+ }
56
74
  destroy() {
75
+ var _a;
76
+ (_a = this._undoManager) == null ? void 0 : _a.destroy();
57
77
  this.value.destroy();
58
78
  }
59
79
  encodeStateAsUpdate() {
@@ -68,6 +88,10 @@ var YjsDoc = class _YjsDoc {
68
88
  {}
69
89
  );
70
90
  }
91
+ redo() {
92
+ var _a;
93
+ (_a = this._undoManager) == null ? void 0 : _a.redo();
94
+ }
71
95
  subscribe(fn) {
72
96
  const _fn = (update, origin, doc2, transaction) => fn(_YjsDoc.fromUint8Array(update), origin, doc2, transaction);
73
97
  this.value.on("update", _fn);
@@ -78,6 +102,16 @@ var YjsDoc = class _YjsDoc {
78
102
  toJSON() {
79
103
  return this._storage.toJSON();
80
104
  }
105
+ trackOrigins(options) {
106
+ const { captureTimeout, trackedOrigins } = options;
107
+ if (this._undoManager) {
108
+ this._undoManager.destroy();
109
+ }
110
+ this._undoManager = new UndoManager(this._storage, {
111
+ captureTimeout,
112
+ trackedOrigins: trackedOrigins ? new Set(trackedOrigins) : void 0
113
+ });
114
+ }
81
115
  transact(fn, origin) {
82
116
  this.value.transact((tx) => {
83
117
  fn(tx);
@@ -89,6 +123,10 @@ var YjsDoc = class _YjsDoc {
89
123
  static toUint8Array(str) {
90
124
  return toUint8Array(str);
91
125
  }
126
+ undo() {
127
+ var _a;
128
+ (_a = this._undoManager) == null ? void 0 : _a.undo();
129
+ }
92
130
  };
93
131
  var doc = (value) => {
94
132
  return new YjsDoc(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/crdt-yjs",
3
- "version": "0.11.1",
3
+ "version": "0.12.1",
4
4
  "description": "yjs for @pluv/io",
5
5
  "author": "leedavidcs",
6
6
  "license": "MIT",
@@ -18,18 +18,18 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "js-base64": "^3.7.5",
21
- "@pluv/types": "^0.11.1"
21
+ "@pluv/types": "^0.12.1"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "yjs": "^13.0.0"
25
25
  },
26
26
  "devDependencies": {
27
- "eslint": "^8.49.0",
27
+ "eslint": "^8.50.0",
28
28
  "tsup": "^7.2.0",
29
29
  "typescript": "^5.2.2",
30
- "yjs": "^13.6.7",
31
- "@pluv/tsconfig": "^0.11.1",
32
- "eslint-config-pluv": "^0.11.1"
30
+ "yjs": "^13.6.8",
31
+ "@pluv/tsconfig": "^0.12.1",
32
+ "eslint-config-pluv": "^0.12.1"
33
33
  },
34
34
  "scripts": {
35
35
  "build": "tsup src/index.ts --format esm,cjs --dts",
package/src/doc.ts CHANGED
@@ -2,6 +2,7 @@ import { fromUint8Array, toUint8Array } from "js-base64";
2
2
  import {
3
3
  AbstractType,
4
4
  Transaction,
5
+ UndoManager,
5
6
  Doc as YDoc,
6
7
  Map as YMap,
7
8
  applyUpdate,
@@ -9,8 +10,25 @@ import {
9
10
  } from "yjs";
10
11
  import type { InferYjsDocJson } from "./types";
11
12
 
13
+ export interface TrackOriginOptions {
14
+ captureTimeout?: number;
15
+ trackedOrigins?: readonly string[];
16
+ }
17
+
12
18
  export class YjsDoc<T extends Record<string, AbstractType<any>> = {}> {
13
19
  public value: YDoc = new YDoc();
20
+ private _undoManager: UndoManager | null = null;
21
+
22
+ public get storage(): T {
23
+ const storage = this._storage;
24
+
25
+ const keys = Array.from(storage.keys());
26
+
27
+ return keys.reduce<T>(
28
+ (acc, key) => ({ ...acc, [key]: storage.get(key) }),
29
+ {} as T,
30
+ );
31
+ }
14
32
 
15
33
  private get _storage(): YMap<any> {
16
34
  return this.value.getMap("storage");
@@ -40,7 +58,16 @@ export class YjsDoc<T extends Record<string, AbstractType<any>> = {}> {
40
58
  return this;
41
59
  }
42
60
 
61
+ public canRedo(): boolean {
62
+ return !!this._undoManager?.canRedo();
63
+ }
64
+
65
+ public canUndo(): boolean {
66
+ return !!this._undoManager?.canUndo();
67
+ }
68
+
43
69
  public destroy(): void {
70
+ this._undoManager?.destroy();
44
71
  this.value.destroy();
45
72
  }
46
73
 
@@ -59,6 +86,10 @@ export class YjsDoc<T extends Record<string, AbstractType<any>> = {}> {
59
86
  );
60
87
  }
61
88
 
89
+ public redo(): void {
90
+ this._undoManager?.redo();
91
+ }
92
+
62
93
  public subscribe(
63
94
  fn: (
64
95
  update: string,
@@ -85,6 +116,21 @@ export class YjsDoc<T extends Record<string, AbstractType<any>> = {}> {
85
116
  return this._storage.toJSON() as InferYjsDocJson<this>;
86
117
  }
87
118
 
119
+ public trackOrigins(options: TrackOriginOptions): void {
120
+ const { captureTimeout, trackedOrigins } = options;
121
+
122
+ if (this._undoManager) {
123
+ this._undoManager.destroy();
124
+ }
125
+
126
+ this._undoManager = new UndoManager(this._storage, {
127
+ captureTimeout,
128
+ trackedOrigins: trackedOrigins
129
+ ? new Set<string>(trackedOrigins)
130
+ : undefined,
131
+ });
132
+ }
133
+
88
134
  public transact(
89
135
  fn: (transaction: Transaction) => void,
90
136
  origin?: any,
@@ -101,6 +147,10 @@ export class YjsDoc<T extends Record<string, AbstractType<any>> = {}> {
101
147
  public static toUint8Array(str: string): Uint8Array {
102
148
  return toUint8Array(str);
103
149
  }
150
+
151
+ public undo(): void {
152
+ this._undoManager?.undo();
153
+ }
104
154
  }
105
155
 
106
156
  export const doc = <T extends Record<string, AbstractType<any>> = {}>(
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export type { AbstractType, Array, Map, Text } from "yjs";
2
2
  export { array } from "./array";
3
+ export type { TrackOriginOptions } from "./doc";
3
4
  export { YjsDoc, doc } from "./doc";
4
5
  export { map } from "./map";
5
6
  export { object } from "./object";