edytor 0.0.7 → 0.0.8

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.
Files changed (107) hide show
  1. package/README.md +225 -5
  2. package/dist/block/block.svelte.d.ts +123 -0
  3. package/dist/block/block.svelte.js +430 -0
  4. package/dist/block/block.utils.d.ts +82 -0
  5. package/dist/block/block.utils.js +499 -0
  6. package/dist/block/content.svelte.d.ts +14 -0
  7. package/dist/block/content.svelte.js +40 -0
  8. package/dist/block/inlineBlock.svelte.d.ts +30 -0
  9. package/dist/block/inlineBlock.svelte.js +53 -0
  10. package/dist/components/Block.svelte +27 -0
  11. package/dist/components/Block.svelte.d.ts +7 -0
  12. package/dist/components/Content.svelte +44 -0
  13. package/dist/components/Content.svelte.d.ts +7 -0
  14. package/dist/components/Edytor.svelte +165 -0
  15. package/dist/components/Edytor.svelte.d.ts +33 -0
  16. package/dist/components/InlineBlock.svelte +17 -0
  17. package/dist/components/InlineBlock.svelte.d.ts +7 -0
  18. package/dist/components/Mark.svelte +38 -0
  19. package/dist/components/Mark.svelte.d.ts +11 -0
  20. package/dist/components/ReadonlyEditor.svelte +46 -0
  21. package/dist/components/ReadonlyEditor.svelte.d.ts +4 -0
  22. package/dist/components/Text.svelte +37 -0
  23. package/dist/components/Text.svelte.d.ts +7 -0
  24. package/dist/components/readonlyElements.svelte.d.ts +82 -0
  25. package/dist/components/readonlyElements.svelte.js +144 -0
  26. package/dist/constants.d.ts +4 -0
  27. package/dist/constants.js +4 -0
  28. package/dist/dnd.svelte.d.ts +17 -0
  29. package/dist/dnd.svelte.js +125 -0
  30. package/dist/edytor.svelte.d.ts +94 -0
  31. package/dist/edytor.svelte.js +262 -0
  32. package/dist/edytor.utils.d.ts +3 -0
  33. package/dist/edytor.utils.js +78 -0
  34. package/dist/events/onBeforeInput.d.ts +2 -2
  35. package/dist/events/onBeforeInput.js +338 -0
  36. package/dist/events/onKeyDown.d.ts +2 -69
  37. package/dist/events/onKeyDown.js +18 -0
  38. package/dist/hotkeys.d.ts +27 -0
  39. package/dist/hotkeys.js +282 -0
  40. package/dist/index.d.ts +1 -5
  41. package/dist/index.js +2 -8
  42. package/dist/localProvider.d.ts +82 -0
  43. package/dist/localProvider.js +267 -0
  44. package/dist/plugins/arrowMove/arrowMove.d.ts +2 -0
  45. package/dist/plugins/arrowMove/arrowMove.js +66 -0
  46. package/dist/plugins/code/CodePlugin.svelte +218 -0
  47. package/dist/plugins/code/CodePlugin.svelte.d.ts +23 -0
  48. package/dist/plugins/code/prism.css +141 -0
  49. package/dist/plugins/image/ImagePlugin.svelte +22 -0
  50. package/dist/plugins/image/ImagePlugin.svelte.d.ts +20 -0
  51. package/dist/plugins/mention/MentionPlugin.svelte +40 -0
  52. package/dist/plugins/mention/MentionPlugin.svelte.d.ts +20 -0
  53. package/dist/plugins/richtext/RichTextPlugin.svelte +241 -0
  54. package/dist/plugins/richtext/RichTextPlugin.svelte.d.ts +26 -0
  55. package/dist/plugins.d.ts +202 -0
  56. package/dist/plugins.js +19 -0
  57. package/dist/selection/selection.svelte.d.ts +68 -0
  58. package/dist/selection/selection.svelte.js +391 -0
  59. package/dist/selection/selection.utils.d.ts +14 -0
  60. package/dist/selection/selection.utils.js +153 -0
  61. package/dist/text/deltas.d.ts +11 -0
  62. package/dist/text/deltas.js +109 -0
  63. package/dist/text/text.svelte.d.ts +70 -0
  64. package/dist/text/text.svelte.js +119 -0
  65. package/dist/text/text.utils.d.ts +40 -0
  66. package/dist/text/text.utils.js +174 -0
  67. package/dist/utils/json.d.ts +32 -0
  68. package/dist/utils/json.js +2 -0
  69. package/dist/utils/jsx.d.ts +25 -0
  70. package/dist/utils/jsx.js +66 -0
  71. package/dist/utils/serialize.d.ts +1 -0
  72. package/dist/utils/serialize.js +1 -0
  73. package/dist/utils.d.ts +6 -0
  74. package/dist/utils.js +19 -0
  75. package/package.json +81 -33
  76. package/dist/edytor.cjs.development.js +0 -1762
  77. package/dist/edytor.cjs.development.js.map +0 -1
  78. package/dist/edytor.cjs.production.min.js +0 -2
  79. package/dist/edytor.cjs.production.min.js.map +0 -1
  80. package/dist/edytor.esm.js +0 -1691
  81. package/dist/edytor.esm.js.map +0 -1
  82. package/dist/events/index.d.ts +0 -3
  83. package/dist/events/onDrop.d.ts +0 -3
  84. package/dist/operations/deleteText.d.ts +0 -7
  85. package/dist/operations/formatText.d.ts +0 -20
  86. package/dist/operations/index.d.ts +0 -9
  87. package/dist/operations/insertText.d.ts +0 -5
  88. package/dist/operations/merge.d.ts +0 -3
  89. package/dist/operations/moveNode.d.ts +0 -12
  90. package/dist/operations/nestNode.d.ts +0 -2
  91. package/dist/operations/removeEmptyText.d.ts +0 -2
  92. package/dist/operations/splitLeaf.d.ts +0 -2
  93. package/dist/operations/splitNode.d.ts +0 -9
  94. package/dist/types.d.ts +0 -140
  95. package/dist/utils/common.d.ts +0 -17
  96. package/dist/utils/dropper.d.ts +0 -26
  97. package/dist/utils/index.d.ts +0 -6
  98. package/dist/utils/leaves.d.ts +0 -34
  99. package/dist/utils/nodes.d.ts +0 -14
  100. package/dist/utils/selection.d.ts +0 -51
  101. package/dist/utils/yClasses/EdytorDoc.d.ts +0 -16
  102. package/dist/utils/yClasses/index.d.ts +0 -3
  103. package/dist/utils/yClasses/yLeaf.d.ts +0 -7
  104. package/dist/utils/yClasses/yNode.d.ts +0 -12
  105. package/dist/yjs/index.d.ts +0 -1
  106. package/dist/yjs/wsProvider.d.ts +0 -1
  107. package/index.ts +0 -1
@@ -0,0 +1,282 @@
1
+ import { Text } from './text/text.svelte.js';
2
+ import { prevent, PreventionError } from './utils.js';
3
+ import { Block } from './block/block.svelte.js';
4
+ import { tick } from 'svelte';
5
+ const letter = new Set([
6
+ 'a',
7
+ 'b',
8
+ 'c',
9
+ 'd',
10
+ 'e',
11
+ 'f',
12
+ 'g',
13
+ 'h',
14
+ 'i',
15
+ 'j',
16
+ 'k',
17
+ 'l',
18
+ 'm',
19
+ 'n',
20
+ 'o',
21
+ 'p',
22
+ 'q',
23
+ 'r',
24
+ 's',
25
+ 't',
26
+ 'u',
27
+ 'v',
28
+ 'w',
29
+ 'x',
30
+ 'y',
31
+ 'z'
32
+ ]);
33
+ const escapedKeys = new Set(['shift']);
34
+ const defaultHotKeys = {
35
+ 'mod+z': ({ edytor }) => {
36
+ prevent(() => {
37
+ edytor.undoManager.undo();
38
+ });
39
+ },
40
+ 'mod+shift+z': ({ edytor, prevent }) => {
41
+ prevent(() => {
42
+ edytor.undoManager.redo();
43
+ });
44
+ },
45
+ 'mod+enter': ({ edytor, prevent }) => {
46
+ prevent(() => {
47
+ const newBlock = edytor.selection.state.startText?.parent.splitBlock({
48
+ index: edytor.selection.state.startText?.yText.length,
49
+ text: edytor.selection.state.startText
50
+ });
51
+ if (newBlock && newBlock.content[0] instanceof Text) {
52
+ newBlock && edytor.selection.setAtTextOffset(newBlock.content[0], newBlock.content.length);
53
+ }
54
+ });
55
+ },
56
+ 'mod+a': ({ edytor, prevent }) => {
57
+ prevent(() => {
58
+ const { startText, startBlock, islandRoot, isVoid, isIsland, voidRoot } = edytor.selection.state;
59
+ if (startText) {
60
+ if (edytor.selection.selectedBlocks.size) {
61
+ edytor.selection.selectBlocks(...edytor.root.children);
62
+ }
63
+ else if (edytor.selection.state.isAtStartOfBlock &&
64
+ edytor.selection.state.isAtEndOfBlock) {
65
+ window.getSelection()?.removeAllRanges();
66
+ edytor.selection.selectBlocks(edytor.selection.state.isIsland ? islandRoot : startText.parent);
67
+ }
68
+ else {
69
+ edytor.selection.setAtBlockRange(startBlock);
70
+ }
71
+ }
72
+ });
73
+ },
74
+ arrowup: ({ edytor, prevent }) => {
75
+ const selectedBlocks = edytor.selection.selectedBlocks;
76
+ if (selectedBlocks.size === 1) {
77
+ prevent(() => {
78
+ const selectedBlock = selectedBlocks.values().next().value;
79
+ let prevBlock = selectedBlock.closestPreviousBlock;
80
+ // If the block is inside an island, we will select the island root
81
+ while (prevBlock?.insideIsland) {
82
+ if (prevBlock.parent instanceof Block) {
83
+ prevBlock = prevBlock.parent;
84
+ }
85
+ }
86
+ if (prevBlock && prevBlock instanceof Block) {
87
+ edytor.selection.selectBlocks(prevBlock);
88
+ edytor.selection.focusBlocks();
89
+ }
90
+ });
91
+ }
92
+ },
93
+ arrowdown: ({ edytor, prevent }) => {
94
+ const selectedBlocks = edytor.selection.selectedBlocks;
95
+ if (selectedBlocks.size === 1) {
96
+ prevent(() => {
97
+ const selectedBlock = selectedBlocks.values().next().value;
98
+ let nextBlock = selectedBlock.definition.island
99
+ ? selectedBlock.nextBlock
100
+ : selectedBlock.closestNextBlock;
101
+ if (nextBlock && nextBlock instanceof Block) {
102
+ edytor.selection.selectBlocks(nextBlock);
103
+ edytor.selection.focusBlocks();
104
+ }
105
+ });
106
+ }
107
+ },
108
+ tab: ({ edytor, prevent }) => {
109
+ prevent(() => {
110
+ const selectedBlocks = edytor.selection.selectedBlocks;
111
+ if (selectedBlocks.size <= 1) {
112
+ const selectedBlock = selectedBlocks.values().next().value;
113
+ const { yStart, startText, startBlock } = edytor.selection.state;
114
+ const blockToNest = selectedBlock || startBlock;
115
+ const newBlock = blockToNest?.nestBlock();
116
+ const index = startText?.index;
117
+ if (selectedBlock) {
118
+ tick().then(() => {
119
+ newBlock && edytor.selection.selectBlocks(newBlock);
120
+ });
121
+ }
122
+ else {
123
+ if (newBlock && index !== undefined) {
124
+ const textToFocus = newBlock.content[index];
125
+ edytor.selection.setAtTextOffset(textToFocus, yStart);
126
+ }
127
+ }
128
+ }
129
+ });
130
+ },
131
+ escape: ({ edytor, prevent }) => {
132
+ if (edytor.selection.selectedBlocks.size > 0) {
133
+ prevent(() => {
134
+ const firstSelectedBlock = edytor.selection.selectedBlocks.values().next().value;
135
+ edytor.selection.selectBlocks();
136
+ if (firstSelectedBlock.firstEditableText) {
137
+ edytor.selection.setAtTextOffset(firstSelectedBlock.firstEditableText, firstSelectedBlock.firstEditableText.yText.length);
138
+ }
139
+ });
140
+ }
141
+ },
142
+ backspace: ({ edytor, prevent }) => {
143
+ if (edytor.selection.selectedBlocks.size) {
144
+ const selectedBlock = edytor.selection.selectedBlocks.values().next().value;
145
+ const isNested = selectedBlock.parent !== edytor.root;
146
+ const isLastChild = selectedBlock.parent?.children.at(-1) === selectedBlock;
147
+ if (isNested && isLastChild) {
148
+ const newBlock = selectedBlock.unNestBlock();
149
+ if (newBlock) {
150
+ setTimeout(() => {
151
+ edytor.selection.selectBlocks(newBlock);
152
+ });
153
+ return;
154
+ }
155
+ }
156
+ const selectedBlocks = Array.from(edytor.selection.selectedBlocks.values());
157
+ edytor.edytor.plugins.forEach((plugin) => {
158
+ plugin.onDeleteSelectedBlocks?.({ prevent, selectedBlocks });
159
+ });
160
+ const firstSelectedBlock = selectedBlocks.at(0);
161
+ const lastSelectedBlock = selectedBlocks.at(-1);
162
+ const blockToFocus = firstSelectedBlock.closestPreviousBlock || lastSelectedBlock.closestNextBlock;
163
+ edytor.edytor.transact(() => {
164
+ edytor.selection.selectedBlocks.forEach((block) => {
165
+ block.removeBlock();
166
+ });
167
+ });
168
+ if (blockToFocus) {
169
+ setTimeout(() => {
170
+ edytor.edytor.node?.focus();
171
+ edytor.selection.setAtTextOffset(blockToFocus.firstEditableText, blockToFocus.firstEditableText?.yText.length);
172
+ });
173
+ }
174
+ }
175
+ }
176
+ };
177
+ // Features:
178
+ // Case insensitive hotkeys
179
+ // Modifier keys in any order
180
+ // Hotkeys can prevent execution of subsequent hotkeys and therefore allow for overriding default hotkeys
181
+ // Mod to match modifier cmd on mac or ctrl on windows
182
+ export class HotKeys {
183
+ edytor;
184
+ userHotKeys;
185
+ plugins;
186
+ hotkeys = new Map();
187
+ get isMac() {
188
+ return typeof window != 'undefined' && /Mac|iPod|iPhone|iPad/.test(window.navigator.platform);
189
+ }
190
+ constructor(edytor, userHotKeys = {}, plugins = []) {
191
+ this.edytor = edytor;
192
+ this.userHotKeys = userHotKeys;
193
+ this.plugins = plugins;
194
+ }
195
+ init = () => {
196
+ if (typeof window === 'undefined')
197
+ return;
198
+ // User hotkeys > plugins hotkeys > default hotkeys
199
+ const entries = [
200
+ this.userHotKeys || {},
201
+ ...this.plugins.map((plugin) => plugin.hotkeys || {}),
202
+ defaultHotKeys
203
+ ];
204
+ entries.forEach((hotKeys) => {
205
+ Object.entries(hotKeys).forEach(([key, func]) => {
206
+ const normalizedKey = this.normalizeKey(key);
207
+ if (this.hotkeys.has(normalizedKey)) {
208
+ this.hotkeys.get(normalizedKey).push(func);
209
+ }
210
+ else {
211
+ this.hotkeys.set(this.normalizeKey(key), [func]);
212
+ }
213
+ });
214
+ });
215
+ };
216
+ normalizeKey = (key) => {
217
+ const parts = key.toLowerCase().split('+');
218
+ const orderedParts = [];
219
+ // Add modifiers in the correct order
220
+ if (parts.includes('mod'))
221
+ orderedParts.push('mod');
222
+ if (parts.includes('alt'))
223
+ orderedParts.push('alt');
224
+ if (parts.includes('ctrl'))
225
+ orderedParts.push('ctrl');
226
+ if (parts.includes('shift'))
227
+ orderedParts.push('shift');
228
+ // Add remaining keys that aren't modifiers
229
+ parts.forEach((part) => {
230
+ if (!['mod', 'alt', 'ctrl', 'shift'].includes(part)) {
231
+ orderedParts.push(part);
232
+ }
233
+ });
234
+ return orderedParts.join('+');
235
+ };
236
+ combination = (e) => {
237
+ const key = e.key.toLowerCase();
238
+ let combination = '';
239
+ // Is modifier
240
+ if (e.ctrlKey || e.metaKey) {
241
+ combination += 'mod+';
242
+ }
243
+ // Is alt
244
+ if (e.altKey) {
245
+ combination += 'alt+';
246
+ }
247
+ // Is ctrl
248
+ if (e.ctrlKey && !e.metaKey) {
249
+ combination += 'ctrl+';
250
+ }
251
+ // Is shift
252
+ if (e.shiftKey) {
253
+ combination += 'shift+';
254
+ }
255
+ if (!escapedKeys.has(key)) {
256
+ combination += key;
257
+ }
258
+ // Remove trailing plus if it exists
259
+ combination = combination.replace(/\+$/, '');
260
+ return combination;
261
+ };
262
+ isHotkey = (e) => {
263
+ const combination = this.combination(e);
264
+ const hotKeys = this.hotkeys.get(combination);
265
+ if (!hotKeys?.length)
266
+ return false;
267
+ try {
268
+ hotKeys.forEach((hotKey) => {
269
+ hotKey({ event: e, edytor: this.edytor, prevent });
270
+ });
271
+ return false;
272
+ }
273
+ catch (error) {
274
+ if (error instanceof PreventionError) {
275
+ e.preventDefault();
276
+ e.stopPropagation();
277
+ error.cb?.();
278
+ }
279
+ return true;
280
+ }
281
+ };
282
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1 @@
1
- export * from "./events";
2
- export * from "./operations";
3
- export * from "./utils";
4
- export * from "./types";
5
- export * from "./yjs";
1
+ export {};
package/dist/index.js CHANGED
@@ -1,8 +1,2 @@
1
-
2
- 'use strict'
3
-
4
- if (process.env.NODE_ENV === 'production') {
5
- module.exports = require('./edytor.cjs.production.min.js')
6
- } else {
7
- module.exports = require('./edytor.cjs.development.js')
8
- }
1
+ "use strict";
2
+ // Reexport your entry components here
@@ -0,0 +1,82 @@
1
+ import * as Y from 'yjs';
2
+ import { ObservableV2 } from 'lib0/observable';
3
+ import * as awarenessProtocol from 'y-protocols/awareness';
4
+ export declare const PREFERRED_TRIM_SIZE = 500;
5
+ type IdbPersistence = {
6
+ db: IDBDatabase | null;
7
+ doc: Y.Doc;
8
+ _dbref: number;
9
+ _dbsize: number;
10
+ _destroyed: boolean;
11
+ };
12
+ /**
13
+ * @param {IndexeddbPersistence} idbPersistence
14
+ * @param {function(IDBObjectStore):void} [beforeApplyUpdatesCallback]
15
+ * @param {function(IDBObjectStore):void} [afterApplyUpdatesCallback]
16
+ */
17
+ export declare const fetchUpdates: (idbPersistence: IdbPersistence, beforeApplyUpdatesCallback?: (store: IDBObjectStore) => void, afterApplyUpdatesCallback?: (store: IDBObjectStore) => void) => Promise<IDBObjectStore>;
18
+ /**
19
+ * @param {IndexeddbPersistence} idbPersistence
20
+ * @param {boolean} forceStore
21
+ */
22
+ export declare const storeState: (idbPersistence: IdbPersistence, forceStore?: boolean) => Promise<void>;
23
+ /**
24
+ * @param {string} name
25
+ */
26
+ export declare const clearDocument: (name: string) => Promise<any>;
27
+ /**
28
+ * @extends Observable<string>
29
+ */
30
+ export declare class IndexeddbPersistence extends ObservableV2<{
31
+ synced: (provider: IndexeddbPersistence) => void;
32
+ }> {
33
+ doc: Y.Doc;
34
+ name: string;
35
+ _dbref: number;
36
+ _dbsize: number;
37
+ _destroyed: boolean;
38
+ db: IDBDatabase | null;
39
+ synced: boolean;
40
+ _db: Promise<IDBDatabase>;
41
+ whenSynced: Promise<IndexeddbPersistence>;
42
+ _storeTimeout: number;
43
+ _storeTimeoutId: number | null;
44
+ _storeUpdate: (update: Uint8Array, origin: any) => void;
45
+ awareness: awarenessProtocol.Awareness;
46
+ bcconnected: boolean;
47
+ private _bcSubscriber;
48
+ private _awarenessUpdateHandler;
49
+ /**
50
+ * @param {string} name
51
+ * @param {Y.Doc} doc
52
+ */
53
+ constructor(name: string, doc: Y.Doc);
54
+ private messageHandlers;
55
+ private readMessage;
56
+ private broadcastMessage;
57
+ private connectBc;
58
+ private disconnectBc;
59
+ /**
60
+ * Destroys this instance and removes all data from indexeddb.
61
+ *
62
+ * @return {Promise<void>}
63
+ */
64
+ destroy(): Promise<void>;
65
+ /**
66
+ * @param {String | number | ArrayBuffer | Date} key
67
+ * @return {Promise<String | number | ArrayBuffer | Date | any>}
68
+ */
69
+ get(key: string | number | ArrayBuffer | Date): Promise<string | number | any[] | ArrayBuffer | Date>;
70
+ /**
71
+ * @param {String | number | ArrayBuffer | Date} key
72
+ * @param {String | number | ArrayBuffer | Date} value
73
+ * @return {Promise<String | number | ArrayBuffer | Date>}
74
+ */
75
+ set(key: string | number | ArrayBuffer | Date, value: string | number | ArrayBuffer | Date): Promise<any>;
76
+ /**
77
+ * @param {String | number | ArrayBuffer | Date} key
78
+ * @return {Promise<undefined>}
79
+ */
80
+ del(key: string | number | ArrayBuffer | Date): Promise<any>;
81
+ }
82
+ export {};
@@ -0,0 +1,267 @@
1
+ import * as Y from 'yjs';
2
+ import * as idb from 'lib0/indexeddb';
3
+ import * as promise from 'lib0/promise';
4
+ import { ObservableV2 } from 'lib0/observable';
5
+ import * as bc from 'lib0/broadcastchannel';
6
+ import * as encoding from 'lib0/encoding';
7
+ import * as decoding from 'lib0/decoding';
8
+ import * as syncProtocol from 'y-protocols/sync';
9
+ import * as awarenessProtocol from 'y-protocols/awareness';
10
+ const customStoreName = 'custom';
11
+ const updatesStoreName = 'updates';
12
+ const messageSync = 0;
13
+ const messageQueryAwareness = 3;
14
+ const messageAwareness = 1;
15
+ export const PREFERRED_TRIM_SIZE = 500;
16
+ /**
17
+ * @param {IndexeddbPersistence} idbPersistence
18
+ * @param {function(IDBObjectStore):void} [beforeApplyUpdatesCallback]
19
+ * @param {function(IDBObjectStore):void} [afterApplyUpdatesCallback]
20
+ */
21
+ export const fetchUpdates = (idbPersistence, beforeApplyUpdatesCallback = () => { }, afterApplyUpdatesCallback = () => { }) => {
22
+ const [updatesStore] = idb.transact(idbPersistence.db, [updatesStoreName]);
23
+ return idb
24
+ .getAll(updatesStore, idb.createIDBKeyRangeLowerBound(idbPersistence._dbref, false))
25
+ .then((updates) => {
26
+ if (!idbPersistence._destroyed) {
27
+ beforeApplyUpdatesCallback(updatesStore);
28
+ Y.transact(idbPersistence.doc, () => {
29
+ updates.forEach((val) => Y.applyUpdate(idbPersistence.doc, val));
30
+ }, idbPersistence, false);
31
+ afterApplyUpdatesCallback(updatesStore);
32
+ }
33
+ })
34
+ .then(() => idb.getLastKey(updatesStore).then((lastKey) => {
35
+ idbPersistence._dbref = lastKey + 1;
36
+ }))
37
+ .then(() => idb.count(updatesStore).then((cnt) => {
38
+ idbPersistence._dbsize = cnt;
39
+ }))
40
+ .then(() => updatesStore);
41
+ };
42
+ /**
43
+ * @param {IndexeddbPersistence} idbPersistence
44
+ * @param {boolean} forceStore
45
+ */
46
+ export const storeState = (idbPersistence, forceStore = true) => fetchUpdates(idbPersistence).then((updatesStore) => {
47
+ if (forceStore || idbPersistence._dbsize >= PREFERRED_TRIM_SIZE) {
48
+ idb
49
+ .addAutoKey(updatesStore, Y.encodeStateAsUpdate(idbPersistence.doc))
50
+ .then(() => idb.del(updatesStore, idb.createIDBKeyRangeUpperBound(idbPersistence._dbref, true)))
51
+ .then(() => idb.count(updatesStore).then((cnt) => {
52
+ idbPersistence._dbsize = cnt;
53
+ }));
54
+ }
55
+ });
56
+ /**
57
+ * @param {string} name
58
+ */
59
+ export const clearDocument = (name) => idb.deleteDB(name);
60
+ /**
61
+ * @extends Observable<string>
62
+ */
63
+ export class IndexeddbPersistence extends ObservableV2 {
64
+ doc;
65
+ name;
66
+ _dbref;
67
+ _dbsize;
68
+ _destroyed;
69
+ db;
70
+ synced;
71
+ _db;
72
+ whenSynced;
73
+ _storeTimeout;
74
+ _storeTimeoutId;
75
+ _storeUpdate;
76
+ awareness;
77
+ bcconnected = false;
78
+ _bcSubscriber;
79
+ _awarenessUpdateHandler;
80
+ /**
81
+ * @param {string} name
82
+ * @param {Y.Doc} doc
83
+ */
84
+ constructor(name, doc) {
85
+ super();
86
+ this.doc = doc;
87
+ this.name = name;
88
+ this._dbref = 0;
89
+ this._dbsize = 0;
90
+ this._destroyed = false;
91
+ this.db = null;
92
+ this.synced = false;
93
+ this.awareness = new awarenessProtocol.Awareness(doc);
94
+ this._db = idb.openDB(name, (db) => idb.createStores(db, [['updates', { autoIncrement: true }], ['custom']]));
95
+ this.whenSynced = promise.create((resolve) => this.on('synced', () => resolve(this)));
96
+ this._bcSubscriber = (data, origin) => {
97
+ if (origin !== this) {
98
+ const encoder = this.readMessage(new Uint8Array(data), false);
99
+ if (encoding.length(encoder) > 1) {
100
+ bc.publish(this.name, encoding.toUint8Array(encoder), this);
101
+ }
102
+ }
103
+ };
104
+ this._awarenessUpdateHandler = ({ added, updated, removed }, _origin) => {
105
+ const changedClients = added.concat(updated).concat(removed);
106
+ const encoder = encoding.createEncoder();
107
+ encoding.writeVarUint(encoder, messageAwareness);
108
+ encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this.awareness, changedClients));
109
+ this.broadcastMessage(encoding.toUint8Array(encoder));
110
+ };
111
+ this._db.then((db) => {
112
+ this.db = db;
113
+ const beforeApplyUpdatesCallback = (updatesStore) => idb.addAutoKey(updatesStore, Y.encodeStateAsUpdate(doc));
114
+ const afterApplyUpdatesCallback = () => {
115
+ if (this._destroyed)
116
+ return this;
117
+ this.connectBc();
118
+ };
119
+ fetchUpdates(this, beforeApplyUpdatesCallback, afterApplyUpdatesCallback);
120
+ });
121
+ this._storeTimeout = 1000;
122
+ this._storeTimeoutId = null;
123
+ this._storeUpdate = (update, origin) => {
124
+ if (this.db && origin !== this) {
125
+ const [updatesStore] = idb.transact(this.db, [updatesStoreName]);
126
+ idb.addAutoKey(updatesStore, update);
127
+ if (++this._dbsize >= PREFERRED_TRIM_SIZE) {
128
+ if (this._storeTimeoutId !== null) {
129
+ clearTimeout(this._storeTimeoutId);
130
+ }
131
+ this._storeTimeoutId = setTimeout(() => {
132
+ storeState(this, false);
133
+ this._storeTimeoutId = null;
134
+ }, this._storeTimeout);
135
+ }
136
+ }
137
+ // Broadcast the update to other tabs
138
+ if (origin !== this) {
139
+ const encoder = encoding.createEncoder();
140
+ encoding.writeVarUint(encoder, messageSync);
141
+ syncProtocol.writeUpdate(encoder, update);
142
+ this.broadcastMessage(encoding.toUint8Array(encoder));
143
+ }
144
+ };
145
+ doc.on('update', this._storeUpdate);
146
+ this.awareness.on('update', this._awarenessUpdateHandler);
147
+ this.destroy = this.destroy.bind(this);
148
+ doc.on('destroy', this.destroy);
149
+ globalThis.addEventListener('beforeunload', () => this.destroy());
150
+ }
151
+ messageHandlers = {
152
+ [messageSync]: (encoder, decoder, provider, _emitSynced) => {
153
+ encoding.writeVarUint(encoder, messageSync);
154
+ const syncMessageType = syncProtocol.readSyncMessage(decoder, encoder, provider.doc, provider);
155
+ if (syncMessageType === syncProtocol.messageYjsSyncStep2 && !provider.synced) {
156
+ //
157
+ }
158
+ },
159
+ [messageQueryAwareness]: (encoder, _decoder, provider) => {
160
+ encoding.writeVarUint(encoder, messageAwareness);
161
+ encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(provider.awareness, Array.from(provider.awareness.getStates().keys())));
162
+ },
163
+ [messageAwareness]: (_encoder, decoder, provider) => {
164
+ awarenessProtocol.applyAwarenessUpdate(provider.awareness, decoding.readVarUint8Array(decoder), provider);
165
+ }
166
+ };
167
+ readMessage = (buf, emitSynced) => {
168
+ const decoder = decoding.createDecoder(buf);
169
+ const encoder = encoding.createEncoder();
170
+ const messageType = decoding.readVarUint(decoder);
171
+ const messageHandler = this.messageHandlers[messageType];
172
+ if (messageHandler) {
173
+ messageHandler(encoder, decoder, this, emitSynced);
174
+ }
175
+ return encoder;
176
+ };
177
+ broadcastMessage(buf) {
178
+ if (this.bcconnected) {
179
+ bc.publish(this.name, buf, this);
180
+ }
181
+ }
182
+ connectBc() {
183
+ if (!this.bcconnected) {
184
+ bc.subscribe(this.name, this._bcSubscriber);
185
+ this.bcconnected = true;
186
+ }
187
+ // Sync initial state
188
+ const encoderSync = encoding.createEncoder();
189
+ encoding.writeVarUint(encoderSync, messageSync);
190
+ syncProtocol.writeSyncStep1(encoderSync, this.doc);
191
+ bc.publish(this.name, encoding.toUint8Array(encoderSync), this);
192
+ const encoderState = encoding.createEncoder();
193
+ encoding.writeVarUint(encoderState, messageSync);
194
+ syncProtocol.writeSyncStep2(encoderState, this.doc);
195
+ bc.publish(this.name, encoding.toUint8Array(encoderState), this);
196
+ // Sync awareness state
197
+ const encoderAwarenessQuery = encoding.createEncoder();
198
+ encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
199
+ bc.publish(this.name, encoding.toUint8Array(encoderAwarenessQuery), this);
200
+ const encoderAwarenessState = encoding.createEncoder();
201
+ encoding.writeVarUint(encoderAwarenessState, messageAwareness);
202
+ encoding.writeVarUint8Array(encoderAwarenessState, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [this.doc.clientID]));
203
+ bc.publish(this.name, encoding.toUint8Array(encoderAwarenessState), this);
204
+ this.synced = true;
205
+ this.emit('synced', [this]);
206
+ }
207
+ disconnectBc() {
208
+ // Notify other clients about disconnection
209
+ const encoder = encoding.createEncoder();
210
+ encoding.writeVarUint(encoder, messageAwareness);
211
+ encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [this.doc.clientID], new Map()));
212
+ this.broadcastMessage(encoding.toUint8Array(encoder));
213
+ if (this.bcconnected) {
214
+ bc.unsubscribe(this.name, this._bcSubscriber);
215
+ this.bcconnected = false;
216
+ }
217
+ }
218
+ /**
219
+ * Destroys this instance and removes all data from indexeddb.
220
+ *
221
+ * @return {Promise<void>}
222
+ */
223
+ destroy() {
224
+ if (this._storeTimeoutId) {
225
+ clearTimeout(this._storeTimeoutId);
226
+ }
227
+ this.doc.off('update', this._storeUpdate);
228
+ this.doc.off('destroy', this.destroy);
229
+ this.awareness.off('update', this._awarenessUpdateHandler);
230
+ this._destroyed = true;
231
+ this.disconnectBc();
232
+ return this._db.then((db) => {
233
+ db.close();
234
+ });
235
+ }
236
+ /**
237
+ * @param {String | number | ArrayBuffer | Date} key
238
+ * @return {Promise<String | number | ArrayBuffer | Date | any>}
239
+ */
240
+ get(key) {
241
+ return this._db.then((db) => {
242
+ const [custom] = idb.transact(db, [customStoreName], 'readonly');
243
+ return idb.get(custom, key);
244
+ });
245
+ }
246
+ /**
247
+ * @param {String | number | ArrayBuffer | Date} key
248
+ * @param {String | number | ArrayBuffer | Date} value
249
+ * @return {Promise<String | number | ArrayBuffer | Date>}
250
+ */
251
+ set(key, value) {
252
+ return this._db.then((db) => {
253
+ const [custom] = idb.transact(db, [customStoreName]);
254
+ return idb.put(custom, value, key);
255
+ });
256
+ }
257
+ /**
258
+ * @param {String | number | ArrayBuffer | Date} key
259
+ * @return {Promise<undefined>}
260
+ */
261
+ del(key) {
262
+ return this._db.then((db) => {
263
+ const [custom] = idb.transact(db, [customStoreName]);
264
+ return idb.del(custom, key);
265
+ });
266
+ }
267
+ }
@@ -0,0 +1,2 @@
1
+ import { type Plugin } from '../../plugins.js';
2
+ export declare const arrowMovePlugin: Plugin;