@pluv/crdt-yjs 0.14.1 → 0.16.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.
- package/.eslintrc.js +2 -2
- package/.turbo/turbo-build.log +9 -9
- package/CHANGELOG.md +44 -37
- package/README.md +13 -29
- package/dist/index.d.mts +152 -55
- package/dist/index.d.ts +152 -55
- package/dist/index.js +433 -107
- package/dist/index.mjs +445 -101
- package/package.json +9 -8
- package/src/array/CrdtYjsArray.ts +55 -0
- package/src/array/array.ts +7 -0
- package/src/array/index.ts +2 -0
- package/src/doc/CrdtYjsDoc.ts +274 -0
- package/src/doc/CrdtYjsDocFactory.ts +83 -0
- package/src/doc/doc.ts +10 -0
- package/src/doc/index.ts +3 -0
- package/src/index.ts +1 -20
- package/src/map/CrdtYjsMap.ts +43 -0
- package/src/map/index.ts +2 -0
- package/src/{map.ts → map/map.ts} +3 -3
- package/src/object/CrdtYjsObject.ts +32 -0
- package/src/object/index.ts +2 -0
- package/src/object/object.ts +7 -0
- package/src/shared/index.ts +2 -0
- package/src/shared/isWrapper.ts +25 -0
- package/src/shared/toYjsValue.ts +5 -0
- package/src/text/CrdtYjsText.ts +34 -0
- package/src/text/index.ts +2 -0
- package/src/text/text.ts +5 -0
- package/src/types.ts +54 -35
- package/src/xmlElement/CrdtYjsXmlElement.ts +60 -0
- package/src/xmlElement/index.ts +2 -0
- package/src/xmlElement/xmlElement.ts +9 -0
- package/src/xmlFragment/CrdtYjsXmlFragment.ts +56 -0
- package/src/xmlFragment/index.ts +2 -0
- package/src/xmlFragment/xmlFragment.ts +9 -0
- package/src/xmlText/CrdtYjsXmlText.ts +38 -0
- package/src/xmlText/index.ts +2 -0
- package/src/xmlText/xmlText.ts +5 -0
- package/src/yjs.ts +9 -0
- package/src/array.ts +0 -11
- package/src/doc.ts +0 -160
- package/src/object.ts +0 -16
- package/src/text.ts +0 -5
- package/src/xmlElement.ts +0 -19
- package/src/xmlFragment.ts +0 -16
- package/src/xmlText.ts +0 -5
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AbstractCrdtType,
|
|
3
|
+
DocApplyEncodedStateParams,
|
|
4
|
+
DocSubscribeCallbackParams,
|
|
5
|
+
InferCrdtStorageJson,
|
|
6
|
+
} from "@pluv/crdt";
|
|
7
|
+
import { AbstractCrdtDoc } from "@pluv/crdt";
|
|
8
|
+
import { fromUint8Array, toUint8Array } from "js-base64";
|
|
9
|
+
import {
|
|
10
|
+
UndoManager,
|
|
11
|
+
AbstractType as YAbstractType,
|
|
12
|
+
Array as YArray,
|
|
13
|
+
Doc as YDoc,
|
|
14
|
+
Map as YMap,
|
|
15
|
+
Text as YText,
|
|
16
|
+
XmlElement as YXmlElement,
|
|
17
|
+
XmlFragment as YXmlFragment,
|
|
18
|
+
XmlText as YXmlText,
|
|
19
|
+
applyUpdate,
|
|
20
|
+
encodeStateAsUpdate,
|
|
21
|
+
} from "yjs";
|
|
22
|
+
import { CrdtYjsArray } from "../array/CrdtYjsArray";
|
|
23
|
+
import { CrdtYjsMap } from "../map/CrdtYjsMap";
|
|
24
|
+
import { CrdtYjsObject } from "../object/CrdtYjsObject";
|
|
25
|
+
import { CrdtYjsText } from "../text/CrdtYjsText";
|
|
26
|
+
import { CrdtYjsXmlElement } from "../xmlElement/CrdtYjsXmlElement";
|
|
27
|
+
import { CrdtYjsXmlFragment } from "../xmlFragment/CrdtYjsXmlFragment";
|
|
28
|
+
import { CrdtYjsXmlText } from "../xmlText/CrdtYjsXmlText";
|
|
29
|
+
|
|
30
|
+
export class CrdtYjsDoc<
|
|
31
|
+
TStorage extends Record<string, AbstractCrdtType<any, any>>,
|
|
32
|
+
> extends AbstractCrdtDoc<TStorage> {
|
|
33
|
+
public value: YDoc = new YDoc();
|
|
34
|
+
|
|
35
|
+
private _storage: TStorage;
|
|
36
|
+
private _undoManager: UndoManager | null = null;
|
|
37
|
+
|
|
38
|
+
constructor(value: TStorage = {} as TStorage) {
|
|
39
|
+
super();
|
|
40
|
+
|
|
41
|
+
this._storage = Object.entries(value).reduce((acc, [key, node]) => {
|
|
42
|
+
if (node instanceof CrdtYjsArray) {
|
|
43
|
+
const yArray = this.value.get(key, YArray) as YArray<any>;
|
|
44
|
+
yArray.insert(0, node.initialValue.slice(0));
|
|
45
|
+
|
|
46
|
+
node.value = yArray;
|
|
47
|
+
|
|
48
|
+
return { ...acc, [key]: node };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (node instanceof CrdtYjsMap || node instanceof CrdtYjsObject) {
|
|
52
|
+
const yMap = this.value.get(key, YMap) as YMap<any>;
|
|
53
|
+
node.initialValue.forEach(([k, v]) => {
|
|
54
|
+
yMap.set(k.toString(), v);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
node.value = yMap;
|
|
58
|
+
|
|
59
|
+
return { ...acc, [key]: node };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (node instanceof CrdtYjsObject) {
|
|
63
|
+
const yMap = this.value.get(key, YMap) as YMap<any>;
|
|
64
|
+
node.initialValue.forEach(([k, v]) => {
|
|
65
|
+
yMap.set(k.toString(), v);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
node.value = yMap;
|
|
69
|
+
|
|
70
|
+
return { ...acc, [key]: node };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (node instanceof CrdtYjsText) {
|
|
74
|
+
const yText = this.value.get(key, YText) as YText;
|
|
75
|
+
yText.insert(0, node.initialValue);
|
|
76
|
+
|
|
77
|
+
node.value = yText;
|
|
78
|
+
|
|
79
|
+
return { ...acc, [key]: node };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (node instanceof CrdtYjsXmlElement) {
|
|
83
|
+
const yXmlElement = this.value.get(
|
|
84
|
+
key,
|
|
85
|
+
YXmlElement,
|
|
86
|
+
) as YXmlElement;
|
|
87
|
+
yXmlElement.insert(0, node.initialValue.slice(0));
|
|
88
|
+
|
|
89
|
+
node.value = yXmlElement;
|
|
90
|
+
|
|
91
|
+
return { ...acc, [key]: node };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (node instanceof CrdtYjsXmlFragment) {
|
|
95
|
+
const yXmlFragment = this.value.get(
|
|
96
|
+
key,
|
|
97
|
+
YXmlFragment,
|
|
98
|
+
) as YXmlFragment;
|
|
99
|
+
yXmlFragment.insert(0, node.initialValue.slice(0));
|
|
100
|
+
|
|
101
|
+
node.value = yXmlFragment;
|
|
102
|
+
|
|
103
|
+
return { ...acc, [key]: node };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (node instanceof CrdtYjsXmlText) {
|
|
107
|
+
const yXmlText = this.value.get(key, YXmlText) as YXmlText;
|
|
108
|
+
yXmlText.insert(0, node.initialValue);
|
|
109
|
+
|
|
110
|
+
node.value = yXmlText;
|
|
111
|
+
|
|
112
|
+
return { ...acc, [key]: node };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return acc;
|
|
116
|
+
}, {} as TStorage);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public applyEncodedState(params: DocApplyEncodedStateParams): this {
|
|
120
|
+
const { origin, update } = params;
|
|
121
|
+
|
|
122
|
+
if (update === null || typeof update === "undefined") return this;
|
|
123
|
+
|
|
124
|
+
const uint8Update =
|
|
125
|
+
typeof update === "string" ? toUint8Array(update) : update;
|
|
126
|
+
|
|
127
|
+
applyUpdate(this.value, uint8Update, origin);
|
|
128
|
+
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public batchApplyEncodedState(
|
|
133
|
+
updates: readonly (
|
|
134
|
+
| DocApplyEncodedStateParams
|
|
135
|
+
| string
|
|
136
|
+
| null
|
|
137
|
+
| undefined
|
|
138
|
+
)[],
|
|
139
|
+
): this {
|
|
140
|
+
const params = updates.reduce<DocApplyEncodedStateParams[]>(
|
|
141
|
+
(acc, update) => {
|
|
142
|
+
if (!update) return acc;
|
|
143
|
+
|
|
144
|
+
if (typeof update === "string") {
|
|
145
|
+
acc.push({ update });
|
|
146
|
+
|
|
147
|
+
return acc;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!!update && typeof update === "object") {
|
|
151
|
+
acc.push(update);
|
|
152
|
+
|
|
153
|
+
return acc;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return acc;
|
|
157
|
+
},
|
|
158
|
+
[],
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
return params.reduce(
|
|
162
|
+
(doc, update) => doc.applyEncodedState(update),
|
|
163
|
+
this,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public canRedo(): boolean {
|
|
168
|
+
return !!this._undoManager?.canRedo();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public canUndo(): boolean {
|
|
172
|
+
return !!this._undoManager?.canUndo();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public destroy(): void {
|
|
176
|
+
this._undoManager?.destroy();
|
|
177
|
+
this.value.destroy();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public get(key?: undefined): TStorage;
|
|
181
|
+
public get<TKey extends keyof TStorage>(key: TKey): TStorage[TKey];
|
|
182
|
+
public get<TKey extends keyof TStorage>(
|
|
183
|
+
key?: TKey,
|
|
184
|
+
): TStorage | TStorage[TKey] {
|
|
185
|
+
if (typeof key === "undefined") return this._storage;
|
|
186
|
+
|
|
187
|
+
return this._storage[key as TKey];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public getEncodedState(): string {
|
|
191
|
+
return fromUint8Array(encodeStateAsUpdate(this.value));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public isEmpty(): boolean {
|
|
195
|
+
return !this.value.share.size;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public redo(): this {
|
|
199
|
+
this._undoManager?.redo();
|
|
200
|
+
|
|
201
|
+
return this;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
public subscribe(
|
|
205
|
+
listener: (params: DocSubscribeCallbackParams<TStorage>) => void,
|
|
206
|
+
): () => void {
|
|
207
|
+
const fn = (update: Uint8Array, origin: any, doc: YDoc) => {
|
|
208
|
+
listener({
|
|
209
|
+
doc: this,
|
|
210
|
+
local: origin === null || typeof origin === "undefined",
|
|
211
|
+
origin: origin ? String(origin) : null,
|
|
212
|
+
update: fromUint8Array(update),
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
this.value.on("update", fn);
|
|
217
|
+
|
|
218
|
+
return () => {
|
|
219
|
+
this.value.off("update", fn);
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
public track(): this {
|
|
224
|
+
if (this._undoManager) this._undoManager.destroy();
|
|
225
|
+
|
|
226
|
+
const sharedTypes = Object.values(this._storage).reduce<
|
|
227
|
+
YAbstractType<any>[]
|
|
228
|
+
>((acc, type) => {
|
|
229
|
+
if (
|
|
230
|
+
type instanceof CrdtYjsArray ||
|
|
231
|
+
type instanceof CrdtYjsMap ||
|
|
232
|
+
type instanceof CrdtYjsObject ||
|
|
233
|
+
type instanceof CrdtYjsText ||
|
|
234
|
+
type instanceof CrdtYjsXmlElement ||
|
|
235
|
+
type instanceof CrdtYjsXmlFragment ||
|
|
236
|
+
type instanceof CrdtYjsXmlText
|
|
237
|
+
) {
|
|
238
|
+
acc.push(type.value);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return acc;
|
|
242
|
+
}, []);
|
|
243
|
+
|
|
244
|
+
if (!sharedTypes.length) {
|
|
245
|
+
this._undoManager?.destroy();
|
|
246
|
+
this._undoManager = null;
|
|
247
|
+
|
|
248
|
+
return this;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
this._undoManager = new UndoManager(sharedTypes, { captureTimeout: 0 });
|
|
252
|
+
|
|
253
|
+
return this;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
public transact(fn: () => void): this {
|
|
257
|
+
this.value.transact(fn);
|
|
258
|
+
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
public toJson(): InferCrdtStorageJson<TStorage> {
|
|
263
|
+
return Object.entries(this._storage).reduce(
|
|
264
|
+
(acc, [key, value]) => ({ ...acc, [key]: value.toJson() }),
|
|
265
|
+
{} as InferCrdtStorageJson<TStorage>,
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
public undo(): this {
|
|
270
|
+
this._undoManager?.undo();
|
|
271
|
+
|
|
272
|
+
return this;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { AbstractCrdtType } from "@pluv/crdt";
|
|
2
|
+
import { AbstractCrdtDocFactory } from "@pluv/crdt";
|
|
3
|
+
import { CrdtYjsArray } from "../array";
|
|
4
|
+
import { CrdtYjsMap } from "../map";
|
|
5
|
+
import { CrdtYjsObject } from "../object";
|
|
6
|
+
import { CrdtYjsText } from "../text";
|
|
7
|
+
import { CrdtYjsXmlElement } from "../xmlElement";
|
|
8
|
+
import { CrdtYjsXmlFragment } from "../xmlFragment";
|
|
9
|
+
import { CrdtYjsXmlText } from "../xmlText";
|
|
10
|
+
import { CrdtYjsDoc } from "./CrdtYjsDoc";
|
|
11
|
+
|
|
12
|
+
export class CrdtYjsDocFactory<
|
|
13
|
+
TStorage extends Record<string, AbstractCrdtType<any, any>>,
|
|
14
|
+
> extends AbstractCrdtDocFactory<TStorage> {
|
|
15
|
+
private _initialStorage: () => TStorage;
|
|
16
|
+
|
|
17
|
+
constructor(initialStorage: () => TStorage = () => ({}) as TStorage) {
|
|
18
|
+
super();
|
|
19
|
+
|
|
20
|
+
this._initialStorage = initialStorage;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public getEmpty(): CrdtYjsDoc<TStorage> {
|
|
24
|
+
return new CrdtYjsDoc<TStorage>();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public getFactory(
|
|
28
|
+
initialStorage?: (() => TStorage) | undefined,
|
|
29
|
+
): CrdtYjsDocFactory<TStorage> {
|
|
30
|
+
return new CrdtYjsDocFactory<TStorage>(
|
|
31
|
+
initialStorage ?? this._initialStorage,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public getFresh(): CrdtYjsDoc<TStorage> {
|
|
36
|
+
const storage = this._initialStorage();
|
|
37
|
+
|
|
38
|
+
return new CrdtYjsDoc<TStorage>(
|
|
39
|
+
Object.entries(storage).reduce((acc, [key, node]) => {
|
|
40
|
+
if (node instanceof CrdtYjsArray) {
|
|
41
|
+
return { ...acc, [key]: new CrdtYjsArray([]) };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (node instanceof CrdtYjsMap) {
|
|
45
|
+
return { ...acc, [key]: new CrdtYjsMap([]) };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (node instanceof CrdtYjsObject) {
|
|
49
|
+
return { ...acc, [key]: new CrdtYjsObject({}) };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (node instanceof CrdtYjsText) {
|
|
53
|
+
return { ...acc, [key]: new CrdtYjsText("") };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (node instanceof CrdtYjsXmlElement) {
|
|
57
|
+
return {
|
|
58
|
+
...acc,
|
|
59
|
+
[key]: new CrdtYjsXmlElement(node.name, []),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (node instanceof CrdtYjsXmlFragment) {
|
|
64
|
+
return { ...acc, [key]: new CrdtYjsXmlFragment([]) };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (node instanceof CrdtYjsXmlText) {
|
|
68
|
+
return { ...acc, [key]: new CrdtYjsXmlText("") };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return acc;
|
|
72
|
+
}, {} as TStorage),
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public getInitialized(
|
|
77
|
+
initialStorage?: () => TStorage,
|
|
78
|
+
): CrdtYjsDoc<TStorage> {
|
|
79
|
+
return new CrdtYjsDoc<TStorage>(
|
|
80
|
+
initialStorage?.() ?? this._initialStorage(),
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/doc/doc.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AbstractCrdtType } from "@pluv/crdt";
|
|
2
|
+
import { CrdtYjsDocFactory } from "./CrdtYjsDocFactory";
|
|
3
|
+
|
|
4
|
+
export const doc = <
|
|
5
|
+
TStorage extends Record<string, AbstractCrdtType<any, any>>,
|
|
6
|
+
>(
|
|
7
|
+
value: () => TStorage = () => ({}) as TStorage,
|
|
8
|
+
): CrdtYjsDocFactory<TStorage> => {
|
|
9
|
+
return new CrdtYjsDocFactory<TStorage>(value);
|
|
10
|
+
};
|
package/src/doc/index.ts
ADDED
package/src/index.ts
CHANGED
|
@@ -1,20 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { array } from "./array";
|
|
3
|
-
export type { TrackOriginOptions } from "./doc";
|
|
4
|
-
export { YjsDoc, doc } from "./doc";
|
|
5
|
-
export { map } from "./map";
|
|
6
|
-
export { object } from "./object";
|
|
7
|
-
export type { YObject, YObjectValue } from "./object";
|
|
8
|
-
export { text } from "./text";
|
|
9
|
-
export type {
|
|
10
|
-
InferYjsDocJson,
|
|
11
|
-
InferYjsDocSharedType,
|
|
12
|
-
InferYjsDocSharedTypeJson,
|
|
13
|
-
InferYjsDocSharedTypes,
|
|
14
|
-
InferYjsSharedTypeJson,
|
|
15
|
-
} from "./types";
|
|
16
|
-
export { xmlElement } from "./xmlElement";
|
|
17
|
-
export type { XmlElementParams } from "./xmlElement";
|
|
18
|
-
export { xmlFragment } from "./xmlFragment";
|
|
19
|
-
export type { XmlFragmentParams } from "./xmlFragment";
|
|
20
|
-
export { xmlText } from "./xmlText";
|
|
1
|
+
export * as yjs from "./yjs";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { InferCrdtStorageJson } from "@pluv/crdt";
|
|
2
|
+
import { AbstractCrdtType } from "@pluv/crdt";
|
|
3
|
+
import { Map as YMap } from "yjs";
|
|
4
|
+
import { toYjsValue } from "../shared";
|
|
5
|
+
import type { InferYjsJson, InferYjsType } from "../types";
|
|
6
|
+
|
|
7
|
+
export class CrdtYjsMap<T extends unknown> extends AbstractCrdtType<
|
|
8
|
+
YMap<InferYjsType<T>>,
|
|
9
|
+
Record<string, InferYjsJson<T>>
|
|
10
|
+
> {
|
|
11
|
+
public initialValue: readonly (readonly [
|
|
12
|
+
key: string,
|
|
13
|
+
value: InferYjsType<T>,
|
|
14
|
+
])[];
|
|
15
|
+
public value: YMap<InferYjsType<T>>;
|
|
16
|
+
|
|
17
|
+
constructor(value: readonly (readonly [key: string, value: T])[] = []) {
|
|
18
|
+
super();
|
|
19
|
+
|
|
20
|
+
this.initialValue = value.map(([k, v]) => [k, toYjsValue(v)]);
|
|
21
|
+
this.value = new YMap(this.initialValue);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public get size(): number {
|
|
25
|
+
return this.value.size;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public delete(prop: string): this {
|
|
29
|
+
this.value.delete(prop);
|
|
30
|
+
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public set(prop: string, value: T): this {
|
|
35
|
+
this.value.set(prop, toYjsValue(value));
|
|
36
|
+
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public toJson(): InferCrdtStorageJson<Record<string, InferYjsJson<T>>> {
|
|
41
|
+
return this.value.toJSON();
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/map/index.ts
ADDED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CrdtYjsMap } from "./CrdtYjsMap";
|
|
2
2
|
|
|
3
3
|
export const map = <T extends unknown>(
|
|
4
4
|
value: readonly (readonly [key: string, value: T])[] = [],
|
|
5
|
-
):
|
|
6
|
-
return new
|
|
5
|
+
): CrdtYjsMap<T> => {
|
|
6
|
+
return new CrdtYjsMap<T>(value);
|
|
7
7
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { InferCrdtStorageJson } from "@pluv/crdt";
|
|
2
|
+
import { AbstractCrdtType } from "@pluv/crdt";
|
|
3
|
+
import { Map as YMap } from "yjs";
|
|
4
|
+
import { toYjsValue } from "../shared";
|
|
5
|
+
import type { InferYjsJson, InferYjsType } from "../types";
|
|
6
|
+
|
|
7
|
+
export class CrdtYjsObject<
|
|
8
|
+
T extends Record<string, any>,
|
|
9
|
+
> extends AbstractCrdtType<YMap<InferYjsType<T[keyof T]>>, InferYjsJson<T>> {
|
|
10
|
+
public initialValue: readonly (readonly [key: string, value: T[keyof T]])[];
|
|
11
|
+
public value: YMap<InferYjsType<T[keyof T]>>;
|
|
12
|
+
|
|
13
|
+
constructor(value: T = {} as T) {
|
|
14
|
+
super();
|
|
15
|
+
|
|
16
|
+
this.initialValue = Object.entries(value).map(([k, v]) => [
|
|
17
|
+
k,
|
|
18
|
+
toYjsValue(v),
|
|
19
|
+
]);
|
|
20
|
+
this.value = new YMap(this.initialValue);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public set<TProp extends keyof T>(prop: TProp, value: T[TProp]): this {
|
|
24
|
+
this.value.set(prop.toString(), toYjsValue(value));
|
|
25
|
+
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public toJson(): InferCrdtStorageJson<InferYjsJson<T>> {
|
|
30
|
+
return this.value.toJSON() as InferCrdtStorageJson<InferYjsJson<T>>;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CrdtYjsArray } from "../array/CrdtYjsArray";
|
|
2
|
+
import { CrdtYjsMap } from "../map/CrdtYjsMap";
|
|
3
|
+
import { CrdtYjsObject } from "../object/CrdtYjsObject";
|
|
4
|
+
import { CrdtYjsText } from "../text/CrdtYjsText";
|
|
5
|
+
import { CrdtYjsXmlElement } from "../xmlElement";
|
|
6
|
+
import { CrdtYjsXmlFragment } from "../xmlFragment";
|
|
7
|
+
import { CrdtYjsXmlText } from "../xmlText";
|
|
8
|
+
|
|
9
|
+
export const isWrapper = (
|
|
10
|
+
item: any,
|
|
11
|
+
): item is
|
|
12
|
+
| CrdtYjsArray<any>
|
|
13
|
+
| CrdtYjsMap<any>
|
|
14
|
+
| CrdtYjsObject<any>
|
|
15
|
+
| CrdtYjsText => {
|
|
16
|
+
return (
|
|
17
|
+
item instanceof CrdtYjsArray ||
|
|
18
|
+
item instanceof CrdtYjsMap ||
|
|
19
|
+
item instanceof CrdtYjsObject ||
|
|
20
|
+
item instanceof CrdtYjsText ||
|
|
21
|
+
item instanceof CrdtYjsXmlElement ||
|
|
22
|
+
item instanceof CrdtYjsXmlFragment ||
|
|
23
|
+
item instanceof CrdtYjsXmlText
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { AbstractCrdtType } from "@pluv/crdt";
|
|
2
|
+
import { Text as YText } from "yjs";
|
|
3
|
+
|
|
4
|
+
export class CrdtYjsText extends AbstractCrdtType<YText, string> {
|
|
5
|
+
public readonly initialValue: string;
|
|
6
|
+
public value: YText;
|
|
7
|
+
|
|
8
|
+
constructor(value: string = "") {
|
|
9
|
+
super();
|
|
10
|
+
|
|
11
|
+
this.initialValue = value;
|
|
12
|
+
this.value = new YText(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public get length(): number {
|
|
16
|
+
return this.value.length;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public delete(index: number, length: number = 1): this {
|
|
20
|
+
this.value.delete(index, length);
|
|
21
|
+
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public insert(index: number, text: string): this {
|
|
26
|
+
this.value.insert(index, text);
|
|
27
|
+
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public toJson(): string {
|
|
32
|
+
return this.value.toJSON();
|
|
33
|
+
}
|
|
34
|
+
}
|