@ngenux/ngage-whiteboarding 1.0.8 → 1.0.9

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 (49) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.esm.js +106 -91
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +113 -90
  6. package/dist/index.js.map +1 -1
  7. package/dist/src/components/Whiteboard/index.d.ts.map +1 -1
  8. package/dist/src/context/WhiteboardContext.d.ts.map +1 -1
  9. package/dist/src/utils/socket-utility.d.ts +6 -1
  10. package/dist/src/utils/socket-utility.d.ts.map +1 -1
  11. package/dist/utils/index.d.ts +13 -0
  12. package/dist/utils/index.d.ts.map +1 -0
  13. package/dist/utils/socket-utility.esm.js +168 -0
  14. package/dist/utils/socket-utility.esm.js.map +1 -0
  15. package/dist/utils/socket-utility.js +177 -0
  16. package/dist/utils/socket-utility.js.map +1 -0
  17. package/dist/utils/src/components/Shapes/Arrow.d.ts +11 -0
  18. package/dist/utils/src/components/Shapes/Arrow.d.ts.map +1 -0
  19. package/dist/utils/src/components/Shapes/Ellipse.d.ts +11 -0
  20. package/dist/utils/src/components/Shapes/Ellipse.d.ts.map +1 -0
  21. package/dist/utils/src/components/Shapes/ErasedShape.d.ts +11 -0
  22. package/dist/utils/src/components/Shapes/ErasedShape.d.ts.map +1 -0
  23. package/dist/utils/src/components/Shapes/FreehandDrawing.d.ts +11 -0
  24. package/dist/utils/src/components/Shapes/FreehandDrawing.d.ts.map +1 -0
  25. package/dist/utils/src/components/Shapes/Line.d.ts +11 -0
  26. package/dist/utils/src/components/Shapes/Line.d.ts.map +1 -0
  27. package/dist/utils/src/components/Shapes/Rectangle.d.ts +11 -0
  28. package/dist/utils/src/components/Shapes/Rectangle.d.ts.map +1 -0
  29. package/dist/utils/src/components/Whiteboard/Board.d.ts +15 -0
  30. package/dist/utils/src/components/Whiteboard/Board.d.ts.map +1 -0
  31. package/dist/utils/src/components/Whiteboard/Toolbar.d.ts +21 -0
  32. package/dist/utils/src/components/Whiteboard/Toolbar.d.ts.map +1 -0
  33. package/dist/utils/src/components/Whiteboard/index.d.ts +11 -0
  34. package/dist/utils/src/components/Whiteboard/index.d.ts.map +1 -0
  35. package/dist/utils/src/context/WhiteboardContext.d.ts +128 -0
  36. package/dist/utils/src/context/WhiteboardContext.d.ts.map +1 -0
  37. package/dist/utils/src/hooks/useCapture.d.ts +4 -0
  38. package/dist/utils/src/hooks/useCapture.d.ts.map +1 -0
  39. package/dist/utils/src/hooks/useCollaborativeWhiteboard.d.ts +27 -0
  40. package/dist/utils/src/hooks/useCollaborativeWhiteboard.d.ts.map +1 -0
  41. package/dist/utils/src/lib/utils.d.ts +3 -0
  42. package/dist/utils/src/lib/utils.d.ts.map +1 -0
  43. package/dist/utils/src/types/index.d.ts +123 -0
  44. package/dist/utils/src/types/index.d.ts.map +1 -0
  45. package/dist/utils/src/utils/compression.d.ts +14 -0
  46. package/dist/utils/src/utils/compression.d.ts.map +1 -0
  47. package/dist/utils/src/utils/socket-utility.d.ts +11 -0
  48. package/dist/utils/src/utils/socket-utility.d.ts.map +1 -0
  49. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import { WhiteboardProvider } from './src/context/WhiteboardContext';
4
4
  import { useCapture } from './src/hooks/useCapture';
5
5
  import { cn } from './src/lib/utils';
6
6
  export { Whiteboard, WhiteboardProvider, useCapture as useWhiteboardStream, cn };
7
+ export { isSocketConnected, getSocket, onSocketStatusChange, onSend, onReceive, leaveRoom, disconnectSocket, waitForSocket } from './src/utils/socket-utility';
7
8
  export type { WhiteboardProps } from './src/components/Whiteboard/index';
8
9
  export type { ShapeProps, ToolType, StrokeStyle, WhiteboardState, DrawingAction, CompressedData } from './src/types';
9
10
  export interface WhiteboardProviderProps {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.tsx"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,UAAU,IAAI,mBAAmB,EAAE,EAAE,EAAE,CAAC;AAGjF,YAAY,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,YAAY,EACV,UAAU,EACV,QAAQ,EACR,WAAW,EACX,eAAe,EACf,aAAa,EACb,cAAc,EACf,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.tsx"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,UAAU,IAAI,mBAAmB,EAAE,EAAE,EAAE,CAAC;AAGjF,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,oBAAoB,EACpB,MAAM,EACN,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,aAAa,EACd,MAAM,4BAA4B,CAAC;AAGpC,YAAY,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,YAAY,EACV,UAAU,EACV,QAAQ,EACR,WAAW,EACX,eAAe,EACf,aAAa,EACb,cAAc,EACf,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB"}
package/dist/index.esm.js CHANGED
@@ -35255,12 +35255,16 @@ const WhiteboardProvider = ({ children, webSocketUrl }) => {
35255
35255
  };
35256
35256
  const requestStateFromPeers = () => {
35257
35257
  if (currentQueueAction) {
35258
- currentQueueAction({
35259
- type: 'request_state',
35260
- payload: '',
35261
- requesterId: state.userId,
35262
- timestamp: Date.now(),
35263
- });
35258
+ setTimeout(() => {
35259
+ if (currentQueueAction) {
35260
+ currentQueueAction({
35261
+ type: 'request_state',
35262
+ payload: '',
35263
+ requesterId: state.userId,
35264
+ timestamp: Date.now(),
35265
+ });
35266
+ }
35267
+ }, 2000);
35264
35268
  }
35265
35269
  else {
35266
35270
  console.warn('[STATE_SYNC] No queue action available for state request');
@@ -37069,32 +37073,6 @@ const Eraser = createLucideIcon("Eraser", [
37069
37073
  */
37070
37074
 
37071
37075
 
37072
- const LockOpen = createLucideIcon("LockOpen", [
37073
- ["rect", { width: "18", height: "11", x: "3", y: "11", rx: "2", ry: "2", key: "1w4ew1" }],
37074
- ["path", { d: "M7 11V7a5 5 0 0 1 9.9-1", key: "1mm8w8" }]
37075
- ]);
37076
-
37077
- /**
37078
- * @license lucide-react v0.460.0 - ISC
37079
- *
37080
- * This source code is licensed under the ISC license.
37081
- * See the LICENSE file in the root directory of this source tree.
37082
- */
37083
-
37084
-
37085
- const Lock = createLucideIcon("Lock", [
37086
- ["rect", { width: "18", height: "11", x: "3", y: "11", rx: "2", ry: "2", key: "1w4ew1" }],
37087
- ["path", { d: "M7 11V7a5 5 0 0 1 10 0v4", key: "fwvmzm" }]
37088
- ]);
37089
-
37090
- /**
37091
- * @license lucide-react v0.460.0 - ISC
37092
- *
37093
- * This source code is licensed under the ISC license.
37094
- * See the LICENSE file in the root directory of this source tree.
37095
- */
37096
-
37097
-
37098
37076
  const Minus = createLucideIcon("Minus", [["path", { d: "M5 12h14", key: "1ays0h" }]]);
37099
37077
 
37100
37078
  /**
@@ -37175,7 +37153,7 @@ const Undo2 = createLucideIcon("Undo2", [
37175
37153
  ]);
37176
37154
 
37177
37155
  // Top Toolbar Component
37178
- const TopToolbar = ({ queueAction, handleExportImage, handleClear, handleLockToggle, isAdmin = false, hasToolAccess = false, isGloballyUnlocked = false, shouldBeOpenByDefault = true, hasVideoBackground = false }) => {
37156
+ const TopToolbar = ({ queueAction, handleExportImage, handleClear, handleLockToggle, isAdmin = false, hasToolAccess = false, isGloballyUnlocked = true, shouldBeOpenByDefault = true, hasVideoBackground = false }) => {
37179
37157
  const { state, dispatch } = useWhiteboard();
37180
37158
  const [isVisible, setIsVisible] = useState(shouldBeOpenByDefault);
37181
37159
  const [isInitialized, setIsInitialized] = useState(false);
@@ -37251,9 +37229,7 @@ const TopToolbar = ({ queueAction, handleExportImage, handleClear, handleLockTog
37251
37229
  if (!isInitialized) {
37252
37230
  return null;
37253
37231
  }
37254
- return (jsxs(Fragment, { children: [jsxs("div", { className: "absolute top-5 left-1/2 transform -translate-x-1/2 flex flex-col items-center z-10", children: [!isVisible && (jsx("button", { className: "w-10 h-10 flex items-center justify-center bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-300", onClick: handleToggleVisibility, title: "Show Tools", children: jsx(ChevronDown, { size: 16, className: "text-current" }) })), isVisible && (jsx("div", { className: "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg", children: jsxs("div", { className: "flex items-center gap-1 p-1", children: [isAdmin && (jsx("button", { className: `w-10 h-10 flex items-center justify-center rounded transition-colors ${isGloballyUnlocked
37255
- ? 'bg-green-100 dark:bg-green-900/50 text-green-600 dark:text-green-400 hover:bg-green-200 dark:hover:bg-green-900/70'
37256
- : 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600'}`, onClick: handleLockToggle, title: isGloballyUnlocked ? 'Whiteboard unlocked for all users - Click to lock' : 'Whiteboard locked - Click to unlock for all users', children: isGloballyUnlocked ? jsx(LockOpen, { size: 16, className: "text-current" }) : jsx(Lock, { size: 16, className: "text-current" }) })), jsx("button", { className: `w-10 h-10 flex items-center justify-center rounded ${hasToolAccess ? 'hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-300' : 'opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600'}`, onClick: handleUndo, disabled: !hasToolAccess, title: hasToolAccess ? 'Undo' : 'Access restricted', children: jsx(Undo2, { size: 16, className: "text-current" }) }), jsx("button", { className: `w-10 h-10 flex items-center justify-center rounded ${hasToolAccess ? 'hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-300' : 'opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600'}`, onClick: handleRedo, disabled: !hasToolAccess, title: hasToolAccess ? 'Redo' : 'Access restricted', children: jsx(Redo2, { size: 16, className: "text-current" }) }), jsx("div", { className: "w-px h-6 bg-gray-300 dark:bg-gray-600 mx-1" }), tools.map((tool) => (jsx("button", { className: `w-10 h-10 flex items-center justify-center rounded transition-colors ${!hasToolAccess
37232
+ return (jsxs(Fragment, { children: [jsxs("div", { className: "absolute top-5 left-1/2 transform -translate-x-1/2 flex flex-col items-center z-10", children: [!isVisible && (jsx("button", { className: "w-10 h-10 flex items-center justify-center bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-300", onClick: handleToggleVisibility, title: "Show Tools", children: jsx(ChevronDown, { size: 16, className: "text-current" }) })), isVisible && (jsx("div", { className: "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg", children: jsxs("div", { className: "flex items-center gap-1 p-1", children: [jsx("button", { className: `w-10 h-10 flex items-center justify-center rounded ${hasToolAccess ? 'hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-300' : 'opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600'}`, onClick: handleUndo, disabled: !hasToolAccess, title: hasToolAccess ? 'Undo' : 'Access restricted', children: jsx(Undo2, { size: 16, className: "text-current" }) }), jsx("button", { className: `w-10 h-10 flex items-center justify-center rounded ${hasToolAccess ? 'hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-300' : 'opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600'}`, onClick: handleRedo, disabled: !hasToolAccess, title: hasToolAccess ? 'Redo' : 'Access restricted', children: jsx(Redo2, { size: 16, className: "text-current" }) }), jsx("div", { className: "w-px h-6 bg-gray-300 dark:bg-gray-600 mx-1" }), tools.map((tool) => (jsx("button", { className: `w-10 h-10 flex items-center justify-center rounded transition-colors ${!hasToolAccess
37257
37233
  ? 'opacity-50 cursor-not-allowed text-gray-400 dark:text-gray-600'
37258
37234
  : state.tool === tool.type
37259
37235
  ? 'bg-purple-100 dark:bg-purple-900/50 text-purple-600 dark:text-purple-300'
@@ -42311,6 +42287,7 @@ Object.assign(lookup, {
42311
42287
  let socket = null;
42312
42288
  const joinedRooms = new Set();
42313
42289
  const setupCallbacks = new Map();
42290
+ const statusChangeCallbacks = new Set();
42314
42291
  let currentWebSocketUrl = undefined;
42315
42292
  // Initialize socket connection
42316
42293
  const initializeSocket = (webSocketUrl) => {
@@ -42326,7 +42303,6 @@ const initializeSocket = (webSocketUrl) => {
42326
42303
  setupCallbacks.clear();
42327
42304
  }
42328
42305
  currentWebSocketUrl = webSocketUrl;
42329
- console.log('[SOCKET] Using socket server URL:', socketServerUrl);
42330
42306
  if (!socketServerUrl) {
42331
42307
  console.error('[SOCKET] No socket server URL provided');
42332
42308
  }
@@ -42337,29 +42313,21 @@ const initializeSocket = (webSocketUrl) => {
42337
42313
  reconnectionDelay: 1000,
42338
42314
  });
42339
42315
  socket.on('connect', () => {
42340
- console.log('[SOCKET] Connected to server');
42341
- // Re-join all rooms after reconnection
42316
+ statusChangeCallbacks.forEach(callback => callback(true));
42342
42317
  joinedRooms.forEach(roomId => {
42343
42318
  socket.emit('join-room', roomId);
42344
- console.log('[SOCKET] Re-joined room:', roomId);
42345
42319
  });
42346
42320
  });
42347
42321
  socket.on('disconnect', () => {
42348
- console.log('[SOCKET] Disconnected from server');
42322
+ statusChangeCallbacks.forEach(callback => callback(false));
42349
42323
  });
42350
- socket.on('connect_error', (error) => {
42351
- console.error('[SOCKET] Connection error:', error);
42324
+ socket.on('connect_error', () => {
42325
+ // Connection error handled by Socket.IO reconnection logic
42352
42326
  });
42353
42327
  // Set up the global receive-message listener once
42354
42328
  socket.on('receive-message', (message) => {
42355
42329
  const callback = setupCallbacks.get(message.roomId);
42356
42330
  if (callback) {
42357
- console.log('[SOCKET] Received message from room:', message.roomId, {
42358
- compression: message.data.compressionType,
42359
- originalSize: message.data.originalSize,
42360
- compressedSize: message.data.compressedSize,
42361
- from: message.from
42362
- });
42363
42331
  callback(message.data);
42364
42332
  }
42365
42333
  });
@@ -42393,18 +42361,23 @@ const onSend = (roomId, data, webSocketUrl) => {
42393
42361
  console.error('[SOCKET] Error sending message:', error);
42394
42362
  }
42395
42363
  };
42396
- const onReceive = (roomId, callback, webSocketUrl) => {
42364
+ const onReceive = (roomId, callback, webSocketUrl, onRoomJoined) => {
42397
42365
  const socketInstance = initializeSocket(webSocketUrl);
42398
42366
  // Store the callback for this room
42399
42367
  setupCallbacks.set(roomId, callback);
42400
- // Only join the room if we haven't already
42401
42368
  if (!joinedRooms.has(roomId)) {
42402
42369
  socketInstance.emit('join-room', roomId);
42403
42370
  joinedRooms.add(roomId);
42404
- console.log('[SOCKET] Joined room:', roomId);
42371
+ if (onRoomJoined) {
42372
+ setTimeout(() => {
42373
+ onRoomJoined();
42374
+ }, 100);
42375
+ }
42405
42376
  }
42406
42377
  else {
42407
- console.log('[SOCKET] Already in room:', roomId);
42378
+ if (onRoomJoined) {
42379
+ onRoomJoined();
42380
+ }
42408
42381
  }
42409
42382
  };
42410
42383
  const leaveRoom = (roomId) => {
@@ -42421,20 +42394,66 @@ const disconnectSocket = () => {
42421
42394
  socket = null;
42422
42395
  joinedRooms.clear();
42423
42396
  setupCallbacks.clear();
42424
- console.log('[SOCKET] Socket disconnected and cleaned up');
42425
42397
  }
42426
42398
  };
42399
+ // Get current socket connection status
42400
+ const isSocketConnected = () => {
42401
+ return socket?.connected ?? false;
42402
+ };
42403
+ // Get current socket instance
42404
+ const getSocket = () => {
42405
+ return socket;
42406
+ };
42407
+ // Subscribe to connection status changes
42408
+ const onSocketStatusChange = (callback) => {
42409
+ const socketInstance = socket || initializeSocket();
42410
+ statusChangeCallbacks.add(callback);
42411
+ callback(socketInstance.connected);
42412
+ return () => {
42413
+ statusChangeCallbacks.delete(callback);
42414
+ };
42415
+ };
42416
+ const waitForSocket = (webSocketUrl, timeoutMs = 5000) => {
42417
+ return new Promise((resolve) => {
42418
+ const socketInstance = initializeSocket(webSocketUrl);
42419
+ if (socketInstance.connected) {
42420
+ resolve();
42421
+ return;
42422
+ }
42423
+ const handleConnect = () => {
42424
+ socketInstance.off('connect', handleConnect);
42425
+ clearTimeout(timeoutHandle);
42426
+ resolve();
42427
+ };
42428
+ socketInstance.on('connect', handleConnect);
42429
+ const timeoutHandle = setTimeout(() => {
42430
+ socketInstance.off('connect', handleConnect);
42431
+ resolve();
42432
+ }, timeoutMs);
42433
+ });
42434
+ };
42427
42435
 
42428
42436
  const Whiteboard = ({ roomId, isAdmin = false, allowedUsers = [], userId, transparentBackground = false, videoStream }) => {
42429
42437
  const { state, dispatch, setQueueAction, requestStateFromPeers, webSocketUrl } = useWhiteboard();
42430
42438
  const [lastCollaborativeAction, setLastCollaborativeAction] = useState(null);
42431
42439
  const [hasRequestedState, setHasRequestedState] = useState(false);
42432
42440
  const [lastStateRequestTime, setLastStateRequestTime] = useState(0);
42433
- const [isGloballyUnlocked, setIsGloballyUnlocked] = useState(false); // Global unlock status
42441
+ const [isSocketConnected, setIsSocketConnected] = useState(false);
42442
+ const [isRoomJoined, setIsRoomJoined] = useState(false);
42443
+ const [isGloballyUnlocked, setIsGloballyUnlocked] = useState(true); // Global unlock status
42434
42444
  const [syncedAllowedUsers, setSyncedAllowedUsers] = useState(allowedUsers); // Synced allowed users from collaboration
42435
42445
  const isCollaborativeUpdateRef = useRef(false); // Track if update came from collaboration
42436
42446
  const lastClearTimeRef = useRef(0); // Track when last clear happened
42437
42447
  const boardRef = useRef(null);
42448
+ useEffect(() => {
42449
+ const unsubscribe = onSocketStatusChange((connected) => {
42450
+ setIsSocketConnected(connected);
42451
+ });
42452
+ return () => {
42453
+ console.log('[WHITEBOARD] Unsubscribing from socket status listener');
42454
+ unsubscribe();
42455
+ };
42456
+ }, []); // Empty dependencies - single listener for component lifecycle
42438
42457
  // Set userId in context when component mounts or userId changes
42439
42458
  useEffect(() => {
42440
42459
  dispatch({ type: 'SET_USER_ID', payload: userId });
@@ -42515,7 +42534,9 @@ const Whiteboard = ({ roomId, isAdmin = false, allowedUsers = [], userId, transp
42515
42534
  setHasRequestedState(false);
42516
42535
  }
42517
42536
  callback(data);
42518
- }, webSocketUrl);
42537
+ }, webSocketUrl, () => {
42538
+ setIsRoomJoined(true);
42539
+ });
42519
42540
  }, [roomId, webSocketUrl]);
42520
42541
  // Initialize the collaborative whiteboard hook
42521
42542
  const collaborativeConfig = useMemo(() => ({
@@ -42552,48 +42573,42 @@ const Whiteboard = ({ roomId, isAdmin = false, allowedUsers = [], userId, transp
42552
42573
  });
42553
42574
  }
42554
42575
  }, [allowedUsers, queueAction, userId, syncedAllowedUsers]);
42555
- // Request state from peers when joining/rejoining the room
42576
+ // Request state from peers when room is successfully joined AND socket is connected
42577
+ // Need both conditions to ensure message can actually be sent
42556
42578
  useEffect(() => {
42557
- if (queueAction && typeof queueAction === 'function' && !hasRequestedState) {
42558
- const requestTimer = setTimeout(() => {
42559
- const now = Date.now();
42560
- if (now - lastClearTimeRef.current < 10000) {
42561
- return;
42562
- }
42563
- if (now - lastStateRequestTime > 5000) {
42564
- requestStateFromPeers();
42565
- setHasRequestedState(true);
42566
- setLastStateRequestTime(now);
42567
- }
42568
- }, 500);
42569
- return () => clearTimeout(requestTimer);
42579
+ if (!isRoomJoined || !isSocketConnected || hasRequestedState || state.shapes.length > 0 || !queueAction) {
42580
+ return;
42570
42581
  }
42571
- }, [roomId, queueAction, requestStateFromPeers, hasRequestedState, lastStateRequestTime]);
42582
+ const now = Date.now();
42583
+ if (now - lastClearTimeRef.current < 10000) {
42584
+ return;
42585
+ }
42586
+ requestStateFromPeers();
42587
+ setHasRequestedState(true);
42588
+ setLastStateRequestTime(Date.now());
42589
+ }, [isRoomJoined, isSocketConnected, state.shapes.length, hasRequestedState, queueAction, requestStateFromPeers, userId, roomId]);
42572
42590
  // Reset request flag when room changes
42573
42591
  useEffect(() => {
42574
42592
  setHasRequestedState(false);
42575
42593
  setLastStateRequestTime(0);
42594
+ setIsRoomJoined(false);
42576
42595
  }, [roomId]);
42577
- // Monitor for empty canvas and request state only if we haven't tried recently
42596
+ // Retry state request if canvas is still empty after 3 seconds
42578
42597
  useEffect(() => {
42579
- if (queueAction &&
42580
- typeof queueAction === 'function' &&
42581
- state.shapes.length === 0 &&
42582
- !hasRequestedState) {
42583
- const now = Date.now();
42584
- if (now - lastClearTimeRef.current < 10000) {
42585
- return;
42586
- }
42587
- if (now - lastStateRequestTime > 10000) {
42588
- const reconnectTimer = setTimeout(() => {
42589
- requestStateFromPeers();
42590
- setHasRequestedState(true);
42591
- setLastStateRequestTime(now);
42592
- }, 2000);
42593
- return () => clearTimeout(reconnectTimer);
42594
- }
42598
+ if (!isRoomJoined || !isSocketConnected || hasRequestedState || state.shapes.length > 0 || !queueAction) {
42599
+ return;
42600
+ }
42601
+ const now = Date.now();
42602
+ // Don't retry if we recently cleared
42603
+ if (now - lastClearTimeRef.current < 10000) {
42604
+ return;
42595
42605
  }
42596
- }, [queueAction, state.shapes.length, requestStateFromPeers, hasRequestedState, lastStateRequestTime]);
42606
+ const retryTimer = setTimeout(() => {
42607
+ requestStateFromPeers();
42608
+ setLastStateRequestTime(Date.now());
42609
+ }, 3000);
42610
+ return () => clearTimeout(retryTimer);
42611
+ }, [isRoomJoined, isSocketConnected, state.shapes.length, queueAction, requestStateFromPeers, lastStateRequestTime, userId]);
42597
42612
  // Cleanup stale active drawings periodically
42598
42613
  useEffect(() => {
42599
42614
  const cleanupInterval = setInterval(() => {
@@ -42795,7 +42810,7 @@ const Whiteboard = ({ roomId, isAdmin = false, allowedUsers = [], userId, transp
42795
42810
  });
42796
42811
  }
42797
42812
  };
42798
- }, [isAdmin, queueAction, userId, dispatch]);
42813
+ }, [isAdmin, userId, dispatch]);
42799
42814
  // Global cleanup on app unmount
42800
42815
  useEffect(() => {
42801
42816
  const handleBeforeUnload = () => {
@@ -45838,5 +45853,5 @@ function cn(...inputs) {
45838
45853
  return twMerge(clsx(inputs));
45839
45854
  }
45840
45855
 
45841
- export { Whiteboard, WhiteboardProvider, cn, useCapture as useWhiteboardStream };
45856
+ export { Whiteboard, WhiteboardProvider, cn, disconnectSocket, getSocket, isSocketConnected, leaveRoom, onReceive, onSend, onSocketStatusChange, useCapture as useWhiteboardStream, waitForSocket };
45842
45857
  //# sourceMappingURL=index.esm.js.map