@pluv/crdt-yjs 0.11.1 → 0.12.0

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.0 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
+ ESM dist/index.mjs 4.70 KB
12
+ ESM ⚡️ Build success in 68ms
13
+ CJS dist/index.js 5.88 KB
14
+ CJS ⚡️ Build success in 68ms
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 1225ms
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,249 @@
1
1
  # @pluv/crdt-yjs
2
2
 
3
+ ## 0.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 436040b: Added ability to undo and redo changes to storage.
8
+
9
+ ## @pluv/crdt-yjs
10
+
11
+ `@pluv/crdt-yjs` now exposes 5 new methods: `canRedo`, `canUndo`, `redo`, `undo` and `trackOrigins`.
12
+
13
+ Refer to the code-example below to better understand how to undo and redo with your doc.
14
+
15
+ ```ts
16
+ // Example
17
+ import { array, doc } from "@pluv/crdt-yjs";
18
+
19
+ // Create your doc with your shared-types
20
+ const myDoc = doc({
21
+ messages: array<string>([]),
22
+ });
23
+
24
+ /**
25
+ * @description Track origins to enable undos and redos for your document.
26
+ * trackOrigins must be called before any storage mutations, to enable those
27
+ * mutations to be undone/redone.
28
+ */
29
+ myDoc.trackOrigins({
30
+ /**
31
+ * @description This is the same `captureTimeout` option from yjs's UndoManager.
32
+ * This specifies a number in ms, during which edits are merged together to be
33
+ * undone together. Set this to 0, to track each transacted change individually.
34
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
35
+ * @default 500
36
+ */
37
+ captureTimeout: 500,
38
+ /**
39
+ * @desription This is the same `trackedOrigins` option from yjs's UndoManager.
40
+ * This specifies transaction origins (strings only) to filter which transactions
41
+ * can be undone.
42
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
43
+ * @default undefined
44
+ */
45
+ trackedOrigins: ["user-123"],
46
+ });
47
+
48
+ /**
49
+ * @description Check whether calling undo will mutate storage
50
+ * @returns boolean
51
+ */
52
+ myDoc.canUndo();
53
+ /**
54
+ * @description Check whether calling redo will mutate storage
55
+ * @returns boolean
56
+ */
57
+ myDoc.canRedo();
58
+
59
+ // Perform a storage mutation within a transaction so that it can be affected
60
+ // by undo/redo operations.
61
+ myDoc.transact(() => {
62
+ myDoc.get("messages").push(["hello world!"]);
63
+ }, "user-123");
64
+
65
+ /**
66
+ * @description Undoes the last valid mutation to storage
67
+ */
68
+ myDoc.undo();
69
+
70
+ /**
71
+ * @description Re-applies the last undone mutation to storage
72
+ */
73
+ myDoc.redo();
74
+ ```
75
+
76
+ ## @pluv/client
77
+
78
+ `@pluv/client`'s `PluvRoom` and `MockedRoom` now exposes 5 new methods: `canRedo`, `canUndo`, `redo`, `undo` and `transact`.
79
+
80
+ Refer to the code-example below to better understand how to undo and redo with your `PluvRoom`.
81
+
82
+ ```ts
83
+ import { createClient, y } from "@pluv/client";
84
+
85
+ const client = createClient({});
86
+
87
+ /**
88
+ * @description When a room is created, undo/redo will automatically
89
+ * be configured to filter for changes made by the connected user
90
+ * (so that users only undo/redo their changes).
91
+ */
92
+ const room = client.createRoom("my-room", {
93
+ initialStorage: () => ({
94
+ messages: y.array<string>([]),
95
+ }),
96
+ /**
97
+ * @description This is the same `captureTimeout` option from yjs's UndoManager.
98
+ * This specifies a number in ms, during which edits are merged together to be
99
+ * undone together. Set this to 0, to track each transacted change individually.
100
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
101
+ * @default 500
102
+ */
103
+ captureTimeout: 500,
104
+ /**
105
+ * @desription This is the same `trackedOrigins` option from yjs's UndoManager.
106
+ * This specifies transaction origins (strings only) to filter which transactions
107
+ * can be undone.
108
+ * When omitted, the user's connection id will be tracked. When provided,
109
+ * specifies additional tracked origins besides the user's connection id.
110
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
111
+ * @default undefined
112
+ */
113
+ trackedOrigins: ["user-123"],
114
+ });
115
+
116
+ /**
117
+ * @description Check whether calling undo will mutate storage
118
+ * @returns boolean
119
+ */
120
+ room.canUndo();
121
+ /**
122
+ * @description Check whether calling redo will mutate storage
123
+ * @returns boolean
124
+ */
125
+ room.canRedo();
126
+
127
+ /**
128
+ * @description Calling transact will enable a storage mutation to be undone/redone.
129
+ * When called without an origin, the origin will default to the user's connection
130
+ * id.
131
+ *
132
+ * You can specify a 2nd parameter to transact with a different transaction origin.
133
+ */
134
+ room.transact(() => {
135
+ room.get("messages").push(["hello world!"]);
136
+ });
137
+
138
+ // This will also be undoable because `"user-123"` is a tracked origin.
139
+ room.transact(() => {
140
+ room.get("messages").push(["hello world!"]);
141
+ }, "user-123");
142
+
143
+ /**
144
+ * @description Undoes the last valid mutation to storage
145
+ */
146
+ room.undo();
147
+
148
+ /**
149
+ * @description Re-applies the last undone mutation to storage
150
+ */
151
+ room.redo();
152
+ ```
153
+
154
+ ## @pluv/react
155
+
156
+ `@pluv/react`'s `createRoomBundle` now exposes 5 new react hooks: `usePluvCanRedo`, `usePluvCanUndo`, `usePluvRedo`, `usePluvUndo` and `usePluvTransact`.
157
+
158
+ Refer to the code-example below to better understand how to undo and redo with your `createRoomBundle`.
159
+
160
+ ```tsx
161
+ import { createBundle, createClient, y } from "@pluv/react";
162
+ import { type io } from "./io";
163
+
164
+ const client = createClient<typeof io>();
165
+
166
+ const { createRoomBundle } = createBundle(client);
167
+
168
+ const {
169
+ usePluvCanRedo,
170
+ usePluvCanUndo,
171
+ usePluvRedo,
172
+ usePluvStorage,
173
+ usePluvTransact,
174
+ usePluvUndo,
175
+ } = createRoomBundle({
176
+ initialStorage: () => ({
177
+ messages: y.array<string>([]),
178
+ }),
179
+ /**
180
+ * @description This is the same `captureTimeout` option from yjs's UndoManager.
181
+ * This specifies a number in ms, during which edits are merged together to be
182
+ * undone together. Set this to 0, to track each transacted change individually.
183
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
184
+ * @default 500
185
+ */
186
+ captureTimeout: 500,
187
+ /**
188
+ * @desription This is the same `trackedOrigins` option from yjs's UndoManager.
189
+ * This specifies transaction origins (strings only) to filter which transactions
190
+ * can be undone.
191
+ * When omitted, the user's connection id will be tracked. When provided,
192
+ * specifies additional tracked origins besides the user's connection id.
193
+ * @see (@link https://docs.yjs.dev/api/undo-manager)
194
+ * @default undefined
195
+ */
196
+ trackedOrigins: ["user-123"],
197
+ });
198
+
199
+ /**
200
+ * @description Check whether calling undo will mutate storage
201
+ */
202
+ const canUndo: boolean = usePluvCanUndo();
203
+ /**
204
+ * @description Check whether calling redo will mutate storage
205
+ */
206
+ const canRedo: boolean = usePluvCanRedo();
207
+
208
+ const [messages, sharedType] = usePluvStorage("messages");
209
+
210
+ /**
211
+ * @description Calling transact will enable a storage mutation to be undone/redone.
212
+ * When called without an origin, the origin will default to the user's connection
213
+ * id.
214
+ *
215
+ * You can specify a 2nd parameter to transact with a different transaction origin.
216
+ */
217
+ const transact = usePluvTransact();
218
+
219
+ transact(() => {
220
+ sharedType?.push(["hello world!"]);
221
+ });
222
+
223
+ // This will also be undoable because `"user-123"` is a tracked origin.
224
+ transact(() => {
225
+ sharedType?.push(["hello world!"]);
226
+ }, "user-123");
227
+
228
+ /**
229
+ * @description Undoes the last valid mutation to storage
230
+ */
231
+ const undo = usePluvUndo();
232
+
233
+ undo();
234
+
235
+ /**
236
+ * @description Re-applies the last undone mutation to storage
237
+ */
238
+ const redo = usePluvRedo();
239
+
240
+ redo();
241
+ ```
242
+
243
+ ### Patch Changes
244
+
245
+ - @pluv/types@0.12.0
246
+
3
247
  ## 0.11.1
4
248
 
5
249
  ### 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.0",
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.0"
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.0",
32
+ "eslint-config-pluv": "^0.12.0"
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";