kritzel-stencil 0.1.76 → 0.1.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs.js +2 -330
- package/dist/cjs/kritzel-active-users_42.cjs.entry.js +36 -18
- package/dist/cjs/{workspace.migrations-DkmVO6dE.js → workspace.migrations-OULs44dI.js} +331 -2
- package/dist/collection/classes/objects/selection-group.class.js +2 -0
- package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.css +6 -1
- package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.js +5 -2
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.css +2 -0
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +12 -6
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +18 -8
- package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.css +1 -0
- package/dist/collection/constants/version.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/kritzel-awareness-cursors.js +1 -1
- package/dist/components/kritzel-controls.js +1 -1
- package/dist/components/kritzel-editor.js +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-settings.js +1 -1
- package/dist/components/kritzel-tool-config.js +1 -1
- package/dist/components/kritzel-utility-panel.js +1 -1
- package/dist/components/{p-DvIEvoZu.js → p-BK1hLBTd.js} +1 -1
- package/dist/components/{p-jdYmu4SA.js → p-BdGcOXa5.js} +2 -2
- package/dist/components/{p-CsoDfhD5.js → p-C_X8stam.js} +1 -1
- package/dist/components/p-WotNmY5q.js +1 -0
- package/dist/components/{p-31FVoNWR.js → p-XS5J5W5_.js} +1 -1
- package/dist/components/{p-CJ2eHeoV.js → p-_CqLIbO6.js} +1 -1
- package/dist/components/{p-2OYw6GJ7.js → p-_LbtY-TA.js} +1 -1
- package/dist/esm/index.js +2 -331
- package/dist/esm/kritzel-active-users_42.entry.js +36 -18
- package/dist/esm/{workspace.migrations-D48_Bqvh.js → workspace.migrations-D6whgl7G.js} +331 -1
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/p-8fe1ec39.entry.js +9 -0
- package/dist/stencil/p-D6whgl7G.js +1 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/objects/selection-group.class.d.ts +1 -0
- package/dist/types/components.d.ts +8 -2
- package/dist/types/constants/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/components/p-xNwOWoiT.js +0 -1
- package/dist/stencil/p-775a7246.entry.js +0 -9
- package/dist/stencil/p-D48_Bqvh.js +0 -1
package/dist/cjs/index.cjs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var workspace_migrations = require('./workspace.migrations-
|
|
3
|
+
var workspace_migrations = require('./workspace.migrations-OULs44dI.js');
|
|
4
4
|
var Y = require('yjs');
|
|
5
5
|
var yWebsocket = require('y-websocket');
|
|
6
6
|
require('y-indexeddb');
|
|
@@ -557,340 +557,13 @@ class WebSocketSyncProvider {
|
|
|
557
557
|
}
|
|
558
558
|
}
|
|
559
559
|
|
|
560
|
-
/**
|
|
561
|
-
* Hocuspocus sync provider for real-time collaboration
|
|
562
|
-
* Supports multiplexing - multiple documents can share the same WebSocket connection
|
|
563
|
-
*/
|
|
564
|
-
class HocuspocusSyncProvider {
|
|
565
|
-
type = 'network';
|
|
566
|
-
provider;
|
|
567
|
-
isConnected = false;
|
|
568
|
-
isSynced = false;
|
|
569
|
-
usesSharedSocket = false;
|
|
570
|
-
isDestroyed = false;
|
|
571
|
-
connectTimeout = null;
|
|
572
|
-
pendingConnectReject = null;
|
|
573
|
-
connectionTimeoutMs;
|
|
574
|
-
_connectionStatus = 'disconnected';
|
|
575
|
-
visibilityHandler = null;
|
|
576
|
-
onlineHandler = null;
|
|
577
|
-
get awareness() {
|
|
578
|
-
return this.provider.awareness;
|
|
579
|
-
}
|
|
580
|
-
get connectionStatus() {
|
|
581
|
-
return this._connectionStatus;
|
|
582
|
-
}
|
|
583
|
-
// Static shared WebSocket instance for multiplexing
|
|
584
|
-
static sharedWebSocketProvider = null;
|
|
585
|
-
constructor(docName, doc, options) {
|
|
586
|
-
const name = options?.name || docName;
|
|
587
|
-
const url = options?.url || 'ws://localhost:1234';
|
|
588
|
-
this.connectionTimeoutMs = options?.connectionTimeout ?? 10000;
|
|
589
|
-
// Use provided websocketProvider or the static shared one
|
|
590
|
-
const websocketProvider = options?.websocketProvider || HocuspocusSyncProvider.sharedWebSocketProvider;
|
|
591
|
-
// Build reconnect config from options
|
|
592
|
-
const reconnectConfig = {};
|
|
593
|
-
if (options?.delay !== undefined)
|
|
594
|
-
reconnectConfig.delay = options.delay;
|
|
595
|
-
if (options?.factor !== undefined)
|
|
596
|
-
reconnectConfig.factor = options.factor;
|
|
597
|
-
if (options?.maxAttempts !== undefined)
|
|
598
|
-
reconnectConfig.maxAttempts = options.maxAttempts;
|
|
599
|
-
if (options?.minDelay !== undefined)
|
|
600
|
-
reconnectConfig.minDelay = options.minDelay;
|
|
601
|
-
if (options?.maxDelay !== undefined)
|
|
602
|
-
reconnectConfig.maxDelay = options.maxDelay;
|
|
603
|
-
const onConnect = () => {
|
|
604
|
-
if (this.isDestroyed) {
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
this.isConnected = true;
|
|
608
|
-
this._connectionStatus = 'connected';
|
|
609
|
-
if (!options?.quiet) {
|
|
610
|
-
console.info(`Hocuspocus connected: ${name}`);
|
|
611
|
-
}
|
|
612
|
-
if (options?.onConnect) {
|
|
613
|
-
options.onConnect();
|
|
614
|
-
}
|
|
615
|
-
};
|
|
616
|
-
const onDisconnect = () => {
|
|
617
|
-
if (this.isDestroyed) {
|
|
618
|
-
return;
|
|
619
|
-
}
|
|
620
|
-
this.isConnected = false;
|
|
621
|
-
this.isSynced = false;
|
|
622
|
-
this._connectionStatus = 'disconnected';
|
|
623
|
-
if (!options?.quiet) {
|
|
624
|
-
console.info(`Hocuspocus disconnected: ${name}`);
|
|
625
|
-
}
|
|
626
|
-
if (options?.onDisconnect) {
|
|
627
|
-
options.onDisconnect();
|
|
628
|
-
}
|
|
629
|
-
};
|
|
630
|
-
const onSynced = () => {
|
|
631
|
-
if (this.isDestroyed) {
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
this.isSynced = true;
|
|
635
|
-
this._connectionStatus = 'synced';
|
|
636
|
-
if (!options?.quiet) {
|
|
637
|
-
console.info(`Hocuspocus synced: ${name}`);
|
|
638
|
-
}
|
|
639
|
-
if (options?.onSynced) {
|
|
640
|
-
options.onSynced();
|
|
641
|
-
}
|
|
642
|
-
};
|
|
643
|
-
const onStatus = (data) => {
|
|
644
|
-
if (this.isDestroyed) {
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
if (data.status === 'connecting') {
|
|
648
|
-
this._connectionStatus = 'connecting';
|
|
649
|
-
}
|
|
650
|
-
if (options?.onStatus) {
|
|
651
|
-
options.onStatus(data);
|
|
652
|
-
}
|
|
653
|
-
};
|
|
654
|
-
if (websocketProvider) {
|
|
655
|
-
// Multiplexing mode - use shared WebSocket connection
|
|
656
|
-
this.usesSharedSocket = true;
|
|
657
|
-
const config = {
|
|
658
|
-
websocketProvider,
|
|
659
|
-
name,
|
|
660
|
-
document: doc,
|
|
661
|
-
token: options?.token || null,
|
|
662
|
-
onStatus,
|
|
663
|
-
onConnect,
|
|
664
|
-
onDisconnect,
|
|
665
|
-
onSynced,
|
|
666
|
-
...reconnectConfig,
|
|
667
|
-
};
|
|
668
|
-
// Add optional settings
|
|
669
|
-
if (options?.forceSyncInterval !== undefined) {
|
|
670
|
-
config.forceSyncInterval = options.forceSyncInterval;
|
|
671
|
-
}
|
|
672
|
-
if (options?.onAuthenticationFailed) {
|
|
673
|
-
config.onAuthenticationFailed = options.onAuthenticationFailed;
|
|
674
|
-
}
|
|
675
|
-
this.provider = new workspace_migrations.HocuspocusProvider(config);
|
|
676
|
-
// Must call attach() explicitly when using shared socket
|
|
677
|
-
this.provider.attach();
|
|
678
|
-
if (!options?.quiet) {
|
|
679
|
-
console.info(`Hocuspocus Provider initialized (multiplexed): ${name}`);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
else {
|
|
683
|
-
// Standalone mode - create own WebSocket connection
|
|
684
|
-
this.usesSharedSocket = false;
|
|
685
|
-
const config = {
|
|
686
|
-
url,
|
|
687
|
-
name,
|
|
688
|
-
document: doc,
|
|
689
|
-
token: options?.token || null,
|
|
690
|
-
autoConnect: false,
|
|
691
|
-
onStatus,
|
|
692
|
-
onConnect,
|
|
693
|
-
onDisconnect,
|
|
694
|
-
onSynced,
|
|
695
|
-
...reconnectConfig,
|
|
696
|
-
};
|
|
697
|
-
// Add optional settings
|
|
698
|
-
if (options?.forceSyncInterval !== undefined) {
|
|
699
|
-
config.forceSyncInterval = options.forceSyncInterval;
|
|
700
|
-
}
|
|
701
|
-
if (options?.onAuthenticationFailed) {
|
|
702
|
-
config.onAuthenticationFailed = options.onAuthenticationFailed;
|
|
703
|
-
}
|
|
704
|
-
if (options?.WebSocketPolyfill) {
|
|
705
|
-
config.WebSocketPolyfill = options.WebSocketPolyfill;
|
|
706
|
-
}
|
|
707
|
-
this.provider = new workspace_migrations.HocuspocusProvider(config);
|
|
708
|
-
if (!options?.quiet) {
|
|
709
|
-
console.info(`Hocuspocus Provider initialized: ${url}/${name}`);
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
this.setupBrowserEventListeners();
|
|
713
|
-
}
|
|
714
|
-
setupBrowserEventListeners() {
|
|
715
|
-
if (typeof document !== 'undefined') {
|
|
716
|
-
this.visibilityHandler = () => {
|
|
717
|
-
if (document.visibilityState === 'visible' && !this.isConnected && !this.isDestroyed) {
|
|
718
|
-
this.provider.connect();
|
|
719
|
-
}
|
|
720
|
-
};
|
|
721
|
-
document.addEventListener('visibilitychange', this.visibilityHandler);
|
|
722
|
-
}
|
|
723
|
-
if (typeof window !== 'undefined') {
|
|
724
|
-
this.onlineHandler = () => {
|
|
725
|
-
if (!this.isConnected && !this.isDestroyed) {
|
|
726
|
-
this.provider.connect();
|
|
727
|
-
}
|
|
728
|
-
};
|
|
729
|
-
window.addEventListener('online', this.onlineHandler);
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
removeBrowserEventListeners() {
|
|
733
|
-
if (this.visibilityHandler && typeof document !== 'undefined') {
|
|
734
|
-
document.removeEventListener('visibilitychange', this.visibilityHandler);
|
|
735
|
-
this.visibilityHandler = null;
|
|
736
|
-
}
|
|
737
|
-
if (this.onlineHandler && typeof window !== 'undefined') {
|
|
738
|
-
window.removeEventListener('online', this.onlineHandler);
|
|
739
|
-
this.onlineHandler = null;
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
/**
|
|
743
|
-
* Create a shared WebSocket connection for multiplexing
|
|
744
|
-
* Call this once to create a shared connection that multiple providers can use
|
|
745
|
-
*/
|
|
746
|
-
static createSharedWebSocket(options) {
|
|
747
|
-
if (HocuspocusSyncProvider.sharedWebSocketProvider) {
|
|
748
|
-
console.warn('Shared WebSocket already exists. Returning existing instance.');
|
|
749
|
-
return HocuspocusSyncProvider.sharedWebSocketProvider;
|
|
750
|
-
}
|
|
751
|
-
const config = {
|
|
752
|
-
url: options.url,
|
|
753
|
-
};
|
|
754
|
-
if (options.WebSocketPolyfill) {
|
|
755
|
-
config.WebSocketPolyfill = options.WebSocketPolyfill;
|
|
756
|
-
}
|
|
757
|
-
if (options.onConnect) {
|
|
758
|
-
config.onConnect = options.onConnect;
|
|
759
|
-
}
|
|
760
|
-
if (options.onDisconnect) {
|
|
761
|
-
config.onDisconnect = options.onDisconnect;
|
|
762
|
-
}
|
|
763
|
-
if (options.onStatus) {
|
|
764
|
-
config.onStatus = options.onStatus;
|
|
765
|
-
}
|
|
766
|
-
HocuspocusSyncProvider.sharedWebSocketProvider = new workspace_migrations.HocuspocusProviderWebsocket(config);
|
|
767
|
-
console.info(`Shared Hocuspocus WebSocket created: ${options.url}`);
|
|
768
|
-
return HocuspocusSyncProvider.sharedWebSocketProvider;
|
|
769
|
-
}
|
|
770
|
-
/**
|
|
771
|
-
* Destroy the shared WebSocket connection
|
|
772
|
-
* Call this when you're done with all multiplexed providers
|
|
773
|
-
*/
|
|
774
|
-
static destroySharedWebSocket() {
|
|
775
|
-
if (HocuspocusSyncProvider.sharedWebSocketProvider) {
|
|
776
|
-
HocuspocusSyncProvider.sharedWebSocketProvider.destroy();
|
|
777
|
-
HocuspocusSyncProvider.sharedWebSocketProvider = null;
|
|
778
|
-
console.info('Shared Hocuspocus WebSocket destroyed');
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
/**
|
|
782
|
-
* Get the shared WebSocket provider instance (if it exists)
|
|
783
|
-
*/
|
|
784
|
-
static getSharedWebSocket() {
|
|
785
|
-
return HocuspocusSyncProvider.sharedWebSocketProvider;
|
|
786
|
-
}
|
|
787
|
-
/**
|
|
788
|
-
* Static factory method for creating HocuspocusSyncProvider with configuration options
|
|
789
|
-
* Returns a ProviderFactory that can be used in sync configuration
|
|
790
|
-
*/
|
|
791
|
-
static with(options) {
|
|
792
|
-
return {
|
|
793
|
-
create: (docName, doc, runtimeOptions) => {
|
|
794
|
-
const mergedOptions = runtimeOptions ? { ...options, ...runtimeOptions } : options;
|
|
795
|
-
return new HocuspocusSyncProvider(docName, doc, mergedOptions);
|
|
796
|
-
},
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
async connect() {
|
|
800
|
-
if (this.isSynced || this.isDestroyed) {
|
|
801
|
-
return;
|
|
802
|
-
}
|
|
803
|
-
this._connectionStatus = 'connecting';
|
|
804
|
-
return new Promise((resolve, reject) => {
|
|
805
|
-
// Store reject function so we can cancel the connection if destroyed
|
|
806
|
-
this.pendingConnectReject = reject;
|
|
807
|
-
this.connectTimeout = setTimeout(() => {
|
|
808
|
-
this.pendingConnectReject = null;
|
|
809
|
-
this.connectTimeout = null;
|
|
810
|
-
reject(new Error('Hocuspocus connection timeout'));
|
|
811
|
-
}, this.connectionTimeoutMs);
|
|
812
|
-
const syncHandler = () => {
|
|
813
|
-
if (this.connectTimeout) {
|
|
814
|
-
clearTimeout(this.connectTimeout);
|
|
815
|
-
this.connectTimeout = null;
|
|
816
|
-
}
|
|
817
|
-
this.pendingConnectReject = null;
|
|
818
|
-
this.provider.off('synced', syncHandler);
|
|
819
|
-
if (!this.isDestroyed) {
|
|
820
|
-
resolve();
|
|
821
|
-
}
|
|
822
|
-
};
|
|
823
|
-
this.provider.on('synced', syncHandler);
|
|
824
|
-
// If already synced, resolve immediately
|
|
825
|
-
if (this.provider.isSynced) {
|
|
826
|
-
if (this.connectTimeout) {
|
|
827
|
-
clearTimeout(this.connectTimeout);
|
|
828
|
-
this.connectTimeout = null;
|
|
829
|
-
}
|
|
830
|
-
this.pendingConnectReject = null;
|
|
831
|
-
this.provider.off('synced', syncHandler);
|
|
832
|
-
resolve();
|
|
833
|
-
return;
|
|
834
|
-
}
|
|
835
|
-
// Connect if not already connected (standalone mode only)
|
|
836
|
-
if (!this.isConnected && !this.usesSharedSocket) {
|
|
837
|
-
this.provider.connect();
|
|
838
|
-
}
|
|
839
|
-
});
|
|
840
|
-
}
|
|
841
|
-
async reconnect() {
|
|
842
|
-
this.disconnect();
|
|
843
|
-
return this.connect();
|
|
844
|
-
}
|
|
845
|
-
disconnect() {
|
|
846
|
-
// Cancel any pending connection attempt
|
|
847
|
-
if (this.connectTimeout) {
|
|
848
|
-
clearTimeout(this.connectTimeout);
|
|
849
|
-
this.connectTimeout = null;
|
|
850
|
-
}
|
|
851
|
-
if (this.pendingConnectReject) {
|
|
852
|
-
this.pendingConnectReject = null; // Don't reject, just abandon the promise
|
|
853
|
-
}
|
|
854
|
-
if (this.provider) {
|
|
855
|
-
if (this.usesSharedSocket) {
|
|
856
|
-
// Detach from shared socket instead of disconnecting
|
|
857
|
-
this.provider.detach();
|
|
858
|
-
}
|
|
859
|
-
else {
|
|
860
|
-
this.provider.disconnect();
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
this.isConnected = false;
|
|
864
|
-
this.isSynced = false;
|
|
865
|
-
this._connectionStatus = 'disconnected';
|
|
866
|
-
}
|
|
867
|
-
destroy() {
|
|
868
|
-
// Mark as destroyed first to prevent any callbacks from doing work
|
|
869
|
-
this.isDestroyed = true;
|
|
870
|
-
// Cancel any pending connection attempt
|
|
871
|
-
if (this.connectTimeout) {
|
|
872
|
-
clearTimeout(this.connectTimeout);
|
|
873
|
-
this.connectTimeout = null;
|
|
874
|
-
}
|
|
875
|
-
if (this.pendingConnectReject) {
|
|
876
|
-
this.pendingConnectReject = null; // Don't reject, just abandon the promise
|
|
877
|
-
}
|
|
878
|
-
this.removeBrowserEventListeners();
|
|
879
|
-
if (this.provider) {
|
|
880
|
-
this.provider.destroy();
|
|
881
|
-
}
|
|
882
|
-
this.isConnected = false;
|
|
883
|
-
this.isSynced = false;
|
|
884
|
-
this._connectionStatus = 'disconnected';
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
|
|
888
560
|
exports.APP_STATE_MIGRATIONS = workspace_migrations.APP_STATE_MIGRATIONS;
|
|
889
561
|
exports.CURRENT_APP_STATE_SCHEMA_VERSION = workspace_migrations.CURRENT_APP_STATE_SCHEMA_VERSION;
|
|
890
562
|
exports.CURRENT_WORKSPACE_SCHEMA_VERSION = workspace_migrations.CURRENT_WORKSPACE_SCHEMA_VERSION;
|
|
891
563
|
exports.DEFAULT_BRUSH_CONFIG = workspace_migrations.DEFAULT_BRUSH_CONFIG;
|
|
892
564
|
exports.DEFAULT_LINE_TOOL_CONFIG = workspace_migrations.DEFAULT_LINE_TOOL_CONFIG;
|
|
893
565
|
exports.DEFAULT_TEXT_CONFIG = workspace_migrations.DEFAULT_TEXT_CONFIG;
|
|
566
|
+
exports.HocuspocusSyncProvider = workspace_migrations.HocuspocusSyncProvider;
|
|
894
567
|
exports.IndexedDBSyncProvider = workspace_migrations.IndexedDBSyncProvider;
|
|
895
568
|
Object.defineProperty(exports, "KritzelAlignment", {
|
|
896
569
|
enumerable: true,
|
|
@@ -923,5 +596,4 @@ exports.darkTheme = workspace_migrations.darkTheme;
|
|
|
923
596
|
exports.lightTheme = workspace_migrations.lightTheme;
|
|
924
597
|
exports.runMigrations = workspace_migrations.runMigrations;
|
|
925
598
|
exports.BroadcastSyncProvider = BroadcastSyncProvider;
|
|
926
|
-
exports.HocuspocusSyncProvider = HocuspocusSyncProvider;
|
|
927
599
|
exports.WebSocketSyncProvider = WebSocketSyncProvider;
|
|
@@ -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-
|
|
4
|
+
var workspace_migrations = require('./workspace.migrations-OULs44dI.js');
|
|
5
5
|
var Y = require('yjs');
|
|
6
6
|
require('y-websocket');
|
|
7
7
|
require('y-indexeddb');
|
|
@@ -176,7 +176,7 @@ const KritzelAvatar = class {
|
|
|
176
176
|
};
|
|
177
177
|
KritzelAvatar.style = kritzelAvatarCss();
|
|
178
178
|
|
|
179
|
-
const kritzelAwarenessCursorsCss = () => `:host{display:block;position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:
|
|
179
|
+
const kritzelAwarenessCursorsCss = () => `:host{display:block;position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:1}.awareness-cursor{position:absolute;top:0;left:0;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, opacity 300ms ease;will-change:transform}.awareness-cursor.stale{opacity:0}.awareness-cursor.tracking-object{transition-duration:0ms}.cursor-arrow{filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.cursor-label{position:absolute;left:16px;top:16px;white-space:nowrap;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;font-size:var(--kritzel-awareness-cursor-label-font-size, 12px);color:var(--kritzel-awareness-cursor-label-text-color, #ffffff);padding:2px 8px;border-radius:4px;line-height:1.4;font-weight:500;pointer-events:none;user-select:none}.edge-indicator{position:absolute;top:-12px;left:-12px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, opacity 300ms ease;will-change:transform;pointer-events:auto;user-select:none;cursor:pointer}.edge-indicator.stale{opacity:0}.edge-indicator.tracking-object{transition-duration:0ms}.edge-arrow{position:absolute;filter:drop-shadow(0 1px 3px rgba(0, 0, 0, 0.3));transition:opacity 300ms ease}.edge-arrow.stale{opacity:0}.edge-label{position:absolute;white-space:nowrap;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;font-size:var(--kritzel-awareness-cursor-label-font-size, 12px);color:var(--kritzel-awareness-cursor-label-text-color, #ffffff);padding:2px 8px;border-radius:4px;line-height:1.4;font-weight:500;pointer-events:none;opacity:0;transform-origin:center;transition:opacity 150ms ease}.edge-indicator:hover .edge-label{opacity:1}.remote-selection-box{position:absolute;top:0;left:0;border-width:2px;border-style:solid;pointer-events:none;will-change:transform, width, height;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, width var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, height var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out}`;
|
|
180
180
|
|
|
181
181
|
const STALE_THRESHOLD_MS = 10_000;
|
|
182
182
|
const REMOVE_THRESHOLD_MS = 30_000;
|
|
@@ -258,6 +258,9 @@ const KritzelAwarenessCursors = class {
|
|
|
258
258
|
updated.delete(clientId);
|
|
259
259
|
changed = true;
|
|
260
260
|
}
|
|
261
|
+
else if (!changed && now - cursor.lastCursorMove > STALE_THRESHOLD_MS) {
|
|
262
|
+
changed = true;
|
|
263
|
+
}
|
|
261
264
|
}
|
|
262
265
|
if (changed) {
|
|
263
266
|
this.remoteCursors = updated;
|
|
@@ -353,7 +356,7 @@ const KritzelAwarenessCursors = class {
|
|
|
353
356
|
}
|
|
354
357
|
render() {
|
|
355
358
|
const cursors = Array.from(this.remoteCursors.values());
|
|
356
|
-
return (index.h(index.Host, { key: '
|
|
359
|
+
return (index.h(index.Host, { key: '5a28def6e024249c4309c087502cde9f219f5421' }, cursors.map(remoteCursor => {
|
|
357
360
|
if (!remoteCursor.cursor)
|
|
358
361
|
return null;
|
|
359
362
|
// When a remote user is actively drawing, derive cursor position from
|
|
@@ -429,7 +432,7 @@ const KritzelAwarenessCursors = class {
|
|
|
429
432
|
const displayName = this.getUserDisplayName(cursor.user);
|
|
430
433
|
return (index.h("div", { key: `edge-${cursor.clientId}`, class: { 'edge-indicator': true, stale, 'tracking-object': trackingObject }, style: {
|
|
431
434
|
transform: `translate(${clamped.x}px, ${clamped.y}px)`,
|
|
432
|
-
} }, index.h("svg", { class:
|
|
435
|
+
} }, index.h("svg", { class: { 'edge-arrow': true, stale }, 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: {
|
|
433
436
|
backgroundColor: color,
|
|
434
437
|
transform: `translate(${labelX}px, ${labelY}px)`,
|
|
435
438
|
} }, displayName)));
|
|
@@ -1854,7 +1857,7 @@ const DEFAULT_SHAPE_CONFIG = {
|
|
|
1854
1857
|
const ABSOLUTE_SCALE_MAX = 1000;
|
|
1855
1858
|
const ABSOLUTE_SCALE_MIN = 0.0001;
|
|
1856
1859
|
|
|
1857
|
-
const kritzelEditorCss = () => `kritzel-editor{display:flex;margin:0;position:relative;overflow:hidden;width:100%;height:100%;align-items:center;justify-content:center;touch-action:manipulation;user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}kritzel-controls{position:absolute;bottom:var(--kritzel-editor-controls-bottom, 14px);transition:transform var(--kritzel-editor-controls-transition-duration, 0.1s) var(--kritzel-editor-controls-transition, ease-in-out)}kritzel-controls.keyboard-open{transform:var(--kritzel-editor-controls-transform, translateY(300%))}.top-left-buttons{position:absolute;top:var(--kritzel-editor-top-left-buttons-top, 14px);left:var(--kritzel-editor-top-left-buttons-left, 14px);display:flex;align-items:flex-start;gap:8px}.top-right-buttons{position:absolute;top:var(--kritzel-editor-top-right-buttons-top, 14px);right:var(--kritzel-editor-top-right-buttons-right, 14px);display:flex;align-items:center;gap:8px}.top-right-button{display:flex;align-items:center;justify-content:center;width:50px;height:50px;padding:0;border:var(--kritzel-split-button-border, 1px solid #ebebeb);border-radius:var(--kritzel-split-button-border-radius, 12px);background-color:var(--kritzel-split-button-background-color, #ffffff);cursor:var(--kritzel-global-pointer-cursor, pointer);box-shadow:var(--kritzel-split-button-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));transition:background-color 150ms ease;-webkit-tap-highlight-color:transparent}.top-right-button:hover{background-color:#f5f5f5}.top-right-button:active{background-color:#ebebeb}`;
|
|
1860
|
+
const kritzelEditorCss = () => `kritzel-editor{display:flex;margin:0;position:relative;overflow:hidden;width:100%;height:100%;align-items:center;justify-content:center;touch-action:manipulation;user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}kritzel-controls{position:absolute;bottom:var(--kritzel-editor-controls-bottom, 14px);transition:transform var(--kritzel-editor-controls-transition-duration, 0.1s) var(--kritzel-editor-controls-transition, ease-in-out)}kritzel-controls.keyboard-open{transform:var(--kritzel-editor-controls-transform, translateY(300%))}.top-left-buttons{position:absolute;top:var(--kritzel-editor-top-left-buttons-top, 14px);left:var(--kritzel-editor-top-left-buttons-left, 14px);display:flex;align-items:flex-start;gap:8px;z-index:10000}.top-right-buttons{position:absolute;top:var(--kritzel-editor-top-right-buttons-top, 14px);right:var(--kritzel-editor-top-right-buttons-right, 14px);display:flex;align-items:center;gap:8px;z-index:10000}.top-right-button{display:flex;align-items:center;justify-content:center;width:50px;height:50px;padding:0;border:var(--kritzel-split-button-border, 1px solid #ebebeb);border-radius:var(--kritzel-split-button-border-radius, 12px);background-color:var(--kritzel-split-button-background-color, #ffffff);cursor:var(--kritzel-global-pointer-cursor, pointer);box-shadow:var(--kritzel-split-button-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));transition:background-color 150ms ease;-webkit-tap-highlight-color:transparent}.top-right-button:hover{background-color:#f5f5f5}.top-right-button:active{background-color:#ebebeb}`;
|
|
1858
1861
|
|
|
1859
1862
|
const KritzelEditor = class {
|
|
1860
1863
|
constructor(hostRef) {
|
|
@@ -1888,7 +1891,11 @@ const KritzelEditor = class {
|
|
|
1888
1891
|
showSyncProviderInfo: true,
|
|
1889
1892
|
showMigrationInfo: true,
|
|
1890
1893
|
};
|
|
1891
|
-
user
|
|
1894
|
+
user = {
|
|
1895
|
+
id: `guest-1`,
|
|
1896
|
+
displayName: 'Guest',
|
|
1897
|
+
isGuest: false,
|
|
1898
|
+
};
|
|
1892
1899
|
activeUsers;
|
|
1893
1900
|
controls = [
|
|
1894
1901
|
{
|
|
@@ -2033,7 +2040,8 @@ const KritzelEditor = class {
|
|
|
2033
2040
|
isControlsVisible = true;
|
|
2034
2041
|
isUtilityPanelVisible = true;
|
|
2035
2042
|
syncConfig = {
|
|
2036
|
-
|
|
2043
|
+
appStateId: 'kritzel-app-test',
|
|
2044
|
+
providers: [workspace_migrations.HocuspocusSyncProvider, workspace_migrations.IndexedDBSyncProvider]
|
|
2037
2045
|
};
|
|
2038
2046
|
/** Optional login configuration. When provided, a "Sign in" button is shown that opens a login dialog with the configured providers. */
|
|
2039
2047
|
loginConfig;
|
|
@@ -2550,7 +2558,7 @@ const KritzelEditor = class {
|
|
|
2550
2558
|
const isLoggedIn = this.isLoggedIn;
|
|
2551
2559
|
const shouldShowCurrentUser = isLoggedIn;
|
|
2552
2560
|
const shouldShowLoginButton = !!this.loginConfig && !isLoggedIn;
|
|
2553
|
-
return (index.h(index.Host, { key: '
|
|
2561
|
+
return (index.h(index.Host, { key: 'b52c23bf28392a0061034c0909aadb7abf4d86a7' }, index.h("div", { key: '7bf75101bef73a2c8481258060e3236a8ca939b4', class: "top-left-buttons" }, index.h("kritzel-workspace-manager", { key: '69adc1756e00ed56c9980e78929543ad4ecc7b0e', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-back-to-content", { key: 'd802fe454738919d9108a807eb379b2f31e94ab6', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), index.h("kritzel-engine", { key: '2d3ce8937285956d978f3947ffa86872e156b04d', 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: '6d9b0640b205143c7dc21572616624ef707cfe06', 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: 'c65f16c40d78d8e3eb585e870e414f496e816e82', class: "top-right-buttons" }, index.h("kritzel-settings", { key: 'a84d5de344011a32be1b4178acc3a5fff246d702', ref: el => (this.settingsRef = el), shortcuts: this.shortcuts, editorId: this.editorId, onSettingsChange: event => this.handleSettingsChange(event) }), index.h("kritzel-export", { key: '67748d0376f4e7ac39edfc61c1c2cd639664ad78', 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: '1155b8784de2353ae208a2910844bad1e945a891', users: this.activeUsers }), shouldShowCurrentUser && index.h("kritzel-current-user", { key: 'fb8951eed7f7f5c9117bb0027e9af1aae95088ed', user: this.user }), shouldShowLoginButton && index.h("kritzel-button", { key: 'd4288b1577082c207696331de4d9fcb1e749fa2a', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in"), index.h("kritzel-more-menu", { key: '66f0990868bf034a172e6e8db3162a1af0637cf8', items: this.moreMenuItems }), index.h("kritzel-share-dialog", { key: 'ce3ab2b6db71bf0a4998c16f04521ee39c1715b7', ref: el => (this.shareDialogRef = el), isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: 'd3ec7461c2e6a8fcdac4ce13a51f80835888cb44', ref: el => (this.loginDialogRef = el), providers: this.loginConfig.providers, dialogTitle: this.loginConfig.title, subtitle: this.loginConfig.subtitle, onProviderLogin: this.handleProviderLogin })))));
|
|
2554
2562
|
}
|
|
2555
2563
|
static get watchers() { return {
|
|
2556
2564
|
"isEngineReady": [{
|
|
@@ -27021,18 +27029,28 @@ const KritzelEngine = class {
|
|
|
27021
27029
|
zIndex: (object.zIndex + 2).toString(),
|
|
27022
27030
|
} }, 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)) &&
|
|
27023
27031
|
(() => {
|
|
27024
|
-
const
|
|
27025
|
-
|
|
27026
|
-
|
|
27027
|
-
|
|
27032
|
+
const isSelectionGroup = workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
|
|
27033
|
+
const localClientId = this.core.store.state.objects?.localClientId;
|
|
27034
|
+
const isRemoteSelection = isSelectionGroup && (
|
|
27035
|
+
// Different user
|
|
27036
|
+
(object.userId != null && this.core.user?.id != null && object.userId !== this.core.user.id) ||
|
|
27037
|
+
// Same user but different client (e.g. same account in two browser tabs)
|
|
27038
|
+
(object.clientId != null && localClientId != null && object.clientId !== localClientId));
|
|
27028
27039
|
let remoteUserColor;
|
|
27029
27040
|
if (isRemoteSelection) {
|
|
27030
27041
|
const awarenessStates = this.core.store.state.objects?.awareness?.getStates();
|
|
27031
27042
|
if (awarenessStates) {
|
|
27032
|
-
|
|
27033
|
-
|
|
27034
|
-
|
|
27035
|
-
|
|
27043
|
+
// Try direct lookup by clientId first (most precise)
|
|
27044
|
+
if (isSelectionGroup && object.clientId != null) {
|
|
27045
|
+
remoteUserColor = awarenessStates.get(object.clientId)?.user?.color;
|
|
27046
|
+
}
|
|
27047
|
+
// Fall back to userId match (for selection groups without clientId)
|
|
27048
|
+
if (!remoteUserColor) {
|
|
27049
|
+
for (const state of awarenessStates.values()) {
|
|
27050
|
+
if (state.user?.id === object.userId) {
|
|
27051
|
+
remoteUserColor = state.user.color;
|
|
27052
|
+
break;
|
|
27053
|
+
}
|
|
27036
27054
|
}
|
|
27037
27055
|
}
|
|
27038
27056
|
}
|
|
@@ -28521,7 +28539,7 @@ const KritzelPortal = class {
|
|
|
28521
28539
|
* This file is auto-generated by the version bump scripts.
|
|
28522
28540
|
* Do not modify manually.
|
|
28523
28541
|
*/
|
|
28524
|
-
const KRITZEL_VERSION = '0.1.
|
|
28542
|
+
const KRITZEL_VERSION = '0.1.77';
|
|
28525
28543
|
|
|
28526
28544
|
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)}`;
|
|
28527
28545
|
|
|
@@ -29366,7 +29384,7 @@ const KritzelTooltip = class {
|
|
|
29366
29384
|
};
|
|
29367
29385
|
KritzelTooltip.style = kritzelTooltipCss();
|
|
29368
29386
|
|
|
29369
|
-
const kritzelUtilityPanelCss = () => `:host{display:flex;flex-direction:row;align-items:center;padding:4px;gap:8px;border-top-left-radius:12px;border-top-right-radius:12px;background-color:var(--kritzel-utility-panel-background-color, #e2e2e2);width:fit-content;user-select:none}.utility-button{display:flex;justify-content:center;align-items:center;width:28px;height:28px;padding:8px 4px;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);color:var(--kritzel-utility-panel-button-color, #333333);--kritzel-icon-color:var(--kritzel-utility-panel-button-color, #333333);-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-utility-panel-button-border-radius, 8px)}.utility-button:hover,.utility-button:focus-visible{background-color:var(--kritzel-utility-panel-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.utility-button:disabled{opacity:0.4;cursor:not-allowed;pointer-events:none}.utility-separator{width:1px;height:16px;background-color:var(--kritzel-utility-panel-separator-color, hsl(0, 0%, 0%, 8%))}`;
|
|
29387
|
+
const kritzelUtilityPanelCss = () => `:host{display:flex;flex-direction:row;align-items:center;padding:4px;gap:8px;border-top-left-radius:12px;border-top-right-radius:12px;background-color:var(--kritzel-utility-panel-background-color, #e2e2e2);width:fit-content;user-select:none;z-index:10000}.utility-button{display:flex;justify-content:center;align-items:center;width:28px;height:28px;padding:8px 4px;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);color:var(--kritzel-utility-panel-button-color, #333333);--kritzel-icon-color:var(--kritzel-utility-panel-button-color, #333333);-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-utility-panel-button-border-radius, 8px)}.utility-button:hover,.utility-button:focus-visible{background-color:var(--kritzel-utility-panel-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.utility-button:disabled{opacity:0.4;cursor:not-allowed;pointer-events:none}.utility-separator{width:1px;height:16px;background-color:var(--kritzel-utility-panel-separator-color, hsl(0, 0%, 0%, 8%))}`;
|
|
29370
29388
|
|
|
29371
29389
|
const KritzelUtilityPanel = class {
|
|
29372
29390
|
constructor(hostRef) {
|