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.
Files changed (177) hide show
  1. package/dist/cjs/index-Dc7LOVhs.js +2 -2
  2. package/dist/cjs/index.cjs.js +58 -18
  3. package/dist/cjs/{kritzel-active-users_41.cjs.entry.js → kritzel-active-users_42.cjs.entry.js} +586 -172
  4. package/dist/cjs/kritzel-brush-style.cjs.entry.js +1 -1
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/cjs/stencil.cjs.js +1 -1
  7. package/dist/cjs/{workspace.migrations-DcwqsqPC.js → workspace.migrations-Dyt35LBC.js} +58 -5
  8. package/dist/collection/classes/core/core.class.js +9 -3
  9. package/dist/collection/classes/core/store.class.js +20 -6
  10. package/dist/collection/classes/handlers/selection.handler.js +15 -2
  11. package/dist/collection/classes/objects/base-object.class.js +2 -0
  12. package/dist/collection/classes/objects/custom-element.class.js +1 -0
  13. package/dist/collection/classes/objects/group.class.js +1 -0
  14. package/dist/collection/classes/objects/image.class.js +1 -0
  15. package/dist/collection/classes/objects/line.class.js +1 -0
  16. package/dist/collection/classes/objects/path.class.js +1 -0
  17. package/dist/collection/classes/objects/selection-box.class.js +1 -0
  18. package/dist/collection/classes/objects/selection-group.class.js +13 -1
  19. package/dist/collection/classes/objects/shape.class.js +1 -0
  20. package/dist/collection/classes/objects/text.class.js +1 -0
  21. package/dist/collection/classes/providers/hocuspocus-sync-provider.class.js +57 -17
  22. package/dist/collection/classes/structures/object-map.structure.js +102 -7
  23. package/dist/collection/classes/tools/brush-tool.class.js +4 -0
  24. package/dist/collection/classes/tools/line-tool.class.js +4 -0
  25. package/dist/collection/classes/tools/shape-tool.class.js +2 -0
  26. package/dist/collection/collection-manifest.json +3 -2
  27. package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.css +110 -0
  28. package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.js +347 -0
  29. package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.js +1 -1
  30. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +3 -3
  31. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +150 -109
  32. package/dist/collection/components/shared/kritzel-avatar/kritzel-avatar.js +3 -3
  33. package/dist/collection/components/shared/kritzel-brush-style/kritzel-brush-style.js +1 -1
  34. package/dist/collection/components/shared/kritzel-button/kritzel-button.js +2 -2
  35. package/dist/collection/components/shared/kritzel-color/kritzel-color.js +2 -2
  36. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js +1 -1
  37. package/dist/collection/components/shared/kritzel-dropdown/kritzel-dropdown.js +1 -1
  38. package/dist/collection/components/shared/kritzel-font/kritzel-font.js +1 -1
  39. package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js +1 -1
  40. package/dist/collection/components/shared/kritzel-input/kritzel-input.js +1 -1
  41. package/dist/collection/components/shared/kritzel-master-detail/kritzel-master-detail.js +3 -3
  42. package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +1 -1
  43. package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js +2 -2
  44. package/dist/collection/components/shared/kritzel-numeric-input/kritzel-numeric-input.js +1 -1
  45. package/dist/collection/components/shared/kritzel-opacity-slider/kritzel-opacity-slider.js +1 -1
  46. package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js +1 -1
  47. package/dist/collection/components/shared/kritzel-slide-toggle/kritzel-slide-toggle.js +1 -1
  48. package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js +1 -1
  49. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js +1 -1
  50. package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js +2 -2
  51. package/dist/collection/components/ui/kritzel-back-to-content/kritzel-back-to-content.js +1 -1
  52. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js +1 -1
  53. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +5 -5
  54. package/dist/collection/components/ui/kritzel-current-user/kritzel-current-user.js +1 -1
  55. package/dist/collection/components/ui/kritzel-current-user-dialog/kritzel-current-user-dialog.js +1 -1
  56. package/dist/collection/components/ui/kritzel-export/kritzel-export.js +1 -1
  57. package/dist/collection/components/ui/kritzel-login-dialog/kritzel-login-dialog.js +1 -1
  58. package/dist/collection/components/ui/kritzel-more-menu/kritzel-more-menu.js +1 -1
  59. package/dist/collection/components/ui/kritzel-settings/kritzel-settings.js +1 -1
  60. package/dist/collection/components/ui/kritzel-share-dialog/kritzel-share-dialog.js +2 -2
  61. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +1 -1
  62. package/dist/collection/constants/schema.constants.js +1 -1
  63. package/dist/collection/constants/version.js +1 -1
  64. package/dist/collection/interfaces/remote-cursor.interface.js +1 -0
  65. package/dist/collection/migrations/workspace.migrations.js +10 -1
  66. package/dist/components/index.d.ts +2 -0
  67. package/dist/components/index.js +1 -1
  68. package/dist/components/kritzel-active-users.js +1 -1
  69. package/dist/components/kritzel-avatar.js +1 -1
  70. package/dist/components/kritzel-awareness-cursors.d.ts +11 -0
  71. package/dist/components/kritzel-awareness-cursors.js +1 -0
  72. package/dist/components/kritzel-back-to-content.js +1 -1
  73. package/dist/components/kritzel-brush-style.js +1 -1
  74. package/dist/components/kritzel-button.js +1 -1
  75. package/dist/components/kritzel-color-palette.js +1 -1
  76. package/dist/components/kritzel-color.js +1 -1
  77. package/dist/components/kritzel-context-menu.js +1 -1
  78. package/dist/components/kritzel-controls.js +1 -1
  79. package/dist/components/kritzel-current-user-dialog.js +1 -1
  80. package/dist/components/kritzel-current-user.js +1 -1
  81. package/dist/components/kritzel-cursor-trail.js +1 -1
  82. package/dist/components/kritzel-dropdown.js +1 -1
  83. package/dist/components/kritzel-editor.js +1 -1
  84. package/dist/components/kritzel-engine.js +1 -1
  85. package/dist/components/kritzel-export.js +1 -1
  86. package/dist/components/kritzel-font-family.js +1 -1
  87. package/dist/components/kritzel-font-size.js +1 -1
  88. package/dist/components/kritzel-font.js +1 -1
  89. package/dist/components/kritzel-input.js +1 -1
  90. package/dist/components/kritzel-login-dialog.js +1 -1
  91. package/dist/components/kritzel-master-detail.js +1 -1
  92. package/dist/components/kritzel-menu-item.js +1 -1
  93. package/dist/components/kritzel-menu.js +1 -1
  94. package/dist/components/kritzel-more-menu.js +1 -1
  95. package/dist/components/kritzel-numeric-input.js +1 -1
  96. package/dist/components/kritzel-opacity-slider.js +1 -1
  97. package/dist/components/kritzel-portal.js +1 -1
  98. package/dist/components/kritzel-settings.js +1 -1
  99. package/dist/components/kritzel-share-dialog.js +1 -1
  100. package/dist/components/kritzel-slide-toggle.js +1 -1
  101. package/dist/components/kritzel-split-button.js +1 -1
  102. package/dist/components/kritzel-stroke-size.js +1 -1
  103. package/dist/components/kritzel-tool-config.js +1 -1
  104. package/dist/components/kritzel-tooltip.js +1 -1
  105. package/dist/components/kritzel-utility-panel.js +1 -1
  106. package/dist/components/kritzel-workspace-manager.js +1 -1
  107. package/dist/components/{p-Dp8idtVD.js → p-0kShCfeb.js} +1 -1
  108. package/dist/components/{p-B47JuZiD.js → p-2OYw6GJ7.js} +1 -1
  109. package/dist/components/p-7o2FWtFx.js +1 -0
  110. package/dist/components/{p-dR_q96Q3.js → p-B4Oqnl55.js} +1 -1
  111. package/dist/components/{p-C5KuV1pK.js → p-BA0ayKqO.js} +1 -1
  112. package/dist/components/{p-NbNVTRk6.js → p-BEJQ2kP7.js} +1 -1
  113. package/dist/components/p-BSipRoFx.js +1 -0
  114. package/dist/components/{p-CDadAOMw.js → p-BeFUNGEI.js} +1 -1
  115. package/dist/components/{p-35nrk8s0.js → p-BiByyU2C.js} +1 -1
  116. package/dist/components/{p-CCAWSyDD.js → p-BiouZo1q.js} +1 -1
  117. package/dist/components/{p-CSExtYKI.js → p-ByR0VXeU.js} +1 -1
  118. package/dist/components/{p-1MGcXTLv.js → p-C1uR_ZNW.js} +1 -1
  119. package/dist/components/{p-x8PzaMuD.js → p-C69Stayh.js} +1 -1
  120. package/dist/components/{p-Ch0UlFwq.js → p-C7SBI_0T.js} +1 -1
  121. package/dist/components/{p-DEzfXrGX.js → p-CAIGuV2J.js} +1 -1
  122. package/dist/components/p-CJ2eHeoV.js +1 -0
  123. package/dist/components/p-CW-VyJgK.js +1 -0
  124. package/dist/components/{p-DW4ADV9w.js → p-CZhyKp-f.js} +1 -1
  125. package/dist/components/p-CsR4owzk.js +1 -0
  126. package/dist/components/{p-BG1IxseV.js → p-CsoDfhD5.js} +1 -1
  127. package/dist/components/{p-DpFu5yAt.js → p-D1O7DxL4.js} +1 -1
  128. package/dist/components/{p-B5ouV8EQ.js → p-DRbG92F9.js} +1 -1
  129. package/dist/components/{p-C3eaM9TB.js → p-DS0xx1eT.js} +1 -1
  130. package/dist/components/{p-jx8VOz7S.js → p-DSzQ6H2j.js} +1 -1
  131. package/dist/components/{p-DsIlDGDO.js → p-DXjuuVq9.js} +1 -1
  132. package/dist/components/p-DXpYcAnT.js +1 -0
  133. package/dist/components/{p-DiFVw6IQ.js → p-Da46jw3N.js} +1 -1
  134. package/dist/components/{p-C6kZf91d.js → p-Dj_Qjga5.js} +1 -1
  135. package/dist/components/{p-Do0Q5-iC.js → p-DvIEvoZu.js} +1 -1
  136. package/dist/components/{p-CnVzLD5e.js → p-GYI7sDxr.js} +1 -1
  137. package/dist/components/{p-CcBM_ClD.js → p-HLbqRJGs.js} +1 -1
  138. package/dist/components/{p-VHyNcODZ.js → p-KQzWumjB.js} +1 -1
  139. package/dist/components/p-RJWe82kG.js +9 -0
  140. package/dist/components/{p-VAkeZOZL.js → p-TyR-YTXm.js} +1 -1
  141. package/dist/components/{p-CHtn5xr6.js → p-b4gyXoju.js} +1 -1
  142. package/dist/components/p-iRL0wQHQ.js +1 -0
  143. package/dist/components/{p-CqLaHE27.js → p-kj9wbLY8.js} +1 -1
  144. package/dist/components/{p-DaHq4iG1.js → p-xM-_OeRO.js} +1 -1
  145. package/dist/esm/index-MV-81ybv.js +2 -2
  146. package/dist/esm/index.js +59 -19
  147. package/dist/esm/{kritzel-active-users_41.entry.js → kritzel-active-users_42.entry.js} +586 -173
  148. package/dist/esm/kritzel-brush-style.entry.js +1 -1
  149. package/dist/esm/loader.js +1 -1
  150. package/dist/esm/stencil.js +1 -1
  151. package/dist/esm/{workspace.migrations-BGixvB76.js → workspace.migrations-B99F1MdT.js} +58 -5
  152. package/dist/stencil/index.esm.js +1 -1
  153. package/dist/stencil/p-2a60e1bc.entry.js +9 -0
  154. package/dist/stencil/p-B99F1MdT.js +1 -0
  155. package/dist/stencil/{p-016ad76a.entry.js → p-fc21e29c.entry.js} +1 -1
  156. package/dist/stencil/stencil.esm.js +1 -1
  157. package/dist/types/classes/core/store.class.d.ts +10 -2
  158. package/dist/types/classes/objects/base-object.class.d.ts +1 -0
  159. package/dist/types/classes/objects/selection-group.class.d.ts +5 -0
  160. package/dist/types/classes/providers/hocuspocus-sync-provider.class.d.ts +3 -0
  161. package/dist/types/classes/structures/object-map.structure.d.ts +41 -0
  162. package/dist/types/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.d.ts +26 -0
  163. package/dist/types/components.d.ts +39 -4
  164. package/dist/types/constants/schema.constants.d.ts +1 -1
  165. package/dist/types/constants/version.d.ts +1 -1
  166. package/dist/types/interfaces/object.interface.d.ts +1 -0
  167. package/dist/types/interfaces/remote-cursor.interface.d.ts +17 -0
  168. package/dist/types/interfaces/theme.interface.d.ts +7 -0
  169. package/package.json +1 -1
  170. package/dist/components/p-B2vjbWy-.js +0 -9
  171. package/dist/components/p-BvToKcu1.js +0 -1
  172. package/dist/components/p-CNro30tB.js +0 -1
  173. package/dist/components/p-Duv3EM3w.js +0 -1
  174. package/dist/components/p-KFsLHwYm.js +0 -1
  175. package/dist/components/p-hCORwbZh.js +0 -1
  176. package/dist/stencil/p-BGixvB76.js +0 -1
  177. package/dist/stencil/p-a0f5c4ad.entry.js +0 -9
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var index = require('./index-Dc7LOVhs.js');
4
- var workspace_migrations = require('./workspace.migrations-DcwqsqPC.js');
4
+ var workspace_migrations = require('./workspace.migrations-Dyt35LBC.js');
5
5
  var Y = require('yjs');
6
6
  require('y-websocket');
7
7
  require('y-indexeddb');
@@ -154,16 +154,16 @@ const KritzelAvatar = class {
154
154
  height: `${this.size}px`,
155
155
  fontSize: `${Math.round(this.size * 0.4)}px`,
156
156
  };
157
- return (index.h(index.Host, { key: '9f2756b21f5cf12c770ecae3917b889e651180fd', style: containerStyles, class: {
157
+ return (index.h(index.Host, { key: '67c0c1f944b9c835d1685d2b743114a1b5a1f061', style: containerStyles, class: {
158
158
  'has-image': !!showImage,
159
159
  'has-initials': !!showInitials,
160
160
  'has-default': !!showDefaultIcon,
161
- }, role: "img", "aria-label": this.getDisplayName() || 'User avatar' }, showImage && (index.h("img", { key: '4d73aed6c3cb4832a661163e780b4950beb33ff3', src: imageUrl, alt: "", class: "avatar-image", ref: (el) => {
161
+ }, role: "img", "aria-label": this.getDisplayName() || 'User avatar' }, showImage && (index.h("img", { key: 'd71ccd7449a27133bcf8cc01f3cd654cc9b00142', src: imageUrl, alt: "", class: "avatar-image", ref: (el) => {
162
162
  if (el) {
163
163
  el.referrerPolicy = 'no-referrer';
164
164
  el.crossOrigin = 'anonymous';
165
165
  }
166
- }, onError: this.handleImageError })), showInitials && (index.h("span", { key: '9e71b25b721d18e213da38ceead31ed5cf861bd8', class: "avatar-initials", style: { backgroundColor: this.getBackgroundColor() } }, initials)), showDefaultIcon && (index.h("span", { key: 'f330747bda5862d9e2d19d9dda331bced2bdc6de', class: "avatar-default" }, index.h("svg", { key: '4eefdc2e502669c193fbe54a20c57701f0ecc0ae', viewBox: "0 0 24 24", fill: "currentColor" }, index.h("path", { key: '1788425bba4559c34d9f16069cfa32bc84cf1b17', d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" }))))));
166
+ }, onError: this.handleImageError })), showInitials && (index.h("span", { key: '818ad4a24d6489565dffc8c64b3d4e76b701444c', class: "avatar-initials", style: { backgroundColor: this.getBackgroundColor() } }, initials)), showDefaultIcon && (index.h("span", { key: '87af93fd968f3bf5b1f86295de6bd4b71c94120c', class: "avatar-default" }, index.h("svg", { key: '3267317fe99fb8d90432e207516bb48f603c08ed', viewBox: "0 0 24 24", fill: "currentColor" }, index.h("path", { key: '9e4e225f9a058a24f63b508f36969c8c429fccd6', d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" }))))));
167
167
  }
168
168
  static get watchers() { return {
169
169
  "user": [{
@@ -176,6 +176,262 @@ 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.3}.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.3}.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
+
181
+ const STALE_THRESHOLD_MS = 10_000;
182
+ const REMOVE_THRESHOLD_MS = 30_000;
183
+ const CLEANUP_INTERVAL_MS = 3_000;
184
+ const KritzelAwarenessCursors = class {
185
+ constructor(hostRef) {
186
+ index.registerInstance(this, hostRef);
187
+ }
188
+ core;
189
+ showEdgeIndicators = true;
190
+ edgeIndicatorPadding = 8;
191
+ remoteCursors = new Map();
192
+ objectVersion = 0;
193
+ cleanupIntervalId;
194
+ objectChangeRafId = null;
195
+ componentDidLoad() {
196
+ this.core.store.state.objects?.onAwarenessChange(states => {
197
+ this.handleAwarenessChange(states);
198
+ });
199
+ this.core.store.state.objects?.onObjectsChange(() => {
200
+ this.handleRemoteObjectChange();
201
+ });
202
+ this.cleanupIntervalId = setInterval(() => {
203
+ this.cleanupStaleCursors();
204
+ }, CLEANUP_INTERVAL_MS);
205
+ }
206
+ disconnectedCallback() {
207
+ if (this.cleanupIntervalId) {
208
+ clearInterval(this.cleanupIntervalId);
209
+ }
210
+ if (this.objectChangeRafId !== null) {
211
+ cancelAnimationFrame(this.objectChangeRafId);
212
+ }
213
+ }
214
+ handleAwarenessChange(states) {
215
+ const localClientId = this.core.store.state.objects?.localClientId;
216
+ const now = Date.now();
217
+ const updated = new Map(this.remoteCursors);
218
+ // Track which clientIds are still present
219
+ const activeClientIds = new Set();
220
+ states.forEach((state, clientId) => {
221
+ if (clientId === localClientId)
222
+ return;
223
+ if (!state.user)
224
+ return;
225
+ activeClientIds.add(clientId);
226
+ const user = state.user;
227
+ const cursor = state.cursor;
228
+ const activeObjectId = state.activeObjectId || null;
229
+ const selectionBox = state.selectionBox || null;
230
+ updated.set(clientId, {
231
+ clientId,
232
+ user,
233
+ cursor,
234
+ activeObjectId,
235
+ selectionBox,
236
+ lastUpdated: now,
237
+ });
238
+ });
239
+ // Remove cursors for disconnected clients
240
+ for (const clientId of updated.keys()) {
241
+ if (!activeClientIds.has(clientId)) {
242
+ updated.delete(clientId);
243
+ }
244
+ }
245
+ this.remoteCursors = updated;
246
+ }
247
+ cleanupStaleCursors() {
248
+ const now = Date.now();
249
+ let changed = false;
250
+ const updated = new Map(this.remoteCursors);
251
+ for (const [clientId, cursor] of updated) {
252
+ if (now - cursor.lastUpdated > REMOVE_THRESHOLD_MS) {
253
+ updated.delete(clientId);
254
+ changed = true;
255
+ }
256
+ }
257
+ if (changed) {
258
+ this.remoteCursors = updated;
259
+ }
260
+ }
261
+ isStale(cursor) {
262
+ return Date.now() - cursor.lastUpdated > STALE_THRESHOLD_MS;
263
+ }
264
+ hasActiveDrawingCursors() {
265
+ for (const cursor of this.remoteCursors.values()) {
266
+ if (cursor.activeObjectId)
267
+ return true;
268
+ }
269
+ return false;
270
+ }
271
+ handleRemoteObjectChange() {
272
+ if (!this.hasActiveDrawingCursors())
273
+ return;
274
+ // Debounce via rAF to batch multiple rapid Yjs updates into a single re-render
275
+ if (this.objectChangeRafId !== null)
276
+ return;
277
+ this.objectChangeRafId = requestAnimationFrame(() => {
278
+ this.objectChangeRafId = null;
279
+ this.objectVersion++;
280
+ });
281
+ }
282
+ getActiveObjectTip(objectId) {
283
+ const obj = this.core.store.state.objects?.findById(objectId);
284
+ if (!obj)
285
+ return null;
286
+ if (obj instanceof workspace_migrations.KritzelPath && !obj.isCompleted) {
287
+ const lastPoint = obj.points[obj.points.length - 1];
288
+ if (!lastPoint)
289
+ return null;
290
+ return {
291
+ x: (lastPoint[0] - obj.x) / obj.scale + obj.translateX,
292
+ y: (lastPoint[1] - obj.y) / obj.scale + obj.translateY,
293
+ };
294
+ }
295
+ if (obj instanceof workspace_migrations.KritzelLine && !obj.isCompleted) {
296
+ return {
297
+ x: (obj.endX - obj.x) / obj.scale + obj.translateX,
298
+ y: (obj.endY - obj.y) / obj.scale + obj.translateY,
299
+ };
300
+ }
301
+ // Shapes normalize their bounding box (x/y always top-left, width/height
302
+ // always positive), so we can't determine which corner the user is actively
303
+ // dragging. Fall back to the throttled awareness cursor position instead.
304
+ return null;
305
+ }
306
+ worldToScreen(worldX, worldY) {
307
+ const { scale, translateX, translateY } = this.core.store.state;
308
+ return {
309
+ x: worldX * scale + translateX,
310
+ y: worldY * scale + translateY,
311
+ };
312
+ }
313
+ isInViewport(screenX, screenY) {
314
+ const { viewportWidth, viewportHeight } = this.core.store.state;
315
+ return screenX >= 0 && screenX <= viewportWidth && screenY >= 0 && screenY <= viewportHeight;
316
+ }
317
+ clampToEdge(screenX, screenY) {
318
+ const { viewportWidth, viewportHeight } = this.core.store.state;
319
+ const padding = this.edgeIndicatorPadding; // 8px
320
+ // Clamp symmetrically
321
+ const clampedX = Math.max(padding, Math.min(viewportWidth - padding, screenX));
322
+ const clampedY = Math.max(padding, Math.min(viewportHeight - padding, screenY));
323
+ // Determine nearest edge to position avatar inside
324
+ const distLeft = clampedX - padding;
325
+ const distRight = (viewportWidth - padding) - clampedX;
326
+ const distTop = clampedY - padding;
327
+ const distBottom = (viewportHeight - padding) - clampedY;
328
+ let edge = 'top';
329
+ const minDist = Math.min(distLeft, distRight, distTop, distBottom);
330
+ if (minDist === distLeft)
331
+ edge = 'left';
332
+ else if (minDist === distRight)
333
+ edge = 'right';
334
+ else if (minDist === distTop)
335
+ edge = 'top';
336
+ else
337
+ edge = 'bottom';
338
+ const angle = Math.atan2(screenY - clampedY, screenX - clampedX);
339
+ return { x: clampedX, y: clampedY, angle, edge };
340
+ }
341
+ getUserDisplayName(user) {
342
+ if (user.displayName)
343
+ return user.displayName;
344
+ if (user.firstName || user.lastName) {
345
+ return [user.firstName, user.lastName].filter(Boolean).join(' ');
346
+ }
347
+ return 'Unknown';
348
+ }
349
+ render() {
350
+ const cursors = Array.from(this.remoteCursors.values());
351
+ return (index.h(index.Host, { key: 'b8676d9a7a3d4a79ea8ad9763355ecf4c2f90e17' }, cursors.map(remoteCursor => {
352
+ if (!remoteCursor.cursor)
353
+ return null;
354
+ // When a remote user is actively drawing, derive cursor position from
355
+ // the object's latest coordinates (synced via Yjs) instead of the
356
+ // throttled awareness cursor position
357
+ let screen;
358
+ let trackingObject = false;
359
+ if (remoteCursor.activeObjectId) {
360
+ const tip = this.getActiveObjectTip(remoteCursor.activeObjectId);
361
+ if (tip) {
362
+ trackingObject = true;
363
+ screen = this.worldToScreen(tip.x, tip.y);
364
+ }
365
+ else {
366
+ screen = this.worldToScreen(remoteCursor.cursor.x, remoteCursor.cursor.y);
367
+ }
368
+ }
369
+ else {
370
+ screen = this.worldToScreen(remoteCursor.cursor.x, remoteCursor.cursor.y);
371
+ }
372
+ const inViewport = this.isInViewport(screen.x, screen.y);
373
+ const stale = this.isStale(remoteCursor);
374
+ const color = remoteCursor.user.color || '#6B7280';
375
+ if (inViewport) {
376
+ return this.renderCursor(remoteCursor, screen.x, screen.y, color, stale, trackingObject);
377
+ }
378
+ if (this.showEdgeIndicators) {
379
+ return this.renderEdgeIndicator(remoteCursor, screen.x, screen.y, color, stale, trackingObject);
380
+ }
381
+ return null;
382
+ }), cursors.map(remoteCursor => {
383
+ if (!remoteCursor.selectionBox)
384
+ return null;
385
+ const color = remoteCursor.user.color || '#6B7280';
386
+ const box = remoteCursor.selectionBox;
387
+ const topLeft = this.worldToScreen(box.x, box.y);
388
+ const { scale } = this.core.store.state;
389
+ const screenWidth = box.width * scale;
390
+ const screenHeight = box.height * scale;
391
+ return (index.h("div", { key: `selection-box-${remoteCursor.clientId}`, class: "remote-selection-box", style: {
392
+ transform: `translate(${topLeft.x}px, ${topLeft.y}px)`,
393
+ width: `${screenWidth}px`,
394
+ height: `${screenHeight}px`,
395
+ backgroundColor: `color-mix(in srgb, ${color} 20%, transparent)`,
396
+ borderColor: `color-mix(in srgb, ${color} 50%, transparent)`,
397
+ } }));
398
+ })));
399
+ }
400
+ renderCursor(cursor, screenX, screenY, color, stale, trackingObject) {
401
+ return (index.h("div", { key: `cursor-${cursor.clientId}`, class: { 'awareness-cursor': true, stale, 'tracking-object': trackingObject }, style: { transform: `translate(${screenX}px, ${screenY}px)` } }, index.h("svg", { class: "cursor-arrow", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, index.h("path", { d: "M5 3L19 12L12 13L9 20L5 3Z", fill: color, stroke: "#ffffff", "stroke-width": "1.5", "stroke-linejoin": "round" })), index.h("span", { class: "cursor-label", style: { backgroundColor: color } }, this.getUserDisplayName(cursor.user))));
402
+ }
403
+ renderEdgeIndicator(cursor, screenX, screenY, color, stale, trackingObject) {
404
+ const clamped = this.clampToEdge(screenX, screenY);
405
+ const arrowDeg = (clamped.angle * 180) / Math.PI + 90;
406
+ // Position the username label opposite to the edge
407
+ const labelOffset = 20;
408
+ let labelX = 0;
409
+ let labelY = 0;
410
+ // Default transform origin is somewhat arbitrary without explicit layout
411
+ // We'll calculate simple translations relative to center point
412
+ if (clamped.edge === 'left') {
413
+ labelX = labelOffset;
414
+ }
415
+ else if (clamped.edge === 'right') {
416
+ labelX = -labelOffset;
417
+ }
418
+ else if (clamped.edge === 'top') {
419
+ labelY = labelOffset;
420
+ }
421
+ else if (clamped.edge === 'bottom') {
422
+ labelY = -labelOffset;
423
+ }
424
+ const displayName = this.getUserDisplayName(cursor.user);
425
+ return (index.h("div", { key: `edge-${cursor.clientId}`, class: { 'edge-indicator': true, stale, 'tracking-object': trackingObject }, style: {
426
+ transform: `translate(${clamped.x}px, ${clamped.y}px)`,
427
+ } }, index.h("svg", { class: "edge-arrow", width: "16", height: "16", viewBox: "0 0 16 16", style: { transform: `rotate(${arrowDeg}deg)` } }, index.h("path", { d: "M8 1L14 13H2L8 1Z", fill: color, stroke: "#ffffff", "stroke-width": "1.5", "stroke-linejoin": "round" })), index.h("span", { class: "edge-label", style: {
428
+ backgroundColor: color,
429
+ transform: `translate(${labelX}px, ${labelY}px)`,
430
+ } }, displayName)));
431
+ }
432
+ };
433
+ KritzelAwarenessCursors.style = kritzelAwarenessCursorsCss();
434
+
179
435
  const kritzelBackToContentCss = () => `:host{display:block;z-index:var(--kritzel-back-to-content-z-index, 1000)}.back-to-content-button{display:flex;align-items:center;justify-content:center;height:var(--kritzel-back-to-content-height, 50px);box-sizing:border-box;gap:var(--kritzel-back-to-content-gap, 6px);padding:var(--kritzel-back-to-content-padding, 0 16px);border:var(--kritzel-back-to-content-border, 1px solid #ebebeb);border-radius:var(--kritzel-back-to-content-border-radius, 12px);background-color:var(--kritzel-back-to-content-background-color, #ffffff);color:var(--kritzel-back-to-content-color, #000000);font-size:var(--kritzel-back-to-content-font-size, 14px);font-weight:var(--kritzel-back-to-content-font-weight, 500);cursor:var(--kritzel-global-pointer-cursor, pointer);box-shadow:var(--kritzel-back-to-content-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));opacity:0;pointer-events:none;transition:opacity 0.2s ease-out, transform 0.2s ease-out, background-color 0.15s ease-out;-webkit-tap-highlight-color:transparent;user-select:none}.back-to-content-button.visible{opacity:1;pointer-events:auto}@media (hover: hover){.back-to-content-button:hover{background-color:var(--kritzel-back-to-content-hover-background-color, hsl(0, 0%, 0%, 4.3%))}}.back-to-content-button:active{background-color:var(--kritzel-back-to-content-active-background-color, hsl(0, 0%, 0%, 8.6%))}`;
180
436
 
181
437
  const KritzelBackToContent = class {
@@ -199,7 +455,7 @@ const KritzelBackToContent = class {
199
455
  this.backToContent.emit();
200
456
  };
201
457
  render() {
202
- return (index.h(index.Host, { key: 'e42bfb365d1ae7fba820234ae0d59cd1e468a258' }, index.h("button", { key: 'b8c376989685c0aca4ee9c425944289ccc6e351a', class: { 'back-to-content-button': true, visible: this.visible }, onClick: this.handleClick }, index.h("kritzel-icon", { key: '7955fafe06de1d2f6827bbd933dffd575c9ba9ed', name: "chevrons-left" }))));
458
+ return (index.h(index.Host, { key: '890501d05ecfadaedbf298590d43b5efd67f1d5f' }, index.h("button", { key: 'fae3acd5aed5d0a5322fe9e0da2186577d873c5c', class: { 'back-to-content-button': true, visible: this.visible }, onClick: this.handleClick }, index.h("kritzel-icon", { key: 'eaa718ab29fad870464c6b67d5ad27c4300dfd54', name: "chevrons-left" }))));
203
459
  }
204
460
  };
205
461
  KritzelBackToContent.style = kritzelBackToContentCss();
@@ -226,11 +482,11 @@ const KritzelButton = class {
226
482
  this.buttonClick.emit();
227
483
  };
228
484
  render() {
229
- return (index.h(index.Host, { key: '3efc2197a7f10b5da36eba52e03b48e6aa2500dc' }, index.h("button", { key: '0d506f62756b3cd60ebdd78c52c903dddcd1d6ff', type: this.type, class: {
485
+ return (index.h(index.Host, { key: '3a285bfdc1b336fb450304856aa81c1bd9c4e5e3' }, index.h("button", { key: 'f3119bfe9cf8ca1b6e031cdcc8bee9549c18e620', type: this.type, class: {
230
486
  'kritzel-button': true,
231
487
  [this.variant]: true,
232
488
  'disabled': this.disabled,
233
- }, disabled: this.disabled, onClick: this.handleClick }, index.h("slot", { key: '76ab315100ff334ad47dad974cd83f117f73e844' }))));
489
+ }, disabled: this.disabled, onClick: this.handleClick }, index.h("slot", { key: '5a26eee0781c5fafc7a41260364b2a2c11f192a6' }))));
234
490
  }
235
491
  };
236
492
  KritzelButton.style = kritzelButtonCss();
@@ -278,13 +534,13 @@ const KritzelColorComponent = class {
278
534
  render() {
279
535
  const resolvedColor = this.resolveColor();
280
536
  const isColorVeryLight = this.isLightColor(resolvedColor);
281
- return (index.h(index.Host, { key: 'a95e6bc89330b9a5baecf53b5fa3e54316ad153d' }, index.h("div", { key: 'e19d5fc8f59dce48f815a382c358a2068b05f8c3', class: "checkerboard-bg", style: {
537
+ return (index.h(index.Host, { key: '7e36e97c383cff73b3146279e971526dd5c7f0f7' }, index.h("div", { key: 'e8ad3ca5e9771c51a96a846627ea20c75212ceeb', class: "checkerboard-bg", style: {
282
538
  width: `${this.size}px`,
283
539
  height: `${this.size}px`,
284
540
  borderRadius: '50%',
285
541
  display: 'inline-block',
286
542
  position: 'relative',
287
- } }, index.h("div", { key: '61678e783b6ea5890fc0eb74f37592b94b09f59e', class: {
543
+ } }, index.h("div", { key: '9269087c7694604d70d50d846cedb6ce022373cd', class: {
288
544
  'color-circle': true,
289
545
  'white': isColorVeryLight,
290
546
  }, style: {
@@ -340,7 +596,7 @@ const KritzelColorPalette = class {
340
596
  render() {
341
597
  const displayedColors = this.isExpanded ? this.colors : this.colors.slice(0, 6);
342
598
  const expandedHeight = this.isExpanded ? this.calculateHeight() : '32px';
343
- return (index.h(index.Host, { key: '8dd3fe8327b3d5ce4f420cbff752b523e66b8356' }, index.h("div", { key: '554f867b63450fa0f423b71cdfa5b1d6de3e12a9', class: {
599
+ return (index.h(index.Host, { key: '22b6f0362933848cd40ad44c73a48fd4d8330884' }, index.h("div", { key: '38adb9abc39d78ae9528341212acf2de425b4eb8', class: {
344
600
  'color-grid': true,
345
601
  'expanded': this.isExpanded,
346
602
  }, style: {
@@ -538,7 +794,7 @@ const KritzelContextMenu = class {
538
794
  })));
539
795
  }
540
796
  render() {
541
- return (index.h(index.Host, { key: 'e1d2c078548eda801784424fb9ba77a8fc905a90' }, index.h("div", { key: '39cba641f90e2ad6d30553974880cdedd7fe3877', class: "menu-container" }, this.processedItems.map(({ item, isDisabled, processedChildren }, index$1) => {
797
+ return (index.h(index.Host, { key: '11f279a1ef329569988b1c1ce6311a1f81695ebe' }, index.h("div", { key: 'e0aa8ab22df018ae0a2b1c22513575d67099d35d', class: "menu-container" }, this.processedItems.map(({ item, isDisabled, processedChildren }, index$1) => {
542
798
  const prevItem = index$1 > 0 ? this.processedItems[index$1 - 1].item : null;
543
799
  const showDivider = prevItem && prevItem.group !== item.group;
544
800
  const hasChildren = processedChildren && processedChildren.length > 0;
@@ -818,13 +1074,13 @@ const KritzelControls = class {
818
1074
  // Separate tool controls from config control
819
1075
  const toolControls = this.controls.filter(c => c.type === 'tool' || c.type === 'separator');
820
1076
  const configControl = this.controls.find(c => c.type === 'config' && c.name === this.firstConfig?.name);
821
- return (index.h(index.Host, { key: 'f706b101d3ec5dd4453ffd906499f6f4bbbb64bf', class: {
1077
+ return (index.h(index.Host, { key: 'fa03f9eae6ebc0a043d6ac3cb774ae32491ae943', class: {
822
1078
  mobile: this.isTouchDevice,
823
- } }, this.isUtilityPanelVisible && (index.h("kritzel-utility-panel", { key: '414bda49650cb551036654639fbf1d9bb6bbac4e', style: {
1079
+ } }, this.isUtilityPanelVisible && (index.h("kritzel-utility-panel", { key: '2e789118656dc3366f131b520f2be4386e5889c8', style: {
824
1080
  position: 'absolute',
825
1081
  bottom: '56px',
826
1082
  left: '12px',
827
- }, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), index.h("div", { key: '1be53e2fba46a37398768d39fbbed0543eb31628', class: "kritzel-controls" }, index.h("div", { key: 'b26fa897d079043ca007a12b8941a9ee474274be', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), index.h("div", { key: 'ff7b7fb6bd24fccc5e42dd29fc449cd69340bf79', class: "kritzel-tools-scroll", ref: el => this.toolsScrollRef = el, onScroll: this.handleToolsScroll }, toolControls.map(control => {
1083
+ }, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), index.h("div", { key: '29b4d14746f81f7def022ec5769c9d1bf21a6dab', class: "kritzel-controls" }, index.h("div", { key: 'eb5a4ddd2c0ee9d77c008ddae1223e4ce4449116', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), index.h("div", { key: '5c41c8fc6770ef5eae7e5b03752f0fe65bcf30e1', class: "kritzel-tools-scroll", ref: el => this.toolsScrollRef = el, onScroll: this.handleToolsScroll }, toolControls.map(control => {
828
1084
  // Check if this control has sub-options (split-button)
829
1085
  if (control.subOptions?.length) {
830
1086
  const selectedSubOption = this.getSelectedSubOption(control);
@@ -854,10 +1110,10 @@ const KritzelControls = class {
854
1110
  'kritzel-control': true,
855
1111
  'selected': this.activeControl?.name === control?.name,
856
1112
  }, key: control.name, "data-testid": `tool-${control.name}`, onClick: _event => this.handleControlClick?.(control) }, index.h("kritzel-icon", { name: control.icon })));
857
- })), index.h("div", { key: '2644af8c1c448ae961e03a6ceab5c978c077b5c9', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight && !(configControl && this.activeControl && hasConfigUI) } }), configControl && this.activeControl && (index.h("div", { class: {
1113
+ })), index.h("div", { key: 'a924ed9102961f992b27afe6945732c8541c13a0', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight && !(configControl && this.activeControl && hasConfigUI) } }), configControl && this.activeControl && (index.h("div", { class: {
858
1114
  'kritzel-config-container': true,
859
1115
  'visible': hasConfigUI,
860
- }, key: configControl.name }, index.h("div", { key: '4f15bb371e325916bdfae2f3137a7cffed47f6ee', class: { 'config-gradient-left': true, 'visible': this.needsScrolling } }), index.h("kritzel-tooltip", { key: 'eac2874ca75faeb68a5623cd1fa96350469a1566', anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), triggerElement: this.configTriggerRef }, index.h("kritzel-tool-config", { key: '139afc8fb1852d196aa9e659a8d9c7a0c97c1453', tool: this.activeControl.tool, theme: this.theme, onToolChange: event => this.handleToolChange?.(event), onDisplayValuesChange: this.handleDisplayValuesChange, style: { width: '100%', height: '100%' } })), index.h("div", { key: 'd8725a81b5bfce5b795175a2ff5f8c3aaef7869e', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", "data-testid": "tool-config", ref: el => {
1116
+ }, key: configControl.name }, index.h("div", { key: '9709b046ceb6ba0982ca45b93212b2d449c2b2fe', class: { 'config-gradient-left': true, 'visible': this.needsScrolling } }), index.h("kritzel-tooltip", { key: 'b2a2521c810f176f54ef8accff5b98a4a1acf42d', anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), triggerElement: this.configTriggerRef }, index.h("kritzel-tool-config", { key: 'cdfc29f2b8a3cd800789f68879216e73700d546e', tool: this.activeControl.tool, theme: this.theme, onToolChange: event => this.handleToolChange?.(event), onDisplayValuesChange: this.handleDisplayValuesChange, style: { width: '100%', height: '100%' } })), index.h("div", { key: '09d77705945e3e52eff40107c3bcbccbb636586d', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", "data-testid": "tool-config", ref: el => {
861
1117
  if (el)
862
1118
  this.configTriggerRef = el;
863
1119
  }, onKeyDown: event => {
@@ -901,7 +1157,7 @@ const KritzelCurrentUser = class {
901
1157
  this.dialogRef?.open();
902
1158
  };
903
1159
  render() {
904
- return (index.h(index.Host, { key: '3e35539db9f34e3da3debb1b32973c597ef4a69e' }, index.h("kritzel-avatar", { key: '9db84121465097a39174d26fbec5edab4c4aecaa', user: this.user, size: this.avatarSize, onClick: this.handleAvatarClick }), index.h("kritzel-current-user-dialog", { key: 'da202b64e1c4781d9d49744ed95e9479780e4cd9', ref: el => (this.dialogRef = el), user: this.user })));
1160
+ return (index.h(index.Host, { key: '603389630e3c1fb02c94663bebdc374bbbfaa79e' }, index.h("kritzel-avatar", { key: 'b346db9aaa7681c484725a42c05ab94f468a19f0', user: this.user, size: this.avatarSize, onClick: this.handleAvatarClick }), index.h("kritzel-current-user-dialog", { key: '647b32cff0ffbfa08ce8d00f1a2f42a6d17027a3', ref: el => (this.dialogRef = el), user: this.user })));
905
1161
  }
906
1162
  };
907
1163
  KritzelCurrentUser.style = kritzelCurrentUserCss();
@@ -933,7 +1189,7 @@ const KritzelCurrentUserDialog = class {
933
1189
  }
934
1190
  render() {
935
1191
  const displayName = this.getDisplayName();
936
- return (index.h(index.Host, { key: '3f315637242364ec1a184ab0287e1647903b00df' }, index.h("kritzel-dialog", { key: '124cbb9e0236e7f1f9abfbf22a7de1ad8e9d418c', dialogTitle: "Account", isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, size: "small" }, index.h("div", { key: '6e74746bb20197e8cf85bc0f9745a7da3a73c248', class: "user-info" }, index.h("kritzel-avatar", { key: '57f6f79b2eb61f503891065845915ca1de8534ad', user: this.user, size: 80 }), displayName && index.h("div", { key: '35d94a67ee50d764484c5f7ad1cbf2a188b030dc', class: "user-name" }, displayName), this.user?.email && index.h("div", { key: '9c118a62a29bc32dfc383d59616581a73f52b6f5', class: "user-email" }, this.user.email)))));
1192
+ return (index.h(index.Host, { key: 'f2b3c74f360bc81671e405d05e9a250878722911' }, index.h("kritzel-dialog", { key: 'c042f0574d72ed8705d27730aea8106e089cbcf6', dialogTitle: "Account", isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, size: "small" }, index.h("div", { key: '3d02828a3444eebb92bdb317923315873e791831', class: "user-info" }, index.h("kritzel-avatar", { key: '172f2a529de8f397e327cbe6395272e12f7a51d0', user: this.user, size: 80 }), displayName && index.h("div", { key: '8537c57e8eaa2172caebcc5d53700f4835b4d1bf', class: "user-name" }, displayName), this.user?.email && index.h("div", { key: '446e60e1d422455518f38049eda813d7c52c8c0d', class: "user-email" }, this.user.email)))));
937
1193
  }
938
1194
  };
939
1195
  KritzelCurrentUserDialog.style = kritzelCurrentUserDialogCss();
@@ -1006,7 +1262,7 @@ const KritzelCursorTrail = class {
1006
1262
  }
1007
1263
  }
1008
1264
  render() {
1009
- return (index.h(index.Host, { key: '603a385702512357af1fbcc778b29feecf8cf208' }, this.cursorTrailPoints.length > 1 && (index.h("svg", { key: '5f7e4478599d482e624b77a752f601088b343f4e', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
1265
+ return (index.h(index.Host, { key: 'b6a9e84ce49dd72f353e0b87ae0bc02b0e5aeb1e' }, this.cursorTrailPoints.length > 1 && (index.h("svg", { key: '238ea314a937d556c75ae080495c2e6559340c6f', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
1010
1266
  position: 'absolute',
1011
1267
  left: '0',
1012
1268
  top: '0',
@@ -1557,7 +1813,7 @@ const KritzelDropdown = class {
1557
1813
  'open-up': this.openDirection === 'up',
1558
1814
  'open-down': this.openDirection === 'down',
1559
1815
  };
1560
- return (index.h(index.Host, { key: 'cc92e22245b066a6fdaa821d97f00b94d7bd6232' }, index.h("div", { key: '281288744c360fba3437394bb0a0270986f49de8', class: "dropdown-wrapper", ref: el => (this.wrapperElement = el) }, index.h("slot", { key: '5fc4058de36acd05f2ab356ac50aa23a526809e1', name: "prefix", ref: el => (this.prefixSlotElement = el), onSlotchange: this.evaluatePrefixContent }), index.h("div", { key: '317fa76695aad0fad9951def45ee3517e5de316d', class: "dropdown-container", style: { width: this.width } }, index.h("button", { key: 'd1221c8b8ea645a6ea19e7ada683405a287f3fe1', type: "button", class: triggerClasses, style: { ...this.selectStyles, ...this.getSelectedStyle() }, onClick: this.toggleMenu, onKeyDown: this.handleTriggerKeyDown, "aria-haspopup": "listbox", "aria-expanded": this.isOpen ? 'true' : 'false', ref: el => (this.triggerElement = el) }, index.h("span", { key: 'd485070f35bddd9af068a361ce3d94407d011af0', class: "dropdown-trigger-label" }, this.getSelectedLabel()), index.h("span", { key: '5d617070fb91996b9af3056b294484794953bfcb', class: "dropdown-trigger-arrow", "aria-hidden": "true" }, index.h("svg", { key: 'd462cbd0d9172f1617abc6bfeaf990e88bd4300d', xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("polyline", { key: '762c57ae655bcf7b3d3f7e29100400c82728f177', points: "6 9 12 15 18 9" }))))), index.h("slot", { key: '8ed792a632ac9b0e91b4b75ce89c4b024ee9b1b9', name: "suffix", ref: el => (this.suffixSlotElement = el), onSlotchange: this.evaluateSuffixContent }), index.h("ul", { key: '7cb57ef569aa447198f98714eb0ed41d9e198d75', class: menuClasses, role: "listbox", tabindex: "-1", onKeyDown: this.handleMenuKeyDown, ref: el => (this.menuElement = el) }, this.options.map((option, index$1) => {
1816
+ return (index.h(index.Host, { key: 'b753a3cf28a0f21625c213c9ec5337b922023206' }, index.h("div", { key: 'dffe30b1d6968ad612c94718eea72f118c43f378', class: "dropdown-wrapper", ref: el => (this.wrapperElement = el) }, index.h("slot", { key: '0a08fa5aa5a2040e85ac80643d11ec778ed89b31', name: "prefix", ref: el => (this.prefixSlotElement = el), onSlotchange: this.evaluatePrefixContent }), index.h("div", { key: '8a8b4519787863d53fa7c72928e7632de6daa848', class: "dropdown-container", style: { width: this.width } }, index.h("button", { key: '803fe1e4ef138a58cde8941771875dd5eadfe944', type: "button", class: triggerClasses, style: { ...this.selectStyles, ...this.getSelectedStyle() }, onClick: this.toggleMenu, onKeyDown: this.handleTriggerKeyDown, "aria-haspopup": "listbox", "aria-expanded": this.isOpen ? 'true' : 'false', ref: el => (this.triggerElement = el) }, index.h("span", { key: '05d9dfe94e62134c91316f33cf64f2a9efb57fbb', class: "dropdown-trigger-label" }, this.getSelectedLabel()), index.h("span", { key: '332d5206a67ae8ef4ce0982d62c108210bca6252', class: "dropdown-trigger-arrow", "aria-hidden": "true" }, index.h("svg", { key: 'f73539b0decf59fd59d075618dc5028ac82d11b5', xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("polyline", { key: '7b45a14ab898233a68845a40363ee37c9922098c', points: "6 9 12 15 18 9" }))))), index.h("slot", { key: '8936739a53b5dca8debdce27c4bead487a5bf803', name: "suffix", ref: el => (this.suffixSlotElement = el), onSlotchange: this.evaluateSuffixContent }), index.h("ul", { key: 'f20417649f8988e46db5992100d93fd7bd827b96', class: menuClasses, role: "listbox", tabindex: "-1", onKeyDown: this.handleMenuKeyDown, ref: el => (this.menuElement = el) }, this.options.map((option, index$1) => {
1561
1817
  const isSelected = option.value === this.internalValue;
1562
1818
  const isFocused = index$1 === this.focusedIndex;
1563
1819
  const optionClasses = {
@@ -1772,7 +2028,7 @@ const KritzelEditor = class {
1772
2028
  isControlsVisible = true;
1773
2029
  isUtilityPanelVisible = true;
1774
2030
  syncConfig = {
1775
- providers: [workspace_migrations.IndexedDBSyncProvider],
2031
+ providers: [workspace_migrations.IndexedDBSyncProvider]
1776
2032
  };
1777
2033
  /** Optional login configuration. When provided, a "Sign in" button is shown that opens a login dialog with the configured providers. */
1778
2034
  loginConfig;
@@ -2289,7 +2545,7 @@ const KritzelEditor = class {
2289
2545
  const isLoggedIn = this.isLoggedIn;
2290
2546
  const shouldShowCurrentUser = isLoggedIn;
2291
2547
  const shouldShowLoginButton = !!this.loginConfig && !isLoggedIn;
2292
- return (index.h(index.Host, { key: '84231308ca4b12863139aeeafa754d544345df3f' }, index.h("div", { key: 'b8cdd2862e9bd892dfeed356e85d608759307bf7', class: "top-left-buttons" }, index.h("kritzel-workspace-manager", { key: '2bce2b9564f5a083ba32667718685310d060f23a', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-back-to-content", { key: 'b013213fc04fe86eefcc324911693fcffb8eea51', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), index.h("kritzel-engine", { key: '7338446462bfdc3995c0897704e9594a875895e1', ref: el => (this.engineRef = el), workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, scaleMin: this.scaleMin, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, wheelEnabled: this.wheelEnabled, theme: this.currentTheme, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event) }), index.h("kritzel-controls", { key: '97b9d8805446afc101f01d99bc96bc24a7054722', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState, theme: this.currentTheme, onIsControlsReady: () => (this.isControlsReady = true) }), index.h("div", { key: '0986b1e82b8fbf989e716fe07a401faca618f642', class: "top-right-buttons" }, index.h("kritzel-settings", { key: '6f4cfe92bb54f0de291b0a0482742b859e86ecf3', ref: el => (this.settingsRef = el), shortcuts: this.shortcuts, editorId: this.editorId, onSettingsChange: event => this.handleSettingsChange(event) }), index.h("kritzel-export", { key: 'd669ecae49f721e765d1f8d2f6725633c28cd635', ref: el => (this.exportRef = el), workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), index.h("kritzel-active-users", { key: 'e44843dcdc9c0ff1e760aadac3f2ec79a7371aba', users: this.activeUsers }), shouldShowCurrentUser && (index.h("kritzel-current-user", { key: '123f7968427b4420c8e29749b6ec679e1df92e95', user: this.user })), shouldShowLoginButton && index.h("kritzel-button", { key: '35b611178e9dfcc3c78a7495965d2844aa33435d', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in"), index.h("kritzel-more-menu", { key: 'bec3ebf5a7a6d40fc334ef34d9b2c030e0c1faf2', items: this.moreMenuItems }), index.h("kritzel-share-dialog", { key: 'ba72f6cc43372cc7fe93090fd6254391494443ff', ref: el => (this.shareDialogRef = el), isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: '319bf700bd96bbdec9d566a7e054cdce4de2a251', ref: el => (this.loginDialogRef = el), providers: this.loginConfig.providers, dialogTitle: this.loginConfig.title, subtitle: this.loginConfig.subtitle, onProviderLogin: this.handleProviderLogin })))));
2548
+ return (index.h(index.Host, { key: 'd1944655652eb2939e3696ed70050baaca0871e2' }, index.h("div", { key: 'ce5dfd9b8f8d9927e9a6ace4056f9053163c7e0a', class: "top-left-buttons" }, index.h("kritzel-workspace-manager", { key: 'e127a667c6e4e853bb4f0c9ffd0edaa6d80d9dfa', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-back-to-content", { key: 'a9abb378f3c79f356d2164cbddf6badba10188a8', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), index.h("kritzel-engine", { key: 'c5f764580f3623eeb9381e54769a891a48c04620', ref: el => (this.engineRef = el), workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, scaleMin: this.scaleMin, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, wheelEnabled: this.wheelEnabled, theme: this.currentTheme, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event) }), index.h("kritzel-controls", { key: '2479b6979d5b2b6c55a873bd1d8468b5fd967f72', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState, theme: this.currentTheme, onIsControlsReady: () => (this.isControlsReady = true) }), index.h("div", { key: 'ec6ac72ba154abe0738259464f20cae9e7dbdd9e', class: "top-right-buttons" }, index.h("kritzel-settings", { key: 'f68f791d673b30331e55f358b9c71b3e2a9a8388', ref: el => (this.settingsRef = el), shortcuts: this.shortcuts, editorId: this.editorId, onSettingsChange: event => this.handleSettingsChange(event) }), index.h("kritzel-export", { key: 'dfe5a051caccee504df4f347705303fa1f812556', ref: el => (this.exportRef = el), workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), index.h("kritzel-active-users", { key: '48983a14d3902cd238cf0d9ed302ed561a655a9a', users: this.activeUsers }), shouldShowCurrentUser && index.h("kritzel-current-user", { key: '589bdc895741a2d17f60c4b549d14fe8fff74c17', user: this.user }), shouldShowLoginButton && index.h("kritzel-button", { key: '50414a9d7ade623678c767ce63c49f5e99336bed', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in"), index.h("kritzel-more-menu", { key: 'db3069ee0b093acd238750df81c6f426139c9b87', items: this.moreMenuItems }), index.h("kritzel-share-dialog", { key: 'e16057838f00b2c3f239e794b4310bd2690d16e2', ref: el => (this.shareDialogRef = el), isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: 'a6d1fc06c983542c6af95e7bb4b2b2d522a03605', ref: el => (this.loginDialogRef = el), providers: this.loginConfig.providers, dialogTitle: this.loginConfig.title, subtitle: this.loginConfig.subtitle, onProviderLogin: this.handleProviderLogin })))));
2293
2549
  }
2294
2550
  static get watchers() { return {
2295
2551
  "isEngineReady": [{
@@ -20414,6 +20670,7 @@ class KritzelCustomElement extends workspace_migrations.KritzelBaseObject {
20414
20670
  object._core = core;
20415
20671
  object.id = object.generateId();
20416
20672
  object.workspaceId = core.store.state.activeWorkspace.id;
20673
+ object.userId = core.user?.id;
20417
20674
  return object;
20418
20675
  }
20419
20676
  /**
@@ -21002,6 +21259,10 @@ class KritzelObjectMap {
21002
21259
  _stackItemPoppedHandler = null;
21003
21260
  _awarenessChangeHandler = null;
21004
21261
  _awarenessChangeCallbacks = [];
21262
+ _objectsChangeCallbacks = [];
21263
+ _lastAwarenessEmitTime = 0;
21264
+ _awarenessEmitTimeout = null;
21265
+ AWARENESS_THROTTLE_INTERVAL = 100; // milliseconds
21005
21266
  /**
21006
21267
  * Indicates whether the object map has been initialized and is ready for use.
21007
21268
  * @returns `true` if providers are connected and the map is operational
@@ -21015,6 +21276,19 @@ class KritzelObjectMap {
21015
21276
  get awareness() {
21016
21277
  return this._awareness;
21017
21278
  }
21279
+ /**
21280
+ * Whether a network awareness instance is available.
21281
+ */
21282
+ get hasAwareness() {
21283
+ return !!this._awareness;
21284
+ }
21285
+ /**
21286
+ * Returns the local client ID from the awareness instance.
21287
+ * Used to filter out the local user when rendering remote cursors.
21288
+ */
21289
+ get localClientId() {
21290
+ return this._awareness?.clientID ?? null;
21291
+ }
21018
21292
  /**
21019
21293
  * Sets the local user identity in the awareness state.
21020
21294
  * This broadcasts the user's identity to all connected peers.
@@ -21023,12 +21297,21 @@ class KritzelObjectMap {
21023
21297
  if (!this._awareness || !user) {
21024
21298
  return;
21025
21299
  }
21300
+ const displayName = user.displayName || user.firstName || 'Anonymous';
21026
21301
  this._awareness.setLocalStateField('user', {
21027
21302
  id: user.id,
21028
- name: user.displayName || user.firstName || 'Anonymous',
21029
- color: user.color,
21303
+ displayName,
21304
+ color: user.color || this.generateColorFromName(displayName),
21030
21305
  });
21031
21306
  }
21307
+ generateColorFromName(name) {
21308
+ let hash = 0;
21309
+ for (let i = 0; i < name.length; i++) {
21310
+ hash = name.charCodeAt(i) + ((hash << 5) - hash);
21311
+ }
21312
+ const hue = Math.abs(hash % 360);
21313
+ return `hsl(${hue}, 45%, 55%)`;
21314
+ }
21032
21315
  /**
21033
21316
  * Updates the local cursor position in the awareness state.
21034
21317
  * This broadcasts the cursor position to all connected peers.
@@ -21048,6 +21331,37 @@ class KritzelObjectMap {
21048
21331
  }
21049
21332
  this._awareness.setLocalStateField('cursor', null);
21050
21333
  }
21334
+ /**
21335
+ * Sets the ID of the object currently being drawn by the local user.
21336
+ * Remote clients use this to derive cursor position from the object's latest
21337
+ * coordinates instead of the throttled awareness cursor, reducing desync.
21338
+ * Pass `null` when drawing ends.
21339
+ */
21340
+ setActiveDrawingObject(objectId) {
21341
+ if (!this._awareness) {
21342
+ return;
21343
+ }
21344
+ this._awareness.setLocalStateField('activeObjectId', objectId);
21345
+ }
21346
+ /**
21347
+ * Broadcasts the local user's selection box bounds via awareness.
21348
+ * Remote clients use this to render the selection rectangle in the user's color.
21349
+ */
21350
+ setLocalSelectionBox(box) {
21351
+ if (!this._awareness) {
21352
+ return;
21353
+ }
21354
+ this._awareness.setLocalStateField('selectionBox', box);
21355
+ }
21356
+ /**
21357
+ * Clears the local selection box from awareness (e.g., when selection completes or is cancelled).
21358
+ */
21359
+ clearLocalSelectionBox() {
21360
+ if (!this._awareness) {
21361
+ return;
21362
+ }
21363
+ this._awareness.setLocalStateField('selectionBox', null);
21364
+ }
21051
21365
  /**
21052
21366
  * Registers a callback to be invoked when the awareness state changes.
21053
21367
  * The callback receives the full awareness states map.
@@ -21055,6 +21369,14 @@ class KritzelObjectMap {
21055
21369
  onAwarenessChange(callback) {
21056
21370
  this._awarenessChangeCallbacks.push(callback);
21057
21371
  }
21372
+ /**
21373
+ * Registers a callback to be invoked when remote object changes are received.
21374
+ * Used by the awareness cursors component to re-derive cursor positions
21375
+ * from the latest object data when a remote user is actively drawing.
21376
+ */
21377
+ onObjectsChange(callback) {
21378
+ this._objectsChangeCallbacks.push(callback);
21379
+ }
21058
21380
  /**
21059
21381
  * Returns the Yjs UndoManager instance for managing undo/redo operations.
21060
21382
  * @returns The UndoManager instance, or `null` if not initialized
@@ -21191,9 +21513,32 @@ class KritzelObjectMap {
21191
21513
  // Subscribe to awareness changes
21192
21514
  if (this._awareness) {
21193
21515
  this._awarenessChangeHandler = () => {
21194
- const states = this._awareness.getStates();
21195
- for (const callback of this._awarenessChangeCallbacks) {
21196
- callback(states);
21516
+ const now = Date.now();
21517
+ const timeSinceLastEmit = now - this._lastAwarenessEmitTime;
21518
+ // Clear any pending timeout since we have a new event
21519
+ if (this._awarenessEmitTimeout !== null) {
21520
+ clearTimeout(this._awarenessEmitTimeout);
21521
+ this._awarenessEmitTimeout = null;
21522
+ }
21523
+ if (timeSinceLastEmit >= this.AWARENESS_THROTTLE_INTERVAL) {
21524
+ // Enough time has passed, emit immediately
21525
+ this._lastAwarenessEmitTime = now;
21526
+ const states = this._awareness.getStates();
21527
+ for (const callback of this._awarenessChangeCallbacks) {
21528
+ callback(states);
21529
+ }
21530
+ }
21531
+ else {
21532
+ // Schedule emission for the remaining time
21533
+ const delayMs = this.AWARENESS_THROTTLE_INTERVAL - timeSinceLastEmit;
21534
+ this._awarenessEmitTimeout = setTimeout(() => {
21535
+ this._lastAwarenessEmitTime = Date.now();
21536
+ this._awarenessEmitTimeout = null;
21537
+ const states = this._awareness.getStates();
21538
+ for (const callback of this._awarenessChangeCallbacks) {
21539
+ callback(states);
21540
+ }
21541
+ }, delayMs);
21197
21542
  }
21198
21543
  };
21199
21544
  this._awareness.on('change', this._awarenessChangeHandler);
@@ -21330,6 +21675,10 @@ class KritzelObjectMap {
21330
21675
  if (updatedObjects.length > 0) {
21331
21676
  this._core?.engine.emitObjectsUpdated(updatedObjects.map(obj => ({ object: obj, changedProperties: [] })));
21332
21677
  }
21678
+ // Notify subscribers of remote object changes (e.g., awareness cursors)
21679
+ for (const callback of this._objectsChangeCallbacks) {
21680
+ callback();
21681
+ }
21333
21682
  }
21334
21683
  /**
21335
21684
  * Initializes document metadata if not already set.
@@ -21713,11 +22062,14 @@ class KritzelObjectMap {
21713
22062
  this._awareness.off('change', this._awarenessChangeHandler);
21714
22063
  this._awarenessChangeHandler = null;
21715
22064
  }
22065
+ if (this._awarenessEmitTimeout !== null) {
22066
+ clearTimeout(this._awarenessEmitTimeout);
22067
+ this._awarenessEmitTimeout = null;
22068
+ }
21716
22069
  this._awareness = null;
21717
22070
  this._awarenessChangeCallbacks = [];
21718
- // Disconnect and destroy providers
22071
+ // Destroy providers (destroy handles disconnection internally)
21719
22072
  this._providers.forEach(p => {
21720
- p.disconnect();
21721
22073
  p.destroy();
21722
22074
  });
21723
22075
  this._providers = [];
@@ -21753,6 +22105,7 @@ class KritzelStore {
21753
22105
  _cachedSelectionGroup = null;
21754
22106
  _selectionBoxCacheValid = false;
21755
22107
  _selectionGroupCacheValid = false;
22108
+ _localUserId = null;
21756
22109
  /**
21757
22110
  * Gets the current engine state.
21758
22111
  * @returns The mutable engine state object
@@ -21830,9 +22183,7 @@ class KritzelStore {
21830
22183
  height: this._state.viewportHeight / this._state.scale,
21831
22184
  depth: 100,
21832
22185
  };
21833
- return this._state.objects
21834
- .query(viewportBounds)
21835
- .sort((a, b) => a.zIndex - b.zIndex);
22186
+ return this._state.objects.query(viewportBounds).sort((a, b) => a.zIndex - b.zIndex);
21836
22187
  }
21837
22188
  /**
21838
22189
  * Gets all objects excluding selection-related objects (selection group and selection box).
@@ -21863,16 +22214,22 @@ class KritzelStore {
21863
22214
  return this._cachedSelectionBox;
21864
22215
  }
21865
22216
  /**
21866
- * Gets the current selection group if one exists.
22217
+ * Gets the current local user's selection group if one exists.
22218
+ * When a local user ID is set, returns only the selection group belonging to that user.
21867
22219
  * Uses caching for O(1) access after initial lookup.
21868
- * @returns The selection group or null if none exists
22220
+ * @returns The local user's selection group or null if none exists
21869
22221
  */
21870
22222
  get selectionGroup() {
21871
22223
  if (this._selectionGroupCacheValid) {
21872
22224
  return this._cachedSelectionGroup;
21873
22225
  }
21874
22226
  const selectionGroups = this._state.objects.filter(o => o instanceof workspace_migrations.KritzelSelectionGroup);
21875
- this._cachedSelectionGroup = selectionGroups.length > 0 ? selectionGroups[0] : null;
22227
+ if (this._localUserId) {
22228
+ this._cachedSelectionGroup = selectionGroups.find(sg => sg.userId === this._localUserId) ?? null;
22229
+ }
22230
+ else {
22231
+ this._cachedSelectionGroup = selectionGroups.length > 0 ? selectionGroups[0] : null;
22232
+ }
21876
22233
  this._selectionGroupCacheValid = true;
21877
22234
  return this._cachedSelectionGroup;
21878
22235
  }
@@ -21901,6 +22258,15 @@ class KritzelStore {
21901
22258
  this._cachedSelectionGroup = group;
21902
22259
  this._selectionGroupCacheValid = true;
21903
22260
  }
22261
+ /**
22262
+ * Sets the local user ID for scoping selection group lookups.
22263
+ * When set, the selectionGroup getter returns only the group owned by this user.
22264
+ * @param userId - The local user's ID, or null for non-collaborative mode
22265
+ */
22266
+ setLocalUserId(userId) {
22267
+ this._localUserId = userId;
22268
+ this.invalidateSelectionCache();
22269
+ }
21904
22270
  /**
21905
22271
  * Gets the currently active text object being edited.
21906
22272
  * @returns The text object in editing mode, or null if none
@@ -22650,6 +23016,7 @@ class KritzelCore {
22650
23016
  */
22651
23017
  setUser(user) {
22652
23018
  this._user = user;
23019
+ this._store.setLocalUserId(user?.id ?? null);
22653
23020
  this._store.state.objects?.setLocalUser(user);
22654
23021
  }
22655
23022
  /**
@@ -22880,13 +23247,11 @@ class KritzelCore {
22880
23247
  * @param workspace - The workspace to create
22881
23248
  */
22882
23249
  createWorkspace(workspace) {
22883
- console.log('Creating workspace:', workspace);
22884
23250
  workspace._core = this;
22885
23251
  workspace.createdAt = new Date();
22886
23252
  workspace.updatedAt = new Date();
22887
23253
  this.saveWorkspaceToAppState(workspace);
22888
23254
  this._store.state.workspaces = this.loadWorkspacesFromAppState();
22889
- console.log('Current workspaces after creation:', this._store.state.workspaces);
22890
23255
  }
22891
23256
  /**
22892
23257
  * Updates an existing workspace in the app state.
@@ -23051,6 +23416,7 @@ class KritzelCore {
23051
23416
  if (selectionBox) {
23052
23417
  this._store.state.objects.remove(object => object.id === selectionBox.id);
23053
23418
  this._store.setSelectionBox(null);
23419
+ this._store.state.objects.clearLocalSelectionBox();
23054
23420
  }
23055
23421
  }
23056
23422
  /**
@@ -23523,7 +23889,9 @@ class KritzelCore {
23523
23889
  */
23524
23890
  clearSelection() {
23525
23891
  this.removeSelectionGroup();
23526
- this._store.state.objects.remove(o => o instanceof workspace_migrations.KritzelSelectionBox || o instanceof workspace_migrations.KritzelSelectionGroup);
23892
+ const localUserId = this._user?.id;
23893
+ this._store.state.objects.remove(o => o instanceof workspace_migrations.KritzelSelectionBox ||
23894
+ (o instanceof workspace_migrations.KritzelSelectionGroup && (localUserId == null || o.userId === localUserId || o.userId == null)));
23527
23895
  this._store.setSelectionBox(null);
23528
23896
  this._store.setSelectionGroup(null);
23529
23897
  this._store.state.isSelecting = false;
@@ -23677,6 +24045,10 @@ class KritzelCore {
23677
24045
  if (!object.isSelected) {
23678
24046
  return false;
23679
24047
  }
24048
+ // Remote selection groups always show group UI (border only, no handles)
24049
+ if (object instanceof workspace_migrations.KritzelSelectionGroup && this._user?.id != null && object.userId != null && object.userId !== this._user.id) {
24050
+ return true;
24051
+ }
23680
24052
  const selectionGroup = this._store.selectionGroup;
23681
24053
  if (!selectionGroup) {
23682
24054
  // During selection phase (no group yet), hide UI for KritzelLine objects
@@ -25409,6 +25781,7 @@ const KritzelEngine = class {
25409
25781
  this.core.store.state.isContextMenuVisible = false;
25410
25782
  this.core.store.state.objects.remove(o => o instanceof workspace_migrations.KritzelSelectionBox);
25411
25783
  this.core.store.setSelectionBox(null);
25784
+ this.core.store.state.objects.clearLocalSelectionBox();
25412
25785
  this.core.store.state.isSelecting = false;
25413
25786
  this.core.store.state.isEnabled = true;
25414
25787
  this.core.rerender();
@@ -26356,6 +26729,7 @@ const KritzelEngine = class {
26356
26729
  this.core.clearSelection();
26357
26730
  this.core.store.state.objects.remove(o => o instanceof workspace_migrations.KritzelSelectionBox);
26358
26731
  this.core.store.setSelectionBox(null);
26732
+ this.core.store.state.objects.clearLocalSelectionBox();
26359
26733
  this.core.store.state.isSelecting = false;
26360
26734
  this.core.store.state.isResizeHandleSelected = false;
26361
26735
  this.core.store.state.isRotationHandleSelected = false;
@@ -26532,114 +26906,153 @@ const KritzelEngine = class {
26532
26906
  left: `${object.totalWidth}px`,
26533
26907
  top: '0',
26534
26908
  zIndex: (object.zIndex + 2).toString(),
26535
- } }, index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) && (index.h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
26536
- zIndex: (object.zIndex + 1).toString(),
26537
- height: object?.totalHeight.toString(),
26538
- width: object?.totalWidth.toString(),
26539
- left: '0',
26540
- top: '0',
26541
- position: 'absolute',
26542
- transform: `rotate(${object.rotationDegrees}deg)`,
26543
- transformOrigin: `${object.totalWidth / 2}px ${object.totalHeight / 2}px`,
26544
- overflow: 'visible',
26545
- pointerEvents: 'none',
26546
- } }, this.core.displaySelectionGroupUI(object) && (index.h("g", { class: "selection-group-ui", style: { pointerEvents: 'none' } }, index.h("g", { class: "selection-group-borders" }, index.h("line", { x1: "0", y1: "0", x2: object.totalWidth, y2: "0", style: {
26547
- stroke: 'var(--kritzel-selection-border-color, #007AFF)',
26548
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26549
- strokeLinecap: 'square',
26550
- } }), index.h("line", { x1: "0", y1: "0", x2: "0", y2: object.totalHeight, style: {
26551
- stroke: 'var(--kritzel-selection-border-color, #007AFF)',
26552
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26553
- strokeLinecap: 'square',
26554
- } }), index.h("line", { x1: "0", y1: object.totalHeight, x2: object.totalWidth, y2: object.totalHeight, style: {
26555
- stroke: 'var(--kritzel-selection-border-color, #007AFF)',
26556
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26557
- strokeLinecap: 'square',
26558
- } }), index.h("line", { x1: object.totalWidth, y1: "0", x2: object.totalWidth, y2: object.totalHeight, style: {
26559
- stroke: 'var(--kritzel-selection-border-color, #007AFF)',
26560
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26561
- strokeLinecap: 'square',
26562
- } })), !this.isSelecting && (index.h("g", { class: "selection-group-handles", style: { pointerEvents: 'auto' } }, index.h("rect", { class: "resize-handle top-left", x: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26563
- fill: 'var(--kritzel-selection-handle-color, #ffffff)',
26564
- stroke: 'var(--kritzel-selection-handle-stroke-color, #007AFF)',
26565
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26566
- paintOrder: 'fill',
26567
- } }), index.h("rect", { class: "resize-handle-overlay top-left", x: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26568
- fill: 'transparent',
26569
- paintOrder: 'fill',
26570
- } }), index.h("rect", { class: "resize-handle top-right", x: `${object.totalWidth - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26571
- fill: 'var(--kritzel-selection-handle-color, #ffffff)',
26572
- stroke: 'var(--kritzel-selection-handle-stroke-color, #007AFF)',
26573
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26574
- paintOrder: 'fill',
26575
- } }), index.h("rect", { class: "resize-handle-overlay top-right", x: `${object.totalWidth - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26576
- fill: 'transparent',
26577
- paintOrder: 'fill',
26578
- } }), index.h("rect", { class: "resize-handle bottom-left", x: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26579
- fill: 'var(--kritzel-selection-handle-color, #ffffff)',
26580
- stroke: 'var(--kritzel-selection-handle-stroke-color, #007AFF)',
26581
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26582
- paintOrder: 'fill',
26583
- } }), index.h("rect", { class: "resize-handle-overlay bottom-left", x: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26584
- fill: 'transparent',
26585
- paintOrder: 'fill',
26586
- } }), index.h("rect", { class: "resize-handle bottom-right", x: `${object.totalWidth - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26587
- fill: 'var(--kritzel-selection-handle-color, #ffffff)',
26588
- stroke: 'var(--kritzel-selection-handle-stroke-color, #007AFF)',
26589
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26590
- paintOrder: 'fill',
26591
- } }), index.h("rect", { class: "resize-handle-overlay bottom-right", x: `${object.totalWidth - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26592
- fill: 'transparent',
26593
- paintOrder: 'fill',
26594
- } }), index.h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 * object.scale) / this.core.store.state?.scale), style: {
26595
- stroke: 'var(--kritzel-selection-border-color, #007AFF)',
26596
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26597
- } }), index.h("circle", { class: "rotation-handle", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.core.store.state?.scale), r: `${((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, style: {
26598
- fill: 'var(--kritzel-selection-handle-color, #ffffff)',
26599
- stroke: 'var(--kritzel-selection-handle-stroke-color, #007AFF)',
26600
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26601
- paintOrder: 'fill',
26602
- } }), index.h("circle", { class: "rotation-handle-overlay", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.core.store.state?.scale), r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
26603
- fill: 'transparent',
26604
- paintOrder: 'fill',
26605
- } }))))), this.core.displaySelectionLineUI(object) && workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (index.h("g", { class: "selection-line-ui", style: { pointerEvents: 'none' } }, index.h("g", { class: "selection-line-borders" }, index.h("path", { class: "selection-line-border", d: this.core.anchorManager.computeClippedLinePath(object, true), style: {
26606
- stroke: 'var(--kritzel-selection-border-color, #007AFF)',
26607
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26608
- strokeLinecap: 'round',
26609
- fill: 'none',
26610
- } })), !this.isSelecting && (index.h("g", { class: "selection-line-handles", style: { pointerEvents: 'auto' } }, index.h("circle", { class: "selection-line-handle start", cx: object.startX - object.x, cy: object.startY - object.y, r: `${((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, style: {
26611
- fill: 'var(--kritzel-selection-handle-color, #000000)',
26612
- stroke: 'var(--kritzel-selection-handle-stroke-color, #007AFF)',
26613
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26614
- paintOrder: 'fill',
26615
- } }), index.h("circle", { class: "selection-line-handle-overlay start", "data-testid": "line-handle-start", cx: object.startX - object.x, cy: object.startY - object.y, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
26616
- fill: 'transparent',
26617
- paintOrder: 'fill',
26618
- } }), index.h("circle", { class: "selection-line-handle center", cx: object.controlX !== undefined
26619
- ? (object.startX + 2 * object.controlX + object.endX) / 4 - object.x
26620
- : (object.startX - object.x + object.endX - object.x) / 2, cy: object.controlY !== undefined
26621
- ? (object.startY + 2 * object.controlY + object.endY) / 4 - object.y
26622
- : (object.startY - object.y + object.endY - object.y) / 2, r: `${((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, style: {
26623
- fill: 'var(--kritzel-selection-handle-color, #000000)',
26624
- stroke: 'var(--kritzel-selection-handle-stroke-color, #007AFF)',
26625
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26626
- paintOrder: 'fill',
26627
- } }), index.h("circle", { class: "selection-line-handle-overlay center", "data-testid": "line-handle-center", cx: object.controlX !== undefined
26628
- ? (object.startX + 2 * object.controlX + object.endX) / 4 - object.x
26629
- : (object.startX - object.x + object.endX - object.x) / 2, cy: object.controlY !== undefined
26630
- ? (object.startY + 2 * object.controlY + object.endY) / 4 - object.y
26631
- : (object.startY - object.y + object.endY - object.y) / 2, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
26632
- fill: 'transparent',
26633
- paintOrder: 'fill',
26634
- } }), index.h("circle", { class: "selection-line-handle end", cx: object.endX - object.x, cy: object.endY - object.y, r: `${((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, style: {
26635
- fill: 'var(--kritzel-selection-handle-color, #000000)',
26636
- stroke: 'var(--kritzel-selection-handle-stroke-color, #007AFF)',
26637
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26638
- paintOrder: 'fill',
26639
- } }), index.h("circle", { class: "selection-line-handle-overlay end", "data-testid": "line-handle-end", cx: object.endX - object.x, cy: object.endY - object.y, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
26640
- fill: 'transparent',
26641
- paintOrder: 'fill',
26642
- } })))))))));
26909
+ } }, index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
26910
+ (() => {
26911
+ const isRemoteSelection = workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') &&
26912
+ object.userId != null &&
26913
+ this.core.user?.id != null &&
26914
+ object.userId !== this.core.user.id;
26915
+ let remoteUserColor;
26916
+ if (isRemoteSelection) {
26917
+ const awarenessStates = this.core.store.state.objects?.awareness?.getStates();
26918
+ if (awarenessStates) {
26919
+ for (const state of awarenessStates.values()) {
26920
+ if (state.user?.id === object.userId) {
26921
+ remoteUserColor = state.user.color;
26922
+ break;
26923
+ }
26924
+ }
26925
+ }
26926
+ }
26927
+ const selectionBorderColor = remoteUserColor
26928
+ ?? (workspace_migrations.KritzelColorHelper.resolveThemeColor(object.borderColor, currentTheme) || 'var(--kritzel-selection-border-color, #007AFF)');
26929
+ const selectionHandleStrokeColor = remoteUserColor
26930
+ ?? 'var(--kritzel-selection-handle-stroke-color, #007AFF)';
26931
+ return (index.h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
26932
+ zIndex: (object.zIndex + 1).toString(),
26933
+ height: object?.totalHeight.toString(),
26934
+ width: object?.totalWidth.toString(),
26935
+ left: '0',
26936
+ top: '0',
26937
+ position: 'absolute',
26938
+ transform: `rotate(${object.rotationDegrees}deg)`,
26939
+ transformOrigin: `${object.totalWidth / 2}px ${object.totalHeight / 2}px`,
26940
+ overflow: 'visible',
26941
+ pointerEvents: 'none',
26942
+ } }, this.core.displaySelectionGroupUI(object) && (index.h("g", { class: "selection-group-ui", style: { pointerEvents: 'none' } }, (() => {
26943
+ const remoteLineObject = isRemoteSelection &&
26944
+ workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') &&
26945
+ object.objects.length === 1 &&
26946
+ workspace_migrations.KritzelClassHelper.isInstanceOf(object.objects[0], 'KritzelLine')
26947
+ ? object.objects[0]
26948
+ : null;
26949
+ if (remoteLineObject) {
26950
+ return (index.h("g", { class: "selection-line-borders" }, index.h("path", { class: "selection-line-border", d: this.core.anchorManager.computeClippedLinePath(remoteLineObject, true), style: {
26951
+ stroke: selectionBorderColor,
26952
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26953
+ strokeLinecap: 'round',
26954
+ fill: 'none',
26955
+ } })));
26956
+ }
26957
+ return (index.h("g", { class: "selection-group-borders" }, index.h("line", { x1: "0", y1: "0", x2: object.totalWidth, y2: "0", style: {
26958
+ stroke: selectionBorderColor,
26959
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26960
+ strokeLinecap: 'square',
26961
+ } }), index.h("line", { x1: "0", y1: "0", x2: "0", y2: object.totalHeight, style: {
26962
+ stroke: selectionBorderColor,
26963
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26964
+ strokeLinecap: 'square',
26965
+ } }), index.h("line", { x1: "0", y1: object.totalHeight, x2: object.totalWidth, y2: object.totalHeight, style: {
26966
+ stroke: selectionBorderColor,
26967
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26968
+ strokeLinecap: 'square',
26969
+ } }), index.h("line", { x1: object.totalWidth, y1: "0", x2: object.totalWidth, y2: object.totalHeight, style: {
26970
+ stroke: selectionBorderColor,
26971
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
26972
+ strokeLinecap: 'square',
26973
+ } })));
26974
+ })(), !this.isSelecting && !isRemoteSelection && (index.h("g", { class: "selection-group-handles", style: { pointerEvents: 'auto' } }, index.h("rect", { class: "resize-handle top-left", x: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26975
+ fill: 'var(--kritzel-selection-handle-color, #ffffff)',
26976
+ stroke: selectionHandleStrokeColor,
26977
+ strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26978
+ paintOrder: 'fill',
26979
+ } }), index.h("rect", { class: "resize-handle-overlay top-left", x: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26980
+ fill: 'transparent',
26981
+ paintOrder: 'fill',
26982
+ } }), index.h("rect", { class: "resize-handle top-right", x: `${object.totalWidth - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26983
+ fill: 'var(--kritzel-selection-handle-color, #ffffff)',
26984
+ stroke: selectionHandleStrokeColor,
26985
+ strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26986
+ paintOrder: 'fill',
26987
+ } }), index.h("rect", { class: "resize-handle-overlay top-right", x: `${object.totalWidth - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26988
+ fill: 'transparent',
26989
+ paintOrder: 'fill',
26990
+ } }), index.h("rect", { class: "resize-handle bottom-left", x: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26991
+ fill: 'var(--kritzel-selection-handle-color, #ffffff)',
26992
+ stroke: selectionHandleStrokeColor,
26993
+ strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
26994
+ paintOrder: 'fill',
26995
+ } }), index.h("rect", { class: "resize-handle-overlay bottom-left", x: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26996
+ fill: 'transparent',
26997
+ paintOrder: 'fill',
26998
+ } }), index.h("rect", { class: "resize-handle bottom-right", x: `${object.totalWidth - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
26999
+ fill: 'var(--kritzel-selection-handle-color, #ffffff)',
27000
+ stroke: selectionHandleStrokeColor,
27001
+ strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
27002
+ paintOrder: 'fill',
27003
+ } }), index.h("rect", { class: "resize-handle-overlay bottom-right", x: `${object.totalWidth - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
27004
+ fill: 'transparent',
27005
+ paintOrder: 'fill',
27006
+ } }), index.h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 * object.scale) / this.core.store.state?.scale), style: {
27007
+ stroke: selectionBorderColor,
27008
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
27009
+ } }), index.h("circle", { class: "rotation-handle", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.core.store.state?.scale), r: `${((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, style: {
27010
+ fill: 'var(--kritzel-selection-handle-color, #ffffff)',
27011
+ stroke: selectionHandleStrokeColor,
27012
+ strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
27013
+ paintOrder: 'fill',
27014
+ } }), index.h("circle", { class: "rotation-handle-overlay", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.core.store.state?.scale), r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
27015
+ fill: 'transparent',
27016
+ paintOrder: 'fill',
27017
+ } }))))), this.core.displaySelectionLineUI(object) && workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (index.h("g", { class: "selection-line-ui", style: { pointerEvents: 'none' } }, index.h("g", { class: "selection-line-borders" }, index.h("path", { class: "selection-line-border", d: this.core.anchorManager.computeClippedLinePath(object, true), style: {
27018
+ stroke: selectionBorderColor,
27019
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
27020
+ strokeLinecap: 'round',
27021
+ fill: 'none',
27022
+ } })), !this.isSelecting && !isRemoteSelection && (index.h("g", { class: "selection-line-handles", style: { pointerEvents: 'auto' } }, index.h("circle", { class: "selection-line-handle start", cx: object.startX - object.x, cy: object.startY - object.y, r: `${((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, style: {
27023
+ fill: 'var(--kritzel-selection-handle-color, #000000)',
27024
+ stroke: selectionHandleStrokeColor,
27025
+ strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
27026
+ paintOrder: 'fill',
27027
+ } }), index.h("circle", { class: "selection-line-handle-overlay start", "data-testid": "line-handle-start", cx: object.startX - object.x, cy: object.startY - object.y, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
27028
+ fill: 'transparent',
27029
+ paintOrder: 'fill',
27030
+ } }), index.h("circle", { class: "selection-line-handle center", cx: object.controlX !== undefined
27031
+ ? (object.startX + 2 * object.controlX + object.endX) / 4 - object.x
27032
+ : (object.startX - object.x + object.endX - object.x) / 2, cy: object.controlY !== undefined
27033
+ ? (object.startY + 2 * object.controlY + object.endY) / 4 - object.y
27034
+ : (object.startY - object.y + object.endY - object.y) / 2, r: `${((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, style: {
27035
+ fill: 'var(--kritzel-selection-handle-color, #000000)',
27036
+ stroke: selectionHandleStrokeColor,
27037
+ strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
27038
+ paintOrder: 'fill',
27039
+ } }), index.h("circle", { class: "selection-line-handle-overlay center", "data-testid": "line-handle-center", cx: object.controlX !== undefined
27040
+ ? (object.startX + 2 * object.controlX + object.endX) / 4 - object.x
27041
+ : (object.startX - object.x + object.endX - object.x) / 2, cy: object.controlY !== undefined
27042
+ ? (object.startY + 2 * object.controlY + object.endY) / 4 - object.y
27043
+ : (object.startY - object.y + object.endY - object.y) / 2, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
27044
+ fill: 'transparent',
27045
+ paintOrder: 'fill',
27046
+ } }), index.h("circle", { class: "selection-line-handle end", cx: object.endX - object.x, cy: object.endY - object.y, r: `${((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, style: {
27047
+ fill: 'var(--kritzel-selection-handle-color, #000000)',
27048
+ stroke: selectionHandleStrokeColor,
27049
+ strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
27050
+ paintOrder: 'fill',
27051
+ } }), index.h("circle", { class: "selection-line-handle-overlay end", "data-testid": "line-handle-end", cx: object.endX - object.x, cy: object.endY - object.y, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
27052
+ fill: 'transparent',
27053
+ paintOrder: 'fill',
27054
+ } })))))));
27055
+ })()));
26643
27056
  }), (() => {
26644
27057
  const data = this.core.anchorManager.getAnchorLinesRenderData();
26645
27058
  if (!data)
@@ -26724,7 +27137,7 @@ const KritzelEngine = class {
26724
27137
  y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
26725
27138
  }, this.core.store.selectionGroup?.objects);
26726
27139
  this.hideContextMenu();
26727
- }, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof workspace_migrations.KritzelEraserTool && !this.core.store.state.isScaling && index.h("kritzel-cursor-trail", { core: this.core })));
27140
+ }, onClose: () => this.hideContextMenu() })), this.core.store.state.objects?.hasAwareness && index.h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof workspace_migrations.KritzelEraserTool && !this.core.store.state.isScaling && index.h("kritzel-cursor-trail", { core: this.core })));
26728
27141
  }
26729
27142
  static get watchers() { return {
26730
27143
  "workspace": [{
@@ -26847,7 +27260,7 @@ const KritzelExport = class {
26847
27260
  return (index.h("div", { class: "export-tab-content" }, index.h("kritzel-input", { label: "Filename", value: this.exportFilename, placeholder: "Enter filename", suffix: ".json", onValueChange: this.handleFilenameChange })));
26848
27261
  }
26849
27262
  render() {
26850
- return (index.h(index.Host, { key: 'e0b87fc15a375fdd82283d75b477d987db8b81ca' }, index.h("kritzel-dialog", { key: 'bd360887428ce5f43f6fc8871c6acb8b5e373216', isOpen: this.isDialogOpen, dialogTitle: "Export", closable: true, onDialogClose: this.closeDialog }, index.h("div", { key: '7787b3be81cfbc812bc7430399a9c3ad4c230cdb', class: "export-content" }, index.h("kritzel-pill-tabs", { key: '942677f661c85092233d69b681fbf174968cbb61', tabs: this.tabs, value: this.activeTab, onValueChange: this.handleTabChange }), this.activeTab === 'viewport' && this.renderViewportExport(), this.activeTab === 'workspace' && this.renderWorkspaceExport(), index.h("button", { key: '19a39246beff8b8b36770581e8d1c45b0a9ea5f4', class: "export-primary-button", onClick: this.handleExport }, "Export")))));
27263
+ return (index.h(index.Host, { key: '89824b452ccc845f4dfd1e13c01a24a72e5d9488' }, index.h("kritzel-dialog", { key: 'a9190d093e84b5850146db39e1016abce9de0d83', isOpen: this.isDialogOpen, dialogTitle: "Export", closable: true, onDialogClose: this.closeDialog }, index.h("div", { key: '3068dbb979a029bf580e2d00a721768bc08d12b3', class: "export-content" }, index.h("kritzel-pill-tabs", { key: '6241491cc549f576b822bc9fda37c9edffd9143f', tabs: this.tabs, value: this.activeTab, onValueChange: this.handleTabChange }), this.activeTab === 'viewport' && this.renderViewportExport(), this.activeTab === 'workspace' && this.renderWorkspaceExport(), index.h("button", { key: 'a9fe2a7ccb5b97095271a6e00fe9585f39b137fc', class: "export-primary-button", onClick: this.handleExport }, "Export")))));
26851
27264
  }
26852
27265
  };
26853
27266
  KritzelExport.style = kritzelExportCss();
@@ -26862,7 +27275,7 @@ const KritzelFont = class {
26862
27275
  size = 24;
26863
27276
  color = '#000000';
26864
27277
  render() {
26865
- return (index.h(index.Host, { key: '70bc1c26fc43bffbd3df59c60453e3229725c8d1' }, index.h("div", { key: 'd7ed7c78581f8ce760dd6c143a311ee540a4df94', class: "font-preview", style: {
27278
+ return (index.h(index.Host, { key: '3d5fd9aecf7abc96c438b890f5831281d6194922' }, index.h("div", { key: '2b3df82e475177e803f172f440ffcee97dbe5aa5', class: "font-preview", style: {
26866
27279
  fontFamily: this.fontFamily,
26867
27280
  fontSize: `${this.size}px`,
26868
27281
  color: this.color
@@ -26937,7 +27350,7 @@ const KritzelFontSize = class {
26937
27350
  }
26938
27351
  render() {
26939
27352
  const color = 'var(--kritzel-global-text-primary)';
26940
- return (index.h(index.Host, { key: 'ceea18a28a3b292ee89839a7a183da2000eaf156' }, this.sizes.map(size => (index.h("div", { tabIndex: 0, class: {
27353
+ return (index.h(index.Host, { key: '32615ac4756efd047219b93642f7b5cc7d80669b' }, this.sizes.map(size => (index.h("div", { tabIndex: 0, class: {
26941
27354
  'size-container': true,
26942
27355
  'selected': this.selectedSize === size,
26943
27356
  }, onClick: () => this.handleSizeClick(size), onKeyDown: event => this.handleKeyDown(event, size) }, index.h("kritzel-font", { fontFamily: this.fontFamily, size: size, color: color }))))));
@@ -27004,7 +27417,7 @@ const KritzelInput = class {
27004
27417
  this.valueChange.emit(input.value);
27005
27418
  };
27006
27419
  render() {
27007
- return (index.h(index.Host, { key: '1b151bb26c9398c5c29e3d3367cb6ba21e6864fe' }, index.h("div", { key: 'd2ba0fa75ad80e357d6684928bd48aeaa102a706', class: "input-container" }, this.label && index.h("label", { key: '47ed17ec74d26b29fc7857780d070d6cfac157f1', class: "input-label" }, this.label), index.h("div", { key: 'bfcbe25bf4b876e7f5466a2f48dd63309fb310a5', class: { 'input-wrapper': true, 'has-suffix': !!this.suffix } }, index.h("input", { key: 'ef58442a0bd2fee845a9d35ddc9d04b357d93940', type: this.type, class: "text-input", value: this.inputValue, placeholder: this.placeholder, disabled: this.disabled, onInput: this.handleInput }), this.suffix && index.h("span", { key: '8b6f73557fa2c44cf0ba7720685306e29df44179', class: "input-suffix" }, this.suffix)))));
27420
+ return (index.h(index.Host, { key: '5cfc93853afd27dd24ff9709dcd277571ae4d0a1' }, index.h("div", { key: 'fa0a43610b98ffbc30bf9485a4f8730b80f74ab7', class: "input-container" }, this.label && index.h("label", { key: '151346732ef4a00a1ea78bbc19ac56a94488dfc4', class: "input-label" }, this.label), index.h("div", { key: '79b28f6f45cdacf7d122988bb4c844c929544cce', class: { 'input-wrapper': true, 'has-suffix': !!this.suffix } }, index.h("input", { key: 'e22abd0e10ee231b2e66f50085693769584a1254', type: this.type, class: "text-input", value: this.inputValue, placeholder: this.placeholder, disabled: this.disabled, onInput: this.handleInput }), this.suffix && index.h("span", { key: '5c96287d24dc28f4ac321f108a356527194f4e81', class: "input-suffix" }, this.suffix)))));
27008
27421
  }
27009
27422
  static get watchers() { return {
27010
27423
  "value": [{
@@ -27144,7 +27557,7 @@ const KritzelLoginDialog = class {
27144
27557
  this.dialogClosed.emit();
27145
27558
  };
27146
27559
  render() {
27147
- return (index.h(index.Host, { key: '1daa4d598e883bb5d212d681692bde9de4a09969' }, index.h("kritzel-dialog", { key: 'ae21cc3a8978ea19cba8a07a3a22f791efd20915', dialogTitle: this.dialogTitle, isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, size: "small" }, index.h("div", { key: '81c278e44685a040066caccb747f272182b10ee6', class: "login-content" }, this.subtitle && (index.h("p", { key: '9a2478c3713cc119b933fbf7f928f4928d14b0d7', class: "login-subtitle" }, this.subtitle)), index.h("div", { key: '0e273e0c48886f68d0ffec9c46a5427cc8949ddc', class: "login-providers" }, this.providers.map(provider => (index.h("button", { key: provider.name, class: {
27560
+ return (index.h(index.Host, { key: '21b548c3d1391203a02a33e66afa5d3dae603071' }, index.h("kritzel-dialog", { key: '1254e8bdc8e84e71e606109e20f938ecb42b05e3', dialogTitle: this.dialogTitle, isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, size: "small" }, index.h("div", { key: '99d23d7c0d52da043c3d59ee9d527d02e68d3b2b', class: "login-content" }, this.subtitle && (index.h("p", { key: '7ce2131761e0127a190dbc1f7b4cd32884e4657b', class: "login-subtitle" }, this.subtitle)), index.h("div", { key: 'bc32c6e61856c963cf9c0d22bfe5935c6c55568d', class: "login-providers" }, this.providers.map(provider => (index.h("button", { key: provider.name, class: {
27148
27561
  'provider-button': true,
27149
27562
  'is-loading': this.loadingProvider === provider.name,
27150
27563
  'is-disabled': this.loadingProvider !== null && this.loadingProvider !== provider.name,
@@ -27250,15 +27663,15 @@ const KritzelMasterDetail = class {
27250
27663
  const selectedItem = this.items.find(item => item.id === this.selectedItemId);
27251
27664
  const panelId = 'master-detail-panel';
27252
27665
  const selectedTabId = selectedItem ? `tab-${selectedItem.id}` : undefined;
27253
- return (index.h(index.Host, { key: 'fbdbf1151992c991945de48b593a8c9d0b6ed788' }, index.h("div", { key: 'e46113c8f3f0aa7ca376a288f5bccc8d25789880', class: {
27666
+ return (index.h(index.Host, { key: '25913464ef131f1332146a5372c0caf9f7050f24' }, index.h("div", { key: '206346f9bee671f1b283ebfaca4c4401706a074f', class: {
27254
27667
  'master-detail-container': true,
27255
27668
  'is-mobile-detail-visible': this.showMobileDetail,
27256
- } }, index.h("nav", { key: '7c125b758e71eb9082d2c0583ba6aad95123776d', class: "master-menu", role: "tablist", "aria-orientation": "vertical", "aria-label": "Settings categories" }, this.items.map((item, index$1) => (index.h("button", { key: item.id, id: `tab-${item.id}`, ref: el => this.setTabRef(el, index$1), class: {
27669
+ } }, index.h("nav", { key: 'f4cf41f060d1d25887d2b11a264de040e878d25c', class: "master-menu", role: "tablist", "aria-orientation": "vertical", "aria-label": "Settings categories" }, this.items.map((item, index$1) => (index.h("button", { key: item.id, id: `tab-${item.id}`, ref: el => this.setTabRef(el, index$1), class: {
27257
27670
  'menu-item': true,
27258
27671
  'is-selected': item.id === this.selectedItemId,
27259
27672
  'is-disabled': !!item.disabled,
27260
27673
  'is-focused': index$1 === this.focusedIndex,
27261
- }, role: "tab", "aria-selected": item.id === this.selectedItemId ? 'true' : 'false', "aria-controls": panelId, "aria-disabled": item.disabled ? 'true' : undefined, tabIndex: this.getTabIndex(item, index$1), disabled: item.disabled, onClick: () => this.handleItemClick(item), onKeyDown: e => this.handleKeyDown(e, item, index$1), onFocus: () => this.handleFocus(index$1), onBlur: this.handleBlur }, item.icon && (index.h("kritzel-icon", { name: item.icon, size: 20, class: "menu-item-icon" })), index.h("span", { class: "menu-item-label" }, item.label), index.h("span", { class: "menu-item-chevron", "aria-hidden": "true" }, index.h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("path", { d: "m9 18 6-6-6-6" }))))))), index.h("div", { key: '1ead5122c67ba7ea40065240d921deaf0c3ca76f', id: panelId, class: "detail-panel", role: "tabpanel", "aria-labelledby": selectedTabId }, index.h("button", { key: 'a31f779aa0a70ce76dadb7028d2cee46e0e8be05', class: "mobile-back-button", onClick: this.handleBackClick, "aria-label": "Back to menu" }, index.h("kritzel-icon", { key: '355c38dfe879ef89a431d0c674304b32cbb2022b', name: "chevron-left", size: 20, class: "mobile-back-icon" }), "Back"), index.h("slot", { key: 'f70d9250d8f7a0c1d31b3f706a1494778b60f5dc' })))));
27674
+ }, role: "tab", "aria-selected": item.id === this.selectedItemId ? 'true' : 'false', "aria-controls": panelId, "aria-disabled": item.disabled ? 'true' : undefined, tabIndex: this.getTabIndex(item, index$1), disabled: item.disabled, onClick: () => this.handleItemClick(item), onKeyDown: e => this.handleKeyDown(e, item, index$1), onFocus: () => this.handleFocus(index$1), onBlur: this.handleBlur }, item.icon && (index.h("kritzel-icon", { name: item.icon, size: 20, class: "menu-item-icon" })), index.h("span", { class: "menu-item-label" }, item.label), index.h("span", { class: "menu-item-chevron", "aria-hidden": "true" }, index.h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("path", { d: "m9 18 6-6-6-6" }))))))), index.h("div", { key: 'efb20b2c1c6dfcf03bee2c1ef06c2c7a6de27e7a', id: panelId, class: "detail-panel", role: "tabpanel", "aria-labelledby": selectedTabId }, index.h("button", { key: '13b97670c0c0b7f8fe493438d26179cd5039cd9c', class: "mobile-back-button", onClick: this.handleBackClick, "aria-label": "Back to menu" }, index.h("kritzel-icon", { key: '6a52e00dd7fc61bcacce71127bf78637bbff7e30', name: "chevron-left", size: 20, class: "mobile-back-icon" }), "Back"), index.h("slot", { key: '99bd31682d0e8accc6c2eacfcbaf6778f3b92d05' })))));
27262
27675
  }
27263
27676
  static get watchers() { return {
27264
27677
  "selectedItemId": [{
@@ -27331,7 +27744,7 @@ const KritzelMenu = class {
27331
27744
  this.itemCloseChildMenu.emit(event.detail);
27332
27745
  };
27333
27746
  render() {
27334
- return (index.h(index.Host, { key: '9c5cf77bd92351cac399076343ca35d26c9d2230', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && index.h("div", { key: 'b7df3b9b683c51093701abd789290ccfcfbdc3cf', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (index.h("kritzel-menu-item", { key: item.id, item: item, parent: this.parent, style: { pointerEvents: this.editingMenuItem && !item.isEditing ? 'none' : 'auto' }, onItemSelect: this.handleItemSelect, onItemSave: this.handleSave, onItemCancel: this.handleCancel, onItemToggleChildMenu: this.handleToggleChildMenu, onItemCloseChildMenu: this.handleCloseChildMenu })))));
27747
+ return (index.h(index.Host, { key: '9a14983012bb0c286a17811d3e3c41743799c560', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && index.h("div", { key: '0540a587c117a09857e9d87b65e019c8fa85c694', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (index.h("kritzel-menu-item", { key: item.id, item: item, parent: this.parent, style: { pointerEvents: this.editingMenuItem && !item.isEditing ? 'none' : 'auto' }, onItemSelect: this.handleItemSelect, onItemSave: this.handleSave, onItemCancel: this.handleCancel, onItemToggleChildMenu: this.handleToggleChildMenu, onItemCloseChildMenu: this.handleCloseChildMenu })))));
27335
27748
  }
27336
27749
  };
27337
27750
  KritzelMenu.style = kritzelMenuCss();
@@ -27436,12 +27849,12 @@ const KritzelMenuItem = class {
27436
27849
  ];
27437
27850
  }
27438
27851
  render() {
27439
- return (index.h(index.Host, { key: 'f81a52f2536c759530b0b069ff02e0a71c363b0a', tabIndex: this.item.isDisabled ? -1 : 0, class: {
27852
+ return (index.h(index.Host, { key: '5a0d685c83cb3f82e64e74feef124ae0c9bca162', tabIndex: this.item.isDisabled ? -1 : 0, class: {
27440
27853
  'selected': this.item.isSelected,
27441
27854
  'editing': this.item.isEditing,
27442
27855
  'disabled': this.item.isDisabled,
27443
27856
  'child-open': this.item.isChildMenuOpen,
27444
- }, onClick: this.handleItemSelect }, index.h("div", { key: '212dbdbfc7a1cac000c8b25f9f51ad3de5420219', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
27857
+ }, onClick: this.handleItemSelect }, index.h("div", { key: '02415ff1e0abf326ae284ed5b31b2a0241d4c7e2', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
27445
27858
  }
27446
27859
  static get watchers() { return {
27447
27860
  "item": [{
@@ -27508,7 +27921,7 @@ const KritzelMoreMenu = class {
27508
27921
  this.closeMenu();
27509
27922
  };
27510
27923
  render() {
27511
- return (index.h(index.Host, { key: '02d18106b6a932cd4508bebc6ada3416f38eafc6', class: { mobile: this.isTouchDevice } }, index.h("button", { key: 'dff3f7bd69f8f1eafbff03b9ecc2f96c85784a85', class: "more-menu-button", onClick: this.toggleMenu }, index.h("kritzel-icon", { key: '28586ce5dd15be347cc59555608a2cbbf2978a2b', name: this.icon, size: this.iconSize })), index.h("kritzel-portal", { key: '3ca9260c3602a639687bc1341736c15a1b5c10a7', anchor: this.menuAnchor, offsetY: this.offsetY, onClose: this.closeMenu }, index.h("kritzel-menu", { key: 'e8e88cc9f827d93d9adcc86ad1041774cfc282af', items: this.visibleItems, onItemSelect: this.handleMenuItemSelect }))));
27924
+ return (index.h(index.Host, { key: '951577ab19a6bb10e7c578546a386e6159d16aff', class: { mobile: this.isTouchDevice } }, index.h("button", { key: '2b5112a4458544945c91536cb974e230401c6cd2', class: "more-menu-button", onClick: this.toggleMenu }, index.h("kritzel-icon", { key: 'e37122c20fa642ad4e53ae039ab43539f3b5b195', name: this.icon, size: this.iconSize })), index.h("kritzel-portal", { key: '5b4fd597eb4ec299ca672194f0dd69d3d50c270b', anchor: this.menuAnchor, offsetY: this.offsetY, onClose: this.closeMenu }, index.h("kritzel-menu", { key: 'a3a48b1ebb064293ecb6bb06f1783cba849d2ade', items: this.visibleItems, onItemSelect: this.handleMenuItemSelect }))));
27512
27925
  }
27513
27926
  };
27514
27927
  KritzelMoreMenu.style = kritzelMoreMenuCss();
@@ -27606,7 +28019,7 @@ const KritzelNumericInput = class {
27606
28019
  this.valueChange.emit(newValue);
27607
28020
  };
27608
28021
  render() {
27609
- return (index.h(index.Host, { key: '8f8984a3b29bad180be48c0d0cfdb269cbfb4c68' }, index.h("div", { key: '94e161c3dd1a8d05270f4611a5ba19323f8d9657', class: "input-container" }, this.label && index.h("label", { key: '53d8ba3d7fd0fcc888aaa167754854cc3ab9c98b', class: "input-label" }, this.label), index.h("div", { key: '4b0d15134fbdacf2a64213e73265adfb1e468525', class: "input-wrapper" }, index.h("input", { key: '59f62088b3a85aa8dfa3d9b1c04f50c289e4ab67', type: "number", class: "numeric-input", title: "", min: this.min === Number.MIN_SAFE_INTEGER ? undefined : this.min, max: this.max === Number.MAX_SAFE_INTEGER ? undefined : this.max, step: this.step, value: this.inputValue, placeholder: this.placeholder, onInput: this.handleInput, onBlur: this.handleBlur, onKeyDown: this.handleKeyDown, onInvalid: this.handleInvalid }), index.h("div", { key: '2fe741f055b0a05e1605096287bda58a84760363', class: "spinner-buttons" }, index.h("button", { key: '0777d4483dc2ec8835a232d5da3f8fb8ce7acce2', type: "button", class: "spinner-button spinner-up", onClick: this.handleIncrement, tabIndex: -1, "aria-label": "Increase value" }, index.h("svg", { key: '37b962d0fcae37f6e8cf552e7a36d015b377f3ff', viewBox: "0 0 10 6", class: "spinner-icon" }, index.h("path", { key: 'd2916bc1cc40476418b9ee2e8c5c16172be90c2b', d: "M1 5L5 1L9 5", stroke: "currentColor", "stroke-width": "1.5", fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }))), index.h("button", { key: 'c3f8c27fef2f95787d3a6e1a1d46c92f4bf20a8e', type: "button", class: "spinner-button spinner-down", onClick: this.handleDecrement, tabIndex: -1, "aria-label": "Decrease value" }, index.h("svg", { key: '35658bd8d44502509b3b6bda3490962e180fb692', viewBox: "0 0 10 6", class: "spinner-icon" }, index.h("path", { key: '67672b3a12f4973570698a8bd0a8cb856c0d0f82', d: "M1 1L5 5L9 1", stroke: "currentColor", "stroke-width": "1.5", fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }))))))));
28022
+ return (index.h(index.Host, { key: '9f5b165e9c4db1cc6724020e12d18beb0a70ad11' }, index.h("div", { key: 'e5e3d790f9d9bd7bb2d25367bb7d7d86c731091f', class: "input-container" }, this.label && index.h("label", { key: '0ee62b45cbfe34405a888d0d61af472936b0a453', class: "input-label" }, this.label), index.h("div", { key: '49bbdca156346c1e0dd7b08d6790ae5829fa6d1f', class: "input-wrapper" }, index.h("input", { key: '986e05275c90bee119ff3c803d90ba16a0005f8d', type: "number", class: "numeric-input", title: "", min: this.min === Number.MIN_SAFE_INTEGER ? undefined : this.min, max: this.max === Number.MAX_SAFE_INTEGER ? undefined : this.max, step: this.step, value: this.inputValue, placeholder: this.placeholder, onInput: this.handleInput, onBlur: this.handleBlur, onKeyDown: this.handleKeyDown, onInvalid: this.handleInvalid }), index.h("div", { key: '4c468fdca0018390bdc57f1b2fd7fa2e68b09f98', class: "spinner-buttons" }, index.h("button", { key: '7b433424c6817049b6229e249d715ebd43dfe350', type: "button", class: "spinner-button spinner-up", onClick: this.handleIncrement, tabIndex: -1, "aria-label": "Increase value" }, index.h("svg", { key: '666b0c184d00d000a1fa97d4bdda3a9a6b0d299d', viewBox: "0 0 10 6", class: "spinner-icon" }, index.h("path", { key: '223f829a0b808e9fdde656294729121e2c8ae0d3', d: "M1 5L5 1L9 5", stroke: "currentColor", "stroke-width": "1.5", fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }))), index.h("button", { key: '40f72b01e59b98c7bca4952c94eeb631fe3d17a1', type: "button", class: "spinner-button spinner-down", onClick: this.handleDecrement, tabIndex: -1, "aria-label": "Decrease value" }, index.h("svg", { key: '5f304877010fc9fa1c7559270b5105659b2f4863', viewBox: "0 0 10 6", class: "spinner-icon" }, index.h("path", { key: 'e31b6f1edb583eebbf608fc5360c53d49d4d2d5c', d: "M1 1L5 5L9 1", stroke: "currentColor", "stroke-width": "1.5", fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }))))))));
27610
28023
  }
27611
28024
  static get watchers() { return {
27612
28025
  "value": [{
@@ -27645,7 +28058,7 @@ const KritzelOpacitySlider = class {
27645
28058
  }
27646
28059
  render() {
27647
28060
  const percentage = this.getPercentage();
27648
- return (index.h(index.Host, { key: '01ab026ae319eaf7bebdd74f5d06e79be4871630' }, index.h("div", { key: '67a5dec5570d7f16162fb5d43f18e020f642df68', class: "opacity-container" }, index.h("div", { key: '87362a95645b164331c58c46add78e1497e27ba1', class: "slider-wrapper" }, index.h("input", { key: '0ec74a8e864c7ac47a5ac4eea4d1c960d10214d4', type: "range", class: "opacity-slider", min: this.min, max: this.max, step: this.step, value: this.value, onInput: (e) => this.handleInput(e), style: {
28061
+ return (index.h(index.Host, { key: 'a0307b2fc97221881f0e2a21035427fcf0c5fdb3' }, index.h("div", { key: 'a77c6e973f92671daa3a8299b51d70b2d2fd98db', class: "opacity-container" }, index.h("div", { key: 'c5df7c6fe6db3aa9a8430ea7580d6cc7a23666b8', class: "slider-wrapper" }, index.h("input", { key: '6d3cae027e5a9b391f36ede911dedb201630d525', type: "range", class: "opacity-slider", min: this.min, max: this.max, step: this.step, value: this.value, onInput: (e) => this.handleInput(e), style: {
27649
28062
  '--slider-progress': `${percentage}%`,
27650
28063
  } })))));
27651
28064
  }
@@ -27981,7 +28394,7 @@ const KritzelPortal = class {
27981
28394
  this.portal.style.visibility = 'visible';
27982
28395
  }
27983
28396
  render() {
27984
- return (index.h(index.Host, { key: '14116403d3ecb83928b66999da1561f233fd23e9', style: { display: this.anchor ? 'block' : 'none' } }, index.h("slot", { key: '1f5d5789b30699de4d332b89e51356fa06b34bf3' })));
28397
+ return (index.h(index.Host, { key: '70a29385ee7f1bef37f903e1e6821b46fc9a147f', style: { display: this.anchor ? 'block' : 'none' } }, index.h("slot", { key: '8f50bce48c3aa82abbfc34331f8e80f205a45f03' })));
27985
28398
  }
27986
28399
  static get watchers() { return {
27987
28400
  "anchor": [{
@@ -27995,7 +28408,7 @@ const KritzelPortal = class {
27995
28408
  * This file is auto-generated by the version bump scripts.
27996
28409
  * Do not modify manually.
27997
28410
  */
27998
- const KRITZEL_VERSION = '0.1.72';
28411
+ const KRITZEL_VERSION = '0.1.74';
27999
28412
 
28000
28413
  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)}`;
28001
28414
 
@@ -28190,7 +28603,7 @@ const KritzelSettings = class {
28190
28603
  }
28191
28604
  }
28192
28605
  render() {
28193
- return (index.h(index.Host, { key: 'fc940d4154b06378cf13f7cde5238f4a1ac1d2ba' }, index.h("kritzel-dialog", { key: '0c50f5cb3570eba67ce4c04f9f453361e0c9626a', isOpen: this.isDialogOpen, dialogTitle: "Settings", size: "large", onDialogClose: this.closeDialog }, index.h("kritzel-master-detail", { key: '974adda5868d1261784366b59e285a0c45d265ca', items: SETTINGS_CATEGORIES, selectedItemId: this.selectedCategoryId, onItemSelect: this.handleCategorySelect }, this.renderCategoryContent()))));
28606
+ return (index.h(index.Host, { key: '0d4cd5ad565a1ff1140f308765ff887ba68ba6c8' }, index.h("kritzel-dialog", { key: '170a15a41d18f56981a99aae266026625d7fe644', isOpen: this.isDialogOpen, dialogTitle: "Settings", size: "large", onDialogClose: this.closeDialog }, index.h("kritzel-master-detail", { key: '6569f351fdef57dd189af63f7d6c4d98ce815c1b', items: SETTINGS_CATEGORIES, selectedItemId: this.selectedCategoryId, onItemSelect: this.handleCategorySelect }, this.renderCategoryContent()))));
28194
28607
  }
28195
28608
  };
28196
28609
  KritzelSettings.style = kritzelSettingsCss();
@@ -28316,9 +28729,9 @@ const KritzelShareDialog = class {
28316
28729
  this.dialogClosed.emit();
28317
28730
  };
28318
28731
  render() {
28319
- return (index.h(index.Host, { key: '0e498848cf6c680cd7ce0233b258317ae967262a' }, index.h("kritzel-dialog", { key: 'f5d1c6fbf454d5a46e60a915a405ca0926e1b5e3', dialogTitle: "Share Workspace", isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, size: "small" }, index.h("div", { key: '1348d2969058a5d4d2e992c9c2df5c7ec57591ed', class: "share-content" }, index.h("div", { key: '7c7c349c0af3b125eff301d229731b64c4a51d0a', class: "share-section" }, index.h("div", { key: 'c1498b2b2ac6717925ce806bc3fea6af3e611709', class: "share-row" }, index.h("div", { key: '44c268fa61994cff17d6a0082347c18374d92243', class: "share-label-group" }, index.h("label", { key: '1a56501131c2dd0666d9755930d52cacc3b703c5', class: "share-label" }, "Link sharing"), index.h("p", { key: 'fd4fca65f5258e040eff95d1f27059240ed7aa6a', class: "share-description" }, this.internalIsPublic
28732
+ return (index.h(index.Host, { key: 'f1d9bac1ed73b3c028d77bec2eb0882b08ec12c8' }, index.h("kritzel-dialog", { key: '952e6c6c8ed5b2260c7b540524044a8704796cd9', dialogTitle: "Share Workspace", isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, size: "small" }, index.h("div", { key: '1834e98b32be60eebf499ff7d021b16f2d9ad018', class: "share-content" }, index.h("div", { key: 'bc19e19e35de1513a1b337ad96a5e58b1c987751', class: "share-section" }, index.h("div", { key: '0310309b3389827d94be755d926eeda87d434148', class: "share-row" }, index.h("div", { key: 'ed3171611a010df28ead03955f413083e615f908', class: "share-label-group" }, index.h("label", { key: '90cc0d814c973bd02e4fb8b871b20561804e08dc', class: "share-label" }, "Link sharing"), index.h("p", { key: '02ae9eb9aeaf7e1153873da7f6501bdf0fc27096', class: "share-description" }, this.internalIsPublic
28320
28733
  ? 'Anyone with the link can access this workspace.'
28321
- : 'Link sharing is disabled. Only you can access this workspace.')), index.h("kritzel-slide-toggle", { key: '69214469344850ac81dad9462e6a3547ebf6f48f', checked: this.internalIsPublic, onCheckedChange: this.handleToggleChange, label: "Enable link sharing" }))), this.internalIsPublic && (index.h("div", { key: '9a26ca0ca3e447ae4cc0b4a20de666b97a90b20f', class: "share-section" }, index.h("div", { key: '753dbfd83f83ac81c6296cfc6bbf59ddf514897c', class: "share-url-container" }, index.h("input", { key: '2515209593b5c59792606f8915d62f83c7b35160', type: "text", class: "share-url-input", value: this.getShareUrl(), readOnly: true, onClick: (e) => e.target.select() }), index.h("button", { key: '1d62fb016514e8a16eb354aff139db43af7585f3', class: { 'copy-button': true, 'copy-success': this.copySuccess }, onClick: this.handleCopyUrl, title: this.copySuccess ? 'Copied!' : 'Copy link' }, index.h("kritzel-icon", { key: 'a9824261a6914aff927866409c02a42ca8faf44f', name: this.copySuccess ? 'check' : 'copy', size: 18 })))))))));
28734
+ : 'Link sharing is disabled. Only you can access this workspace.')), index.h("kritzel-slide-toggle", { key: '656ff6bff6dff3956b73072766b73642c13cf968', checked: this.internalIsPublic, onCheckedChange: this.handleToggleChange, label: "Enable link sharing" }))), this.internalIsPublic && (index.h("div", { key: 'dfc591b157b9ae5c268d77b7a7aab4168c80690d', class: "share-section" }, index.h("div", { key: '54f71d05705ddca92ccf1637e0ad7318127b6e72', class: "share-url-container" }, index.h("input", { key: 'fa1a9fad703a30e87daa8c3f83c782349103809a', type: "text", class: "share-url-input", value: this.getShareUrl(), readOnly: true, onClick: (e) => e.target.select() }), index.h("button", { key: 'd879775f7df013855e748c48dda63470ee0f66c4', class: { 'copy-button': true, 'copy-success': this.copySuccess }, onClick: this.handleCopyUrl, title: this.copySuccess ? 'Copied!' : 'Copy link' }, index.h("kritzel-icon", { key: '985ee904561df3bd182697f7b95bc0e64c7f70d5', name: this.copySuccess ? 'check' : 'copy', size: 18 })))))))));
28322
28735
  }
28323
28736
  static get watchers() { return {
28324
28737
  "isPublic": [{
@@ -28356,7 +28769,7 @@ const KritzelSlideToggle = class {
28356
28769
  }
28357
28770
  };
28358
28771
  render() {
28359
- return (index.h(index.Host, { key: 'd294d9becd13e8373bd029508ded3f47ee344184', class: { checked: this.checked, disabled: this.disabled }, tabIndex: this.disabled ? -1 : 0, role: "switch", "aria-checked": this.checked ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.label, onClick: this.handleToggle, onKeyDown: this.handleKeyDown }, index.h("div", { key: '3b5349c9b1f2126c9075f979c8b1a7b098060abb', class: "toggle-track" }, index.h("div", { key: '0bb5a44e73071d819611863e24af433ed56fb80d', class: "toggle-thumb" }))));
28772
+ return (index.h(index.Host, { key: 'fa4a31e3978f5a7187c8e011d58278829f60f912', class: { checked: this.checked, disabled: this.disabled }, tabIndex: this.disabled ? -1 : 0, role: "switch", "aria-checked": this.checked ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.label, onClick: this.handleToggle, onKeyDown: this.handleKeyDown }, index.h("div", { key: '1ae5a58c6cedf19626cba1e04abe566669582081', class: "toggle-track" }, index.h("div", { key: 'e11d42017fd624837f9e44f2671b74d38e4d015f', class: "toggle-thumb" }))));
28360
28773
  }
28361
28774
  };
28362
28775
  KritzelSlideToggle.style = kritzelSlideToggleCss();
@@ -28456,7 +28869,7 @@ const KritzelSplitButton = class {
28456
28869
  this.menuScrollTop = event.target.scrollTop;
28457
28870
  };
28458
28871
  render() {
28459
- return (index.h(index.Host, { key: '1e85f2b22cde41378d03710bd1332e2eb91ebe5a', class: { mobile: this.isTouchDevice } }, index.h("button", { key: '56573ad5655b2f61e1ebf3c4d85b489375beb62e', class: "split-main-button", tabIndex: 0, onClick: this.handleButtonClick, disabled: this.mainButtonDisabled }, this.buttonIcon && index.h("kritzel-icon", { key: '335c2f5418e305f3e48e3caabc4c48001ddd5ec3', name: this.buttonIcon })), index.h("div", { key: '733e48020f3b21b22de3774323e5a2d024686c2c', class: "split-divider" }), index.h("button", { key: '650cd557b856b5527910cbdeb6d14fe7a88bc0ab', ref: el => (this.splitMenuButtonRef = el), class: "split-menu-button", tabIndex: 0, onClick: this.toggleMenu, disabled: this.menuButtonDisabled }, index.h("kritzel-icon", { key: '3aaacbcdd66583e3884fe44777794209753fe594', name: this.dropdownIcon })), index.h("kritzel-portal", { key: 'd0ca70c21dfbf1684ab84650a31aae77df5cb52e', anchor: this.anchorElement, offsetY: 4, onClose: this.closeMenu }, index.h("kritzel-menu", { key: '9e38d4d6e1c82b6dca3c6d23fb5c0df12bfbefb4', ref: el => (this.menuRef = el), items: this.items, onItemSelect: this.handleItemSelect, onItemSave: this.handleItemSave, onItemCancel: this.handleItemCancel, onItemToggleChildMenu: this.handleItemToggleChildMenu, onItemCloseChildMenu: this.handleItemCloseChildMenu, onClose: this.closeMenu, onScroll: this.handleScroll }))));
28872
+ return (index.h(index.Host, { key: 'dbb1a5f61cae17d47d3d31959172189d842a1e0c', class: { mobile: this.isTouchDevice } }, index.h("button", { key: '081650f6ee9f8f4c6c7d8d0d72b72d116162034b', class: "split-main-button", tabIndex: 0, onClick: this.handleButtonClick, disabled: this.mainButtonDisabled }, this.buttonIcon && index.h("kritzel-icon", { key: '870353d092212556316e5881cd817208f138dfff', name: this.buttonIcon })), index.h("div", { key: '2254a771e8b73a5e0037e48f45cbf3819f6d83a6', class: "split-divider" }), index.h("button", { key: '0c42a970441e6f3530f686b8825f7de9b8395a07', ref: el => (this.splitMenuButtonRef = el), class: "split-menu-button", tabIndex: 0, onClick: this.toggleMenu, disabled: this.menuButtonDisabled }, index.h("kritzel-icon", { key: 'a958954d14c3f8f0e86d7d927f116c9a28a1fb43', name: this.dropdownIcon })), index.h("kritzel-portal", { key: '98b72e3da54dadb51a51f591dbae47dab439ac8e', anchor: this.anchorElement, offsetY: 4, onClose: this.closeMenu }, index.h("kritzel-menu", { key: '9f505415219b5741f483c659a00c1655c6652ca7', ref: el => (this.menuRef = el), items: this.items, onItemSelect: this.handleItemSelect, onItemSave: this.handleItemSave, onItemCancel: this.handleItemCancel, onItemToggleChildMenu: this.handleItemToggleChildMenu, onItemCloseChildMenu: this.handleItemCloseChildMenu, onClose: this.closeMenu, onScroll: this.handleScroll }))));
28460
28873
  }
28461
28874
  };
28462
28875
  KritzelSplitButton.style = kritzelSplitButtonCss();
@@ -28476,7 +28889,7 @@ const KritzelStrokeSize = class {
28476
28889
  this.sizeChange.emit(size);
28477
28890
  }
28478
28891
  render() {
28479
- return (index.h(index.Host, { key: '2095245a9a1ae7781cf1030baaa93e6462b3c09e' }, index.h("div", { key: 'b83777024ef29d90f072a0ab002cf17a766825be', class: "size-grid" }, this.sizes.map(size => (index.h("div", { tabIndex: 0, class: {
28892
+ return (index.h(index.Host, { key: 'd7b77c754e247879f94b05f9c7b282d2aec22035' }, index.h("div", { key: '1f1c95ccb4b8f5500d73e4eafa775aa1dd93d83c', class: "size-grid" }, this.sizes.map(size => (index.h("div", { tabIndex: 0, class: {
28480
28893
  'size-container': true,
28481
28894
  'selected': this.selectedSize === size,
28482
28895
  }, onClick: () => this.handleSizeClick(size) }, index.h("kritzel-color", { value: 'var(--kritzel-global-text-primary)', size: size })))))));
@@ -28820,14 +29233,14 @@ const KritzelTooltip = class {
28820
29233
  }
28821
29234
  }
28822
29235
  render() {
28823
- return (index.h(index.Host, { key: '788500c800ec72ed8fd1ac7972d503c0a60a35b1', style: {
29236
+ return (index.h(index.Host, { key: '0f67bc5736d65b2dcb277bfea3a052e165213c01', style: {
28824
29237
  position: 'fixed',
28825
29238
  zIndex: '9999',
28826
29239
  transition: 'opacity 0.3s ease-in-out, transform 0.3s ease-in-out',
28827
29240
  visibility: this.isVisible ? 'visible' : 'hidden',
28828
29241
  left: `${this.positionX}px`,
28829
29242
  bottom: `${this.positionY}px`,
28830
- } }, index.h("div", { key: '7d0633d32290a5c0dc2cef32fac5cf78bb36619b', class: "tooltip-content", onClick: event => event.stopPropagation(), onPointerDown: event => event.stopPropagation(), onMouseDown: event => event.stopPropagation() }, index.h("slot", { key: '512e9e39b890672e09542913783f7b16fae6f444' }))));
29243
+ } }, index.h("div", { key: 'd193b1b6dd28022da87bcce832ae72d630fcd7e0', class: "tooltip-content", onClick: event => event.stopPropagation(), onPointerDown: event => event.stopPropagation(), onMouseDown: event => event.stopPropagation() }, index.h("slot", { key: 'a06478f4a9c995bad3558287341003effa6fc834' }))));
28831
29244
  }
28832
29245
  static get watchers() { return {
28833
29246
  "triggerElement": [{
@@ -28866,7 +29279,7 @@ const KritzelUtilityPanel = class {
28866
29279
  this.redo.emit();
28867
29280
  }
28868
29281
  render() {
28869
- return (index.h(index.Host, { key: '02831a892fee80cc9300282eceb6ee8abcba017e' }, index.h("button", { key: 'a22749cc8772e23d1ed848be2f4173ca9e0023b6', class: "utility-button", "data-testid": "utility-undo", disabled: !this.undoState?.canUndo, onClick: event => this.handleUndo(event) }, index.h("kritzel-icon", { key: '52f08e9e950501151f2f9196d248caa493d46f14', name: "undo" })), index.h("button", { key: '5a858ce4415d29d50928b42c8b7e9bf5380ab08e', class: "utility-button", "data-testid": "utility-redo", disabled: !this.undoState?.canRedo, onClick: event => this.handleRedo(event) }, index.h("kritzel-icon", { key: '9d995aedbcedc5b55021c7bb9c10dddb90602ea0', name: "redo" })), index.h("div", { key: '248c5499808553b0ac587b0aedeaf9db82e21991', class: "utility-separator" }), index.h("button", { key: '901f30f009abc873d360118088886b6f20d672c5', class: "utility-button", "data-testid": "utility-delete", onClick: () => this.delete.emit() }, index.h("kritzel-icon", { key: '82d4e1531360cc57038f161f13212cccd9df1285', name: "delete" }))));
29282
+ return (index.h(index.Host, { key: '0277e775741c91fe53daea8b14f9fdec550bef45' }, index.h("button", { key: '7eff5491f732dc6871b382612cf64a4d661fa39b', class: "utility-button", "data-testid": "utility-undo", disabled: !this.undoState?.canUndo, onClick: event => this.handleUndo(event) }, index.h("kritzel-icon", { key: '4eff979e1b6158df5a1b17c702765432bd18f642', name: "undo" })), index.h("button", { key: '73d75b36bfbd9d4299aea16be54ed6e1687a47d1', class: "utility-button", "data-testid": "utility-redo", disabled: !this.undoState?.canRedo, onClick: event => this.handleRedo(event) }, index.h("kritzel-icon", { key: 'd1556e8b7aa32b102aad9ea572d040e8863197c3', name: "redo" })), index.h("div", { key: 'eefbdb33bb73d5a48db79fe9621a91da77ddd46d', class: "utility-separator" }), index.h("button", { key: '15630243403ff4475123e209d0c3e7919718bc00', class: "utility-button", "data-testid": "utility-delete", onClick: () => this.delete.emit() }, index.h("kritzel-icon", { key: '7a423865d246a4752fc8fa3411133d0bd4f1c75d', name: "delete" }))));
28870
29283
  }
28871
29284
  };
28872
29285
  KritzelUtilityPanel.style = kritzelUtilityPanelCss();
@@ -29016,6 +29429,7 @@ KritzelWorkspaceManager.style = kritzelWorkspaceManagerCss();
29016
29429
 
29017
29430
  exports.kritzel_active_users = KritzelActiveUsers;
29018
29431
  exports.kritzel_avatar = KritzelAvatar;
29432
+ exports.kritzel_awareness_cursors = KritzelAwarenessCursors;
29019
29433
  exports.kritzel_back_to_content = KritzelBackToContent;
29020
29434
  exports.kritzel_button = KritzelButton;
29021
29435
  exports.kritzel_color = KritzelColorComponent;