kritzel-stencil 0.1.72 → 0.1.74
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/index-Dc7LOVhs.js +2 -2
- package/dist/cjs/index.cjs.js +58 -18
- package/dist/cjs/{kritzel-active-users_41.cjs.entry.js → kritzel-active-users_42.cjs.entry.js} +586 -172
- package/dist/cjs/kritzel-brush-style.cjs.entry.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/stencil.cjs.js +1 -1
- package/dist/cjs/{workspace.migrations-DcwqsqPC.js → workspace.migrations-Dyt35LBC.js} +58 -5
- package/dist/collection/classes/core/core.class.js +9 -3
- package/dist/collection/classes/core/store.class.js +20 -6
- package/dist/collection/classes/handlers/selection.handler.js +15 -2
- package/dist/collection/classes/objects/base-object.class.js +2 -0
- package/dist/collection/classes/objects/custom-element.class.js +1 -0
- package/dist/collection/classes/objects/group.class.js +1 -0
- package/dist/collection/classes/objects/image.class.js +1 -0
- package/dist/collection/classes/objects/line.class.js +1 -0
- package/dist/collection/classes/objects/path.class.js +1 -0
- package/dist/collection/classes/objects/selection-box.class.js +1 -0
- package/dist/collection/classes/objects/selection-group.class.js +13 -1
- package/dist/collection/classes/objects/shape.class.js +1 -0
- package/dist/collection/classes/objects/text.class.js +1 -0
- package/dist/collection/classes/providers/hocuspocus-sync-provider.class.js +57 -17
- package/dist/collection/classes/structures/object-map.structure.js +102 -7
- package/dist/collection/classes/tools/brush-tool.class.js +4 -0
- package/dist/collection/classes/tools/line-tool.class.js +4 -0
- package/dist/collection/classes/tools/shape-tool.class.js +2 -0
- package/dist/collection/collection-manifest.json +3 -2
- package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.css +110 -0
- package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.js +347 -0
- package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.js +1 -1
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +3 -3
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +150 -109
- package/dist/collection/components/shared/kritzel-avatar/kritzel-avatar.js +3 -3
- package/dist/collection/components/shared/kritzel-brush-style/kritzel-brush-style.js +1 -1
- package/dist/collection/components/shared/kritzel-button/kritzel-button.js +2 -2
- package/dist/collection/components/shared/kritzel-color/kritzel-color.js +2 -2
- package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js +1 -1
- package/dist/collection/components/shared/kritzel-dropdown/kritzel-dropdown.js +1 -1
- package/dist/collection/components/shared/kritzel-font/kritzel-font.js +1 -1
- package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js +1 -1
- package/dist/collection/components/shared/kritzel-input/kritzel-input.js +1 -1
- package/dist/collection/components/shared/kritzel-master-detail/kritzel-master-detail.js +3 -3
- package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +1 -1
- package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js +2 -2
- package/dist/collection/components/shared/kritzel-numeric-input/kritzel-numeric-input.js +1 -1
- package/dist/collection/components/shared/kritzel-opacity-slider/kritzel-opacity-slider.js +1 -1
- package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js +1 -1
- package/dist/collection/components/shared/kritzel-slide-toggle/kritzel-slide-toggle.js +1 -1
- package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js +1 -1
- package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js +1 -1
- package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js +2 -2
- package/dist/collection/components/ui/kritzel-back-to-content/kritzel-back-to-content.js +1 -1
- package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js +1 -1
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +5 -5
- package/dist/collection/components/ui/kritzel-current-user/kritzel-current-user.js +1 -1
- package/dist/collection/components/ui/kritzel-current-user-dialog/kritzel-current-user-dialog.js +1 -1
- package/dist/collection/components/ui/kritzel-export/kritzel-export.js +1 -1
- package/dist/collection/components/ui/kritzel-login-dialog/kritzel-login-dialog.js +1 -1
- package/dist/collection/components/ui/kritzel-more-menu/kritzel-more-menu.js +1 -1
- package/dist/collection/components/ui/kritzel-settings/kritzel-settings.js +1 -1
- package/dist/collection/components/ui/kritzel-share-dialog/kritzel-share-dialog.js +2 -2
- package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +1 -1
- package/dist/collection/constants/schema.constants.js +1 -1
- package/dist/collection/constants/version.js +1 -1
- package/dist/collection/interfaces/remote-cursor.interface.js +1 -0
- package/dist/collection/migrations/workspace.migrations.js +10 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +1 -1
- package/dist/components/kritzel-active-users.js +1 -1
- package/dist/components/kritzel-avatar.js +1 -1
- package/dist/components/kritzel-awareness-cursors.d.ts +11 -0
- package/dist/components/kritzel-awareness-cursors.js +1 -0
- package/dist/components/kritzel-back-to-content.js +1 -1
- package/dist/components/kritzel-brush-style.js +1 -1
- package/dist/components/kritzel-button.js +1 -1
- package/dist/components/kritzel-color-palette.js +1 -1
- package/dist/components/kritzel-color.js +1 -1
- package/dist/components/kritzel-context-menu.js +1 -1
- package/dist/components/kritzel-controls.js +1 -1
- package/dist/components/kritzel-current-user-dialog.js +1 -1
- package/dist/components/kritzel-current-user.js +1 -1
- package/dist/components/kritzel-cursor-trail.js +1 -1
- package/dist/components/kritzel-dropdown.js +1 -1
- package/dist/components/kritzel-editor.js +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-export.js +1 -1
- package/dist/components/kritzel-font-family.js +1 -1
- package/dist/components/kritzel-font-size.js +1 -1
- package/dist/components/kritzel-font.js +1 -1
- package/dist/components/kritzel-input.js +1 -1
- package/dist/components/kritzel-login-dialog.js +1 -1
- package/dist/components/kritzel-master-detail.js +1 -1
- package/dist/components/kritzel-menu-item.js +1 -1
- package/dist/components/kritzel-menu.js +1 -1
- package/dist/components/kritzel-more-menu.js +1 -1
- package/dist/components/kritzel-numeric-input.js +1 -1
- package/dist/components/kritzel-opacity-slider.js +1 -1
- package/dist/components/kritzel-portal.js +1 -1
- package/dist/components/kritzel-settings.js +1 -1
- package/dist/components/kritzel-share-dialog.js +1 -1
- package/dist/components/kritzel-slide-toggle.js +1 -1
- package/dist/components/kritzel-split-button.js +1 -1
- package/dist/components/kritzel-stroke-size.js +1 -1
- package/dist/components/kritzel-tool-config.js +1 -1
- package/dist/components/kritzel-tooltip.js +1 -1
- package/dist/components/kritzel-utility-panel.js +1 -1
- package/dist/components/kritzel-workspace-manager.js +1 -1
- package/dist/components/{p-Dp8idtVD.js → p-0kShCfeb.js} +1 -1
- package/dist/components/{p-B47JuZiD.js → p-2OYw6GJ7.js} +1 -1
- package/dist/components/p-7o2FWtFx.js +1 -0
- package/dist/components/{p-dR_q96Q3.js → p-B4Oqnl55.js} +1 -1
- package/dist/components/{p-C5KuV1pK.js → p-BA0ayKqO.js} +1 -1
- package/dist/components/{p-NbNVTRk6.js → p-BEJQ2kP7.js} +1 -1
- package/dist/components/p-BSipRoFx.js +1 -0
- package/dist/components/{p-CDadAOMw.js → p-BeFUNGEI.js} +1 -1
- package/dist/components/{p-35nrk8s0.js → p-BiByyU2C.js} +1 -1
- package/dist/components/{p-CCAWSyDD.js → p-BiouZo1q.js} +1 -1
- package/dist/components/{p-CSExtYKI.js → p-ByR0VXeU.js} +1 -1
- package/dist/components/{p-1MGcXTLv.js → p-C1uR_ZNW.js} +1 -1
- package/dist/components/{p-x8PzaMuD.js → p-C69Stayh.js} +1 -1
- package/dist/components/{p-Ch0UlFwq.js → p-C7SBI_0T.js} +1 -1
- package/dist/components/{p-DEzfXrGX.js → p-CAIGuV2J.js} +1 -1
- package/dist/components/p-CJ2eHeoV.js +1 -0
- package/dist/components/p-CW-VyJgK.js +1 -0
- package/dist/components/{p-DW4ADV9w.js → p-CZhyKp-f.js} +1 -1
- package/dist/components/p-CsR4owzk.js +1 -0
- package/dist/components/{p-BG1IxseV.js → p-CsoDfhD5.js} +1 -1
- package/dist/components/{p-DpFu5yAt.js → p-D1O7DxL4.js} +1 -1
- package/dist/components/{p-B5ouV8EQ.js → p-DRbG92F9.js} +1 -1
- package/dist/components/{p-C3eaM9TB.js → p-DS0xx1eT.js} +1 -1
- package/dist/components/{p-jx8VOz7S.js → p-DSzQ6H2j.js} +1 -1
- package/dist/components/{p-DsIlDGDO.js → p-DXjuuVq9.js} +1 -1
- package/dist/components/p-DXpYcAnT.js +1 -0
- package/dist/components/{p-DiFVw6IQ.js → p-Da46jw3N.js} +1 -1
- package/dist/components/{p-C6kZf91d.js → p-Dj_Qjga5.js} +1 -1
- package/dist/components/{p-Do0Q5-iC.js → p-DvIEvoZu.js} +1 -1
- package/dist/components/{p-CnVzLD5e.js → p-GYI7sDxr.js} +1 -1
- package/dist/components/{p-CcBM_ClD.js → p-HLbqRJGs.js} +1 -1
- package/dist/components/{p-VHyNcODZ.js → p-KQzWumjB.js} +1 -1
- package/dist/components/p-RJWe82kG.js +9 -0
- package/dist/components/{p-VAkeZOZL.js → p-TyR-YTXm.js} +1 -1
- package/dist/components/{p-CHtn5xr6.js → p-b4gyXoju.js} +1 -1
- package/dist/components/p-iRL0wQHQ.js +1 -0
- package/dist/components/{p-CqLaHE27.js → p-kj9wbLY8.js} +1 -1
- package/dist/components/{p-DaHq4iG1.js → p-xM-_OeRO.js} +1 -1
- package/dist/esm/index-MV-81ybv.js +2 -2
- package/dist/esm/index.js +59 -19
- package/dist/esm/{kritzel-active-users_41.entry.js → kritzel-active-users_42.entry.js} +586 -173
- package/dist/esm/kritzel-brush-style.entry.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/stencil.js +1 -1
- package/dist/esm/{workspace.migrations-BGixvB76.js → workspace.migrations-B99F1MdT.js} +58 -5
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/p-2a60e1bc.entry.js +9 -0
- package/dist/stencil/p-B99F1MdT.js +1 -0
- package/dist/stencil/{p-016ad76a.entry.js → p-fc21e29c.entry.js} +1 -1
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/core/store.class.d.ts +10 -2
- package/dist/types/classes/objects/base-object.class.d.ts +1 -0
- package/dist/types/classes/objects/selection-group.class.d.ts +5 -0
- package/dist/types/classes/providers/hocuspocus-sync-provider.class.d.ts +3 -0
- package/dist/types/classes/structures/object-map.structure.d.ts +41 -0
- package/dist/types/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.d.ts +26 -0
- package/dist/types/components.d.ts +39 -4
- package/dist/types/constants/schema.constants.d.ts +1 -1
- package/dist/types/constants/version.d.ts +1 -1
- package/dist/types/interfaces/object.interface.d.ts +1 -0
- package/dist/types/interfaces/remote-cursor.interface.d.ts +17 -0
- package/dist/types/interfaces/theme.interface.d.ts +7 -0
- package/package.json +1 -1
- package/dist/components/p-B2vjbWy-.js +0 -9
- package/dist/components/p-BvToKcu1.js +0 -1
- package/dist/components/p-CNro30tB.js +0 -1
- package/dist/components/p-Duv3EM3w.js +0 -1
- package/dist/components/p-KFsLHwYm.js +0 -1
- package/dist/components/p-hCORwbZh.js +0 -1
- package/dist/stencil/p-BGixvB76.js +0 -1
- package/dist/stencil/p-a0f5c4ad.entry.js +0 -9
|
@@ -28,6 +28,7 @@ export class KritzelBaseObject {
|
|
|
28
28
|
rotation = 0;
|
|
29
29
|
markedForRemoval = false;
|
|
30
30
|
zIndex = 0;
|
|
31
|
+
userId;
|
|
31
32
|
/** Whether the object is currently visible on the canvas */
|
|
32
33
|
isVisible = true;
|
|
33
34
|
isSelected = false;
|
|
@@ -208,6 +209,7 @@ export class KritzelBaseObject {
|
|
|
208
209
|
object._core = core;
|
|
209
210
|
object.zIndex = core.store.currentZIndex;
|
|
210
211
|
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
212
|
+
object.userId = core.user?.id;
|
|
211
213
|
return object;
|
|
212
214
|
}
|
|
213
215
|
/**
|
|
@@ -70,6 +70,7 @@ export class KritzelGroup extends KritzelBaseObject {
|
|
|
70
70
|
group._core = core;
|
|
71
71
|
group.id = group.generateId();
|
|
72
72
|
group.workspaceId = core.store.state.activeWorkspace.id;
|
|
73
|
+
group.userId = core.user?.id;
|
|
73
74
|
group.scale = core.store.state.scale;
|
|
74
75
|
group.zIndex = core.store.currentZIndex;
|
|
75
76
|
return group;
|
|
@@ -40,6 +40,7 @@ export class KritzelImage extends KritzelBaseObject {
|
|
|
40
40
|
object._core = core;
|
|
41
41
|
object.id = object.generateId();
|
|
42
42
|
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
43
|
+
object.userId = core.user?.id;
|
|
43
44
|
object.x = 0;
|
|
44
45
|
object.y = 0;
|
|
45
46
|
object.translateX = 0;
|
|
@@ -80,6 +80,7 @@ export class KritzelLine extends KritzelBaseObject {
|
|
|
80
80
|
object._core = core;
|
|
81
81
|
object.id = object.generateId();
|
|
82
82
|
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
83
|
+
object.userId = core.user?.id;
|
|
83
84
|
object.options = options;
|
|
84
85
|
object.startX = options?.startX ?? 0;
|
|
85
86
|
object.startY = options?.startY ?? 0;
|
|
@@ -62,6 +62,7 @@ export class KritzelPath extends KritzelBaseObject {
|
|
|
62
62
|
object._core = core;
|
|
63
63
|
object.id = object.generateId();
|
|
64
64
|
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
65
|
+
object.userId = core.user?.id;
|
|
65
66
|
object.options = options;
|
|
66
67
|
object.points = options?.points ?? [];
|
|
67
68
|
object.translateX = options?.translateX ?? 0;
|
|
@@ -19,6 +19,7 @@ export class KritzelSelectionBox extends KritzelBaseObject {
|
|
|
19
19
|
object._core = core;
|
|
20
20
|
object.id = object.generateId();
|
|
21
21
|
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
22
|
+
object.userId = core.user?.id;
|
|
22
23
|
object.scale = core.store.state.scale;
|
|
23
24
|
object.zIndex = 99999;
|
|
24
25
|
object.backgroundColor = { light: 'rgba(0, 122, 255, 0.2)', dark: 'rgba(0, 122, 255, 0.2)' };
|
|
@@ -24,6 +24,10 @@ export class KritzelSelectionGroup extends KritzelBaseObject {
|
|
|
24
24
|
maxX;
|
|
25
25
|
minY;
|
|
26
26
|
maxY;
|
|
27
|
+
// Selection styling properties
|
|
28
|
+
handleColor;
|
|
29
|
+
handleStrokeColor;
|
|
30
|
+
handleSize = 6;
|
|
27
31
|
/**
|
|
28
32
|
* Gets the array of object IDs contained in this selection group.
|
|
29
33
|
* @returns Array of string IDs for the selected objects
|
|
@@ -78,6 +82,7 @@ export class KritzelSelectionGroup extends KritzelBaseObject {
|
|
|
78
82
|
/**
|
|
79
83
|
* Factory method to create a new KritzelSelectionGroup instance.
|
|
80
84
|
* Initializes the selection group with default properties and associates it with the core instance.
|
|
85
|
+
* Default styling uses values from the theme system (selection section).
|
|
81
86
|
* @param core - The KritzelCore instance to associate with this selection group
|
|
82
87
|
* @returns A new KritzelSelectionGroup instance configured with default settings
|
|
83
88
|
*/
|
|
@@ -86,8 +91,15 @@ export class KritzelSelectionGroup extends KritzelBaseObject {
|
|
|
86
91
|
object._core = core;
|
|
87
92
|
object.id = object.generateId();
|
|
88
93
|
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
94
|
+
object.userId = core.user?.id;
|
|
89
95
|
object.scale = core.store.state.scale;
|
|
90
96
|
object.zIndex = 99999;
|
|
97
|
+
// Initialize styling with theme-aware defaults
|
|
98
|
+
object.borderColor = { light: '#007AFF', dark: '#0A84FF' };
|
|
99
|
+
object.borderWidth = 2;
|
|
100
|
+
object.handleColor = { light: '#ffffff', dark: '#1a1a1a' };
|
|
101
|
+
object.handleStrokeColor = { light: '#007AFF', dark: '#0A84FF' };
|
|
102
|
+
object.handleSize = 6;
|
|
91
103
|
return object;
|
|
92
104
|
}
|
|
93
105
|
/**
|
|
@@ -253,7 +265,7 @@ export class KritzelSelectionGroup extends KritzelBaseObject {
|
|
|
253
265
|
* @returns A serializable object representation of the selection group
|
|
254
266
|
*/
|
|
255
267
|
serialize() {
|
|
256
|
-
const { _core, _elementRef, element, totalWidth, totalHeight, unchangedObjectSnapshots, _cachedObjects, _cachedObjectIdsHash, snapshotWidth, snapshotHeight, snapshotTranslateX, snapshotTranslateY, ...remainingProps } = this;
|
|
268
|
+
const { _core, _elementRef, element, totalWidth, totalHeight, unchangedObjectSnapshots, _cachedObjects, _cachedObjectIdsHash, snapshotWidth, snapshotHeight, snapshotTranslateX, snapshotTranslateY, snapshotRotation, ...remainingProps } = this;
|
|
257
269
|
const clonedProps = structuredClone(remainingProps);
|
|
258
270
|
// Ensure objectIds is serialized with the correct key name (getter returns _objectIds)
|
|
259
271
|
clonedProps.objectIds = this.objectIds;
|
|
@@ -100,6 +100,7 @@ export class KritzelShape extends KritzelBaseObject {
|
|
|
100
100
|
object._core = core;
|
|
101
101
|
object.id = object.generateId();
|
|
102
102
|
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
103
|
+
object.userId = core.user?.id;
|
|
103
104
|
object.x = config?.x ?? 0;
|
|
104
105
|
object.y = config?.y ?? 0;
|
|
105
106
|
object.translateX = config?.translateX ?? 0;
|
|
@@ -116,6 +116,7 @@ export class KritzelText extends KritzelBaseObject {
|
|
|
116
116
|
object._core = core;
|
|
117
117
|
object.id = object.generateId();
|
|
118
118
|
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
119
|
+
object.userId = core.user?.id;
|
|
119
120
|
object.fontSize = fontSize;
|
|
120
121
|
object.fontFamily = fontFamily;
|
|
121
122
|
object.translateX = 0;
|
|
@@ -8,6 +8,9 @@ export class HocuspocusSyncProvider {
|
|
|
8
8
|
isConnected = false;
|
|
9
9
|
isSynced = false;
|
|
10
10
|
usesSharedSocket = false;
|
|
11
|
+
isDestroyed = false;
|
|
12
|
+
connectTimeout = null;
|
|
13
|
+
pendingConnectReject = null;
|
|
11
14
|
get awareness() {
|
|
12
15
|
return this.provider.awareness;
|
|
13
16
|
}
|
|
@@ -26,8 +29,13 @@ export class HocuspocusSyncProvider {
|
|
|
26
29
|
name,
|
|
27
30
|
document: doc,
|
|
28
31
|
token: options?.token || null,
|
|
32
|
+
onStatus: (data) => {
|
|
33
|
+
if (options?.onStatus) {
|
|
34
|
+
options.onStatus(data);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
29
37
|
onConnect: () => {
|
|
30
|
-
if (this.isConnected) {
|
|
38
|
+
if (this.isConnected || this.isDestroyed) {
|
|
31
39
|
return;
|
|
32
40
|
}
|
|
33
41
|
this.isConnected = true;
|
|
@@ -39,7 +47,7 @@ export class HocuspocusSyncProvider {
|
|
|
39
47
|
}
|
|
40
48
|
},
|
|
41
49
|
onDisconnect: () => {
|
|
42
|
-
if (!this.isConnected && !this.isSynced) {
|
|
50
|
+
if (this.isDestroyed || (!this.isConnected && !this.isSynced)) {
|
|
43
51
|
return;
|
|
44
52
|
}
|
|
45
53
|
this.isConnected = false;
|
|
@@ -52,7 +60,7 @@ export class HocuspocusSyncProvider {
|
|
|
52
60
|
}
|
|
53
61
|
},
|
|
54
62
|
onSynced: () => {
|
|
55
|
-
if (this.isSynced) {
|
|
63
|
+
if (this.isSynced || this.isDestroyed) {
|
|
56
64
|
return;
|
|
57
65
|
}
|
|
58
66
|
this.isSynced = true;
|
|
@@ -71,9 +79,6 @@ export class HocuspocusSyncProvider {
|
|
|
71
79
|
if (options?.onAuthenticationFailed) {
|
|
72
80
|
config.onAuthenticationFailed = options.onAuthenticationFailed;
|
|
73
81
|
}
|
|
74
|
-
if (options?.onStatus) {
|
|
75
|
-
config.onStatus = options.onStatus;
|
|
76
|
-
}
|
|
77
82
|
this.provider = new HocuspocusProvider(config);
|
|
78
83
|
// Must call attach() explicitly when using shared socket
|
|
79
84
|
this.provider.attach();
|
|
@@ -89,8 +94,14 @@ export class HocuspocusSyncProvider {
|
|
|
89
94
|
name,
|
|
90
95
|
document: doc,
|
|
91
96
|
token: options?.token || null,
|
|
97
|
+
autoConnect: false,
|
|
98
|
+
onStatus: (data) => {
|
|
99
|
+
if (options?.onStatus) {
|
|
100
|
+
options.onStatus(data);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
92
103
|
onConnect: () => {
|
|
93
|
-
if (this.isConnected) {
|
|
104
|
+
if (this.isConnected || this.isDestroyed) {
|
|
94
105
|
return;
|
|
95
106
|
}
|
|
96
107
|
this.isConnected = true;
|
|
@@ -102,7 +113,7 @@ export class HocuspocusSyncProvider {
|
|
|
102
113
|
}
|
|
103
114
|
},
|
|
104
115
|
onDisconnect: () => {
|
|
105
|
-
if (!this.isConnected && !this.isSynced) {
|
|
116
|
+
if (this.isDestroyed || (!this.isConnected && !this.isSynced)) {
|
|
106
117
|
return;
|
|
107
118
|
}
|
|
108
119
|
this.isConnected = false;
|
|
@@ -115,7 +126,7 @@ export class HocuspocusSyncProvider {
|
|
|
115
126
|
}
|
|
116
127
|
},
|
|
117
128
|
onSynced: () => {
|
|
118
|
-
if (this.isSynced) {
|
|
129
|
+
if (this.isSynced || this.isDestroyed) {
|
|
119
130
|
return;
|
|
120
131
|
}
|
|
121
132
|
this.isSynced = true;
|
|
@@ -134,9 +145,6 @@ export class HocuspocusSyncProvider {
|
|
|
134
145
|
if (options?.onAuthenticationFailed) {
|
|
135
146
|
config.onAuthenticationFailed = options.onAuthenticationFailed;
|
|
136
147
|
}
|
|
137
|
-
if (options?.onStatus) {
|
|
138
|
-
config.onStatus = options.onStatus;
|
|
139
|
-
}
|
|
140
148
|
if (options?.WebSocketPolyfill) {
|
|
141
149
|
config.WebSocketPolyfill = options.WebSocketPolyfill;
|
|
142
150
|
}
|
|
@@ -204,22 +212,36 @@ export class HocuspocusSyncProvider {
|
|
|
204
212
|
};
|
|
205
213
|
}
|
|
206
214
|
async connect() {
|
|
207
|
-
if (this.isSynced) {
|
|
215
|
+
if (this.isSynced || this.isDestroyed) {
|
|
208
216
|
return;
|
|
209
217
|
}
|
|
210
218
|
return new Promise((resolve, reject) => {
|
|
211
|
-
|
|
219
|
+
// Store reject function so we can cancel the connection if destroyed
|
|
220
|
+
this.pendingConnectReject = reject;
|
|
221
|
+
this.connectTimeout = setTimeout(() => {
|
|
222
|
+
this.pendingConnectReject = null;
|
|
223
|
+
this.connectTimeout = null;
|
|
212
224
|
reject(new Error('Hocuspocus connection timeout'));
|
|
213
225
|
}, 10000); // 10 second timeout
|
|
214
226
|
const syncHandler = () => {
|
|
215
|
-
|
|
227
|
+
if (this.connectTimeout) {
|
|
228
|
+
clearTimeout(this.connectTimeout);
|
|
229
|
+
this.connectTimeout = null;
|
|
230
|
+
}
|
|
231
|
+
this.pendingConnectReject = null;
|
|
216
232
|
this.provider.off('synced', syncHandler);
|
|
217
|
-
|
|
233
|
+
if (!this.isDestroyed) {
|
|
234
|
+
resolve();
|
|
235
|
+
}
|
|
218
236
|
};
|
|
219
237
|
this.provider.on('synced', syncHandler);
|
|
220
238
|
// If already synced, resolve immediately
|
|
221
239
|
if (this.provider.isSynced) {
|
|
222
|
-
|
|
240
|
+
if (this.connectTimeout) {
|
|
241
|
+
clearTimeout(this.connectTimeout);
|
|
242
|
+
this.connectTimeout = null;
|
|
243
|
+
}
|
|
244
|
+
this.pendingConnectReject = null;
|
|
223
245
|
this.provider.off('synced', syncHandler);
|
|
224
246
|
resolve();
|
|
225
247
|
return;
|
|
@@ -231,6 +253,14 @@ export class HocuspocusSyncProvider {
|
|
|
231
253
|
});
|
|
232
254
|
}
|
|
233
255
|
disconnect() {
|
|
256
|
+
// Cancel any pending connection attempt
|
|
257
|
+
if (this.connectTimeout) {
|
|
258
|
+
clearTimeout(this.connectTimeout);
|
|
259
|
+
this.connectTimeout = null;
|
|
260
|
+
}
|
|
261
|
+
if (this.pendingConnectReject) {
|
|
262
|
+
this.pendingConnectReject = null; // Don't reject, just abandon the promise
|
|
263
|
+
}
|
|
234
264
|
if (this.provider) {
|
|
235
265
|
if (this.usesSharedSocket) {
|
|
236
266
|
// Detach from shared socket instead of disconnecting
|
|
@@ -244,6 +274,16 @@ export class HocuspocusSyncProvider {
|
|
|
244
274
|
this.isSynced = false;
|
|
245
275
|
}
|
|
246
276
|
destroy() {
|
|
277
|
+
// Mark as destroyed first to prevent any callbacks from doing work
|
|
278
|
+
this.isDestroyed = true;
|
|
279
|
+
// Cancel any pending connection attempt
|
|
280
|
+
if (this.connectTimeout) {
|
|
281
|
+
clearTimeout(this.connectTimeout);
|
|
282
|
+
this.connectTimeout = null;
|
|
283
|
+
}
|
|
284
|
+
if (this.pendingConnectReject) {
|
|
285
|
+
this.pendingConnectReject = null; // Don't reject, just abandon the promise
|
|
286
|
+
}
|
|
247
287
|
if (this.provider) {
|
|
248
288
|
this.provider.destroy();
|
|
249
289
|
}
|
|
@@ -34,6 +34,10 @@ export class KritzelObjectMap {
|
|
|
34
34
|
_stackItemPoppedHandler = null;
|
|
35
35
|
_awarenessChangeHandler = null;
|
|
36
36
|
_awarenessChangeCallbacks = [];
|
|
37
|
+
_objectsChangeCallbacks = [];
|
|
38
|
+
_lastAwarenessEmitTime = 0;
|
|
39
|
+
_awarenessEmitTimeout = null;
|
|
40
|
+
AWARENESS_THROTTLE_INTERVAL = 100; // milliseconds
|
|
37
41
|
/**
|
|
38
42
|
* Indicates whether the object map has been initialized and is ready for use.
|
|
39
43
|
* @returns `true` if providers are connected and the map is operational
|
|
@@ -47,6 +51,19 @@ export class KritzelObjectMap {
|
|
|
47
51
|
get awareness() {
|
|
48
52
|
return this._awareness;
|
|
49
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Whether a network awareness instance is available.
|
|
56
|
+
*/
|
|
57
|
+
get hasAwareness() {
|
|
58
|
+
return !!this._awareness;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns the local client ID from the awareness instance.
|
|
62
|
+
* Used to filter out the local user when rendering remote cursors.
|
|
63
|
+
*/
|
|
64
|
+
get localClientId() {
|
|
65
|
+
return this._awareness?.clientID ?? null;
|
|
66
|
+
}
|
|
50
67
|
/**
|
|
51
68
|
* Sets the local user identity in the awareness state.
|
|
52
69
|
* This broadcasts the user's identity to all connected peers.
|
|
@@ -55,12 +72,21 @@ export class KritzelObjectMap {
|
|
|
55
72
|
if (!this._awareness || !user) {
|
|
56
73
|
return;
|
|
57
74
|
}
|
|
75
|
+
const displayName = user.displayName || user.firstName || 'Anonymous';
|
|
58
76
|
this._awareness.setLocalStateField('user', {
|
|
59
77
|
id: user.id,
|
|
60
|
-
|
|
61
|
-
color: user.color,
|
|
78
|
+
displayName,
|
|
79
|
+
color: user.color || this.generateColorFromName(displayName),
|
|
62
80
|
});
|
|
63
81
|
}
|
|
82
|
+
generateColorFromName(name) {
|
|
83
|
+
let hash = 0;
|
|
84
|
+
for (let i = 0; i < name.length; i++) {
|
|
85
|
+
hash = name.charCodeAt(i) + ((hash << 5) - hash);
|
|
86
|
+
}
|
|
87
|
+
const hue = Math.abs(hash % 360);
|
|
88
|
+
return `hsl(${hue}, 45%, 55%)`;
|
|
89
|
+
}
|
|
64
90
|
/**
|
|
65
91
|
* Updates the local cursor position in the awareness state.
|
|
66
92
|
* This broadcasts the cursor position to all connected peers.
|
|
@@ -80,6 +106,37 @@ export class KritzelObjectMap {
|
|
|
80
106
|
}
|
|
81
107
|
this._awareness.setLocalStateField('cursor', null);
|
|
82
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Sets the ID of the object currently being drawn by the local user.
|
|
111
|
+
* Remote clients use this to derive cursor position from the object's latest
|
|
112
|
+
* coordinates instead of the throttled awareness cursor, reducing desync.
|
|
113
|
+
* Pass `null` when drawing ends.
|
|
114
|
+
*/
|
|
115
|
+
setActiveDrawingObject(objectId) {
|
|
116
|
+
if (!this._awareness) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this._awareness.setLocalStateField('activeObjectId', objectId);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Broadcasts the local user's selection box bounds via awareness.
|
|
123
|
+
* Remote clients use this to render the selection rectangle in the user's color.
|
|
124
|
+
*/
|
|
125
|
+
setLocalSelectionBox(box) {
|
|
126
|
+
if (!this._awareness) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this._awareness.setLocalStateField('selectionBox', box);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Clears the local selection box from awareness (e.g., when selection completes or is cancelled).
|
|
133
|
+
*/
|
|
134
|
+
clearLocalSelectionBox() {
|
|
135
|
+
if (!this._awareness) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this._awareness.setLocalStateField('selectionBox', null);
|
|
139
|
+
}
|
|
83
140
|
/**
|
|
84
141
|
* Registers a callback to be invoked when the awareness state changes.
|
|
85
142
|
* The callback receives the full awareness states map.
|
|
@@ -87,6 +144,14 @@ export class KritzelObjectMap {
|
|
|
87
144
|
onAwarenessChange(callback) {
|
|
88
145
|
this._awarenessChangeCallbacks.push(callback);
|
|
89
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Registers a callback to be invoked when remote object changes are received.
|
|
149
|
+
* Used by the awareness cursors component to re-derive cursor positions
|
|
150
|
+
* from the latest object data when a remote user is actively drawing.
|
|
151
|
+
*/
|
|
152
|
+
onObjectsChange(callback) {
|
|
153
|
+
this._objectsChangeCallbacks.push(callback);
|
|
154
|
+
}
|
|
90
155
|
/**
|
|
91
156
|
* Returns the Yjs UndoManager instance for managing undo/redo operations.
|
|
92
157
|
* @returns The UndoManager instance, or `null` if not initialized
|
|
@@ -223,9 +288,32 @@ export class KritzelObjectMap {
|
|
|
223
288
|
// Subscribe to awareness changes
|
|
224
289
|
if (this._awareness) {
|
|
225
290
|
this._awarenessChangeHandler = () => {
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
291
|
+
const now = Date.now();
|
|
292
|
+
const timeSinceLastEmit = now - this._lastAwarenessEmitTime;
|
|
293
|
+
// Clear any pending timeout since we have a new event
|
|
294
|
+
if (this._awarenessEmitTimeout !== null) {
|
|
295
|
+
clearTimeout(this._awarenessEmitTimeout);
|
|
296
|
+
this._awarenessEmitTimeout = null;
|
|
297
|
+
}
|
|
298
|
+
if (timeSinceLastEmit >= this.AWARENESS_THROTTLE_INTERVAL) {
|
|
299
|
+
// Enough time has passed, emit immediately
|
|
300
|
+
this._lastAwarenessEmitTime = now;
|
|
301
|
+
const states = this._awareness.getStates();
|
|
302
|
+
for (const callback of this._awarenessChangeCallbacks) {
|
|
303
|
+
callback(states);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
// Schedule emission for the remaining time
|
|
308
|
+
const delayMs = this.AWARENESS_THROTTLE_INTERVAL - timeSinceLastEmit;
|
|
309
|
+
this._awarenessEmitTimeout = setTimeout(() => {
|
|
310
|
+
this._lastAwarenessEmitTime = Date.now();
|
|
311
|
+
this._awarenessEmitTimeout = null;
|
|
312
|
+
const states = this._awareness.getStates();
|
|
313
|
+
for (const callback of this._awarenessChangeCallbacks) {
|
|
314
|
+
callback(states);
|
|
315
|
+
}
|
|
316
|
+
}, delayMs);
|
|
229
317
|
}
|
|
230
318
|
};
|
|
231
319
|
this._awareness.on('change', this._awarenessChangeHandler);
|
|
@@ -362,6 +450,10 @@ export class KritzelObjectMap {
|
|
|
362
450
|
if (updatedObjects.length > 0) {
|
|
363
451
|
this._core?.engine.emitObjectsUpdated(updatedObjects.map(obj => ({ object: obj, changedProperties: [] })));
|
|
364
452
|
}
|
|
453
|
+
// Notify subscribers of remote object changes (e.g., awareness cursors)
|
|
454
|
+
for (const callback of this._objectsChangeCallbacks) {
|
|
455
|
+
callback();
|
|
456
|
+
}
|
|
365
457
|
}
|
|
366
458
|
/**
|
|
367
459
|
* Initializes document metadata if not already set.
|
|
@@ -752,11 +844,14 @@ export class KritzelObjectMap {
|
|
|
752
844
|
this._awareness.off('change', this._awarenessChangeHandler);
|
|
753
845
|
this._awarenessChangeHandler = null;
|
|
754
846
|
}
|
|
847
|
+
if (this._awarenessEmitTimeout !== null) {
|
|
848
|
+
clearTimeout(this._awarenessEmitTimeout);
|
|
849
|
+
this._awarenessEmitTimeout = null;
|
|
850
|
+
}
|
|
755
851
|
this._awareness = null;
|
|
756
852
|
this._awarenessChangeCallbacks = [];
|
|
757
|
-
//
|
|
853
|
+
// Destroy providers (destroy handles disconnection internally)
|
|
758
854
|
this._providers.forEach(p => {
|
|
759
|
-
p.disconnect();
|
|
760
855
|
p.destroy();
|
|
761
856
|
});
|
|
762
857
|
this._providers = [];
|
|
@@ -55,6 +55,7 @@ export class KritzelBrushTool extends KritzelBaseTool {
|
|
|
55
55
|
path.isCompleted = false;
|
|
56
56
|
this._currentPathId = path.id;
|
|
57
57
|
this._core.store.state.objects.insert(path);
|
|
58
|
+
this._core.store.state.objects?.setActiveDrawingObject(path.id);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
if (event.pointerType === 'touch' || event.pointerType === 'pen') {
|
|
@@ -78,6 +79,7 @@ export class KritzelBrushTool extends KritzelBaseTool {
|
|
|
78
79
|
path.isCompleted = false;
|
|
79
80
|
this._currentPathId = path.id;
|
|
80
81
|
this._core.store.state.objects.insert(path);
|
|
82
|
+
this._core.store.state.objects?.setActiveDrawingObject(path.id);
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
}
|
|
@@ -168,6 +170,7 @@ export class KritzelBrushTool extends KritzelBaseTool {
|
|
|
168
170
|
this._core.engine.emitObjectsChange();
|
|
169
171
|
this._core.engine.emitObjectsAdded([currentPath]);
|
|
170
172
|
}
|
|
173
|
+
this._core.store.state.objects?.setActiveDrawingObject(null);
|
|
171
174
|
this._currentPathId = null;
|
|
172
175
|
}
|
|
173
176
|
}
|
|
@@ -183,6 +186,7 @@ export class KritzelBrushTool extends KritzelBaseTool {
|
|
|
183
186
|
this._core.engine.emitObjectsChange();
|
|
184
187
|
this._core.engine.emitObjectsAdded([currentPath]);
|
|
185
188
|
}
|
|
189
|
+
this._core.store.state.objects?.setActiveDrawingObject(null);
|
|
186
190
|
this._currentPathId = null;
|
|
187
191
|
}
|
|
188
192
|
}
|
|
@@ -70,6 +70,7 @@ export class KritzelLineTool extends KritzelBaseTool {
|
|
|
70
70
|
line.isCompleted = false;
|
|
71
71
|
this._currentLineId = line.id;
|
|
72
72
|
this._core.store.state.objects.insert(line);
|
|
73
|
+
this._core.store.state.objects?.setActiveDrawingObject(line.id);
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
if (event.pointerType === 'touch' || event.pointerType === 'pen') {
|
|
@@ -99,6 +100,7 @@ export class KritzelLineTool extends KritzelBaseTool {
|
|
|
99
100
|
line.isCompleted = false;
|
|
100
101
|
this._currentLineId = line.id;
|
|
101
102
|
this._core.store.state.objects.insert(line);
|
|
103
|
+
this._core.store.state.objects?.setActiveDrawingObject(line.id);
|
|
102
104
|
}
|
|
103
105
|
}
|
|
104
106
|
}
|
|
@@ -197,6 +199,7 @@ export class KritzelLineTool extends KritzelBaseTool {
|
|
|
197
199
|
// Switch to selection tool and select the drawn line
|
|
198
200
|
this.selectLineAndSwitchTool(currentLine);
|
|
199
201
|
}
|
|
202
|
+
this._core.store.state.objects?.setActiveDrawingObject(null);
|
|
200
203
|
this._currentLineId = null;
|
|
201
204
|
}
|
|
202
205
|
}
|
|
@@ -214,6 +217,7 @@ export class KritzelLineTool extends KritzelBaseTool {
|
|
|
214
217
|
// Switch to selection tool and select the drawn line
|
|
215
218
|
this.selectLineAndSwitchTool(currentLine);
|
|
216
219
|
}
|
|
220
|
+
this._core.store.state.objects?.setActiveDrawingObject(null);
|
|
217
221
|
this._currentLineId = null;
|
|
218
222
|
}
|
|
219
223
|
}
|
|
@@ -179,6 +179,7 @@ export class KritzelShapeTool extends KritzelBaseTool {
|
|
|
179
179
|
scale: lockScale ? 1 : viewportScale,
|
|
180
180
|
});
|
|
181
181
|
this._core.store.state.objects.insert(this.currentShape);
|
|
182
|
+
this._core.store.state.objects?.setActiveDrawingObject(this.currentShape.id);
|
|
182
183
|
this._core.rerender();
|
|
183
184
|
}
|
|
184
185
|
/**
|
|
@@ -239,6 +240,7 @@ export class KritzelShapeTool extends KritzelBaseTool {
|
|
|
239
240
|
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
240
241
|
}
|
|
241
242
|
this.isDrawing = false;
|
|
243
|
+
this._core.store.state.objects?.setActiveDrawingObject(null);
|
|
242
244
|
this.currentShape = null;
|
|
243
245
|
this._core.rerender();
|
|
244
246
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"entries": [
|
|
3
|
-
"components/shared/kritzel-dropdown/kritzel-dropdown.js",
|
|
4
|
-
"components/shared/kritzel-brush-style/kritzel-brush-style.js",
|
|
5
3
|
"components/core/kritzel-engine/kritzel-engine.js",
|
|
6
4
|
"components/ui/kritzel-context-menu/kritzel-context-menu.js",
|
|
5
|
+
"components/shared/kritzel-dropdown/kritzel-dropdown.js",
|
|
6
|
+
"components/shared/kritzel-brush-style/kritzel-brush-style.js",
|
|
7
7
|
"components/shared/kritzel-font-family/kritzel-font-family.js",
|
|
8
8
|
"components/shared/kritzel-line-endings/kritzel-line-endings.js",
|
|
9
9
|
"components/shared/kritzel-pill-tabs/kritzel-pill-tabs.js",
|
|
10
10
|
"components/shared/kritzel-shape-fill/kritzel-shape-fill.js",
|
|
11
|
+
"components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.js",
|
|
11
12
|
"components/core/kritzel-cursor-trail/kritzel-cursor-trail.js",
|
|
12
13
|
"components/core/kritzel-editor/kritzel-editor.js",
|
|
13
14
|
"components/shared/kritzel-avatar/kritzel-avatar.js",
|
package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.css
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
position: fixed;
|
|
4
|
+
top: 0;
|
|
5
|
+
left: 0;
|
|
6
|
+
width: 100vw;
|
|
7
|
+
height: 100vh;
|
|
8
|
+
pointer-events: none;
|
|
9
|
+
z-index: 9500;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.awareness-cursor {
|
|
13
|
+
position: absolute;
|
|
14
|
+
top: 0;
|
|
15
|
+
left: 0;
|
|
16
|
+
transition: transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out,
|
|
17
|
+
opacity 300ms ease;
|
|
18
|
+
will-change: transform;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.awareness-cursor.stale {
|
|
22
|
+
opacity: 0.3;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.awareness-cursor.tracking-object {
|
|
26
|
+
transition-duration: 0ms;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.cursor-arrow {
|
|
30
|
+
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.cursor-label {
|
|
34
|
+
position: absolute;
|
|
35
|
+
left: 16px;
|
|
36
|
+
top: 16px;
|
|
37
|
+
white-space: nowrap;
|
|
38
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
39
|
+
font-size: var(--kritzel-awareness-cursor-label-font-size, 12px);
|
|
40
|
+
color: var(--kritzel-awareness-cursor-label-text-color, #ffffff);
|
|
41
|
+
padding: 2px 8px;
|
|
42
|
+
border-radius: 4px;
|
|
43
|
+
line-height: 1.4;
|
|
44
|
+
font-weight: 500;
|
|
45
|
+
pointer-events: none;
|
|
46
|
+
user-select: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.edge-indicator {
|
|
50
|
+
position: absolute;
|
|
51
|
+
top: -12px;
|
|
52
|
+
left: -12px;
|
|
53
|
+
width: 24px;
|
|
54
|
+
height: 24px;
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
transition: transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out,
|
|
59
|
+
opacity 300ms ease;
|
|
60
|
+
will-change: transform;
|
|
61
|
+
pointer-events: auto;
|
|
62
|
+
user-select: none;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.edge-indicator.stale {
|
|
67
|
+
opacity: 0.3;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.edge-indicator.tracking-object {
|
|
71
|
+
transition-duration: 0ms;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.edge-arrow {
|
|
75
|
+
position: absolute;
|
|
76
|
+
filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.3));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.edge-label {
|
|
80
|
+
position: absolute;
|
|
81
|
+
white-space: nowrap;
|
|
82
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
83
|
+
font-size: var(--kritzel-awareness-cursor-label-font-size, 12px);
|
|
84
|
+
color: var(--kritzel-awareness-cursor-label-text-color, #ffffff);
|
|
85
|
+
padding: 2px 8px;
|
|
86
|
+
border-radius: 4px;
|
|
87
|
+
line-height: 1.4;
|
|
88
|
+
font-weight: 500;
|
|
89
|
+
pointer-events: none;
|
|
90
|
+
opacity: 0;
|
|
91
|
+
transform-origin: center;
|
|
92
|
+
transition: opacity 150ms ease;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.edge-indicator:hover .edge-label {
|
|
96
|
+
opacity: 1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.remote-selection-box {
|
|
100
|
+
position: absolute;
|
|
101
|
+
top: 0;
|
|
102
|
+
left: 0;
|
|
103
|
+
border-width: 2px;
|
|
104
|
+
border-style: solid;
|
|
105
|
+
pointer-events: none;
|
|
106
|
+
will-change: transform, width, height;
|
|
107
|
+
transition: transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out,
|
|
108
|
+
width var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out,
|
|
109
|
+
height var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out;
|
|
110
|
+
}
|