kritzel-stencil 0.4.21 → 0.4.22

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 (29) hide show
  1. package/dist/cjs/index.cjs.js +50 -1
  2. package/dist/cjs/kritzel-active-users_47.cjs.entry.js +128 -31
  3. package/dist/collection/classes/providers/sync/hocuspocus-sync-provider.class.js +21 -0
  4. package/dist/collection/classes/providers/sync/websocket-sync-provider.class.js +29 -1
  5. package/dist/collection/classes/structures/app-state-map.structure.js +4 -1
  6. package/dist/collection/classes/structures/object-map.structure.js +66 -4
  7. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +42 -9
  8. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +44 -17
  9. package/dist/collection/constants/version.js +1 -1
  10. package/dist/components/index.js +51 -2
  11. package/dist/components/kritzel-editor.js +16 -11
  12. package/dist/components/kritzel-engine.js +1 -1
  13. package/dist/components/kritzel-settings.js +1 -1
  14. package/dist/components/{p-C_f_QElb.js → p-BNeE3SiZ.js} +113 -21
  15. package/dist/components/{p-BdCrcQ0_.js → p-Dx5NfJ0U.js} +1 -1
  16. package/dist/esm/index.js +50 -1
  17. package/dist/esm/kritzel-active-users_47.entry.js +128 -31
  18. package/dist/stencil/index.esm.js +50 -1
  19. package/dist/stencil/{p-832b80e9.entry.js → p-ab5c4292.entry.js} +128 -31
  20. package/dist/stencil/stencil.esm.js +1 -1
  21. package/dist/types/classes/providers/sync/hocuspocus-sync-provider.class.d.ts +5 -0
  22. package/dist/types/classes/providers/sync/websocket-sync-provider.class.d.ts +6 -0
  23. package/dist/types/classes/structures/object-map.structure.d.ts +26 -2
  24. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +3 -0
  25. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +9 -1
  26. package/dist/types/components.d.ts +8 -1
  27. package/dist/types/constants/version.d.ts +1 -1
  28. package/dist/types/interfaces/sync-provider.interface.d.ts +13 -0
  29. package/package.json +1 -1
@@ -2146,6 +2146,8 @@ const KritzelEditor = class {
2146
2146
  this.login = createEvent(this, "login");
2147
2147
  this.isPublicChange = createEvent(this, "isPublicChange");
2148
2148
  this.awarenessChange = createEvent(this, "awarenessChange");
2149
+ this.syncingChange = createEvent(this, "syncingChange");
2150
+ this.loadingChange = createEvent(this, "loadingChange");
2149
2151
  }
2150
2152
  get host() { return getElement(this); }
2151
2153
  scaleMax = ABSOLUTE_SCALE_MAX;
@@ -2385,6 +2387,9 @@ const KritzelEditor = class {
2385
2387
  login;
2386
2388
  isPublicChange;
2387
2389
  awarenessChange;
2390
+ /** Emitted while remote changes are being applied to the active workspace. Stays silent when the remote holds nothing new. */
2391
+ syncingChange;
2392
+ loadingChange;
2388
2393
  isEngineReady = false;
2389
2394
  isControlsReady = false;
2390
2395
  isWorkspaceManagerReady = false;
@@ -3203,40 +3208,40 @@ const KritzelEditor = class {
3203
3208
  const isLoggedIn = this.isLoggedIn;
3204
3209
  const shouldShowCurrentUser = isLoggedIn;
3205
3210
  const shouldShowLoginButton = this.isReady && !!this.loginConfig && !isLoggedIn;
3206
- return (h(Host, { key: 'd9d87b5ca40972d7ab2c5986f340278347f78c6e' }, h("div", { key: 'd8da2ed24d19c550420689c6720dc491fe0d3a22', class: "editor-content", style: {
3211
+ return (h(Host, { key: 'ff7d505697bd4c4bd840dadcb04a934b7e243a01' }, h("div", { key: 'b40076c3c79ad3f879e80c58b412b79266de2ea8', class: "editor-content", style: {
3207
3212
  opacity: this.isEditorVisible ? '1' : '0',
3208
3213
  visibility: this.isEditorVisible ? 'visible' : 'hidden',
3209
3214
  transition: 'opacity 0.2s ease-in-out, visibility 0.2s ease-in-out',
3210
- } }, h("div", { key: '82a5d216e7c95307b1bdbd1f06fdfe881c1c50d4', class: "top-left-buttons" }, h("kritzel-workspace-manager", { key: 'de13673384b44bb6bd309a927a2866a9b78b519e', visible: this.isWorkspaceManagerVisible, workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, terms: this.resolvedTerms, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-back-to-content", { key: 'f68610d7d91713f7a0ec5f0135d208769f7fab9c', visible: this.isBackToContentButtonVisible, text: this.resolvedTerms['backToContent.label'] ?? 'Back to content', onBackToContent: () => this.backToContent() })), this.activeNotification && (h("div", { key: '9d1f972fb67050b1f996e3088710713fa1219b9a', class: "top-center-notification-layer", role: "presentation" }, h("div", { key: '295eff0a02f7cc79ad8e80cda23baa3c576ce156', class: { 'top-center-notification-container': true, 'is-dismissing': this.isNotificationDismissing }, role: "presentation" }, h("kritzel-notification-card", { key: '1d1bf140ddfb7b927d30fb1d77e7b887240d7deb', notification: this.activeNotification, locale: this.locale, onDismiss: this.dismissNotification, onHoverChange: event => this.handleNotificationHoverChange(event) })))), this.contextMenuState && this.contextMenuState.items.length > 0 && (h("kritzel-context-menu", { key: '1062bc9554e5834ef2002fbfe953f7938866fb84', class: "context-menu", items: this.contextMenuState.items, objects: this.contextMenuState.objects, style: {
3215
+ } }, h("div", { key: '1b1171eea60a36ad06da55a3da564bc356526266', class: "top-left-buttons" }, h("kritzel-workspace-manager", { key: '48b59f3f57ace57debc19a295d4fb642e8c3b23d', visible: this.isWorkspaceManagerVisible, workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, terms: this.resolvedTerms, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-back-to-content", { key: 'c66a6faae8bf7115dcce47630ad820af9ba76eb0', visible: this.isBackToContentButtonVisible, text: this.resolvedTerms['backToContent.label'] ?? 'Back to content', onBackToContent: () => this.backToContent() })), this.activeNotification && (h("div", { key: '834baedc5f20328deb4ee586f693313306895a71', class: "top-center-notification-layer", role: "presentation" }, h("div", { key: 'f800508a2e076ee3e89820ffff4df81842b175b3', class: { 'top-center-notification-container': true, 'is-dismissing': this.isNotificationDismissing }, role: "presentation" }, h("kritzel-notification-card", { key: '2835ea84e8fa92c41637adaa29d9005f209b2da9', notification: this.activeNotification, locale: this.locale, onDismiss: this.dismissNotification, onHoverChange: event => this.handleNotificationHoverChange(event) })))), this.contextMenuState && this.contextMenuState.items.length > 0 && (h("kritzel-context-menu", { key: '6c49e899b7f933d3f06cd1f8696a590d542214a7', class: "context-menu", items: this.contextMenuState.items, objects: this.contextMenuState.objects, style: {
3211
3216
  position: 'absolute',
3212
3217
  left: `${this.contextMenuState.position.x}px`,
3213
3218
  top: `${this.contextMenuState.position.y}px`,
3214
3219
  zIndex: '10002',
3215
- }, onActionSelected: event => this.handleContextMenuActionSelected(event), onClose: () => this.hideContextMenu() })), h("kritzel-sync-indicator", { key: '0094a026828473988f857d82cfccb811f36f049c', visible: this.isSyncing, text: "Syncing..." }), h("kritzel-loading-overlay", { key: '680096e20b6175104a866b9a92ca4c1d0087c93a', visible: this.isLoadingOverlayVisible, text: this.resolvedTerms['editor.loading'] ?? 'Loading...' }), h("kritzel-engine", { key: '0698a44fcbf2d6ea786d53502350ac0c9ffb9d66', ref: el => {
3220
+ }, onActionSelected: event => this.handleContextMenuActionSelected(event), onClose: () => this.hideContextMenu() })), h("kritzel-sync-indicator", { key: '9622af1634a939d6689d5a133496d536f5d7865f', visible: this.isSyncing, text: "Syncing..." }), h("kritzel-loading-overlay", { key: '00f142a3eb8b23fbd0bdb6ec53ae95855434516c', visible: this.isLoadingOverlayVisible, text: this.resolvedTerms['editor.loading'] ?? 'Loading...' }), h("kritzel-engine", { key: '39b1d7bfce0a5347fec60cd135d6db8fb4250bfa', ref: el => {
3216
3221
  if (el) {
3217
3222
  this.engineRef = el;
3218
3223
  }
3219
- }, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, assetStorageConfig: this.assetStorageConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, isObjectDistanceFadingActive: this.isObjectDistanceFadingActive, scaleMin: this.scaleMin, cursorTarget: this.cursorTarget, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, isPanningEnabled: this.isPanningEnabled, isZoomingEnabled: this.isZoomingEnabled, theme: this.theme, themes: this.themes, licenseKey: this.licenseKey, locale: this.locale, locales: this.locales, fallbackLocale: this.fallbackLocale, 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), onNotificationsChange: event => this.handleNotificationsChange(event), onContextMenuStateChange: event => this.handleContextMenuStateChange(event), onSyncingChange: event => (this.isSyncing = event.detail), onLoadingChange: event => (this.isLoadingOverlayVisible = event.detail) }), h("kritzel-controls", { key: '765a670807111ad68e9f8d14bdca2651a33704d4', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
3224
+ }, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, assetStorageConfig: this.assetStorageConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, isObjectDistanceFadingActive: this.isObjectDistanceFadingActive, scaleMin: this.scaleMin, cursorTarget: this.cursorTarget, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, isPanningEnabled: this.isPanningEnabled, isZoomingEnabled: this.isZoomingEnabled, theme: this.theme, themes: this.themes, licenseKey: this.licenseKey, locale: this.locale, locales: this.locales, fallbackLocale: this.fallbackLocale, 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), onNotificationsChange: event => this.handleNotificationsChange(event), onContextMenuStateChange: event => this.handleContextMenuStateChange(event), onSyncingChange: event => (this.isSyncing = event.detail), onLoadingChange: event => (this.isLoadingOverlayVisible = event.detail) }), h("kritzel-controls", { key: '9a708f21ab92ecc6953a35f5db8001b2403f330e', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
3220
3225
  if (el) {
3221
3226
  this.controlsRef = el;
3222
3227
  }
3223
- }, controls: this.normalizedControls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, terms: this.resolvedTerms, onIsControlsReady: () => (this.isControlsReady = true) }), h("div", { key: 'e7c5ebab4a40b7ab4fa5d19d203129326c0009ed', class: "bottom-left-buttons" }, h("kritzel-zoom-panel", { key: '0aa3891b553d2abcd06e635227fd6bb6656ed739', visible: this.isZoomPanelVisible, disabled: !this.isZoomingEnabled, zoomPercent: this.currentZoomPercent, terms: this.resolvedTerms, onZoomIn: () => this.zoomIn(), onZoomOut: () => this.zoomOut() })), h("div", { key: '824244bbd78784c1d78ab89cc12e206ca61d84cc', class: "top-right-buttons" }, h("kritzel-settings", { key: 'baf4830b6b9ccb6241b1a1baa5cc6ff9d0295fb9', ref: el => {
3228
+ }, controls: this.normalizedControls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, terms: this.resolvedTerms, onIsControlsReady: () => (this.isControlsReady = true) }), h("div", { key: '6a2b1cd72099db86952ac31aad9655693d0a6a0d', class: "bottom-left-buttons" }, h("kritzel-zoom-panel", { key: 'b3756514bf8de6de8ac7586c626f9759da7f231d', visible: this.isZoomPanelVisible, disabled: !this.isZoomingEnabled, zoomPercent: this.currentZoomPercent, terms: this.resolvedTerms, onZoomIn: () => this.zoomIn(), onZoomOut: () => this.zoomOut() })), h("div", { key: 'd5e118bc4d60b867006bac287c5516baf3aa890e', class: "top-right-buttons" }, h("kritzel-settings", { key: 'e4065d36beb9283cdbbf3ae9800f4f8011c0b4f0', ref: el => {
3224
3229
  if (el) {
3225
3230
  this.settingsRef = el;
3226
3231
  }
3227
- }, shortcuts: this.shortcuts, availableThemes: this.themes && this.themes.length > 0 ? this.themes.map(t => t.name) : ['light', 'dark'], availableLocales: this.availableLocaleOptions, settings: this.currentSettingsConfig, terms: this.resolvedTerms, onSettingsChange: event => this.handleSettingsChange(event) }), h("kritzel-export", { key: '57e2682450c71803cd49bfe65f16e02d9d3358bc', ref: el => {
3232
+ }, shortcuts: this.shortcuts, availableThemes: this.themes && this.themes.length > 0 ? this.themes.map(t => t.name) : ['light', 'dark'], availableLocales: this.availableLocaleOptions, settings: this.currentSettingsConfig, terms: this.resolvedTerms, onSettingsChange: event => this.handleSettingsChange(event) }), h("kritzel-export", { key: '4e18d9b42c9e7fef9433577b983c508559461da2', ref: el => {
3228
3233
  if (el) {
3229
3234
  this.exportRef = el;
3230
3235
  }
3231
- }, workspaceName: this.activeWorkspace?.name || 'workspace', terms: this.resolvedTerms, onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: '955d2a61b98d937f8eec39ab19f1b73e702c9fd7', users: this.activeUsers }), shouldShowCurrentUser && h("kritzel-current-user", { key: 'c0885e0c8cab1a4cb50c8f6d4b17e03f32cc2b87', user: this.user, terms: this.resolvedTerms, onClick: () => this.currentUserDialogRef?.open() }), shouldShowCurrentUser && (h("kritzel-current-user-dialog", { key: 'fc70555061d2aeaebdbe981bdbe8cf501bd8120e', ref: el => {
3236
+ }, workspaceName: this.activeWorkspace?.name || 'workspace', terms: this.resolvedTerms, onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: '56e6b29c9c3dcd7b68af4a1ef7d34224d592ce34', users: this.activeUsers }), shouldShowCurrentUser && h("kritzel-current-user", { key: '3b90bcc7e583fcf3c6845d222ad181ccf234a423', user: this.user, terms: this.resolvedTerms, onClick: () => this.currentUserDialogRef?.open() }), shouldShowCurrentUser && (h("kritzel-current-user-dialog", { key: 'f87702c5a708b6afdb2bc3760895e3e3650a4cb5', ref: el => {
3232
3237
  if (el) {
3233
3238
  this.currentUserDialogRef = el;
3234
3239
  }
3235
- }, user: this.user, terms: this.resolvedTerms, onLogoutRequest: this.handleCurrentUserLogout })), shouldShowLoginButton && h("kritzel-button", { key: '9666163a2a36a64ecb641659dca515ae30409d0f', onButtonClick: () => this.loginDialogRef?.open() }, this.resolvedTerms['login.dialogTitle'] ?? 'Sign in'), h("kritzel-more-menu", { key: '167ac17ea93897597e83d4fe8b3b561fac848bb6', items: this.resolvedMoreMenuItems, visible: this.isMoreMenuVisible, terms: this.resolvedTerms }), h("kritzel-share-dialog", { key: '10cfb0b794d613ec39299f06ac1a3402d1ad3084', ref: el => {
3240
+ }, user: this.user, terms: this.resolvedTerms, onLogoutRequest: this.handleCurrentUserLogout })), shouldShowLoginButton && h("kritzel-button", { key: '015bc0f4c66352136de66d35d28c20070366933f', onButtonClick: () => this.loginDialogRef?.open() }, this.resolvedTerms['login.dialogTitle'] ?? 'Sign in'), h("kritzel-more-menu", { key: 'b3fdf9fdb2a34508002e82dfdef9e9bdbbe57ecc', items: this.resolvedMoreMenuItems, visible: this.isMoreMenuVisible, terms: this.resolvedTerms }), h("kritzel-share-dialog", { key: 'bac4fbbfa04c261e2b128e766cc43c1062aec2ff', ref: el => {
3236
3241
  if (el) {
3237
3242
  this.shareDialogRef = el;
3238
3243
  }
3239
- }, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, terms: this.resolvedTerms, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: '99dcb9051382982ec5a8975bdd991bae57745bb9', ref: el => {
3244
+ }, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, terms: this.resolvedTerms, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: 'a7d52bad9e752ad546adf80d257c6a46de031e76', ref: el => {
3240
3245
  if (el) {
3241
3246
  this.loginDialogRef = el;
3242
3247
  }
@@ -22279,6 +22284,10 @@ class KritzelObjectMap {
22279
22284
  _awarenessChangeHandler = null;
22280
22285
  _awarenessChangeCallbacks = [];
22281
22286
  _objectsChangeCallbacks = [];
22287
+ _remoteChangesCallbacks = [];
22288
+ _docUpdateHandler = null;
22289
+ _remoteOrigins = new Set();
22290
+ _appliedRemoteChanges = false;
22282
22291
  _lastAwarenessEmitTime = 0;
22283
22292
  _awarenessEmitTimeout = null;
22284
22293
  AWARENESS_THROTTLE_INTERVAL = 100; // milliseconds
@@ -22302,12 +22311,44 @@ class KritzelObjectMap {
22302
22311
  return this._isReady;
22303
22312
  }
22304
22313
  /**
22305
- * Promise that settles when network providers finish connecting.
22306
- * Resolves immediately if no network providers. Awaited by the loading overlay.
22314
+ * Promise that settles when network providers finish connecting and complete
22315
+ * their Yjs sync handshake. Resolves immediately if no network providers.
22307
22316
  */
22308
22317
  whenNetworkSynced() {
22309
22318
  return this._networkSyncPromise ?? Promise.resolve();
22310
22319
  }
22320
+ /**
22321
+ * Whether any configured provider synchronizes over the network.
22322
+ */
22323
+ get hasNetworkSyncProvider() {
22324
+ return this._providers.some(provider => provider.type === 'network');
22325
+ }
22326
+ /**
22327
+ * Whether remote-originated changes can be told apart from local writes.
22328
+ * Requires every network provider to expose its Yjs update origin.
22329
+ */
22330
+ get supportsRemoteChangeDetection() {
22331
+ const networkProviders = this._providers.filter(provider => provider.type === 'network');
22332
+ return networkProviders.length > 0 && networkProviders.every(provider => provider.updateOrigin !== undefined);
22333
+ }
22334
+ /**
22335
+ * Whether at least one update originating from a network provider has been
22336
+ * applied to this document. Stays `false` when the remote held no data the
22337
+ * local document was missing, because Yjs suppresses empty updates.
22338
+ */
22339
+ get hasAppliedRemoteChanges() {
22340
+ return this._appliedRemoteChanges;
22341
+ }
22342
+ /**
22343
+ * Registers a callback invoked whenever a network provider applies changes to this document.
22344
+ * @returns A function that unregisters the callback.
22345
+ */
22346
+ onRemoteChangesApplied(callback) {
22347
+ this._remoteChangesCallbacks.push(callback);
22348
+ return () => {
22349
+ this._remoteChangesCallbacks = this._remoteChangesCallbacks.filter(registered => registered !== callback);
22350
+ };
22351
+ }
22311
22352
  /**
22312
22353
  * Returns the Yjs Awareness instance, if a network provider is available.
22313
22354
  */
@@ -22550,6 +22591,22 @@ class KritzelObjectMap {
22550
22591
  const providerList = this._providers.map(p => `${p.constructor.name} (${p.type})`).join(', ');
22551
22592
  console.info(`[Kritzel] Workspace sync providers initialized for ${docName}: ${providerList || 'none'}`);
22552
22593
  }
22594
+ // Registered before any provider connects so no remote update can be missed.
22595
+ for (const provider of this._providers) {
22596
+ if (provider.type === 'network' && provider.updateOrigin !== undefined) {
22597
+ this._remoteOrigins.add(provider.updateOrigin);
22598
+ }
22599
+ }
22600
+ this._docUpdateHandler = (_update, origin) => {
22601
+ if (!this._remoteOrigins.has(origin)) {
22602
+ return;
22603
+ }
22604
+ this._appliedRemoteChanges = true;
22605
+ for (const callback of [...this._remoteChangesCallbacks]) {
22606
+ callback();
22607
+ }
22608
+ };
22609
+ this._ydoc.on('update', this._docUpdateHandler);
22553
22610
  // captureTimeout is effectively infinite — undo-step boundaries are
22554
22611
  // marked explicitly via markUndoBoundary() in insert/remove/reset and
22555
22612
  // at stroke/gesture boundaries in the tools. This prevents a single
@@ -22603,12 +22660,15 @@ class KritzelObjectMap {
22603
22660
  if (showSyncProviderInfo && networkProviders.length > 0) {
22604
22661
  console.info(`[Kritzel] Workspace network providers connecting in background: ${networkProviders.length}`);
22605
22662
  }
22606
- const networkConnectPromises = networkProviders.map(provider => provider.connect().catch(err => {
22663
+ const networkConnectPromises = networkProviders.map(provider => provider
22664
+ .connect()
22665
+ .then(() => provider.whenSynced?.())
22666
+ .catch(err => {
22607
22667
  if (showSyncProviderInfo) {
22608
22668
  console.error(`[Kritzel] Network sync provider "${provider.constructor.name}" failed to connect:`, err);
22609
22669
  }
22610
22670
  }));
22611
- // Network sync awaited by loading overlay to show remote workspace hydration
22671
+ // Settles once remote data has been reconciled, not merely once the transport connected
22612
22672
  this._networkSyncPromise = networkConnectPromises.length > 0 ? Promise.allSettled(networkConnectPromises).then(() => undefined) : null;
22613
22673
  this._isReady = true;
22614
22674
  // Find the first provider that exposes awareness (network providers)
@@ -23266,6 +23326,13 @@ class KritzelObjectMap {
23266
23326
  this._objectsMap.unobserve(this._objectsObserver);
23267
23327
  this._objectsObserver = null;
23268
23328
  }
23329
+ if (this._ydoc && this._docUpdateHandler) {
23330
+ this._ydoc.off('update', this._docUpdateHandler);
23331
+ }
23332
+ this._docUpdateHandler = null;
23333
+ this._remoteOrigins.clear();
23334
+ this._remoteChangesCallbacks = [];
23335
+ this._appliedRemoteChanges = false;
23269
23336
  // Remove undo manager event listeners
23270
23337
  if (this._undoManager) {
23271
23338
  if (this._stackItemAddedHandler) {
@@ -23761,7 +23828,10 @@ class KritzelAppStateMap {
23761
23828
  if (showSyncProviderInfo && networkProviders.length > 0) {
23762
23829
  console.info(`[Kritzel] App-state network providers connecting in background: ${networkProviders.length}`);
23763
23830
  }
23764
- const networkConnectPromises = networkProviders.map(provider => provider.connect().catch(err => {
23831
+ const networkConnectPromises = networkProviders.map(provider => provider
23832
+ .connect()
23833
+ .then(() => provider.whenSynced?.())
23834
+ .catch(err => {
23765
23835
  if (showSyncProviderInfo) {
23766
23836
  console.error(`[Kritzel] Network sync provider "${provider.constructor.name}" failed to connect:`, err);
23767
23837
  }
@@ -27865,7 +27935,7 @@ const KritzelEngine = class {
27865
27935
  contextMenuStateChange;
27866
27936
  /** Emitted when the combined loading state (external `isLoading` prop or internal workspace loading) changes. */
27867
27937
  loadingChange;
27868
- /** Emitted when remote workspace synchronization is in progress. */
27938
+ /** Emitted while remote changes are being applied to the active workspace. Stays silent when the remote holds nothing new. */
27869
27939
  syncingChange;
27870
27940
  forceUpdate = 0;
27871
27941
  isSyncing = false;
@@ -29452,6 +29522,7 @@ const KritzelEngine = class {
29452
29522
  _sceneBootstrapOpacity = 1;
29453
29523
  _sceneBootstrapTransitionEnabled = false;
29454
29524
  _sceneBootstrapTransitionTimer = null;
29525
+ _remoteChangesUnsubscribe = null;
29455
29526
  _defaultUndoState = {
29456
29527
  canUndo: false,
29457
29528
  canRedo: false,
@@ -29469,9 +29540,16 @@ const KritzelEngine = class {
29469
29540
  this.loadingChange.emit(this.core.store.state.isLoading);
29470
29541
  }
29471
29542
  syncSyncingState(isSyncing) {
29543
+ if (this.isSyncing === isSyncing) {
29544
+ return;
29545
+ }
29472
29546
  this.isSyncing = isSyncing;
29473
29547
  this.syncingChange.emit(isSyncing);
29474
29548
  }
29549
+ clearRemoteChangesSubscription() {
29550
+ this._remoteChangesUnsubscribe?.();
29551
+ this._remoteChangesUnsubscribe = null;
29552
+ }
29475
29553
  isNetworkAvailable() {
29476
29554
  return typeof navigator !== 'undefined' && navigator.onLine;
29477
29555
  }
@@ -29583,6 +29661,7 @@ const KritzelEngine = class {
29583
29661
  disconnectedCallback() {
29584
29662
  this.throttledPointerMoveMulti.cancel();
29585
29663
  this._revealedImageKeys.clear();
29664
+ this.clearRemoteChangesSubscription();
29586
29665
  if (this._sceneBootstrapTransitionTimer !== null) {
29587
29666
  clearTimeout(this._sceneBootstrapTransitionTimer);
29588
29667
  this._sceneBootstrapTransitionTimer = null;
@@ -29837,21 +29916,7 @@ const KritzelEngine = class {
29837
29916
  this._workspaceInitializationTargetKey = targetKey;
29838
29917
  try {
29839
29918
  await initializationPromise;
29840
- // Track remote sync in the background without blocking the loading overlay.
29841
- const initializedObjects = this.core.store.objects;
29842
- const networkSyncPromise = initializedObjects?.whenNetworkSynced();
29843
- if (networkSyncPromise && this.isNetworkAvailable()) {
29844
- this.syncSyncingState(true);
29845
- void networkSyncPromise.finally(() => {
29846
- // Only clear syncing for the currently active object map.
29847
- if (this.core.store.objects === initializedObjects) {
29848
- this.syncSyncingState(false);
29849
- }
29850
- });
29851
- }
29852
- else {
29853
- this.syncSyncingState(false);
29854
- }
29919
+ this.trackRemoteSynchronization();
29855
29920
  }
29856
29921
  finally {
29857
29922
  // Only the most recent init clears loading state to prevent race conditions
@@ -29863,6 +29928,38 @@ const KritzelEngine = class {
29863
29928
  }
29864
29929
  }
29865
29930
  }
29931
+ /**
29932
+ * Reports syncing only while remote data is actually being reconciled into the
29933
+ * active workspace. Yjs suppresses updates that carry nothing new, so a workspace
29934
+ * that already matches the remote never reports syncing at all.
29935
+ */
29936
+ trackRemoteSynchronization() {
29937
+ this.clearRemoteChangesSubscription();
29938
+ this.syncSyncingState(false);
29939
+ const initializedObjects = this.core.store.objects;
29940
+ if (!initializedObjects?.hasNetworkSyncProvider || !this.isNetworkAvailable()) {
29941
+ return;
29942
+ }
29943
+ if (initializedObjects.supportsRemoteChangeDetection) {
29944
+ this._remoteChangesUnsubscribe = initializedObjects.onRemoteChangesApplied(() => {
29945
+ if (this.core.store.objects !== initializedObjects) {
29946
+ return;
29947
+ }
29948
+ this.syncSyncingState(true);
29949
+ });
29950
+ }
29951
+ else {
29952
+ // Custom providers without an update origin cannot be diffed, so fall back to reporting the whole handshake.
29953
+ this.syncSyncingState(true);
29954
+ }
29955
+ void initializedObjects.whenNetworkSynced().finally(() => {
29956
+ if (this.core.store.objects !== initializedObjects) {
29957
+ return;
29958
+ }
29959
+ this.clearRemoteChangesSubscription();
29960
+ this.syncSyncingState(false);
29961
+ });
29962
+ }
29866
29963
  emitObjectsChange() {
29867
29964
  const objectsMap = this.core.store.objects;
29868
29965
  if (!objectsMap) {
@@ -32007,7 +32104,7 @@ const KritzelPortal = class {
32007
32104
  * This file is auto-generated by the version bump scripts.
32008
32105
  * Do not modify manually.
32009
32106
  */
32010
- const KRITZEL_VERSION = '0.4.21';
32107
+ const KRITZEL_VERSION = '0.4.22';
32011
32108
 
32012
32109
  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-tab-panel{display:none}.settings-tab-panel.is-active{display:block}.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)}`;
32013
32110
 
@@ -17,5 +17,5 @@ var patchBrowser = () => {
17
17
 
18
18
  patchBrowser().then(async (options) => {
19
19
  await globalScripts();
20
- return bootstrapLazy(JSON.parse("[[\"p-832b80e9\",[[512,\"kritzel-editor\",{\"scaleMax\":[1026,\"scale-max\"],\"scaleMin\":[1026,\"scale-min\"],\"lockDrawingScale\":[1028,\"lock-drawing-scale\"],\"viewportBoundaryLeft\":[1026,\"viewport-boundary-left\"],\"viewportBoundaryRight\":[1026,\"viewport-boundary-right\"],\"viewportBoundaryTop\":[1026,\"viewport-boundary-top\"],\"viewportBoundaryBottom\":[1026,\"viewport-boundary-bottom\"],\"debugInfo\":[1040],\"user\":[16],\"activeUsers\":[16],\"controls\":[16],\"globalContextMenuItems\":[16],\"objectContextMenuItems\":[16],\"moreMenuItems\":[16],\"themes\":[16],\"theme\":[1025],\"licenseKey\":[1,\"license-key\"],\"locale\":[1025],\"locales\":[16],\"fallbackLocale\":[1,\"fallback-locale\"],\"customSvgIcons\":[16],\"customFonts\":[16],\"isPanningEnabled\":[1028,\"is-panning-enabled\"],\"isZoomingEnabled\":[1028,\"is-zooming-enabled\"],\"isControlsVisible\":[4,\"is-controls-visible\"],\"isUtilityPanelVisible\":[4,\"is-utility-panel-visible\"],\"isWorkspaceManagerVisible\":[4,\"is-workspace-manager-visible\"],\"isMoreMenuVisible\":[4,\"is-more-menu-visible\"],\"isZoomPanelVisible\":[4,\"is-zoom-panel-visible\"],\"isObjectDistanceFadingActive\":[4,\"is-object-distance-fading-active\"],\"syncConfig\":[16],\"assetStorageConfig\":[16],\"cursorTarget\":[16],\"loginConfig\":[16],\"isLoading\":[4,\"is-loading\"],\"editorId\":[1,\"editor-id\"],\"activeWorkspaceId\":[1,\"active-workspace-id\"],\"isEngineReady\":[32],\"isControlsReady\":[32],\"isWorkspaceManagerReady\":[32],\"workspaces\":[32],\"activeWorkspace\":[32],\"isVirtualKeyboardOpen\":[32],\"undoState\":[32],\"isBackToContentButtonVisible\":[32],\"resolvedTerms\":[32],\"availableLocaleOptions\":[32],\"currentZoomPercent\":[32],\"shortcuts\":[32],\"currentIsPublic\":[32],\"isEditorVisible\":[32],\"activeNotification\":[32],\"isNotificationDismissing\":[32],\"contextMenuState\":[32],\"normalizedControls\":[32],\"resolvedMoreMenuItems\":[32],\"isSyncing\":[32],\"isLoadingOverlayVisible\":[32],\"getObjectById\":[64],\"addObject\":[64],\"addObjects\":[64],\"updateObject\":[64],\"removeObject\":[64],\"removeObjects\":[64],\"getSelectedObjects\":[64],\"selectObjects\":[64],\"selectAllObjectsInViewport\":[64],\"clearSelection\":[64],\"centerObjectInViewport\":[64],\"panToObject\":[64],\"backToContent\":[64],\"centerAllObjects\":[64],\"centerObjects\":[64],\"setViewport\":[64],\"panTo\":[64],\"zoomTo\":[64],\"zoomIn\":[64],\"zoomOut\":[64],\"getViewport\":[64],\"screenToWorld\":[64],\"worldToScreen\":[64],\"createWorkspace\":[64],\"updateWorkspace\":[64],\"deleteWorkspace\":[64],\"getWorkspaces\":[64],\"getActiveWorkspace\":[64],\"loadSharedWorkspace\":[64],\"reinitSync\":[64],\"registerTool\":[64],\"changeActiveTool\":[64],\"changeActiveToolByName\":[64],\"disable\":[64],\"enable\":[64],\"copy\":[64],\"cut\":[64],\"paste\":[64],\"delete\":[64],\"bringForward\":[64],\"sendBackward\":[64],\"bringToFront\":[64],\"sendToBack\":[64],\"alignObjects\":[64],\"group\":[64],\"ungroup\":[64],\"undo\":[64],\"redo\":[64],\"getScreenshot\":[64],\"exportViewportAsPng\":[64],\"exportViewportAsSvg\":[64],\"getSelectedObjectSupportedExportFormats\":[64],\"canExportSelectedObjectAs\":[64],\"exportSelectedObject\":[64],\"downloadAsJson\":[64],\"importFromFile\":[64],\"loadObjectsFromJson\":[64],\"getObjectsTotalCount\":[64],\"getAllObjects\":[64],\"findObjects\":[64],\"getObjectsInViewport\":[64],\"hideContextMenu\":[64],\"openContextMenu\":[64],\"triggerSelectionChange\":[64],\"beginSceneBootstrap\":[64],\"endSceneBootstrap\":[64],\"getDisplayableShortcuts\":[64],\"triggerNotification\":[64],\"openLoginDialog\":[64],\"setLoginLoading\":[64],\"setLocale\":[64],\"getLocale\":[64],\"getAvailableLocales\":[64],\"registerLocales\":[64],\"registerFonts\":[64],\"t\":[64]},[[0,\"dblclick\",\"onTouchStart\"]],{\"isEngineReady\":[{\"onIsEngineReady\":0}],\"isControlsReady\":[{\"onIsControlsReady\":0}],\"workspaces\":[{\"onWorkspacesChange\":0}],\"activeWorkspace\":[{\"onActiveWorkspaceChange\":0}],\"customFonts\":[{\"onCustomFontsChange\":0}],\"controls\":[{\"onControlsChange\":0}],\"moreMenuItems\":[{\"onMoreMenuItemsChange\":0}],\"syncConfig\":[{\"onSyncConfigChange\":0}],\"loginConfig\":[{\"onLoginConfigChange\":0}],\"user\":[{\"onUserChange\":0}],\"activeWorkspaceId\":[{\"onActiveWorkspaceIdChange\":0}],\"theme\":[{\"onCurrentThemeChange\":0}],\"themes\":[{\"onThemesChange\":0}],\"locale\":[{\"onLocaleChange\":0}]}],[513,\"kritzel-controls\",{\"visible\":[4],\"controls\":[16],\"activeControl\":[1040],\"isUtilityPanelVisible\":[4,\"is-utility-panel-visible\"],\"undoState\":[16],\"theme\":[1],\"terms\":[16],\"firstConfig\":[32],\"isTouchDevice\":[32],\"selectedSubOptions\":[32],\"canScrollLeft\":[32],\"canScrollRight\":[32],\"needsScrolling\":[32],\"displayValues\":[32],\"internalControls\":[32],\"closeTooltip\":[64]},[[8,\"keydown\",\"handleKeyDown\"]],{\"controls\":[{\"onControlsChange\":0}],\"theme\":[{\"onThemeChange\":0}]}],[513,\"kritzel-settings\",{\"availableThemes\":[16],\"availableLocales\":[16],\"shortcuts\":[16],\"terms\":[16],\"settings\":[16],\"isDialogOpen\":[32],\"selectedCategoryId\":[32],\"scaleMin\":[32],\"scaleMax\":[32],\"lockDrawingScale\":[32],\"theme\":[32],\"locale\":[32],\"viewportBoundaryLeft\":[32],\"viewportBoundaryRight\":[32],\"viewportBoundaryTop\":[32],\"viewportBoundaryBottom\":[32],\"debugInfo\":[32],\"open\":[64]},null,{\"settings\":[{\"onSettingsPropChange\":0}]}],[513,\"kritzel-export\",{\"workspaceName\":[1,\"workspace-name\"],\"terms\":[16],\"isDialogOpen\":[32],\"previewUrl\":[32],\"isLoading\":[32],\"activeTab\":[32],\"exportFilename\":[32],\"viewportExportFormat\":[32],\"open\":[64]}],[513,\"kritzel-workspace-manager\",{\"visible\":[4],\"activeWorkspace\":[1040],\"workspaces\":[16],\"terms\":[16],\"childMenuAnchor\":[32],\"openChildMenuItem\":[32],\"newWorkspace\":[32],\"editingItemId\":[32]},[[8,\"wheel\",\"handleWheel\"]]],[513,\"kritzel-engine\",{\"workspace\":[16],\"editorId\":[1,\"editor-id\"],\"activeWorkspaceId\":[1,\"active-workspace-id\"],\"syncConfig\":[16],\"assetStorageConfig\":[16],\"user\":[16],\"globalContextMenuItems\":[16],\"objectContextMenuItems\":[16],\"scaleMax\":[1026,\"scale-max\"],\"scaleMin\":[1026,\"scale-min\"],\"cursorTarget\":[16],\"lockDrawingScale\":[4,\"lock-drawing-scale\"],\"isObjectDistanceFadingActive\":[4,\"is-object-distance-fading-active\"],\"theme\":[1],\"licenseKey\":[1,\"license-key\"],\"themes\":[16],\"locale\":[1],\"locales\":[16],\"fallbackLocale\":[1,\"fallback-locale\"],\"viewportBoundaryLeft\":[2,\"viewport-boundary-left\"],\"viewportBoundaryRight\":[2,\"viewport-boundary-right\"],\"viewportBoundaryTop\":[2,\"viewport-boundary-top\"],\"viewportBoundaryBottom\":[2,\"viewport-boundary-bottom\"],\"debugInfo\":[16],\"isPanningEnabled\":[4,\"is-panning-enabled\"],\"isZoomingEnabled\":[4,\"is-zooming-enabled\"],\"isLoading\":[4,\"is-loading\"],\"forceUpdate\":[32],\"isSyncing\":[32],\"triggerSelectionChange\":[64],\"beginSceneBootstrap\":[64],\"endSceneBootstrap\":[64],\"registerTool\":[64],\"changeActiveTool\":[64],\"changeActiveToolByName\":[64],\"disable\":[64],\"enable\":[64],\"delete\":[64],\"copy\":[64],\"cut\":[64],\"paste\":[64],\"bringForward\":[64],\"sendBackward\":[64],\"bringToFront\":[64],\"sendToBack\":[64],\"alignObjects\":[64],\"group\":[64],\"ungroup\":[64],\"undo\":[64],\"redo\":[64],\"hideContextMenu\":[64],\"openContextMenu\":[64],\"getObjectById\":[64],\"getAllObjects\":[64],\"findObjects\":[64],\"getObjectsTotalCount\":[64],\"addObject\":[64],\"addObjects\":[64],\"updateObject\":[64],\"removeObject\":[64],\"removeObjects\":[64],\"getSelectedObjects\":[64],\"getDisplayableShortcuts\":[64],\"selectObjects\":[64],\"selectAllObjectsInViewport\":[64],\"clearSelection\":[64],\"centerObjectInViewport\":[64],\"panToObject\":[64],\"backToContent\":[64],\"centerAllObjects\":[64],\"centerObjects\":[64],\"setViewport\":[64],\"panTo\":[64],\"zoomTo\":[64],\"zoomIn\":[64],\"zoomOut\":[64],\"getViewport\":[64],\"screenToWorld\":[64],\"worldToScreen\":[64],\"getObjectsInViewport\":[64],\"getScreenshot\":[64],\"exportViewportAsPng\":[64],\"exportViewportAsSvg\":[64],\"getSelectedObjectSupportedExportFormats\":[64],\"canExportSelectedObjectAs\":[64],\"exportSelectedObject\":[64],\"exportAsJson\":[64],\"importFromJson\":[64],\"loadObjectsFromJson\":[64],\"downloadAsJson\":[64],\"importFromFile\":[64],\"createWorkspace\":[64],\"updateWorkspace\":[64],\"deleteWorkspace\":[64],\"getWorkspaces\":[64],\"getActiveWorkspace\":[64],\"getIsPublic\":[64],\"loadSharedWorkspace\":[64],\"reinitSync\":[64],\"saveSettings\":[64],\"loadSettings\":[64],\"registerLocales\":[64],\"setLocale\":[64],\"getLocale\":[64],\"getAvailableLocales\":[64],\"getAvailableLocaleOptions\":[64],\"t\":[64],\"getResolvedTerms\":[64]},[[1,\"wheel\",\"handleWheel\"],[0,\"pointerdown\",\"handlePointerDown\"],[0,\"pointermove\",\"handlePointerMove\"],[0,\"pointerup\",\"handlePointerUp\"],[0,\"pointercancel\",\"handlePointerCancel\"],[1,\"pointerleave\",\"handlePointerLeave\"],[1,\"longpress\",\"handleLongPress\"],[0,\"contextmenu\",\"handleContextMenu\"],[9,\"resize\",\"handleResize\"],[8,\"keydown\",\"handleKeyDown\"],[8,\"keyup\",\"handleKeyUp\"],[8,\"copy\",\"handleCopy\"],[8,\"cut\",\"handleCut\"],[8,\"paste\",\"handlePaste\"],[4,\"dblclick\",\"preventDoubleTapZoomOnTouchDevices\"]],{\"workspace\":[{\"onWorkspaceChange\":0}],\"activeWorkspaceId\":[{\"onActiveWorkspaceIdChange\":0}],\"syncConfig\":[{\"onSyncConfigChange\":0}],\"assetStorageConfig\":[{\"onAssetStorageConfigChange\":0}],\"user\":[{\"onUserChange\":0}],\"globalContextMenuItems\":[{\"onGlobalContextMenuItemsChange\":0}],\"objectContextMenuItems\":[{\"onObjectContextMenuItemsChange\":0}],\"scaleMax\":[{\"validateScaleMax\":0}],\"scaleMin\":[{\"validateScaleMin\":0}],\"cursorTarget\":[{\"onCursorTargetChange\":0}],\"lockDrawingScale\":[{\"onLockDrawingScaleChange\":0}],\"isObjectDistanceFadingActive\":[{\"onIsObjectDistanceFadingActiveChange\":0}],\"theme\":[{\"onThemeChange\":0}],\"licenseKey\":[{\"onLicenseKeyChange\":0}],\"themes\":[{\"onThemesChange\":0}],\"locale\":[{\"onLocaleChange\":0}],\"locales\":[{\"onLocalesChange\":0}],\"fallbackLocale\":[{\"onFallbackLocaleChange\":0}],\"viewportBoundaryLeft\":[{\"onViewportBoundaryLeftChange\":0}],\"viewportBoundaryRight\":[{\"onViewportBoundaryRightChange\":0}],\"viewportBoundaryTop\":[{\"onViewportBoundaryTopChange\":0}],\"viewportBoundaryBottom\":[{\"onViewportBoundaryBottomChange\":0}],\"debugInfo\":[{\"onDebugInfoChange\":0}],\"isLoading\":[{\"onIsLoadingChange\":0}]}],[513,\"kritzel-more-menu\",{\"visible\":[4],\"items\":[16],\"icon\":[1],\"iconSize\":[2,\"icon-size\"],\"offsetY\":[2,\"offset-y\"],\"terms\":[16],\"menuAnchor\":[32],\"isTouchDevice\":[32],\"visibleItems\":[32]},null,{\"items\":[{\"onItemsChange\":0}]}],[513,\"kritzel-current-user-dialog\",{\"user\":[16],\"terms\":[16],\"isDialogOpen\":[32],\"open\":[64],\"close\":[64]}],[513,\"kritzel-share-dialog\",{\"isPublic\":[4,\"is-public\"],\"workspaceId\":[1,\"workspace-id\"],\"terms\":[16],\"isDialogOpen\":[32],\"internalIsPublic\":[32],\"copySuccess\":[32],\"qrCodeDataUrl\":[32],\"open\":[64],\"close\":[64]},null,{\"isPublic\":[{\"onIsPublicChange\":0}],\"workspaceId\":[{\"onWorkspaceIdChange\":0}]}],[513,\"kritzel-login-dialog\",{\"providers\":[16],\"dialogTitle\":[1,\"dialog-title\"],\"subtitle\":[1],\"isDialogOpen\":[32],\"loadingProvider\":[32],\"open\":[64],\"close\":[64],\"setLoading\":[64]}],[513,\"kritzel-active-users\",{\"users\":[16],\"avatarSize\":[2,\"avatar-size\"],\"maxVisible\":[2,\"max-visible\"],\"overlap\":[2]}],[513,\"kritzel-back-to-content\",{\"visible\":[4],\"text\":[1]}],[513,\"kritzel-context-menu\",{\"items\":[16],\"objects\":[16],\"processedItems\":[32],\"openSubmenuPath\":[32],\"submenuPositions\":[32]},[[9,\"pointerdown\",\"handleOutsideClick\"]],{\"items\":[{\"onItemsChanged\":0}]}],[513,\"kritzel-current-user\",{\"user\":[16],\"avatarSize\":[2,\"avatar-size\"],\"terms\":[16]}],[513,\"kritzel-notification-card\",{\"notification\":[16],\"showTimestamp\":[4,\"show-timestamp\"],\"locale\":[1]}],[513,\"kritzel-zoom-panel\",{\"visible\":[4],\"disabled\":[4],\"zoomPercent\":[2,\"zoom-percent\"],\"terms\":[16]}],[513,\"kritzel-loading-overlay\",{\"visible\":[4],\"text\":[1]}],[513,\"kritzel-sync-indicator\",{\"visible\":[4],\"text\":[1]}],[513,\"kritzel-tool-config\",{\"tool\":[1040],\"isExpanded\":[1028,\"is-expanded\"],\"theme\":[1],\"engine\":[16],\"terms\":[16],\"config\":[32],\"palette\":[32],\"sizes\":[32],\"currentOpacity\":[32],\"updateTrigger\":[32]},null,{\"tool\":[{\"handleToolChange\":0}],\"theme\":[{\"onThemeChange\":0}],\"engine\":[{\"handleEngineChange\":0}]}],[513,\"kritzel-split-button\",{\"buttonIcon\":[1,\"button-icon\"],\"dropdownIcon\":[1,\"dropdown-icon\"],\"items\":[16],\"mainButtonDisabled\":[4,\"main-button-disabled\"],\"menuButtonDisabled\":[4,\"menu-button-disabled\"],\"isMenuOpen\":[32],\"isTouchDevice\":[32],\"anchorElement\":[32],\"menuScrollTop\":[32],\"open\":[64],\"focusMenu\":[64]}],[769,\"kritzel-master-detail\",{\"items\":[16],\"selectedItemId\":[1,\"selected-item-id\"],\"focusedIndex\":[32],\"showMobileDetail\":[32]},null,{\"selectedItemId\":[{\"watchSelectedItemId\":0}]}],[513,\"kritzel-pill-tabs\",{\"tabs\":[16],\"value\":[1025]}],[513,\"kritzel-utility-panel\",{\"undoState\":[16],\"terms\":[16]}],[513,\"kritzel-awareness-cursors\",{\"core\":[16],\"showEdgeIndicators\":[4,\"show-edge-indicators\"],\"edgeIndicatorPadding\":[2,\"edge-indicator-padding\"],\"remoteCursors\":[32],\"objectVersion\":[32]}],[769,\"kritzel-button\",{\"variant\":[1],\"disabled\":[4],\"type\":[1]}],[513,\"kritzel-cursor-trail\",{\"core\":[16],\"cursorTrailPoints\":[32],\"isLeftButtonDown\":[32]},[[9,\"pointerdown\",\"handleMouseDown\"],[9,\"pointermove\",\"handlePointerMove\"],[9,\"pointerup\",\"handlePointerUp\"]]],[513,\"kritzel-input\",{\"value\":[1025],\"label\":[1],\"placeholder\":[1],\"suffix\":[1],\"type\":[1],\"disabled\":[4],\"inputValue\":[32]},null,{\"value\":[{\"onValueChange\":0}]}],[513,\"kritzel-numeric-input\",{\"value\":[1026],\"min\":[2],\"max\":[2],\"step\":[2],\"label\":[1],\"placeholder\":[1],\"inputValue\":[32]},null,{\"value\":[{\"onValueChange\":0}]}],[769,\"kritzel-tooltip\",{\"isVisible\":[1028,\"is-visible\"],\"anchorElement\":[16],\"triggerElement\":[16],\"offsetY\":[2,\"offset-y\"],\"positionX\":[32],\"positionY\":[32],\"open\":[64],\"close\":[64],\"toggle\":[64],\"focusContent\":[64]},[[4,\"click\",\"handleOutsideClick\"],[6,\"pointerdown\",\"handleOutsidePointerDown\"],[4,\"kritzelTooltipCloseAll\",\"handleCloseAll\"],[9,\"resize\",\"handleWindowResize\"]],{\"triggerElement\":[{\"handleTriggerElementChange\":0}],\"isVisible\":[{\"handleVisibilityChange\":0}]}],[513,\"kritzel-watermark\",{\"core\":[16],\"label\":[1]}],[513,\"kritzel-color-palette\",{\"colors\":[16],\"selectedColor\":[1040],\"isExpanded\":[4,\"is-expanded\"],\"isOpaque\":[4,\"is-opaque\"],\"opacity\":[2],\"theme\":[1]}],[513,\"kritzel-font-family\",{\"fontOptions\":[16],\"selectedFontFamily\":[1025,\"selected-font-family\"]},null,{\"fontOptions\":[{\"handleFontOptionsChange\":0}]}],[513,\"kritzel-font-size\",{\"sizes\":[16],\"selectedSize\":[1026,\"selected-size\"],\"fontFamily\":[1,\"font-family\"]}],[513,\"kritzel-stroke-size\",{\"sizes\":[16],\"selectedSize\":[1026,\"selected-size\"]}],[513,\"kritzel-line-endings\",{\"styles\":[16],\"value\":[1040]}],[513,\"kritzel-opacity-slider\",{\"value\":[1026],\"min\":[2],\"max\":[2],\"step\":[2],\"previewColor\":[1,\"preview-color\"]}],[513,\"kritzel-shape-fill\",{\"value\":[1025]}],[513,\"kritzel-slide-toggle\",{\"checked\":[1028],\"disabled\":[4],\"label\":[1]}],[513,\"kritzel-avatar\",{\"user\":[16],\"name\":[1],\"size\":[2],\"color\":[1],\"imageError\":[32]},null,{\"user\":[{\"userChanged\":0}],\"profileImageUrl\":[{\"profileImageUrlChanged\":0}]}],[513,\"kritzel-font\",{\"fontFamily\":[1,\"font-family\"],\"size\":[2],\"color\":[1]}],[513,\"kritzel-color\",{\"value\":[1],\"theme\":[1],\"size\":[2]}],[513,\"kritzel-menu\",{\"items\":[16],\"parent\":[16],\"selectedIndex\":[32],\"setScrollTop\":[64],\"setFocus\":[64]}],[513,\"kritzel-menu-item\",{\"item\":[16],\"parent\":[16],\"isDirty\":[32]},null,{\"item\":[{\"onItemChange\":0}]}],[769,\"kritzel-dialog\",{\"isOpen\":[516,\"is-open\"],\"dialogTitle\":[1,\"dialog-title\"],\"closable\":[4],\"closeOnBackdrop\":[4,\"close-on-backdrop\"],\"closeOnEscape\":[4,\"close-on-escape\"],\"autoFocus\":[4,\"auto-focus\"],\"trapFocus\":[4,\"trap-focus\"],\"size\":[1],\"fullscreenOnMobile\":[4,\"fullscreen-on-mobile\"],\"contained\":[516],\"isAnimating\":[32],\"mobileLockedHeight\":[32],\"containerRect\":[32],\"containerBorderRadius\":[32],\"open\":[64],\"close\":[64],\"focusFirstElement\":[64]},[[8,\"keydown\",\"handleKeyDown\"],[9,\"resize\",\"handleWindowResize\"],[8,\"orientationchange\",\"handleOrientationChange\"]],{\"isOpen\":[{\"handleIsOpenChange\":0}]}],[769,\"kritzel-portal\",{\"anchor\":[16],\"offsetX\":[2,\"offset-x\"],\"offsetY\":[2,\"offset-y\"],\"autoFocus\":[4,\"auto-focus\"]},[[8,\"kritzel-dismiss-menus\",\"handleDismissMenus\"],[8,\"click\",\"handleOutsideClick\"],[6,\"pointerdown\",\"handleOutsidePointerDown\"],[8,\"keydown\",\"handleKeyDown\"],[11,\"resize\",\"handleResize\"],[11,\"scroll\",\"handleWindowScroll\"]],{\"anchor\":[{\"anchorChanged\":0}]}],[769,\"kritzel-dropdown\",{\"options\":[16],\"value\":[1],\"width\":[1],\"selectStyles\":[16],\"forceOpenDirection\":[1,\"force-open-direction\"],\"internalValue\":[32],\"hasSuffixContent\":[32],\"hasPrefixContent\":[32],\"isOpen\":[32],\"focusedIndex\":[32],\"openDirection\":[32]},[[4,\"click\",\"handleDocumentClick\"],[4,\"keydown\",\"handleDocumentKeydown\"]],{\"options\":[{\"optionsChanged\":0}],\"value\":[{\"externalValueChanged\":0}]}],[513,\"kritzel-icon\",{\"name\":[1],\"label\":[1],\"size\":[2]}]]],[\"p-fb32cd8f\",[[513,\"kritzel-brush-style\",{\"type\":[1],\"brushOptions\":[16]}]]]]"), options);
20
+ return bootstrapLazy(JSON.parse("[[\"p-ab5c4292\",[[512,\"kritzel-editor\",{\"scaleMax\":[1026,\"scale-max\"],\"scaleMin\":[1026,\"scale-min\"],\"lockDrawingScale\":[1028,\"lock-drawing-scale\"],\"viewportBoundaryLeft\":[1026,\"viewport-boundary-left\"],\"viewportBoundaryRight\":[1026,\"viewport-boundary-right\"],\"viewportBoundaryTop\":[1026,\"viewport-boundary-top\"],\"viewportBoundaryBottom\":[1026,\"viewport-boundary-bottom\"],\"debugInfo\":[1040],\"user\":[16],\"activeUsers\":[16],\"controls\":[16],\"globalContextMenuItems\":[16],\"objectContextMenuItems\":[16],\"moreMenuItems\":[16],\"themes\":[16],\"theme\":[1025],\"licenseKey\":[1,\"license-key\"],\"locale\":[1025],\"locales\":[16],\"fallbackLocale\":[1,\"fallback-locale\"],\"customSvgIcons\":[16],\"customFonts\":[16],\"isPanningEnabled\":[1028,\"is-panning-enabled\"],\"isZoomingEnabled\":[1028,\"is-zooming-enabled\"],\"isControlsVisible\":[4,\"is-controls-visible\"],\"isUtilityPanelVisible\":[4,\"is-utility-panel-visible\"],\"isWorkspaceManagerVisible\":[4,\"is-workspace-manager-visible\"],\"isMoreMenuVisible\":[4,\"is-more-menu-visible\"],\"isZoomPanelVisible\":[4,\"is-zoom-panel-visible\"],\"isObjectDistanceFadingActive\":[4,\"is-object-distance-fading-active\"],\"syncConfig\":[16],\"assetStorageConfig\":[16],\"cursorTarget\":[16],\"loginConfig\":[16],\"isLoading\":[4,\"is-loading\"],\"editorId\":[1,\"editor-id\"],\"activeWorkspaceId\":[1,\"active-workspace-id\"],\"isEngineReady\":[32],\"isControlsReady\":[32],\"isWorkspaceManagerReady\":[32],\"workspaces\":[32],\"activeWorkspace\":[32],\"isVirtualKeyboardOpen\":[32],\"undoState\":[32],\"isBackToContentButtonVisible\":[32],\"resolvedTerms\":[32],\"availableLocaleOptions\":[32],\"currentZoomPercent\":[32],\"shortcuts\":[32],\"currentIsPublic\":[32],\"isEditorVisible\":[32],\"activeNotification\":[32],\"isNotificationDismissing\":[32],\"contextMenuState\":[32],\"normalizedControls\":[32],\"resolvedMoreMenuItems\":[32],\"isSyncing\":[32],\"isLoadingOverlayVisible\":[32],\"getObjectById\":[64],\"addObject\":[64],\"addObjects\":[64],\"updateObject\":[64],\"removeObject\":[64],\"removeObjects\":[64],\"getSelectedObjects\":[64],\"selectObjects\":[64],\"selectAllObjectsInViewport\":[64],\"clearSelection\":[64],\"centerObjectInViewport\":[64],\"panToObject\":[64],\"backToContent\":[64],\"centerAllObjects\":[64],\"centerObjects\":[64],\"setViewport\":[64],\"panTo\":[64],\"zoomTo\":[64],\"zoomIn\":[64],\"zoomOut\":[64],\"getViewport\":[64],\"screenToWorld\":[64],\"worldToScreen\":[64],\"createWorkspace\":[64],\"updateWorkspace\":[64],\"deleteWorkspace\":[64],\"getWorkspaces\":[64],\"getActiveWorkspace\":[64],\"loadSharedWorkspace\":[64],\"reinitSync\":[64],\"registerTool\":[64],\"changeActiveTool\":[64],\"changeActiveToolByName\":[64],\"disable\":[64],\"enable\":[64],\"copy\":[64],\"cut\":[64],\"paste\":[64],\"delete\":[64],\"bringForward\":[64],\"sendBackward\":[64],\"bringToFront\":[64],\"sendToBack\":[64],\"alignObjects\":[64],\"group\":[64],\"ungroup\":[64],\"undo\":[64],\"redo\":[64],\"getScreenshot\":[64],\"exportViewportAsPng\":[64],\"exportViewportAsSvg\":[64],\"getSelectedObjectSupportedExportFormats\":[64],\"canExportSelectedObjectAs\":[64],\"exportSelectedObject\":[64],\"downloadAsJson\":[64],\"importFromFile\":[64],\"loadObjectsFromJson\":[64],\"getObjectsTotalCount\":[64],\"getAllObjects\":[64],\"findObjects\":[64],\"getObjectsInViewport\":[64],\"hideContextMenu\":[64],\"openContextMenu\":[64],\"triggerSelectionChange\":[64],\"beginSceneBootstrap\":[64],\"endSceneBootstrap\":[64],\"getDisplayableShortcuts\":[64],\"triggerNotification\":[64],\"openLoginDialog\":[64],\"setLoginLoading\":[64],\"setLocale\":[64],\"getLocale\":[64],\"getAvailableLocales\":[64],\"registerLocales\":[64],\"registerFonts\":[64],\"t\":[64]},[[0,\"dblclick\",\"onTouchStart\"]],{\"isEngineReady\":[{\"onIsEngineReady\":0}],\"isControlsReady\":[{\"onIsControlsReady\":0}],\"workspaces\":[{\"onWorkspacesChange\":0}],\"activeWorkspace\":[{\"onActiveWorkspaceChange\":0}],\"customFonts\":[{\"onCustomFontsChange\":0}],\"controls\":[{\"onControlsChange\":0}],\"moreMenuItems\":[{\"onMoreMenuItemsChange\":0}],\"syncConfig\":[{\"onSyncConfigChange\":0}],\"loginConfig\":[{\"onLoginConfigChange\":0}],\"user\":[{\"onUserChange\":0}],\"activeWorkspaceId\":[{\"onActiveWorkspaceIdChange\":0}],\"theme\":[{\"onCurrentThemeChange\":0}],\"themes\":[{\"onThemesChange\":0}],\"locale\":[{\"onLocaleChange\":0}]}],[513,\"kritzel-controls\",{\"visible\":[4],\"controls\":[16],\"activeControl\":[1040],\"isUtilityPanelVisible\":[4,\"is-utility-panel-visible\"],\"undoState\":[16],\"theme\":[1],\"terms\":[16],\"firstConfig\":[32],\"isTouchDevice\":[32],\"selectedSubOptions\":[32],\"canScrollLeft\":[32],\"canScrollRight\":[32],\"needsScrolling\":[32],\"displayValues\":[32],\"internalControls\":[32],\"closeTooltip\":[64]},[[8,\"keydown\",\"handleKeyDown\"]],{\"controls\":[{\"onControlsChange\":0}],\"theme\":[{\"onThemeChange\":0}]}],[513,\"kritzel-settings\",{\"availableThemes\":[16],\"availableLocales\":[16],\"shortcuts\":[16],\"terms\":[16],\"settings\":[16],\"isDialogOpen\":[32],\"selectedCategoryId\":[32],\"scaleMin\":[32],\"scaleMax\":[32],\"lockDrawingScale\":[32],\"theme\":[32],\"locale\":[32],\"viewportBoundaryLeft\":[32],\"viewportBoundaryRight\":[32],\"viewportBoundaryTop\":[32],\"viewportBoundaryBottom\":[32],\"debugInfo\":[32],\"open\":[64]},null,{\"settings\":[{\"onSettingsPropChange\":0}]}],[513,\"kritzel-export\",{\"workspaceName\":[1,\"workspace-name\"],\"terms\":[16],\"isDialogOpen\":[32],\"previewUrl\":[32],\"isLoading\":[32],\"activeTab\":[32],\"exportFilename\":[32],\"viewportExportFormat\":[32],\"open\":[64]}],[513,\"kritzel-workspace-manager\",{\"visible\":[4],\"activeWorkspace\":[1040],\"workspaces\":[16],\"terms\":[16],\"childMenuAnchor\":[32],\"openChildMenuItem\":[32],\"newWorkspace\":[32],\"editingItemId\":[32]},[[8,\"wheel\",\"handleWheel\"]]],[513,\"kritzel-engine\",{\"workspace\":[16],\"editorId\":[1,\"editor-id\"],\"activeWorkspaceId\":[1,\"active-workspace-id\"],\"syncConfig\":[16],\"assetStorageConfig\":[16],\"user\":[16],\"globalContextMenuItems\":[16],\"objectContextMenuItems\":[16],\"scaleMax\":[1026,\"scale-max\"],\"scaleMin\":[1026,\"scale-min\"],\"cursorTarget\":[16],\"lockDrawingScale\":[4,\"lock-drawing-scale\"],\"isObjectDistanceFadingActive\":[4,\"is-object-distance-fading-active\"],\"theme\":[1],\"licenseKey\":[1,\"license-key\"],\"themes\":[16],\"locale\":[1],\"locales\":[16],\"fallbackLocale\":[1,\"fallback-locale\"],\"viewportBoundaryLeft\":[2,\"viewport-boundary-left\"],\"viewportBoundaryRight\":[2,\"viewport-boundary-right\"],\"viewportBoundaryTop\":[2,\"viewport-boundary-top\"],\"viewportBoundaryBottom\":[2,\"viewport-boundary-bottom\"],\"debugInfo\":[16],\"isPanningEnabled\":[4,\"is-panning-enabled\"],\"isZoomingEnabled\":[4,\"is-zooming-enabled\"],\"isLoading\":[4,\"is-loading\"],\"forceUpdate\":[32],\"isSyncing\":[32],\"triggerSelectionChange\":[64],\"beginSceneBootstrap\":[64],\"endSceneBootstrap\":[64],\"registerTool\":[64],\"changeActiveTool\":[64],\"changeActiveToolByName\":[64],\"disable\":[64],\"enable\":[64],\"delete\":[64],\"copy\":[64],\"cut\":[64],\"paste\":[64],\"bringForward\":[64],\"sendBackward\":[64],\"bringToFront\":[64],\"sendToBack\":[64],\"alignObjects\":[64],\"group\":[64],\"ungroup\":[64],\"undo\":[64],\"redo\":[64],\"hideContextMenu\":[64],\"openContextMenu\":[64],\"getObjectById\":[64],\"getAllObjects\":[64],\"findObjects\":[64],\"getObjectsTotalCount\":[64],\"addObject\":[64],\"addObjects\":[64],\"updateObject\":[64],\"removeObject\":[64],\"removeObjects\":[64],\"getSelectedObjects\":[64],\"getDisplayableShortcuts\":[64],\"selectObjects\":[64],\"selectAllObjectsInViewport\":[64],\"clearSelection\":[64],\"centerObjectInViewport\":[64],\"panToObject\":[64],\"backToContent\":[64],\"centerAllObjects\":[64],\"centerObjects\":[64],\"setViewport\":[64],\"panTo\":[64],\"zoomTo\":[64],\"zoomIn\":[64],\"zoomOut\":[64],\"getViewport\":[64],\"screenToWorld\":[64],\"worldToScreen\":[64],\"getObjectsInViewport\":[64],\"getScreenshot\":[64],\"exportViewportAsPng\":[64],\"exportViewportAsSvg\":[64],\"getSelectedObjectSupportedExportFormats\":[64],\"canExportSelectedObjectAs\":[64],\"exportSelectedObject\":[64],\"exportAsJson\":[64],\"importFromJson\":[64],\"loadObjectsFromJson\":[64],\"downloadAsJson\":[64],\"importFromFile\":[64],\"createWorkspace\":[64],\"updateWorkspace\":[64],\"deleteWorkspace\":[64],\"getWorkspaces\":[64],\"getActiveWorkspace\":[64],\"getIsPublic\":[64],\"loadSharedWorkspace\":[64],\"reinitSync\":[64],\"saveSettings\":[64],\"loadSettings\":[64],\"registerLocales\":[64],\"setLocale\":[64],\"getLocale\":[64],\"getAvailableLocales\":[64],\"getAvailableLocaleOptions\":[64],\"t\":[64],\"getResolvedTerms\":[64]},[[1,\"wheel\",\"handleWheel\"],[0,\"pointerdown\",\"handlePointerDown\"],[0,\"pointermove\",\"handlePointerMove\"],[0,\"pointerup\",\"handlePointerUp\"],[0,\"pointercancel\",\"handlePointerCancel\"],[1,\"pointerleave\",\"handlePointerLeave\"],[1,\"longpress\",\"handleLongPress\"],[0,\"contextmenu\",\"handleContextMenu\"],[9,\"resize\",\"handleResize\"],[8,\"keydown\",\"handleKeyDown\"],[8,\"keyup\",\"handleKeyUp\"],[8,\"copy\",\"handleCopy\"],[8,\"cut\",\"handleCut\"],[8,\"paste\",\"handlePaste\"],[4,\"dblclick\",\"preventDoubleTapZoomOnTouchDevices\"]],{\"workspace\":[{\"onWorkspaceChange\":0}],\"activeWorkspaceId\":[{\"onActiveWorkspaceIdChange\":0}],\"syncConfig\":[{\"onSyncConfigChange\":0}],\"assetStorageConfig\":[{\"onAssetStorageConfigChange\":0}],\"user\":[{\"onUserChange\":0}],\"globalContextMenuItems\":[{\"onGlobalContextMenuItemsChange\":0}],\"objectContextMenuItems\":[{\"onObjectContextMenuItemsChange\":0}],\"scaleMax\":[{\"validateScaleMax\":0}],\"scaleMin\":[{\"validateScaleMin\":0}],\"cursorTarget\":[{\"onCursorTargetChange\":0}],\"lockDrawingScale\":[{\"onLockDrawingScaleChange\":0}],\"isObjectDistanceFadingActive\":[{\"onIsObjectDistanceFadingActiveChange\":0}],\"theme\":[{\"onThemeChange\":0}],\"licenseKey\":[{\"onLicenseKeyChange\":0}],\"themes\":[{\"onThemesChange\":0}],\"locale\":[{\"onLocaleChange\":0}],\"locales\":[{\"onLocalesChange\":0}],\"fallbackLocale\":[{\"onFallbackLocaleChange\":0}],\"viewportBoundaryLeft\":[{\"onViewportBoundaryLeftChange\":0}],\"viewportBoundaryRight\":[{\"onViewportBoundaryRightChange\":0}],\"viewportBoundaryTop\":[{\"onViewportBoundaryTopChange\":0}],\"viewportBoundaryBottom\":[{\"onViewportBoundaryBottomChange\":0}],\"debugInfo\":[{\"onDebugInfoChange\":0}],\"isLoading\":[{\"onIsLoadingChange\":0}]}],[513,\"kritzel-more-menu\",{\"visible\":[4],\"items\":[16],\"icon\":[1],\"iconSize\":[2,\"icon-size\"],\"offsetY\":[2,\"offset-y\"],\"terms\":[16],\"menuAnchor\":[32],\"isTouchDevice\":[32],\"visibleItems\":[32]},null,{\"items\":[{\"onItemsChange\":0}]}],[513,\"kritzel-current-user-dialog\",{\"user\":[16],\"terms\":[16],\"isDialogOpen\":[32],\"open\":[64],\"close\":[64]}],[513,\"kritzel-share-dialog\",{\"isPublic\":[4,\"is-public\"],\"workspaceId\":[1,\"workspace-id\"],\"terms\":[16],\"isDialogOpen\":[32],\"internalIsPublic\":[32],\"copySuccess\":[32],\"qrCodeDataUrl\":[32],\"open\":[64],\"close\":[64]},null,{\"isPublic\":[{\"onIsPublicChange\":0}],\"workspaceId\":[{\"onWorkspaceIdChange\":0}]}],[513,\"kritzel-login-dialog\",{\"providers\":[16],\"dialogTitle\":[1,\"dialog-title\"],\"subtitle\":[1],\"isDialogOpen\":[32],\"loadingProvider\":[32],\"open\":[64],\"close\":[64],\"setLoading\":[64]}],[513,\"kritzel-active-users\",{\"users\":[16],\"avatarSize\":[2,\"avatar-size\"],\"maxVisible\":[2,\"max-visible\"],\"overlap\":[2]}],[513,\"kritzel-back-to-content\",{\"visible\":[4],\"text\":[1]}],[513,\"kritzel-context-menu\",{\"items\":[16],\"objects\":[16],\"processedItems\":[32],\"openSubmenuPath\":[32],\"submenuPositions\":[32]},[[9,\"pointerdown\",\"handleOutsideClick\"]],{\"items\":[{\"onItemsChanged\":0}]}],[513,\"kritzel-current-user\",{\"user\":[16],\"avatarSize\":[2,\"avatar-size\"],\"terms\":[16]}],[513,\"kritzel-notification-card\",{\"notification\":[16],\"showTimestamp\":[4,\"show-timestamp\"],\"locale\":[1]}],[513,\"kritzel-zoom-panel\",{\"visible\":[4],\"disabled\":[4],\"zoomPercent\":[2,\"zoom-percent\"],\"terms\":[16]}],[513,\"kritzel-loading-overlay\",{\"visible\":[4],\"text\":[1]}],[513,\"kritzel-sync-indicator\",{\"visible\":[4],\"text\":[1]}],[513,\"kritzel-tool-config\",{\"tool\":[1040],\"isExpanded\":[1028,\"is-expanded\"],\"theme\":[1],\"engine\":[16],\"terms\":[16],\"config\":[32],\"palette\":[32],\"sizes\":[32],\"currentOpacity\":[32],\"updateTrigger\":[32]},null,{\"tool\":[{\"handleToolChange\":0}],\"theme\":[{\"onThemeChange\":0}],\"engine\":[{\"handleEngineChange\":0}]}],[513,\"kritzel-split-button\",{\"buttonIcon\":[1,\"button-icon\"],\"dropdownIcon\":[1,\"dropdown-icon\"],\"items\":[16],\"mainButtonDisabled\":[4,\"main-button-disabled\"],\"menuButtonDisabled\":[4,\"menu-button-disabled\"],\"isMenuOpen\":[32],\"isTouchDevice\":[32],\"anchorElement\":[32],\"menuScrollTop\":[32],\"open\":[64],\"focusMenu\":[64]}],[769,\"kritzel-master-detail\",{\"items\":[16],\"selectedItemId\":[1,\"selected-item-id\"],\"focusedIndex\":[32],\"showMobileDetail\":[32]},null,{\"selectedItemId\":[{\"watchSelectedItemId\":0}]}],[513,\"kritzel-pill-tabs\",{\"tabs\":[16],\"value\":[1025]}],[513,\"kritzel-utility-panel\",{\"undoState\":[16],\"terms\":[16]}],[513,\"kritzel-awareness-cursors\",{\"core\":[16],\"showEdgeIndicators\":[4,\"show-edge-indicators\"],\"edgeIndicatorPadding\":[2,\"edge-indicator-padding\"],\"remoteCursors\":[32],\"objectVersion\":[32]}],[769,\"kritzel-button\",{\"variant\":[1],\"disabled\":[4],\"type\":[1]}],[513,\"kritzel-cursor-trail\",{\"core\":[16],\"cursorTrailPoints\":[32],\"isLeftButtonDown\":[32]},[[9,\"pointerdown\",\"handleMouseDown\"],[9,\"pointermove\",\"handlePointerMove\"],[9,\"pointerup\",\"handlePointerUp\"]]],[513,\"kritzel-input\",{\"value\":[1025],\"label\":[1],\"placeholder\":[1],\"suffix\":[1],\"type\":[1],\"disabled\":[4],\"inputValue\":[32]},null,{\"value\":[{\"onValueChange\":0}]}],[513,\"kritzel-numeric-input\",{\"value\":[1026],\"min\":[2],\"max\":[2],\"step\":[2],\"label\":[1],\"placeholder\":[1],\"inputValue\":[32]},null,{\"value\":[{\"onValueChange\":0}]}],[769,\"kritzel-tooltip\",{\"isVisible\":[1028,\"is-visible\"],\"anchorElement\":[16],\"triggerElement\":[16],\"offsetY\":[2,\"offset-y\"],\"positionX\":[32],\"positionY\":[32],\"open\":[64],\"close\":[64],\"toggle\":[64],\"focusContent\":[64]},[[4,\"click\",\"handleOutsideClick\"],[6,\"pointerdown\",\"handleOutsidePointerDown\"],[4,\"kritzelTooltipCloseAll\",\"handleCloseAll\"],[9,\"resize\",\"handleWindowResize\"]],{\"triggerElement\":[{\"handleTriggerElementChange\":0}],\"isVisible\":[{\"handleVisibilityChange\":0}]}],[513,\"kritzel-watermark\",{\"core\":[16],\"label\":[1]}],[513,\"kritzel-color-palette\",{\"colors\":[16],\"selectedColor\":[1040],\"isExpanded\":[4,\"is-expanded\"],\"isOpaque\":[4,\"is-opaque\"],\"opacity\":[2],\"theme\":[1]}],[513,\"kritzel-font-family\",{\"fontOptions\":[16],\"selectedFontFamily\":[1025,\"selected-font-family\"]},null,{\"fontOptions\":[{\"handleFontOptionsChange\":0}]}],[513,\"kritzel-font-size\",{\"sizes\":[16],\"selectedSize\":[1026,\"selected-size\"],\"fontFamily\":[1,\"font-family\"]}],[513,\"kritzel-stroke-size\",{\"sizes\":[16],\"selectedSize\":[1026,\"selected-size\"]}],[513,\"kritzel-line-endings\",{\"styles\":[16],\"value\":[1040]}],[513,\"kritzel-opacity-slider\",{\"value\":[1026],\"min\":[2],\"max\":[2],\"step\":[2],\"previewColor\":[1,\"preview-color\"]}],[513,\"kritzel-shape-fill\",{\"value\":[1025]}],[513,\"kritzel-slide-toggle\",{\"checked\":[1028],\"disabled\":[4],\"label\":[1]}],[513,\"kritzel-avatar\",{\"user\":[16],\"name\":[1],\"size\":[2],\"color\":[1],\"imageError\":[32]},null,{\"user\":[{\"userChanged\":0}],\"profileImageUrl\":[{\"profileImageUrlChanged\":0}]}],[513,\"kritzel-font\",{\"fontFamily\":[1,\"font-family\"],\"size\":[2],\"color\":[1]}],[513,\"kritzel-color\",{\"value\":[1],\"theme\":[1],\"size\":[2]}],[513,\"kritzel-menu\",{\"items\":[16],\"parent\":[16],\"selectedIndex\":[32],\"setScrollTop\":[64],\"setFocus\":[64]}],[513,\"kritzel-menu-item\",{\"item\":[16],\"parent\":[16],\"isDirty\":[32]},null,{\"item\":[{\"onItemChange\":0}]}],[769,\"kritzel-dialog\",{\"isOpen\":[516,\"is-open\"],\"dialogTitle\":[1,\"dialog-title\"],\"closable\":[4],\"closeOnBackdrop\":[4,\"close-on-backdrop\"],\"closeOnEscape\":[4,\"close-on-escape\"],\"autoFocus\":[4,\"auto-focus\"],\"trapFocus\":[4,\"trap-focus\"],\"size\":[1],\"fullscreenOnMobile\":[4,\"fullscreen-on-mobile\"],\"contained\":[516],\"isAnimating\":[32],\"mobileLockedHeight\":[32],\"containerRect\":[32],\"containerBorderRadius\":[32],\"open\":[64],\"close\":[64],\"focusFirstElement\":[64]},[[8,\"keydown\",\"handleKeyDown\"],[9,\"resize\",\"handleWindowResize\"],[8,\"orientationchange\",\"handleOrientationChange\"]],{\"isOpen\":[{\"handleIsOpenChange\":0}]}],[769,\"kritzel-portal\",{\"anchor\":[16],\"offsetX\":[2,\"offset-x\"],\"offsetY\":[2,\"offset-y\"],\"autoFocus\":[4,\"auto-focus\"]},[[8,\"kritzel-dismiss-menus\",\"handleDismissMenus\"],[8,\"click\",\"handleOutsideClick\"],[6,\"pointerdown\",\"handleOutsidePointerDown\"],[8,\"keydown\",\"handleKeyDown\"],[11,\"resize\",\"handleResize\"],[11,\"scroll\",\"handleWindowScroll\"]],{\"anchor\":[{\"anchorChanged\":0}]}],[769,\"kritzel-dropdown\",{\"options\":[16],\"value\":[1],\"width\":[1],\"selectStyles\":[16],\"forceOpenDirection\":[1,\"force-open-direction\"],\"internalValue\":[32],\"hasSuffixContent\":[32],\"hasPrefixContent\":[32],\"isOpen\":[32],\"focusedIndex\":[32],\"openDirection\":[32]},[[4,\"click\",\"handleDocumentClick\"],[4,\"keydown\",\"handleDocumentKeydown\"]],{\"options\":[{\"optionsChanged\":0}],\"value\":[{\"externalValueChanged\":0}]}],[513,\"kritzel-icon\",{\"name\":[1],\"label\":[1],\"size\":[2]}]]],[\"p-fb32cd8f\",[[513,\"kritzel-brush-style\",{\"type\":[1],\"brushOptions\":[16]}]]]]"), options);
21
21
  });
@@ -130,7 +130,10 @@ export declare class HocuspocusSyncProvider implements ISyncProvider {
130
130
  private _connectionStatus;
131
131
  private visibilityHandler;
132
132
  private onlineHandler;
133
+ private syncedResolvers;
133
134
  get awareness(): Awareness | null;
135
+ /** HocuspocusProvider applies remote updates with itself as the Yjs transaction origin. */
136
+ get updateOrigin(): unknown;
134
137
  get connectionStatus(): ConnectionStatus;
135
138
  private static sharedWebSocketProvider;
136
139
  constructor(docName: string, doc: Y.Doc, options?: HocuspocusOptions);
@@ -157,6 +160,8 @@ export declare class HocuspocusSyncProvider implements ISyncProvider {
157
160
  static with(options?: HocuspocusOptions): ProviderFactory;
158
161
  connect(): Promise<void>;
159
162
  reconnect(): Promise<void>;
163
+ private releaseSyncedWaiters;
164
+ whenSynced(): Promise<void>;
160
165
  disconnect(): void;
161
166
  destroy(): void;
162
167
  }
@@ -47,7 +47,11 @@ export declare class WebSocketSyncProvider implements ISyncProvider {
47
47
  private provider;
48
48
  private isConnected;
49
49
  private _quiet;
50
+ private _isSynced;
51
+ private _syncedResolvers;
50
52
  get awareness(): Awareness;
53
+ /** y-websocket applies remote updates with the underlying provider as the Yjs transaction origin. */
54
+ get updateOrigin(): unknown;
51
55
  constructor(docName: string, doc: Y.Doc, options?: WebSocketOptions);
52
56
  /**
53
57
  * Static factory method for creating WebSocketSyncProvider with configuration options
@@ -55,6 +59,8 @@ export declare class WebSocketSyncProvider implements ISyncProvider {
55
59
  */
56
60
  static with(options?: WebSocketOptions): ProviderFactory;
57
61
  private setupEventListeners;
62
+ private releaseSyncedWaiters;
63
+ whenSynced(): Promise<void>;
58
64
  connect(): Promise<void>;
59
65
  disconnect(): void;
60
66
  reconnect(): Promise<void>;
@@ -34,6 +34,10 @@ export declare class KritzelObjectMap<T extends KritzelBaseObject<any>> {
34
34
  private _awarenessChangeHandler;
35
35
  private _awarenessChangeCallbacks;
36
36
  private _objectsChangeCallbacks;
37
+ private _remoteChangesCallbacks;
38
+ private _docUpdateHandler;
39
+ private _remoteOrigins;
40
+ private _appliedRemoteChanges;
37
41
  private _lastAwarenessEmitTime;
38
42
  private _awarenessEmitTimeout;
39
43
  private readonly AWARENESS_THROTTLE_INTERVAL;
@@ -55,10 +59,30 @@ export declare class KritzelObjectMap<T extends KritzelBaseObject<any>> {
55
59
  */
56
60
  get isReady(): boolean;
57
61
  /**
58
- * Promise that settles when network providers finish connecting.
59
- * Resolves immediately if no network providers. Awaited by the loading overlay.
62
+ * Promise that settles when network providers finish connecting and complete
63
+ * their Yjs sync handshake. Resolves immediately if no network providers.
60
64
  */
61
65
  whenNetworkSynced(): Promise<void>;
66
+ /**
67
+ * Whether any configured provider synchronizes over the network.
68
+ */
69
+ get hasNetworkSyncProvider(): boolean;
70
+ /**
71
+ * Whether remote-originated changes can be told apart from local writes.
72
+ * Requires every network provider to expose its Yjs update origin.
73
+ */
74
+ get supportsRemoteChangeDetection(): boolean;
75
+ /**
76
+ * Whether at least one update originating from a network provider has been
77
+ * applied to this document. Stays `false` when the remote held no data the
78
+ * local document was missing, because Yjs suppresses empty updates.
79
+ */
80
+ get hasAppliedRemoteChanges(): boolean;
81
+ /**
82
+ * Registers a callback invoked whenever a network provider applies changes to this document.
83
+ * @returns A function that unregisters the callback.
84
+ */
85
+ onRemoteChangesApplied(callback: () => void): () => void;
62
86
  /**
63
87
  * Returns the Yjs Awareness instance, if a network provider is available.
64
88
  */
@@ -92,6 +92,9 @@ export declare class KritzelEditor {
92
92
  login: EventEmitter<LoginEvent>;
93
93
  isPublicChange: EventEmitter<IKritzelIsPublicChangedEvent>;
94
94
  awarenessChange: EventEmitter<Map<number, Record<string, any>>>;
95
+ /** Emitted while remote changes are being applied to the active workspace. Stays silent when the remote holds nothing new. */
96
+ syncingChange: EventEmitter<boolean>;
97
+ loadingChange: EventEmitter<boolean>;
95
98
  isEngineReady: boolean;
96
99
  isControlsReady: boolean;
97
100
  isWorkspaceManagerReady: boolean;
@@ -146,7 +146,7 @@ export declare class KritzelEngine {
146
146
  contextMenuStateChange: EventEmitter<KritzelContextMenuState>;
147
147
  /** Emitted when the combined loading state (external `isLoading` prop or internal workspace loading) changes. */
148
148
  loadingChange: EventEmitter<boolean>;
149
- /** Emitted when remote workspace synchronization is in progress. */
149
+ /** Emitted while remote changes are being applied to the active workspace. Stays silent when the remote holds nothing new. */
150
150
  syncingChange: EventEmitter<boolean>;
151
151
  forceUpdate: number;
152
152
  isSyncing: boolean;
@@ -634,6 +634,7 @@ export declare class KritzelEngine {
634
634
  private _sceneBootstrapOpacity;
635
635
  private _sceneBootstrapTransitionEnabled;
636
636
  private _sceneBootstrapTransitionTimer;
637
+ private _remoteChangesUnsubscribe;
637
638
  private readonly _defaultUndoState;
638
639
  private readonly _objectDistanceFadeNearScale;
639
640
  private readonly _objectDistanceFadeFarScale;
@@ -643,6 +644,7 @@ export declare class KritzelEngine {
643
644
  private readonly _objectDistanceFadeCloseMinOpacity;
644
645
  private syncLoadingState;
645
646
  private syncSyncingState;
647
+ private clearRemoteChangesSubscription;
646
648
  private isNetworkAvailable;
647
649
  private emitContextMenuStateChange;
648
650
  private applyToolConfig;
@@ -680,6 +682,12 @@ export declare class KritzelEngine {
680
682
  private tryResolveActiveWorkspaceFromId;
681
683
  private switchToWorkspaceById;
682
684
  private initializeWorkspaceIfNeeded;
685
+ /**
686
+ * Reports syncing only while remote data is actually being reconciled into the
687
+ * active workspace. Yjs suppresses updates that carry nothing new, so a workspace
688
+ * that already matches the remote never reports syncing at all.
689
+ */
690
+ private trackRemoteSynchronization;
683
691
  emitObjectsChange(): void;
684
692
  emitObjectsAdded(objects: KritzelBaseObject<any>[]): void;
685
693
  emitObjectsRemoved(objects: KritzelBaseObject<any>[]): void;
@@ -2003,6 +2003,8 @@ declare global {
2003
2003
  "login": LoginEvent;
2004
2004
  "isPublicChange": IKritzelIsPublicChangedEvent;
2005
2005
  "awarenessChange": Map<number, Record<string, any>>;
2006
+ "syncingChange": boolean;
2007
+ "loadingChange": boolean;
2006
2008
  }
2007
2009
  interface HTMLKritzelEditorElement extends Components.KritzelEditor, HTMLStencilElement {
2008
2010
  addEventListener<K extends keyof HTMLKritzelEditorElementEventMap>(type: K, listener: (this: HTMLKritzelEditorElement, ev: KritzelEditorCustomEvent<HTMLKritzelEditorElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
@@ -3011,6 +3013,7 @@ declare namespace LocalJSX {
3011
3013
  "onAwarenessChange"?: (event: KritzelEditorCustomEvent<Map<number, Record<string, any>>>) => void;
3012
3014
  "onIsPublicChange"?: (event: KritzelEditorCustomEvent<IKritzelIsPublicChangedEvent>) => void;
3013
3015
  "onIsReady"?: (event: KritzelEditorCustomEvent<EditorIsReadyEvent>) => void;
3016
+ "onLoadingChange"?: (event: KritzelEditorCustomEvent<boolean>) => void;
3014
3017
  "onLocaleChange"?: (event: KritzelEditorCustomEvent<LocaleCode>) => void;
3015
3018
  "onLogin"?: (event: KritzelEditorCustomEvent<LoginEvent>) => void;
3016
3019
  "onLogout"?: (event: KritzelEditorCustomEvent<void>) => void;
@@ -3018,6 +3021,10 @@ declare namespace LocalJSX {
3018
3021
  "onObjectsChange"?: (event: KritzelEditorCustomEvent<KritzelBaseObject[]>) => void;
3019
3022
  "onObjectsRemoved"?: (event: KritzelEditorCustomEvent<ObjectsRemovedEvent>) => void;
3020
3023
  "onObjectsUpdated"?: (event: KritzelEditorCustomEvent<ObjectsUpdatedEvent>) => void;
3024
+ /**
3025
+ * Emitted while remote changes are being applied to the active workspace. Stays silent when the remote holds nothing new.
3026
+ */
3027
+ "onSyncingChange"?: (event: KritzelEditorCustomEvent<boolean>) => void;
3021
3028
  "onThemeChange"?: (event: KritzelEditorCustomEvent<ThemeName>) => void;
3022
3029
  "onUndoStateChange"?: (event: KritzelEditorCustomEvent<KritzelUndoState1>) => void;
3023
3030
  "onViewportChange"?: (event: KritzelEditorCustomEvent<KritzelViewportState>) => void;
@@ -3185,7 +3192,7 @@ declare namespace LocalJSX {
3185
3192
  */
3186
3193
  "onObjectsUpdated"?: (event: KritzelEngineCustomEvent<ObjectsUpdatedEvent>) => void;
3187
3194
  /**
3188
- * Emitted when remote workspace synchronization is in progress.
3195
+ * Emitted while remote changes are being applied to the active workspace. Stays silent when the remote holds nothing new.
3189
3196
  */
3190
3197
  "onSyncingChange"?: (event: KritzelEngineCustomEvent<boolean>) => void;
3191
3198
  /**