kritzel-stencil 0.1.75 → 0.1.76
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/dist/cjs/kritzel-active-users_42.cjs.entry.js +91 -7
- package/dist/collection/classes/core/viewport.class.js +24 -1
- package/dist/collection/classes/structures/object-map.structure.js +58 -2
- package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.css +2 -2
- package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.js +7 -2
- package/dist/collection/constants/version.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/kritzel-awareness-cursors.js +1 -1
- package/dist/components/kritzel-editor.js +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-settings.js +1 -1
- package/dist/components/{p-D0MQFmqi.js → p-31FVoNWR.js} +1 -1
- package/dist/components/p-jdYmu4SA.js +9 -0
- package/dist/components/p-xNwOWoiT.js +1 -0
- package/dist/esm/kritzel-active-users_42.entry.js +91 -7
- package/dist/stencil/p-775a7246.entry.js +9 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/core/viewport.class.d.ts +8 -0
- package/dist/types/classes/structures/object-map.structure.d.ts +6 -0
- package/dist/types/constants/version.d.ts +1 -1
- package/dist/types/interfaces/remote-cursor.interface.d.ts +1 -0
- package/package.json +1 -1
- package/dist/components/p-BSipRoFx.js +0 -1
- package/dist/components/p-WmxufeOo.js +0 -9
- package/dist/stencil/p-0dbd9a2f.entry.js +0 -9
|
@@ -176,7 +176,7 @@ const KritzelAvatar = class {
|
|
|
176
176
|
};
|
|
177
177
|
KritzelAvatar.style = kritzelAvatarCss();
|
|
178
178
|
|
|
179
|
-
const kritzelAwarenessCursorsCss = () => `:host{display:block;position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:9500}.awareness-cursor{position:absolute;top:0;left:0;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, opacity 300ms ease;will-change:transform}.awareness-cursor.stale{opacity:0
|
|
179
|
+
const kritzelAwarenessCursorsCss = () => `:host{display:block;position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:9500}.awareness-cursor{position:absolute;top:0;left:0;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, opacity 300ms ease;will-change:transform}.awareness-cursor.stale{opacity:0}.awareness-cursor.tracking-object{transition-duration:0ms}.cursor-arrow{filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.cursor-label{position:absolute;left:16px;top:16px;white-space:nowrap;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;font-size:var(--kritzel-awareness-cursor-label-font-size, 12px);color:var(--kritzel-awareness-cursor-label-text-color, #ffffff);padding:2px 8px;border-radius:4px;line-height:1.4;font-weight:500;pointer-events:none;user-select:none}.edge-indicator{position:absolute;top:-12px;left:-12px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, opacity 300ms ease;will-change:transform;pointer-events:auto;user-select:none;cursor:pointer}.edge-indicator.stale{opacity:0}.edge-indicator.tracking-object{transition-duration:0ms}.edge-arrow{position:absolute;filter:drop-shadow(0 1px 3px rgba(0, 0, 0, 0.3))}.edge-label{position:absolute;white-space:nowrap;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;font-size:var(--kritzel-awareness-cursor-label-font-size, 12px);color:var(--kritzel-awareness-cursor-label-text-color, #ffffff);padding:2px 8px;border-radius:4px;line-height:1.4;font-weight:500;pointer-events:none;opacity:0;transform-origin:center;transition:opacity 150ms ease}.edge-indicator:hover .edge-label{opacity:1}.remote-selection-box{position:absolute;top:0;left:0;border-width:2px;border-style:solid;pointer-events:none;will-change:transform, width, height;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, width var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, height var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out}`;
|
|
180
180
|
|
|
181
181
|
const STALE_THRESHOLD_MS = 10_000;
|
|
182
182
|
const REMOVE_THRESHOLD_MS = 30_000;
|
|
@@ -227,6 +227,10 @@ const KritzelAwarenessCursors = class {
|
|
|
227
227
|
const cursor = state.cursor;
|
|
228
228
|
const activeObjectId = state.activeObjectId || null;
|
|
229
229
|
const selectionBox = state.selectionBox || null;
|
|
230
|
+
const existing = updated.get(clientId);
|
|
231
|
+
const cursorMoved = !existing ||
|
|
232
|
+
!existing.cursor !== !cursor ||
|
|
233
|
+
(cursor && existing.cursor && (cursor.x !== existing.cursor.x || cursor.y !== existing.cursor.y));
|
|
230
234
|
updated.set(clientId, {
|
|
231
235
|
clientId,
|
|
232
236
|
user,
|
|
@@ -234,6 +238,7 @@ const KritzelAwarenessCursors = class {
|
|
|
234
238
|
activeObjectId,
|
|
235
239
|
selectionBox,
|
|
236
240
|
lastUpdated: now,
|
|
241
|
+
lastCursorMove: cursorMoved ? now : (existing?.lastCursorMove ?? now),
|
|
237
242
|
});
|
|
238
243
|
});
|
|
239
244
|
// Remove cursors for disconnected clients
|
|
@@ -259,7 +264,7 @@ const KritzelAwarenessCursors = class {
|
|
|
259
264
|
}
|
|
260
265
|
}
|
|
261
266
|
isStale(cursor) {
|
|
262
|
-
return Date.now() - cursor.
|
|
267
|
+
return Date.now() - cursor.lastCursorMove > STALE_THRESHOLD_MS;
|
|
263
268
|
}
|
|
264
269
|
hasActiveDrawingCursors() {
|
|
265
270
|
for (const cursor of this.remoteCursors.values()) {
|
|
@@ -348,7 +353,7 @@ const KritzelAwarenessCursors = class {
|
|
|
348
353
|
}
|
|
349
354
|
render() {
|
|
350
355
|
const cursors = Array.from(this.remoteCursors.values());
|
|
351
|
-
return (index.h(index.Host, { key: '
|
|
356
|
+
return (index.h(index.Host, { key: '4dd962322c7e955b9038c55cb10f8ffda1e0b246' }, cursors.map(remoteCursor => {
|
|
352
357
|
if (!remoteCursor.cursor)
|
|
353
358
|
return null;
|
|
354
359
|
// When a remote user is actively drawing, derive cursor position from
|
|
@@ -19840,6 +19845,14 @@ class KritzelViewport {
|
|
|
19840
19845
|
startX = 0;
|
|
19841
19846
|
/** Starting Y position for pan/zoom gestures */
|
|
19842
19847
|
startY = 0;
|
|
19848
|
+
/** Minimum movement distance (in screen pixels) before broadcasting touch cursor position */
|
|
19849
|
+
static TOUCH_CURSOR_BROADCAST_THRESHOLD = 5;
|
|
19850
|
+
/** Screen X position where the current touch interaction started */
|
|
19851
|
+
_touchStartScreenX = 0;
|
|
19852
|
+
/** Screen Y position where the current touch interaction started */
|
|
19853
|
+
_touchStartScreenY = 0;
|
|
19854
|
+
/** Whether the touch movement threshold has been exceeded for cursor broadcasting */
|
|
19855
|
+
_touchCursorBroadcastActive = false;
|
|
19843
19856
|
/**
|
|
19844
19857
|
* Creates a new KritzelViewport instance and initializes viewport state.
|
|
19845
19858
|
* Sets up debounced handlers for viewport updates and scaling end events.
|
|
@@ -19967,6 +19980,11 @@ class KritzelViewport {
|
|
|
19967
19980
|
}
|
|
19968
19981
|
if (event.pointerType === 'touch' || event.pointerType === 'pen') {
|
|
19969
19982
|
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
19983
|
+
if (activePointers.length === 1) {
|
|
19984
|
+
this._touchStartScreenX = event.clientX;
|
|
19985
|
+
this._touchStartScreenY = event.clientY;
|
|
19986
|
+
this._touchCursorBroadcastActive = false;
|
|
19987
|
+
}
|
|
19970
19988
|
if (activePointers.length === 2) {
|
|
19971
19989
|
this._core.store.state.objects?.clearCursorPosition();
|
|
19972
19990
|
const currentPath = this._core.store.currentPath;
|
|
@@ -20036,7 +20054,16 @@ class KritzelViewport {
|
|
|
20036
20054
|
else {
|
|
20037
20055
|
this._core.store.state.pointerX = (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale;
|
|
20038
20056
|
this._core.store.state.pointerY = (yRelativeToHost - this._core.store.state.translateY) / this._core.store.state.scale;
|
|
20039
|
-
|
|
20057
|
+
if (!this._touchCursorBroadcastActive) {
|
|
20058
|
+
const dx = event.clientX - this._touchStartScreenX;
|
|
20059
|
+
const dy = event.clientY - this._touchStartScreenY;
|
|
20060
|
+
if (Math.sqrt(dx * dx + dy * dy) >= KritzelViewport.TOUCH_CURSOR_BROADCAST_THRESHOLD) {
|
|
20061
|
+
this._touchCursorBroadcastActive = true;
|
|
20062
|
+
}
|
|
20063
|
+
}
|
|
20064
|
+
if (this._touchCursorBroadcastActive) {
|
|
20065
|
+
this._core.store.state.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
|
|
20066
|
+
}
|
|
20040
20067
|
}
|
|
20041
20068
|
if (activePointers.length === 2) {
|
|
20042
20069
|
const firstTouchX = activePointers[0].clientX - this._core.store.offsetX;
|
|
@@ -20089,6 +20116,7 @@ class KritzelViewport {
|
|
|
20089
20116
|
}
|
|
20090
20117
|
}
|
|
20091
20118
|
if (event.pointerType === 'touch' || event.pointerType === 'pen') {
|
|
20119
|
+
this._touchCursorBroadcastActive = false;
|
|
20092
20120
|
if (this._core.store.state.pointers.size === 0) {
|
|
20093
20121
|
this._debounceEndScaling();
|
|
20094
20122
|
}
|
|
@@ -21368,6 +21396,42 @@ class KritzelObjectMap {
|
|
|
21368
21396
|
}
|
|
21369
21397
|
this._awareness.setLocalStateField('selectionBox', null);
|
|
21370
21398
|
}
|
|
21399
|
+
/**
|
|
21400
|
+
* Removes selection groups whose owner is no longer present in awareness.
|
|
21401
|
+
* Called when remote clients disconnect to prevent orphaned selection groups
|
|
21402
|
+
* from persisting in the workspace state.
|
|
21403
|
+
*/
|
|
21404
|
+
removeOrphanedSelectionGroups() {
|
|
21405
|
+
if (!this._awareness) {
|
|
21406
|
+
return;
|
|
21407
|
+
}
|
|
21408
|
+
const states = this._awareness.getStates();
|
|
21409
|
+
const activeUserIds = new Set();
|
|
21410
|
+
states.forEach(state => {
|
|
21411
|
+
const userId = state.user?.id;
|
|
21412
|
+
if (userId) {
|
|
21413
|
+
activeUserIds.add(userId);
|
|
21414
|
+
}
|
|
21415
|
+
});
|
|
21416
|
+
const localUserId = this._core?.user?.id;
|
|
21417
|
+
const orphanedGroups = this.quadtree.filter(o => o instanceof workspace_migrations.KritzelSelectionGroup
|
|
21418
|
+
&& o.userId != null
|
|
21419
|
+
&& o.userId !== localUserId
|
|
21420
|
+
&& !activeUserIds.has(o.userId));
|
|
21421
|
+
for (const group of orphanedGroups) {
|
|
21422
|
+
this.quadtree.remove(o => o.id === group.id);
|
|
21423
|
+
this._idMap.delete(group.id);
|
|
21424
|
+
if (this._objectsMap) {
|
|
21425
|
+
this._ydoc.transact(() => {
|
|
21426
|
+
this._objectsMap.delete(group.id);
|
|
21427
|
+
}, 'local');
|
|
21428
|
+
}
|
|
21429
|
+
}
|
|
21430
|
+
if (orphanedGroups.length > 0) {
|
|
21431
|
+
this._core?.store.invalidateSelectionCache();
|
|
21432
|
+
this._core?.rerender();
|
|
21433
|
+
}
|
|
21434
|
+
}
|
|
21371
21435
|
/**
|
|
21372
21436
|
* Registers a callback to be invoked when the awareness state changes.
|
|
21373
21437
|
* The callback receives the full awareness states map.
|
|
@@ -21530,7 +21594,11 @@ class KritzelObjectMap {
|
|
|
21530
21594
|
}
|
|
21531
21595
|
// Subscribe to awareness changes
|
|
21532
21596
|
if (this._awareness) {
|
|
21533
|
-
this._awarenessChangeHandler = () => {
|
|
21597
|
+
this._awarenessChangeHandler = (change) => {
|
|
21598
|
+
// Clean up selection groups belonging to disconnected users
|
|
21599
|
+
if (change.removed.length > 0) {
|
|
21600
|
+
this.removeOrphanedSelectionGroups();
|
|
21601
|
+
}
|
|
21534
21602
|
const now = Date.now();
|
|
21535
21603
|
const timeSinceLastEmit = now - this._lastAwarenessEmitTime;
|
|
21536
21604
|
// Clear any pending timeout since we have a new event
|
|
@@ -21793,11 +21861,27 @@ class KritzelObjectMap {
|
|
|
21793
21861
|
}
|
|
21794
21862
|
this.quadtree.reset();
|
|
21795
21863
|
this._idMap.clear();
|
|
21796
|
-
this.
|
|
21864
|
+
const localUserId = this._core?.user?.id;
|
|
21865
|
+
const staleSelectionGroupIds = [];
|
|
21866
|
+
this._objectsMap.forEach((serialized, key) => {
|
|
21797
21867
|
const object = this._reviver.revive(serialized);
|
|
21868
|
+
// Remove remote selection groups on startup — they are transient UI state
|
|
21869
|
+
// that should not survive an app restart. The owning user's session is gone.
|
|
21870
|
+
if (object instanceof workspace_migrations.KritzelSelectionGroup && object.userId != null && object.userId !== localUserId) {
|
|
21871
|
+
staleSelectionGroupIds.push(key);
|
|
21872
|
+
return;
|
|
21873
|
+
}
|
|
21798
21874
|
this.quadtree.insert(object);
|
|
21799
21875
|
this._idMap.set(object.id, object);
|
|
21800
21876
|
});
|
|
21877
|
+
// Clean up stale remote selection groups from Yjs
|
|
21878
|
+
if (staleSelectionGroupIds.length > 0) {
|
|
21879
|
+
this._ydoc.transact(() => {
|
|
21880
|
+
for (const id of staleSelectionGroupIds) {
|
|
21881
|
+
this._objectsMap.delete(id);
|
|
21882
|
+
}
|
|
21883
|
+
}, 'local');
|
|
21884
|
+
}
|
|
21801
21885
|
}
|
|
21802
21886
|
/**
|
|
21803
21887
|
* Resets the object map by clearing both the local quadtree and the Yjs objects map.
|
|
@@ -28437,7 +28521,7 @@ const KritzelPortal = class {
|
|
|
28437
28521
|
* This file is auto-generated by the version bump scripts.
|
|
28438
28522
|
* Do not modify manually.
|
|
28439
28523
|
*/
|
|
28440
|
-
const KRITZEL_VERSION = '0.1.
|
|
28524
|
+
const KRITZEL_VERSION = '0.1.76';
|
|
28441
28525
|
|
|
28442
28526
|
const kritzelSettingsCss = () => `:host{display:contents}kritzel-dialog{--kritzel-dialog-body-padding:0;--kritzel-dialog-width-large:800px;--kritzel-dialog-height-large:500px}.footer-button{padding:8px 16px;border-radius:6px;cursor:pointer;font-size:14px}.cancel-button{border:1px solid #ebebeb;background:#fff;color:inherit}.cancel-button:hover{background:#f5f5f5}.settings-content{padding:0}.settings-content h3{margin:0 0 16px 0;font-size:18px;font-weight:600;color:var(--kritzel-settings-content-heading-color, #333333)}.settings-content p{margin:0;font-size:14px;color:var(--kritzel-settings-content-text-color, #666666);line-height:1.5}.settings-group{display:flex;flex-direction:column;gap:24px}.settings-item{display:flex;flex-direction:column;gap:8px}.settings-row{display:flex;align-items:center;justify-content:space-between;gap:16px}.settings-label{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.settings-description{font-size:12px;color:var(--kritzel-settings-description-color, #888888);margin:0;line-height:1.4}.shortcuts-list{display:flex;flex-direction:column;gap:24px}.shortcuts-category{display:flex;flex-direction:column;gap:8px}.shortcuts-category-title{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.shortcuts-group{display:flex;flex-direction:column;gap:4px}.shortcut-item{display:flex;justify-content:space-between;align-items:center;padding:6px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-item-bg, rgba(0, 0, 0, 0.02))}.shortcut-label{font-size:14px;color:var(--kritzel-settings-content-text-color, #666666)}.shortcut-key{font-family:monospace;font-size:12px;padding:2px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-key-bg, #f0f0f0);color:var(--kritzel-settings-shortcut-key-color, #333333);border:1px solid var(--kritzel-settings-shortcut-key-border, #ddd)}`;
|
|
28443
28527
|
|
|
@@ -21,6 +21,14 @@ export class KritzelViewport {
|
|
|
21
21
|
startX = 0;
|
|
22
22
|
/** Starting Y position for pan/zoom gestures */
|
|
23
23
|
startY = 0;
|
|
24
|
+
/** Minimum movement distance (in screen pixels) before broadcasting touch cursor position */
|
|
25
|
+
static TOUCH_CURSOR_BROADCAST_THRESHOLD = 5;
|
|
26
|
+
/** Screen X position where the current touch interaction started */
|
|
27
|
+
_touchStartScreenX = 0;
|
|
28
|
+
/** Screen Y position where the current touch interaction started */
|
|
29
|
+
_touchStartScreenY = 0;
|
|
30
|
+
/** Whether the touch movement threshold has been exceeded for cursor broadcasting */
|
|
31
|
+
_touchCursorBroadcastActive = false;
|
|
24
32
|
/**
|
|
25
33
|
* Creates a new KritzelViewport instance and initializes viewport state.
|
|
26
34
|
* Sets up debounced handlers for viewport updates and scaling end events.
|
|
@@ -148,6 +156,11 @@ export class KritzelViewport {
|
|
|
148
156
|
}
|
|
149
157
|
if (event.pointerType === 'touch' || event.pointerType === 'pen') {
|
|
150
158
|
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
159
|
+
if (activePointers.length === 1) {
|
|
160
|
+
this._touchStartScreenX = event.clientX;
|
|
161
|
+
this._touchStartScreenY = event.clientY;
|
|
162
|
+
this._touchCursorBroadcastActive = false;
|
|
163
|
+
}
|
|
151
164
|
if (activePointers.length === 2) {
|
|
152
165
|
this._core.store.state.objects?.clearCursorPosition();
|
|
153
166
|
const currentPath = this._core.store.currentPath;
|
|
@@ -217,7 +230,16 @@ export class KritzelViewport {
|
|
|
217
230
|
else {
|
|
218
231
|
this._core.store.state.pointerX = (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale;
|
|
219
232
|
this._core.store.state.pointerY = (yRelativeToHost - this._core.store.state.translateY) / this._core.store.state.scale;
|
|
220
|
-
|
|
233
|
+
if (!this._touchCursorBroadcastActive) {
|
|
234
|
+
const dx = event.clientX - this._touchStartScreenX;
|
|
235
|
+
const dy = event.clientY - this._touchStartScreenY;
|
|
236
|
+
if (Math.sqrt(dx * dx + dy * dy) >= KritzelViewport.TOUCH_CURSOR_BROADCAST_THRESHOLD) {
|
|
237
|
+
this._touchCursorBroadcastActive = true;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (this._touchCursorBroadcastActive) {
|
|
241
|
+
this._core.store.state.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
|
|
242
|
+
}
|
|
221
243
|
}
|
|
222
244
|
if (activePointers.length === 2) {
|
|
223
245
|
const firstTouchX = activePointers[0].clientX - this._core.store.offsetX;
|
|
@@ -270,6 +292,7 @@ export class KritzelViewport {
|
|
|
270
292
|
}
|
|
271
293
|
}
|
|
272
294
|
if (event.pointerType === 'touch' || event.pointerType === 'pen') {
|
|
295
|
+
this._touchCursorBroadcastActive = false;
|
|
273
296
|
if (this._core.store.state.pointers.size === 0) {
|
|
274
297
|
this._debounceEndScaling();
|
|
275
298
|
}
|
|
@@ -137,6 +137,42 @@ export class KritzelObjectMap {
|
|
|
137
137
|
}
|
|
138
138
|
this._awareness.setLocalStateField('selectionBox', null);
|
|
139
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Removes selection groups whose owner is no longer present in awareness.
|
|
142
|
+
* Called when remote clients disconnect to prevent orphaned selection groups
|
|
143
|
+
* from persisting in the workspace state.
|
|
144
|
+
*/
|
|
145
|
+
removeOrphanedSelectionGroups() {
|
|
146
|
+
if (!this._awareness) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const states = this._awareness.getStates();
|
|
150
|
+
const activeUserIds = new Set();
|
|
151
|
+
states.forEach(state => {
|
|
152
|
+
const userId = state.user?.id;
|
|
153
|
+
if (userId) {
|
|
154
|
+
activeUserIds.add(userId);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
const localUserId = this._core?.user?.id;
|
|
158
|
+
const orphanedGroups = this.quadtree.filter(o => o instanceof KritzelSelectionGroup
|
|
159
|
+
&& o.userId != null
|
|
160
|
+
&& o.userId !== localUserId
|
|
161
|
+
&& !activeUserIds.has(o.userId));
|
|
162
|
+
for (const group of orphanedGroups) {
|
|
163
|
+
this.quadtree.remove(o => o.id === group.id);
|
|
164
|
+
this._idMap.delete(group.id);
|
|
165
|
+
if (this._objectsMap) {
|
|
166
|
+
this._ydoc.transact(() => {
|
|
167
|
+
this._objectsMap.delete(group.id);
|
|
168
|
+
}, 'local');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (orphanedGroups.length > 0) {
|
|
172
|
+
this._core?.store.invalidateSelectionCache();
|
|
173
|
+
this._core?.rerender();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
140
176
|
/**
|
|
141
177
|
* Registers a callback to be invoked when the awareness state changes.
|
|
142
178
|
* The callback receives the full awareness states map.
|
|
@@ -299,7 +335,11 @@ export class KritzelObjectMap {
|
|
|
299
335
|
}
|
|
300
336
|
// Subscribe to awareness changes
|
|
301
337
|
if (this._awareness) {
|
|
302
|
-
this._awarenessChangeHandler = () => {
|
|
338
|
+
this._awarenessChangeHandler = (change) => {
|
|
339
|
+
// Clean up selection groups belonging to disconnected users
|
|
340
|
+
if (change.removed.length > 0) {
|
|
341
|
+
this.removeOrphanedSelectionGroups();
|
|
342
|
+
}
|
|
303
343
|
const now = Date.now();
|
|
304
344
|
const timeSinceLastEmit = now - this._lastAwarenessEmitTime;
|
|
305
345
|
// Clear any pending timeout since we have a new event
|
|
@@ -562,11 +602,27 @@ export class KritzelObjectMap {
|
|
|
562
602
|
}
|
|
563
603
|
this.quadtree.reset();
|
|
564
604
|
this._idMap.clear();
|
|
565
|
-
this.
|
|
605
|
+
const localUserId = this._core?.user?.id;
|
|
606
|
+
const staleSelectionGroupIds = [];
|
|
607
|
+
this._objectsMap.forEach((serialized, key) => {
|
|
566
608
|
const object = this._reviver.revive(serialized);
|
|
609
|
+
// Remove remote selection groups on startup — they are transient UI state
|
|
610
|
+
// that should not survive an app restart. The owning user's session is gone.
|
|
611
|
+
if (object instanceof KritzelSelectionGroup && object.userId != null && object.userId !== localUserId) {
|
|
612
|
+
staleSelectionGroupIds.push(key);
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
567
615
|
this.quadtree.insert(object);
|
|
568
616
|
this._idMap.set(object.id, object);
|
|
569
617
|
});
|
|
618
|
+
// Clean up stale remote selection groups from Yjs
|
|
619
|
+
if (staleSelectionGroupIds.length > 0) {
|
|
620
|
+
this._ydoc.transact(() => {
|
|
621
|
+
for (const id of staleSelectionGroupIds) {
|
|
622
|
+
this._objectsMap.delete(id);
|
|
623
|
+
}
|
|
624
|
+
}, 'local');
|
|
625
|
+
}
|
|
570
626
|
}
|
|
571
627
|
/**
|
|
572
628
|
* Resets the object map by clearing both the local quadtree and the Yjs objects map.
|
package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.css
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
.awareness-cursor.stale {
|
|
22
|
-
opacity: 0
|
|
22
|
+
opacity: 0;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
.awareness-cursor.tracking-object {
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
.edge-indicator.stale {
|
|
67
|
-
opacity: 0
|
|
67
|
+
opacity: 0;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
.edge-indicator.tracking-object {
|
package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.js
CHANGED
|
@@ -47,6 +47,10 @@ export class KritzelAwarenessCursors {
|
|
|
47
47
|
const cursor = state.cursor;
|
|
48
48
|
const activeObjectId = state.activeObjectId || null;
|
|
49
49
|
const selectionBox = state.selectionBox || null;
|
|
50
|
+
const existing = updated.get(clientId);
|
|
51
|
+
const cursorMoved = !existing ||
|
|
52
|
+
!existing.cursor !== !cursor ||
|
|
53
|
+
(cursor && existing.cursor && (cursor.x !== existing.cursor.x || cursor.y !== existing.cursor.y));
|
|
50
54
|
updated.set(clientId, {
|
|
51
55
|
clientId,
|
|
52
56
|
user,
|
|
@@ -54,6 +58,7 @@ export class KritzelAwarenessCursors {
|
|
|
54
58
|
activeObjectId,
|
|
55
59
|
selectionBox,
|
|
56
60
|
lastUpdated: now,
|
|
61
|
+
lastCursorMove: cursorMoved ? now : (existing?.lastCursorMove ?? now),
|
|
57
62
|
});
|
|
58
63
|
});
|
|
59
64
|
// Remove cursors for disconnected clients
|
|
@@ -79,7 +84,7 @@ export class KritzelAwarenessCursors {
|
|
|
79
84
|
}
|
|
80
85
|
}
|
|
81
86
|
isStale(cursor) {
|
|
82
|
-
return Date.now() - cursor.
|
|
87
|
+
return Date.now() - cursor.lastCursorMove > STALE_THRESHOLD_MS;
|
|
83
88
|
}
|
|
84
89
|
hasActiveDrawingCursors() {
|
|
85
90
|
for (const cursor of this.remoteCursors.values()) {
|
|
@@ -177,7 +182,7 @@ export class KritzelAwarenessCursors {
|
|
|
177
182
|
void _ty;
|
|
178
183
|
void this.objectVersion;
|
|
179
184
|
const cursors = Array.from(this.remoteCursors.values());
|
|
180
|
-
return (h(Host, { key: '
|
|
185
|
+
return (h(Host, { key: '4dd962322c7e955b9038c55cb10f8ffda1e0b246' }, cursors.map(remoteCursor => {
|
|
181
186
|
if (!remoteCursor.cursor)
|
|
182
187
|
return null;
|
|
183
188
|
// When a remote user is actively drawing, derive cursor position from
|
package/dist/components/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{g as getAssetPath,r as render,s as setAssetPath,a as setNonce,b as setPlatformOptions}from"./p-pebXO4LU.js";export{d as KritzelBrushTool,b as KritzelGroup,a as KritzelImage,e as KritzelLineTool,h as KritzelSelectionTool,c as KritzelShape,g as KritzelShapeTool,K as KritzelText,f as KritzelTextTool,S as ShapeType}from"./p-CJ2eHeoV.js";export{a as KritzelLine,K as KritzelPath}from"./p-DXpYcAnT.js";export{A as APP_STATE_MIGRATIONS,I as IndexedDBSyncProvider,d as KritzelAlignment,c as KritzelAnchorManager,b as KritzelCursorHelper,K as KritzelEraserTool,a as KritzelImageTool,W as WORKSPACE_MIGRATIONS,r as runMigrations}from"./p-WmxufeOo.js";import*as t from"yjs";import{WebsocketProvider as i}from"y-websocket";import{H as n,a as o}from"./kritzel-editor.js";export{D as DEFAULT_BRUSH_CONFIG,c as DEFAULT_LINE_TOOL_CONFIG,b as DEFAULT_TEXT_CONFIG,KritzelEditor,defineCustomElement as defineCustomElementKritzelEditor}from"./kritzel-editor.js";export{K as KritzelWorkspace,W as WORKSPACE_EXPORT_VERSION}from"./p-DhMlShij.js";export{K as KritzelThemeManager,d as darkTheme,l as lightTheme}from"./p-CjazGGq3.js";export{C as CURRENT_APP_STATE_SCHEMA_VERSION,a as CURRENT_WORKSPACE_SCHEMA_VERSION}from"./p-CW-VyJgK.js";export{KritzelActiveUsers,defineCustomElement as defineCustomElementKritzelActiveUsers}from"./kritzel-active-users.js";export{KritzelAvatar,defineCustomElement as defineCustomElementKritzelAvatar}from"./kritzel-avatar.js";export{KritzelAwarenessCursors,defineCustomElement as defineCustomElementKritzelAwarenessCursors}from"./kritzel-awareness-cursors.js";export{KritzelBackToContent,defineCustomElement as defineCustomElementKritzelBackToContent}from"./kritzel-back-to-content.js";export{KritzelBrushStyle,defineCustomElement as defineCustomElementKritzelBrushStyle}from"./kritzel-brush-style.js";export{KritzelButton,defineCustomElement as defineCustomElementKritzelButton}from"./kritzel-button.js";export{KritzelColor,defineCustomElement as defineCustomElementKritzelColor}from"./kritzel-color.js";export{KritzelColorPalette,defineCustomElement as defineCustomElementKritzelColorPalette}from"./kritzel-color-palette.js";export{KritzelContextMenu,defineCustomElement as defineCustomElementKritzelContextMenu}from"./kritzel-context-menu.js";export{KritzelControls,defineCustomElement as defineCustomElementKritzelControls}from"./kritzel-controls.js";export{KritzelCurrentUser,defineCustomElement as defineCustomElementKritzelCurrentUser}from"./kritzel-current-user.js";export{KritzelCurrentUserDialog,defineCustomElement as defineCustomElementKritzelCurrentUserDialog}from"./kritzel-current-user-dialog.js";export{KritzelCursorTrail,defineCustomElement as defineCustomElementKritzelCursorTrail}from"./kritzel-cursor-trail.js";export{KritzelDialog,defineCustomElement as defineCustomElementKritzelDialog}from"./kritzel-dialog.js";export{KritzelDropdown,defineCustomElement as defineCustomElementKritzelDropdown}from"./kritzel-dropdown.js";export{KritzelEngine,defineCustomElement as defineCustomElementKritzelEngine}from"./kritzel-engine.js";export{KritzelExport,defineCustomElement as defineCustomElementKritzelExport}from"./kritzel-export.js";export{KritzelFont,defineCustomElement as defineCustomElementKritzelFont}from"./kritzel-font.js";export{KritzelFontFamily,defineCustomElement as defineCustomElementKritzelFontFamily}from"./kritzel-font-family.js";export{KritzelFontSize,defineCustomElement as defineCustomElementKritzelFontSize}from"./kritzel-font-size.js";export{KritzelIcon,defineCustomElement as defineCustomElementKritzelIcon}from"./kritzel-icon.js";export{KritzelInput,defineCustomElement as defineCustomElementKritzelInput}from"./kritzel-input.js";export{KritzelLineEndings,defineCustomElement as defineCustomElementKritzelLineEndings}from"./kritzel-line-endings.js";export{KritzelLoginDialog,defineCustomElement as defineCustomElementKritzelLoginDialog}from"./kritzel-login-dialog.js";export{KritzelMasterDetail,defineCustomElement as defineCustomElementKritzelMasterDetail}from"./kritzel-master-detail.js";export{KritzelMenu,defineCustomElement as defineCustomElementKritzelMenu}from"./kritzel-menu.js";export{KritzelMenuItem,defineCustomElement as defineCustomElementKritzelMenuItem}from"./kritzel-menu-item.js";export{KritzelMoreMenu,defineCustomElement as defineCustomElementKritzelMoreMenu}from"./kritzel-more-menu.js";export{KritzelNumericInput,defineCustomElement as defineCustomElementKritzelNumericInput}from"./kritzel-numeric-input.js";export{KritzelOpacitySlider,defineCustomElement as defineCustomElementKritzelOpacitySlider}from"./kritzel-opacity-slider.js";export{KritzelPillTabs,defineCustomElement as defineCustomElementKritzelPillTabs}from"./kritzel-pill-tabs.js";export{KritzelPortal,defineCustomElement as defineCustomElementKritzelPortal}from"./kritzel-portal.js";export{KritzelSettings,defineCustomElement as defineCustomElementKritzelSettings}from"./kritzel-settings.js";export{KritzelShapeFill,defineCustomElement as defineCustomElementKritzelShapeFill}from"./kritzel-shape-fill.js";export{KritzelShareDialog,defineCustomElement as defineCustomElementKritzelShareDialog}from"./kritzel-share-dialog.js";export{KritzelSlideToggle,defineCustomElement as defineCustomElementKritzelSlideToggle}from"./kritzel-slide-toggle.js";export{KritzelSplitButton,defineCustomElement as defineCustomElementKritzelSplitButton}from"./kritzel-split-button.js";export{KritzelStrokeSize,defineCustomElement as defineCustomElementKritzelStrokeSize}from"./kritzel-stroke-size.js";export{KritzelToolConfig,defineCustomElement as defineCustomElementKritzelToolConfig}from"./kritzel-tool-config.js";export{KritzelTooltip,defineCustomElement as defineCustomElementKritzelTooltip}from"./kritzel-tooltip.js";export{KritzelUtilityPanel,defineCustomElement as defineCustomElementKritzelUtilityPanel}from"./kritzel-utility-panel.js";export{KritzelWorkspaceManager,defineCustomElement as defineCustomElementKritzelWorkspaceManager}from"./kritzel-workspace-manager.js";const m=Math.floor,u=127,z=Number.MAX_SAFE_INTEGER;class p{constructor(){this.cpos=0,this.cbuf=new Uint8Array(100),this.bufs=[]}}const E=()=>new p,k=e=>{const t=new Uint8Array((e=>{let t=e.cpos;for(let s=0;s<e.bufs.length;s++)t+=e.bufs[s].length;return t})(e));let s=0;for(let i=0;i<e.bufs.length;i++){const n=e.bufs[i];t.set(n,s),s+=n.length}return t.set(new Uint8Array(e.cbuf.buffer,0,e.cpos),s),t},x=(e,t)=>{const s=e.cbuf.length;e.cpos===s&&(e.bufs.push(e.cbuf),e.cbuf=new Uint8Array(2*s),e.cpos=0),e.cbuf[e.cpos++]=t},y=(e,t)=>{for(;t>u;)x(e,128|u&t),t=m(t/128);x(e,u&t)},j=(e,t)=>{y(e,t.byteLength),((e,t)=>{const s=e.cbuf.length,i=e.cpos,n=((e,t)=>e<t?e:t)(s-i,t.length),o=t.length-n;e.cbuf.set(t.subarray(0,n),i),e.cpos+=n,o>0&&(e.bufs.push(e.cbuf),e.cbuf=new Uint8Array(((e,t)=>e>t?e:t)(2*s,o)),e.cbuf.set(t.subarray(n)),e.cpos=o)})(e,t)},T=e=>Error(e),w=T("Unexpected end of array"),v=T("Integer out of Range");class P{constructor(e){this.arr=e,this.pos=0}}const M=e=>((e,t)=>{const s=new Uint8Array(e.arr.buffer,e.pos+e.arr.byteOffset,t);return e.pos+=t,s})(e,U(e)),U=e=>{let t=0,s=1;const i=e.arr.length;for(;e.pos<i;){const i=e.arr[e.pos++];if(t+=(i&u)*s,s*=128,i<128)return t;if(t>z)throw v}throw w};class _{type="local";doc;channel;_synced=!1;constructor(e,t,s){this.doc=t,this.channel=new BroadcastChannel(e),this.channel.onmessage=e=>{this.handleMessage(e.data)},this.doc.on("update",this.handleDocUpdate),this.broadcastSync(),setTimeout((()=>{this._synced=!0}),100),s?.quiet||console.info("BroadcastChannel Provider initialized: "+e)}handleDocUpdate=(e,t)=>{if(t!==this){const t=E();y(t,0),j(t,e),this.channel.postMessage(k(t))}};handleMessage(e){const s=(e=>new P(e))(new Uint8Array(e));switch(U(s)){case 0:const e=M(s);t.applyUpdate(this.doc,e,this);break;case 1:this.broadcastSync();break;case 2:const i=M(s),n=t.encodeStateAsUpdate(this.doc,i);if(n.length>0){const e=E();y(e,0),j(e,n),this.channel.postMessage(k(e))}}}broadcastSync(){const e=E();y(e,2),j(e,t.encodeStateVector(this.doc)),this.channel.postMessage(k(e))}async connect(){if(!this._synced)return new Promise((e=>{const t=()=>{this._synced?e():setTimeout(t,50)};t()}))}disconnect(){}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.doc.off("update",this.handleDocUpdate),this.channel.close()}}class O{type="network";provider;isConnected=!1;_quiet=!1;get awareness(){return this.provider.awareness}constructor(e,t,s){const n=s?.url||"ws://localhost:1234",o=s?.roomName||e;this.provider=new i(n,o,t,{params:s?.params,protocols:s?.protocols,WebSocketPolyfill:s?.WebSocketPolyfill,awareness:s?.awareness,maxBackoffTime:s?.maxBackoffTime,disableBc:!0}),this._quiet=s?.quiet??!1,this.setupEventListeners(),this._quiet||console.info(`WebSocket Provider initialized: ${n}/${o}`)}static with(e){return{create:(t,s,i)=>{const n=i?{...e,...i}:e;return new O(t,s,n)}}}setupEventListeners(){this.provider.on("status",(({status:e})=>{"connected"===e?(this.isConnected=!0,this._quiet||console.info("WebSocket connected")):"disconnected"===e&&(this.isConnected=!1,this._quiet||console.info("WebSocket disconnected"))})),this.provider.on("sync",(e=>{e&&!this._quiet&&console.info("WebSocket synced")}))}async connect(){if(!this.isConnected)return new Promise(((e,t)=>{const s=setTimeout((()=>{t(Error("WebSocket connection timeout"))}),1e4),i=({status:t})=>{"connected"===t&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,e())};this.provider.on("status",i),this.provider.wsconnected&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,e())}))}disconnect(){this.provider&&this.provider.disconnect(),this.isConnected=!1}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.provider&&this.provider.destroy(),this.isConnected=!1}}class B{type="network";provider;isConnected=!1;isSynced=!1;usesSharedSocket=!1;isDestroyed=!1;connectTimeout=null;pendingConnectReject=null;connectionTimeoutMs;_connectionStatus="disconnected";visibilityHandler=null;onlineHandler=null;get awareness(){return this.provider.awareness}get connectionStatus(){return this._connectionStatus}static sharedWebSocketProvider=null;constructor(e,t,s){const i=s?.name||e,o=s?.url||"ws://localhost:1234";this.connectionTimeoutMs=s?.connectionTimeout??1e4;const r=s?.websocketProvider||B.sharedWebSocketProvider,l={};void 0!==s?.delay&&(l.delay=s.delay),void 0!==s?.factor&&(l.factor=s.factor),void 0!==s?.maxAttempts&&(l.maxAttempts=s.maxAttempts),void 0!==s?.minDelay&&(l.minDelay=s.minDelay),void 0!==s?.maxDelay&&(l.maxDelay=s.maxDelay);const m=()=>{this.isDestroyed||(this.isConnected=!0,this._connectionStatus="connected",s?.quiet||console.info("Hocuspocus connected: "+i),s?.onConnect&&s.onConnect())},a=()=>{this.isDestroyed||(this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected",s?.quiet||console.info("Hocuspocus disconnected: "+i),s?.onDisconnect&&s.onDisconnect())},c=()=>{this.isDestroyed||(this.isSynced=!0,this._connectionStatus="synced",s?.quiet||console.info("Hocuspocus synced: "+i),s?.onSynced&&s.onSynced())},u=e=>{this.isDestroyed||("connecting"===e.status&&(this._connectionStatus="connecting"),s?.onStatus&&s.onStatus(e))};if(r){this.usesSharedSocket=!0;const e={websocketProvider:r,name:i,document:t,token:s?.token||null,onStatus:u,onConnect:m,onDisconnect:a,onSynced:c,...l};void 0!==s?.forceSyncInterval&&(e.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(e.onAuthenticationFailed=s.onAuthenticationFailed),this.provider=new n(e),this.provider.attach(),s?.quiet||console.info("Hocuspocus Provider initialized (multiplexed): "+i)}else{this.usesSharedSocket=!1;const e={url:o,name:i,document:t,token:s?.token||null,autoConnect:!1,onStatus:u,onConnect:m,onDisconnect:a,onSynced:c,...l};void 0!==s?.forceSyncInterval&&(e.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(e.onAuthenticationFailed=s.onAuthenticationFailed),s?.WebSocketPolyfill&&(e.WebSocketPolyfill=s.WebSocketPolyfill),this.provider=new n(e),s?.quiet||console.info(`Hocuspocus Provider initialized: ${o}/${i}`)}this.setupBrowserEventListeners()}setupBrowserEventListeners(){"undefined"!=typeof document&&(this.visibilityHandler=()=>{"visible"!==document.visibilityState||this.isConnected||this.isDestroyed||this.provider.connect()},document.addEventListener("visibilitychange",this.visibilityHandler)),"undefined"!=typeof window&&(this.onlineHandler=()=>{this.isConnected||this.isDestroyed||this.provider.connect()},window.addEventListener("online",this.onlineHandler))}removeBrowserEventListeners(){this.visibilityHandler&&"undefined"!=typeof document&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.onlineHandler&&"undefined"!=typeof window&&(window.removeEventListener("online",this.onlineHandler),this.onlineHandler=null)}static createSharedWebSocket(e){if(B.sharedWebSocketProvider)return console.warn("Shared WebSocket already exists. Returning existing instance."),B.sharedWebSocketProvider;const t={url:e.url};return e.WebSocketPolyfill&&(t.WebSocketPolyfill=e.WebSocketPolyfill),e.onConnect&&(t.onConnect=e.onConnect),e.onDisconnect&&(t.onDisconnect=e.onDisconnect),e.onStatus&&(t.onStatus=e.onStatus),B.sharedWebSocketProvider=new o(t),console.info("Shared Hocuspocus WebSocket created: "+e.url),B.sharedWebSocketProvider}static destroySharedWebSocket(){B.sharedWebSocketProvider&&(B.sharedWebSocketProvider.destroy(),B.sharedWebSocketProvider=null,console.info("Shared Hocuspocus WebSocket destroyed"))}static getSharedWebSocket(){return B.sharedWebSocketProvider}static with(e){return{create:(t,s,i)=>{const n=i?{...e,...i}:e;return new B(t,s,n)}}}async connect(){if(!this.isSynced&&!this.isDestroyed)return this._connectionStatus="connecting",new Promise(((e,t)=>{this.pendingConnectReject=t,this.connectTimeout=setTimeout((()=>{this.pendingConnectReject=null,this.connectTimeout=null,t(Error("Hocuspocus connection timeout"))}),this.connectionTimeoutMs);const s=()=>{this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),this.isDestroyed||e()};if(this.provider.on("synced",s),this.provider.isSynced)return this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),void e();this.isConnected||this.usesSharedSocket||this.provider.connect()}))}async reconnect(){return this.disconnect(),this.connect()}disconnect(){this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.provider&&(this.usesSharedSocket?this.provider.detach():this.provider.disconnect()),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}destroy(){this.isDestroyed=!0,this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.removeBrowserEventListeners(),this.provider&&this.provider.destroy(),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}}export{_ as BroadcastSyncProvider,B as HocuspocusSyncProvider,O as WebSocketSyncProvider}
|
|
1
|
+
export{g as getAssetPath,r as render,s as setAssetPath,a as setNonce,b as setPlatformOptions}from"./p-pebXO4LU.js";export{d as KritzelBrushTool,b as KritzelGroup,a as KritzelImage,e as KritzelLineTool,h as KritzelSelectionTool,c as KritzelShape,g as KritzelShapeTool,K as KritzelText,f as KritzelTextTool,S as ShapeType}from"./p-CJ2eHeoV.js";export{a as KritzelLine,K as KritzelPath}from"./p-DXpYcAnT.js";export{A as APP_STATE_MIGRATIONS,I as IndexedDBSyncProvider,d as KritzelAlignment,c as KritzelAnchorManager,b as KritzelCursorHelper,K as KritzelEraserTool,a as KritzelImageTool,W as WORKSPACE_MIGRATIONS,r as runMigrations}from"./p-jdYmu4SA.js";import*as t from"yjs";import{WebsocketProvider as i}from"y-websocket";import{H as n,a as o}from"./kritzel-editor.js";export{D as DEFAULT_BRUSH_CONFIG,c as DEFAULT_LINE_TOOL_CONFIG,b as DEFAULT_TEXT_CONFIG,KritzelEditor,defineCustomElement as defineCustomElementKritzelEditor}from"./kritzel-editor.js";export{K as KritzelWorkspace,W as WORKSPACE_EXPORT_VERSION}from"./p-DhMlShij.js";export{K as KritzelThemeManager,d as darkTheme,l as lightTheme}from"./p-CjazGGq3.js";export{C as CURRENT_APP_STATE_SCHEMA_VERSION,a as CURRENT_WORKSPACE_SCHEMA_VERSION}from"./p-CW-VyJgK.js";export{KritzelActiveUsers,defineCustomElement as defineCustomElementKritzelActiveUsers}from"./kritzel-active-users.js";export{KritzelAvatar,defineCustomElement as defineCustomElementKritzelAvatar}from"./kritzel-avatar.js";export{KritzelAwarenessCursors,defineCustomElement as defineCustomElementKritzelAwarenessCursors}from"./kritzel-awareness-cursors.js";export{KritzelBackToContent,defineCustomElement as defineCustomElementKritzelBackToContent}from"./kritzel-back-to-content.js";export{KritzelBrushStyle,defineCustomElement as defineCustomElementKritzelBrushStyle}from"./kritzel-brush-style.js";export{KritzelButton,defineCustomElement as defineCustomElementKritzelButton}from"./kritzel-button.js";export{KritzelColor,defineCustomElement as defineCustomElementKritzelColor}from"./kritzel-color.js";export{KritzelColorPalette,defineCustomElement as defineCustomElementKritzelColorPalette}from"./kritzel-color-palette.js";export{KritzelContextMenu,defineCustomElement as defineCustomElementKritzelContextMenu}from"./kritzel-context-menu.js";export{KritzelControls,defineCustomElement as defineCustomElementKritzelControls}from"./kritzel-controls.js";export{KritzelCurrentUser,defineCustomElement as defineCustomElementKritzelCurrentUser}from"./kritzel-current-user.js";export{KritzelCurrentUserDialog,defineCustomElement as defineCustomElementKritzelCurrentUserDialog}from"./kritzel-current-user-dialog.js";export{KritzelCursorTrail,defineCustomElement as defineCustomElementKritzelCursorTrail}from"./kritzel-cursor-trail.js";export{KritzelDialog,defineCustomElement as defineCustomElementKritzelDialog}from"./kritzel-dialog.js";export{KritzelDropdown,defineCustomElement as defineCustomElementKritzelDropdown}from"./kritzel-dropdown.js";export{KritzelEngine,defineCustomElement as defineCustomElementKritzelEngine}from"./kritzel-engine.js";export{KritzelExport,defineCustomElement as defineCustomElementKritzelExport}from"./kritzel-export.js";export{KritzelFont,defineCustomElement as defineCustomElementKritzelFont}from"./kritzel-font.js";export{KritzelFontFamily,defineCustomElement as defineCustomElementKritzelFontFamily}from"./kritzel-font-family.js";export{KritzelFontSize,defineCustomElement as defineCustomElementKritzelFontSize}from"./kritzel-font-size.js";export{KritzelIcon,defineCustomElement as defineCustomElementKritzelIcon}from"./kritzel-icon.js";export{KritzelInput,defineCustomElement as defineCustomElementKritzelInput}from"./kritzel-input.js";export{KritzelLineEndings,defineCustomElement as defineCustomElementKritzelLineEndings}from"./kritzel-line-endings.js";export{KritzelLoginDialog,defineCustomElement as defineCustomElementKritzelLoginDialog}from"./kritzel-login-dialog.js";export{KritzelMasterDetail,defineCustomElement as defineCustomElementKritzelMasterDetail}from"./kritzel-master-detail.js";export{KritzelMenu,defineCustomElement as defineCustomElementKritzelMenu}from"./kritzel-menu.js";export{KritzelMenuItem,defineCustomElement as defineCustomElementKritzelMenuItem}from"./kritzel-menu-item.js";export{KritzelMoreMenu,defineCustomElement as defineCustomElementKritzelMoreMenu}from"./kritzel-more-menu.js";export{KritzelNumericInput,defineCustomElement as defineCustomElementKritzelNumericInput}from"./kritzel-numeric-input.js";export{KritzelOpacitySlider,defineCustomElement as defineCustomElementKritzelOpacitySlider}from"./kritzel-opacity-slider.js";export{KritzelPillTabs,defineCustomElement as defineCustomElementKritzelPillTabs}from"./kritzel-pill-tabs.js";export{KritzelPortal,defineCustomElement as defineCustomElementKritzelPortal}from"./kritzel-portal.js";export{KritzelSettings,defineCustomElement as defineCustomElementKritzelSettings}from"./kritzel-settings.js";export{KritzelShapeFill,defineCustomElement as defineCustomElementKritzelShapeFill}from"./kritzel-shape-fill.js";export{KritzelShareDialog,defineCustomElement as defineCustomElementKritzelShareDialog}from"./kritzel-share-dialog.js";export{KritzelSlideToggle,defineCustomElement as defineCustomElementKritzelSlideToggle}from"./kritzel-slide-toggle.js";export{KritzelSplitButton,defineCustomElement as defineCustomElementKritzelSplitButton}from"./kritzel-split-button.js";export{KritzelStrokeSize,defineCustomElement as defineCustomElementKritzelStrokeSize}from"./kritzel-stroke-size.js";export{KritzelToolConfig,defineCustomElement as defineCustomElementKritzelToolConfig}from"./kritzel-tool-config.js";export{KritzelTooltip,defineCustomElement as defineCustomElementKritzelTooltip}from"./kritzel-tooltip.js";export{KritzelUtilityPanel,defineCustomElement as defineCustomElementKritzelUtilityPanel}from"./kritzel-utility-panel.js";export{KritzelWorkspaceManager,defineCustomElement as defineCustomElementKritzelWorkspaceManager}from"./kritzel-workspace-manager.js";const m=Math.floor,u=127,z=Number.MAX_SAFE_INTEGER;class p{constructor(){this.cpos=0,this.cbuf=new Uint8Array(100),this.bufs=[]}}const E=()=>new p,k=e=>{const t=new Uint8Array((e=>{let t=e.cpos;for(let s=0;s<e.bufs.length;s++)t+=e.bufs[s].length;return t})(e));let s=0;for(let i=0;i<e.bufs.length;i++){const n=e.bufs[i];t.set(n,s),s+=n.length}return t.set(new Uint8Array(e.cbuf.buffer,0,e.cpos),s),t},x=(e,t)=>{const s=e.cbuf.length;e.cpos===s&&(e.bufs.push(e.cbuf),e.cbuf=new Uint8Array(2*s),e.cpos=0),e.cbuf[e.cpos++]=t},y=(e,t)=>{for(;t>u;)x(e,128|u&t),t=m(t/128);x(e,u&t)},j=(e,t)=>{y(e,t.byteLength),((e,t)=>{const s=e.cbuf.length,i=e.cpos,n=((e,t)=>e<t?e:t)(s-i,t.length),o=t.length-n;e.cbuf.set(t.subarray(0,n),i),e.cpos+=n,o>0&&(e.bufs.push(e.cbuf),e.cbuf=new Uint8Array(((e,t)=>e>t?e:t)(2*s,o)),e.cbuf.set(t.subarray(n)),e.cpos=o)})(e,t)},T=e=>Error(e),w=T("Unexpected end of array"),v=T("Integer out of Range");class P{constructor(e){this.arr=e,this.pos=0}}const M=e=>((e,t)=>{const s=new Uint8Array(e.arr.buffer,e.pos+e.arr.byteOffset,t);return e.pos+=t,s})(e,U(e)),U=e=>{let t=0,s=1;const i=e.arr.length;for(;e.pos<i;){const i=e.arr[e.pos++];if(t+=(i&u)*s,s*=128,i<128)return t;if(t>z)throw v}throw w};class _{type="local";doc;channel;_synced=!1;constructor(e,t,s){this.doc=t,this.channel=new BroadcastChannel(e),this.channel.onmessage=e=>{this.handleMessage(e.data)},this.doc.on("update",this.handleDocUpdate),this.broadcastSync(),setTimeout((()=>{this._synced=!0}),100),s?.quiet||console.info("BroadcastChannel Provider initialized: "+e)}handleDocUpdate=(e,t)=>{if(t!==this){const t=E();y(t,0),j(t,e),this.channel.postMessage(k(t))}};handleMessage(e){const s=(e=>new P(e))(new Uint8Array(e));switch(U(s)){case 0:const e=M(s);t.applyUpdate(this.doc,e,this);break;case 1:this.broadcastSync();break;case 2:const i=M(s),n=t.encodeStateAsUpdate(this.doc,i);if(n.length>0){const e=E();y(e,0),j(e,n),this.channel.postMessage(k(e))}}}broadcastSync(){const e=E();y(e,2),j(e,t.encodeStateVector(this.doc)),this.channel.postMessage(k(e))}async connect(){if(!this._synced)return new Promise((e=>{const t=()=>{this._synced?e():setTimeout(t,50)};t()}))}disconnect(){}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.doc.off("update",this.handleDocUpdate),this.channel.close()}}class O{type="network";provider;isConnected=!1;_quiet=!1;get awareness(){return this.provider.awareness}constructor(e,t,s){const n=s?.url||"ws://localhost:1234",o=s?.roomName||e;this.provider=new i(n,o,t,{params:s?.params,protocols:s?.protocols,WebSocketPolyfill:s?.WebSocketPolyfill,awareness:s?.awareness,maxBackoffTime:s?.maxBackoffTime,disableBc:!0}),this._quiet=s?.quiet??!1,this.setupEventListeners(),this._quiet||console.info(`WebSocket Provider initialized: ${n}/${o}`)}static with(e){return{create:(t,s,i)=>{const n=i?{...e,...i}:e;return new O(t,s,n)}}}setupEventListeners(){this.provider.on("status",(({status:e})=>{"connected"===e?(this.isConnected=!0,this._quiet||console.info("WebSocket connected")):"disconnected"===e&&(this.isConnected=!1,this._quiet||console.info("WebSocket disconnected"))})),this.provider.on("sync",(e=>{e&&!this._quiet&&console.info("WebSocket synced")}))}async connect(){if(!this.isConnected)return new Promise(((e,t)=>{const s=setTimeout((()=>{t(Error("WebSocket connection timeout"))}),1e4),i=({status:t})=>{"connected"===t&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,e())};this.provider.on("status",i),this.provider.wsconnected&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,e())}))}disconnect(){this.provider&&this.provider.disconnect(),this.isConnected=!1}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.provider&&this.provider.destroy(),this.isConnected=!1}}class B{type="network";provider;isConnected=!1;isSynced=!1;usesSharedSocket=!1;isDestroyed=!1;connectTimeout=null;pendingConnectReject=null;connectionTimeoutMs;_connectionStatus="disconnected";visibilityHandler=null;onlineHandler=null;get awareness(){return this.provider.awareness}get connectionStatus(){return this._connectionStatus}static sharedWebSocketProvider=null;constructor(e,t,s){const i=s?.name||e,o=s?.url||"ws://localhost:1234";this.connectionTimeoutMs=s?.connectionTimeout??1e4;const r=s?.websocketProvider||B.sharedWebSocketProvider,l={};void 0!==s?.delay&&(l.delay=s.delay),void 0!==s?.factor&&(l.factor=s.factor),void 0!==s?.maxAttempts&&(l.maxAttempts=s.maxAttempts),void 0!==s?.minDelay&&(l.minDelay=s.minDelay),void 0!==s?.maxDelay&&(l.maxDelay=s.maxDelay);const m=()=>{this.isDestroyed||(this.isConnected=!0,this._connectionStatus="connected",s?.quiet||console.info("Hocuspocus connected: "+i),s?.onConnect&&s.onConnect())},a=()=>{this.isDestroyed||(this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected",s?.quiet||console.info("Hocuspocus disconnected: "+i),s?.onDisconnect&&s.onDisconnect())},c=()=>{this.isDestroyed||(this.isSynced=!0,this._connectionStatus="synced",s?.quiet||console.info("Hocuspocus synced: "+i),s?.onSynced&&s.onSynced())},u=e=>{this.isDestroyed||("connecting"===e.status&&(this._connectionStatus="connecting"),s?.onStatus&&s.onStatus(e))};if(r){this.usesSharedSocket=!0;const e={websocketProvider:r,name:i,document:t,token:s?.token||null,onStatus:u,onConnect:m,onDisconnect:a,onSynced:c,...l};void 0!==s?.forceSyncInterval&&(e.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(e.onAuthenticationFailed=s.onAuthenticationFailed),this.provider=new n(e),this.provider.attach(),s?.quiet||console.info("Hocuspocus Provider initialized (multiplexed): "+i)}else{this.usesSharedSocket=!1;const e={url:o,name:i,document:t,token:s?.token||null,autoConnect:!1,onStatus:u,onConnect:m,onDisconnect:a,onSynced:c,...l};void 0!==s?.forceSyncInterval&&(e.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(e.onAuthenticationFailed=s.onAuthenticationFailed),s?.WebSocketPolyfill&&(e.WebSocketPolyfill=s.WebSocketPolyfill),this.provider=new n(e),s?.quiet||console.info(`Hocuspocus Provider initialized: ${o}/${i}`)}this.setupBrowserEventListeners()}setupBrowserEventListeners(){"undefined"!=typeof document&&(this.visibilityHandler=()=>{"visible"!==document.visibilityState||this.isConnected||this.isDestroyed||this.provider.connect()},document.addEventListener("visibilitychange",this.visibilityHandler)),"undefined"!=typeof window&&(this.onlineHandler=()=>{this.isConnected||this.isDestroyed||this.provider.connect()},window.addEventListener("online",this.onlineHandler))}removeBrowserEventListeners(){this.visibilityHandler&&"undefined"!=typeof document&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.onlineHandler&&"undefined"!=typeof window&&(window.removeEventListener("online",this.onlineHandler),this.onlineHandler=null)}static createSharedWebSocket(e){if(B.sharedWebSocketProvider)return console.warn("Shared WebSocket already exists. Returning existing instance."),B.sharedWebSocketProvider;const t={url:e.url};return e.WebSocketPolyfill&&(t.WebSocketPolyfill=e.WebSocketPolyfill),e.onConnect&&(t.onConnect=e.onConnect),e.onDisconnect&&(t.onDisconnect=e.onDisconnect),e.onStatus&&(t.onStatus=e.onStatus),B.sharedWebSocketProvider=new o(t),console.info("Shared Hocuspocus WebSocket created: "+e.url),B.sharedWebSocketProvider}static destroySharedWebSocket(){B.sharedWebSocketProvider&&(B.sharedWebSocketProvider.destroy(),B.sharedWebSocketProvider=null,console.info("Shared Hocuspocus WebSocket destroyed"))}static getSharedWebSocket(){return B.sharedWebSocketProvider}static with(e){return{create:(t,s,i)=>{const n=i?{...e,...i}:e;return new B(t,s,n)}}}async connect(){if(!this.isSynced&&!this.isDestroyed)return this._connectionStatus="connecting",new Promise(((e,t)=>{this.pendingConnectReject=t,this.connectTimeout=setTimeout((()=>{this.pendingConnectReject=null,this.connectTimeout=null,t(Error("Hocuspocus connection timeout"))}),this.connectionTimeoutMs);const s=()=>{this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),this.isDestroyed||e()};if(this.provider.on("synced",s),this.provider.isSynced)return this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),void e();this.isConnected||this.usesSharedSocket||this.provider.connect()}))}async reconnect(){return this.disconnect(),this.connect()}disconnect(){this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.provider&&(this.usesSharedSocket?this.provider.detach():this.provider.disconnect()),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}destroy(){this.isDestroyed=!0,this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.removeBrowserEventListeners(),this.provider&&this.provider.destroy(),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}}export{_ as BroadcastSyncProvider,B as HocuspocusSyncProvider,O as WebSocketSyncProvider}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{K as o,d as
|
|
1
|
+
import{K as o,d as s}from"./p-xNwOWoiT.js";const p=o,r=s;export{p as KritzelAwarenessCursors,r as defineCustomElement}
|