@q9labsai/chalk-react 4.1.3 → 4.1.5

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.
@@ -7665,7 +7665,7 @@ function choosePrimary(items, context) {
7665
7665
  if (items.length === 0) return null;
7666
7666
  const pinned = context.pinnedId ? items.find((item) => item.id === context.pinnedId) : void 0;
7667
7667
  if (pinned) return pinned;
7668
- const content = () => newestScreenShare(items, context.seenAt) ?? items.find((item) => item.kind === "whiteboard");
7668
+ const content = () => items.find((item) => item.kind === "whiteboard") ?? newestScreenShare(items, context.seenAt);
7669
7669
  const speaker = () => participantWhere(items, (participant) => participant.isActiveSpeaker === true) ?? participantWhere(items, (participant) => participant.isSpeaking === true) ?? (context.lastSpeakerId ? items.find((item) => item.kind === "participant" && item.id === context.lastSpeakerId) : void 0);
7670
7670
  const ordered = context.layout === "presentation" ? [content, speaker] : [speaker, content];
7671
7671
  for (const pick of ordered) {
@@ -8024,7 +8024,35 @@ ParticipantGrid.displayName = "ParticipantGrid";
8024
8024
 
8025
8025
  // src/components/chalk/Chalk.tsx
8026
8026
  import { createSpaceClient } from "@q9labsai/chalk-client";
8027
- import { useCallback as useCallback21, useEffect as useEffect47, useMemo as useMemo38, useRef as useRef34, useState as useState50 } from "react";
8027
+ import { useCallback as useCallback21, useEffect as useEffect48, useMemo as useMemo38, useRef as useRef34, useState as useState51 } from "react";
8028
+
8029
+ // src/internal/useWhiteboardSceneSubscription.ts
8030
+ import { useEffect as useEffect30, useState as useState35 } from "react";
8031
+ var errorMessage = (cause) => cause instanceof Error ? cause : new Error("Whiteboard could not connect.");
8032
+ function useWhiteboardSceneSubscription(transport, active) {
8033
+ const [subscription, setSubscription] = useState35({ status: "closed" });
8034
+ useEffect30(() => {
8035
+ if (!active || !transport) {
8036
+ setSubscription({ status: "closed" });
8037
+ return;
8038
+ }
8039
+ let disposed = false;
8040
+ setSubscription({ status: "loading" });
8041
+ void Promise.resolve().then(() => transport.startSceneSubscription()).then(
8042
+ () => {
8043
+ if (!disposed) setSubscription({ status: "ready", transport });
8044
+ },
8045
+ (cause) => {
8046
+ if (!disposed) setSubscription({ status: "failed", error: errorMessage(cause) });
8047
+ }
8048
+ );
8049
+ return () => {
8050
+ disposed = true;
8051
+ transport.stopSceneSubscription();
8052
+ };
8053
+ }, [active, transport]);
8054
+ return subscription;
8055
+ }
8028
8056
 
8029
8057
  // src/whiteboard/wire-adapters.ts
8030
8058
  function fromWhiteboardWireElement(element) {
@@ -8121,7 +8149,7 @@ function MediaRequestDialog(props) {
8121
8149
 
8122
8150
  // src/components/composite/SettingsDialog.tsx
8123
8151
  import { Dialog as Dialog2 } from "@base-ui/react/dialog";
8124
- import React47, { useCallback as useCallback12, useEffect as useEffect31, useMemo as useMemo30, useState as useState36 } from "react";
8152
+ import React47, { useCallback as useCallback12, useEffect as useEffect32, useMemo as useMemo30, useState as useState37 } from "react";
8125
8153
 
8126
8154
  // src/components/composite/BackgroundEffectsPicker.tsx
8127
8155
  import React45, { useMemo as useMemo28, useRef as useRef19 } from "react";
@@ -8300,7 +8328,7 @@ BackgroundEffectsPicker.displayName = "BackgroundEffectsPicker";
8300
8328
 
8301
8329
  // src/components/composite/ClassicSettingsDialog.tsx
8302
8330
  import { Dialog } from "@base-ui/react/dialog";
8303
- import React46, { useCallback as useCallback11, useEffect as useEffect30, useMemo as useMemo29, useState as useState35 } from "react";
8331
+ import React46, { useCallback as useCallback11, useEffect as useEffect31, useMemo as useMemo29, useState as useState36 } from "react";
8304
8332
  import { IconButton as IconButton6, Input as Input2, Toggle as Toggle5 } from "@q9labsai/chalk-ui";
8305
8333
  import { jsx as jsx84, jsxs as jsxs71 } from "react/jsx-runtime";
8306
8334
  var EMPTY_DEVICE_GROUPS = {
@@ -8412,10 +8440,10 @@ var ClassicSettingsDialog = React46.memo(
8412
8440
  const resolvedTexture = settings.appearance.texture ?? "none";
8413
8441
  const resolvedTheme = getThemeMode(resolvedPalette);
8414
8442
  const usesDarkPalette = isDarkMode || isDarkThemePalette(resolvedPalette);
8415
- const [activeSection, setActiveSection] = useState35(initialSection);
8416
- const [isNavOpen, setIsNavOpen] = useState35(true);
8417
- const [searchQuery, setSearchQuery] = useState35("");
8418
- const [detectedDevices, setDetectedDevices] = useState35(EMPTY_DEVICE_GROUPS);
8443
+ const [activeSection, setActiveSection] = useState36(initialSection);
8444
+ const [isNavOpen, setIsNavOpen] = useState36(true);
8445
+ const [searchQuery, setSearchQuery] = useState36("");
8446
+ const [detectedDevices, setDetectedDevices] = useState36(EMPTY_DEVICE_GROUPS);
8419
8447
  const effectiveParticipantSeed = useMemo29(() => participantColorSeed?.trim() || settings.identity.displayName.trim() || "You", [participantColorSeed, settings.identity.displayName]);
8420
8448
  const autoProfileColors = useMemo29(() => getParticipantColor(effectiveParticipantSeed), [effectiveParticipantSeed]);
8421
8449
  const profileGradient = settings.appearance.profileGradient;
@@ -8452,17 +8480,17 @@ var ClassicSettingsDialog = React46.memo(
8452
8480
  return section.label.toLowerCase().includes(query) || section.description.toLowerCase().includes(query) || section.keywords.some((keyword) => keyword.includes(query));
8453
8481
  });
8454
8482
  }, [searchQuery]);
8455
- useEffect30(() => {
8483
+ useEffect31(() => {
8456
8484
  if (!filteredSections.some((section) => section.id === activeSection)) {
8457
8485
  setActiveSection(filteredSections[0]?.id ?? "audio");
8458
8486
  }
8459
8487
  }, [activeSection, filteredSections]);
8460
- useEffect30(() => {
8488
+ useEffect31(() => {
8461
8489
  if (isOpen) {
8462
8490
  setIsNavOpen(true);
8463
8491
  }
8464
8492
  }, [isOpen]);
8465
- useEffect30(() => {
8493
+ useEffect31(() => {
8466
8494
  if (!isOpen) {
8467
8495
  return;
8468
8496
  }
@@ -9059,10 +9087,10 @@ var ChalkSettingsDialog = React47.memo(
9059
9087
  const resolvedTexture = settings.appearance.texture ?? "none";
9060
9088
  const resolvedTheme = getThemeMode(resolvedPalette);
9061
9089
  const usesDarkPalette = isDarkMode || isDarkThemePalette(resolvedPalette);
9062
- const [activeSection, setActiveSection] = useState36(initialSection);
9063
- const [isNavOpen, setIsNavOpen] = useState36(true);
9064
- const [searchQuery, setSearchQuery] = useState36("");
9065
- const [detectedDevices, setDetectedDevices] = useState36(EMPTY_DEVICE_GROUPS2);
9090
+ const [activeSection, setActiveSection] = useState37(initialSection);
9091
+ const [isNavOpen, setIsNavOpen] = useState37(true);
9092
+ const [searchQuery, setSearchQuery] = useState37("");
9093
+ const [detectedDevices, setDetectedDevices] = useState37(EMPTY_DEVICE_GROUPS2);
9066
9094
  const effectiveParticipantSeed = useMemo30(() => participantColorSeed?.trim() || settings.identity.displayName.trim() || "You", [participantColorSeed, settings.identity.displayName]);
9067
9095
  const autoProfileColors = useMemo30(() => getParticipantColor(effectiveParticipantSeed), [effectiveParticipantSeed]);
9068
9096
  const profileGradient = settings.appearance.profileGradient;
@@ -9099,17 +9127,17 @@ var ChalkSettingsDialog = React47.memo(
9099
9127
  return section.label.toLowerCase().includes(query) || section.description.toLowerCase().includes(query) || section.keywords.some((keyword) => keyword.includes(query));
9100
9128
  });
9101
9129
  }, [searchQuery]);
9102
- useEffect31(() => {
9130
+ useEffect32(() => {
9103
9131
  if (!filteredSections.some((section) => section.id === activeSection)) {
9104
9132
  setActiveSection(filteredSections[0]?.id ?? "audio");
9105
9133
  }
9106
9134
  }, [activeSection, filteredSections]);
9107
- useEffect31(() => {
9135
+ useEffect32(() => {
9108
9136
  if (isOpen) {
9109
9137
  setIsNavOpen(true);
9110
9138
  }
9111
9139
  }, [isOpen]);
9112
- useEffect31(() => {
9140
+ useEffect32(() => {
9113
9141
  if (!isOpen) {
9114
9142
  return;
9115
9143
  }
@@ -9617,7 +9645,7 @@ var SettingsDialog = React47.memo((props) => {
9617
9645
  const skin = props.settings.appearance.skin ?? inheritedSkin;
9618
9646
  const previousSkin = React47.useRef(skin);
9619
9647
  const switchedSkinWhileOpen = props.isOpen && previousSkin.current !== skin;
9620
- useEffect31(() => {
9648
+ useEffect32(() => {
9621
9649
  previousSkin.current = skin;
9622
9650
  }, [skin]);
9623
9651
  const rendererProps = switchedSkinWhileOpen ? { ...props, initialSection: "appearance" } : props;
@@ -9626,10 +9654,10 @@ var SettingsDialog = React47.memo((props) => {
9626
9654
  SettingsDialog.displayName = "SettingsDialog";
9627
9655
 
9628
9656
  // src/components/space-view/SpaceView.tsx
9629
- import React66, { useCallback as useCallback20, useEffect as useEffect46, useMemo as useMemo37, useState as useState49 } from "react";
9657
+ import React66, { useCallback as useCallback20, useEffect as useEffect47, useMemo as useMemo37, useState as useState50 } from "react";
9630
9658
 
9631
9659
  // src/internal/useSoundCues.ts
9632
- import { useEffect as useEffect32, useRef as useRef20 } from "react";
9660
+ import { useEffect as useEffect33, useRef as useRef20 } from "react";
9633
9661
 
9634
9662
  // src/internal/sound-cues.ts
9635
9663
  import { CHALK_SOUND_ASSETS } from "@q9labsai/chalk-ui/assets";
@@ -9754,7 +9782,7 @@ function useSoundCues(enabled, createPlayer = createSoundPlayer) {
9754
9782
  const outputDeviceId = useMedia().selection.speaker ?? void 0;
9755
9783
  const createPlayerRef = useRef20(createPlayer);
9756
9784
  createPlayerRef.current = createPlayer;
9757
- useEffect32(() => {
9785
+ useEffect33(() => {
9758
9786
  if (!enabled) return;
9759
9787
  const player = createPlayerRef.current({ outputDeviceId });
9760
9788
  let previous = client.getSnapshot();
@@ -9771,25 +9799,25 @@ function useSoundCues(enabled, createPlayer = createSoundPlayer) {
9771
9799
  }
9772
9800
 
9773
9801
  // src/components/composite/ReactionPicker.tsx
9774
- import React50, { useMemo as useMemo32, useState as useState38, useCallback as useCallback15, useEffect as useEffect35, useRef as useRef23 } from "react";
9802
+ import React50, { useMemo as useMemo32, useState as useState39, useCallback as useCallback15, useEffect as useEffect36, useRef as useRef23 } from "react";
9775
9803
  import { DEFAULT_QUICK_REACTIONS as DEFAULT_QUICK_REACTIONS2, EMOJI_CATEGORIES as EMOJI_CATEGORIES2, EMOJI_KEYWORDS as EMOJI_KEYWORDS2 } from "@q9labsai/chalk-ui/reactions";
9776
9804
 
9777
9805
  // src/components/composite/ClassicReactionPicker.tsx
9778
- import React49, { useMemo as useMemo31, useState as useState37, useCallback as useCallback14, useEffect as useEffect34, useRef as useRef22 } from "react";
9806
+ import React49, { useMemo as useMemo31, useState as useState38, useCallback as useCallback14, useEffect as useEffect35, useRef as useRef22 } from "react";
9779
9807
  import { DEFAULT_QUICK_REACTIONS, EMOJI_CATEGORIES, EMOJI_KEYWORDS } from "@q9labsai/chalk-ui/reactions";
9780
9808
 
9781
9809
  // src/components/composite/ReactionTray.tsx
9782
- import { useCallback as useCallback13, useEffect as useEffect33, useRef as useRef21 } from "react";
9810
+ import { useCallback as useCallback13, useEffect as useEffect34, useRef as useRef21 } from "react";
9783
9811
  import { Fragment as Fragment17, jsx as jsx86, jsxs as jsxs73 } from "react/jsx-runtime";
9784
9812
  function ReactionTray({ reactions, onSelect, onClose, position = "top", className }) {
9785
9813
  const skin = useSkin();
9786
9814
  const prefersReducedMotion = usePrefersReducedMotion2();
9787
9815
  const { trigger } = useHaptics();
9788
9816
  const listRef = useRef21(null);
9789
- useEffect33(() => {
9817
+ useEffect34(() => {
9790
9818
  listRef.current?.querySelector("button")?.focus();
9791
9819
  }, []);
9792
- useEffect33(() => {
9820
+ useEffect34(() => {
9793
9821
  const handleKeyDown2 = (event) => {
9794
9822
  if (event.key === "Escape") onClose();
9795
9823
  };
@@ -9840,11 +9868,11 @@ import { Fragment as Fragment18, jsx as jsx87, jsxs as jsxs74 } from "react/jsx-
9840
9868
  var ClassicReactionPicker = React49.memo(({ isOpen, onClose, onSelect, recentReactions = [], allowedReactions, position = "top", participantColorSeed, participantGradientPreference, className, size = "default" }) => {
9841
9869
  const prefersReducedMotion = usePrefersReducedMotion2();
9842
9870
  const { trigger } = useHaptics();
9843
- const [activeCategory, setActiveCategory] = useState37("smileys");
9844
- const [searchQuery, setSearchQuery] = useState37("");
9871
+ const [activeCategory, setActiveCategory] = useState38("smileys");
9872
+ const [searchQuery, setSearchQuery] = useState38("");
9845
9873
  const inputRef = useRef22(null);
9846
9874
  const themeVariables = useMemo31(() => getParticipantThemeVariables(participantColorSeed, participantGradientPreference), [participantColorSeed, participantGradientPreference]);
9847
- useEffect34(() => {
9875
+ useEffect35(() => {
9848
9876
  if (isOpen) {
9849
9877
  setTimeout(() => inputRef.current?.focus(), 50);
9850
9878
  setSearchQuery("");
@@ -9859,7 +9887,7 @@ var ClassicReactionPicker = React49.memo(({ isOpen, onClose, onSelect, recentRea
9859
9887
  },
9860
9888
  [onClose, onSelect, trigger]
9861
9889
  );
9862
- useEffect34(() => {
9890
+ useEffect35(() => {
9863
9891
  if (!isOpen || typeof window === "undefined") return;
9864
9892
  const handleKeyDown = (e) => {
9865
9893
  if (e.key === "Escape") onClose();
@@ -10000,11 +10028,11 @@ import { Fragment as Fragment19, jsx as jsx88, jsxs as jsxs75 } from "react/jsx-
10000
10028
  var ChalkReactionPicker = React50.memo(({ isOpen, onClose, onSelect, recentReactions = [], allowedReactions, position = "top", participantColorSeed, participantGradientPreference, className, size = "default" }) => {
10001
10029
  const prefersReducedMotion = usePrefersReducedMotion2();
10002
10030
  const { trigger } = useHaptics();
10003
- const [activeCategory, setActiveCategory] = useState38("smileys");
10004
- const [searchQuery, setSearchQuery] = useState38("");
10031
+ const [activeCategory, setActiveCategory] = useState39("smileys");
10032
+ const [searchQuery, setSearchQuery] = useState39("");
10005
10033
  const inputRef = useRef23(null);
10006
10034
  const themeVariables = useMemo32(() => getParticipantThemeVariables(participantColorSeed, participantGradientPreference), [participantColorSeed, participantGradientPreference]);
10007
- useEffect35(() => {
10035
+ useEffect36(() => {
10008
10036
  if (isOpen) {
10009
10037
  setTimeout(() => inputRef.current?.focus(), 50);
10010
10038
  setSearchQuery("");
@@ -10019,7 +10047,7 @@ var ChalkReactionPicker = React50.memo(({ isOpen, onClose, onSelect, recentReact
10019
10047
  },
10020
10048
  [onClose, onSelect, trigger]
10021
10049
  );
10022
- useEffect35(() => {
10050
+ useEffect36(() => {
10023
10051
  if (!isOpen || typeof window === "undefined") return;
10024
10052
  const handleKeyDown = (e) => {
10025
10053
  if (e.key === "Escape") onClose();
@@ -10145,10 +10173,10 @@ var ReactionPicker = React50.memo((props) => {
10145
10173
  ReactionPicker.displayName = "ReactionPicker";
10146
10174
 
10147
10175
  // src/components/invite-dialog/InviteDialog.tsx
10148
- import React52, { useEffect as useEffect37, useRef as useRef25, useState as useState40 } from "react";
10176
+ import React52, { useEffect as useEffect38, useRef as useRef25, useState as useState41 } from "react";
10149
10177
 
10150
10178
  // src/components/invite-dialog/ClassicInviteDialog.tsx
10151
- import React51, { useEffect as useEffect36, useRef as useRef24, useState as useState39 } from "react";
10179
+ import React51, { useEffect as useEffect37, useRef as useRef24, useState as useState40 } from "react";
10152
10180
  import { Input as Input3 } from "@q9labsai/chalk-ui";
10153
10181
  import { jsx as jsx89, jsxs as jsxs76 } from "react/jsx-runtime";
10154
10182
  var ClassicInviteDialog = React51.memo(({ isOpen, onClose, inviteLink, spaceId, onCopyLink, onShareEmail, onShareCalendar, className }) => {
@@ -10156,8 +10184,8 @@ var ClassicInviteDialog = React51.memo(({ isOpen, onClose, inviteLink, spaceId,
10156
10184
  const prefersReducedMotion = usePrefersReducedMotion2();
10157
10185
  const modalRef = useRef24(null);
10158
10186
  const copyResetTimeoutRef = useRef24(null);
10159
- const [isCopyFeedbackVisible, setIsCopyFeedbackVisible] = useState39(false);
10160
- useEffect36(() => {
10187
+ const [isCopyFeedbackVisible, setIsCopyFeedbackVisible] = useState40(false);
10188
+ useEffect37(() => {
10161
10189
  const handleEscape = (e) => {
10162
10190
  if (e.key === "Escape" && isOpen) {
10163
10191
  onClose();
@@ -10166,7 +10194,7 @@ var ClassicInviteDialog = React51.memo(({ isOpen, onClose, inviteLink, spaceId,
10166
10194
  document.addEventListener("keydown", handleEscape);
10167
10195
  return () => document.removeEventListener("keydown", handleEscape);
10168
10196
  }, [isOpen, onClose]);
10169
- useEffect36(() => {
10197
+ useEffect37(() => {
10170
10198
  return () => {
10171
10199
  if (copyResetTimeoutRef.current) {
10172
10200
  window.clearTimeout(copyResetTimeoutRef.current);
@@ -10271,8 +10299,8 @@ var ChalkInviteDialog = React52.memo(({ isOpen, onClose, inviteLink, spaceId, on
10271
10299
  const prefersReducedMotion = usePrefersReducedMotion2();
10272
10300
  const modalRef = useRef25(null);
10273
10301
  const copyResetTimeoutRef = useRef25(null);
10274
- const [isCopyFeedbackVisible, setIsCopyFeedbackVisible] = useState40(false);
10275
- useEffect37(() => {
10302
+ const [isCopyFeedbackVisible, setIsCopyFeedbackVisible] = useState41(false);
10303
+ useEffect38(() => {
10276
10304
  const handleEscape = (e) => {
10277
10305
  if (e.key === "Escape" && isOpen) {
10278
10306
  onClose();
@@ -10281,7 +10309,7 @@ var ChalkInviteDialog = React52.memo(({ isOpen, onClose, inviteLink, spaceId, on
10281
10309
  document.addEventListener("keydown", handleEscape);
10282
10310
  return () => document.removeEventListener("keydown", handleEscape);
10283
10311
  }, [isOpen, onClose]);
10284
- useEffect37(() => {
10312
+ useEffect38(() => {
10285
10313
  return () => {
10286
10314
  if (copyResetTimeoutRef.current) {
10287
10315
  window.clearTimeout(copyResetTimeoutRef.current);
@@ -10392,21 +10420,21 @@ var InviteDialog = React52.memo((props) => {
10392
10420
  InviteDialog.displayName = "InviteDialog";
10393
10421
 
10394
10422
  // src/components/leave-dialog/LeaveDialog.tsx
10395
- import React54, { useEffect as useEffect39, useRef as useRef27, useState as useState42 } from "react";
10423
+ import React54, { useEffect as useEffect40, useRef as useRef27, useState as useState43 } from "react";
10396
10424
 
10397
10425
  // src/components/leave-dialog/ClassicLeaveDialog.tsx
10398
- import React53, { useEffect as useEffect38, useRef as useRef26, useState as useState41 } from "react";
10426
+ import React53, { useEffect as useEffect39, useRef as useRef26, useState as useState42 } from "react";
10399
10427
  import { jsx as jsx91, jsxs as jsxs78 } from "react/jsx-runtime";
10400
10428
  var ClassicLeaveDialog = React53.memo(({ isOpen, onClose, onConfirm, onEndEpisode, palette, texture = "none", className }) => {
10401
10429
  const skin = useSkin();
10402
10430
  const prefersReducedMotion = usePrefersReducedMotion2();
10403
10431
  const portalTheme = resolvePortalThemeFromDocument();
10404
10432
  const modalRef = useRef26(null);
10405
- const [confirmingEndEpisode, setConfirmingEndEpisode] = useState41(false);
10406
- useEffect38(() => {
10433
+ const [confirmingEndEpisode, setConfirmingEndEpisode] = useState42(false);
10434
+ useEffect39(() => {
10407
10435
  if (!isOpen) setConfirmingEndEpisode(false);
10408
10436
  }, [isOpen]);
10409
- useEffect38(() => {
10437
+ useEffect39(() => {
10410
10438
  const handleEscape = (e) => {
10411
10439
  if (e.key === "Escape" && isOpen) {
10412
10440
  onClose();
@@ -10500,11 +10528,11 @@ var ChalkLeaveDialog = React54.memo(({ isOpen, onClose, onConfirm, onEndEpisode,
10500
10528
  const prefersReducedMotion = usePrefersReducedMotion2();
10501
10529
  const portalTheme = resolvePortalThemeFromDocument();
10502
10530
  const modalRef = useRef27(null);
10503
- const [confirmingEndEpisode, setConfirmingEndEpisode] = useState42(false);
10504
- useEffect39(() => {
10531
+ const [confirmingEndEpisode, setConfirmingEndEpisode] = useState43(false);
10532
+ useEffect40(() => {
10505
10533
  if (!isOpen) setConfirmingEndEpisode(false);
10506
10534
  }, [isOpen]);
10507
- useEffect39(() => {
10535
+ useEffect40(() => {
10508
10536
  const handleEscape = (e) => {
10509
10537
  if (e.key === "Escape" && isOpen) {
10510
10538
  onClose();
@@ -10778,10 +10806,10 @@ var SpaceHeader = React59.memo((props) => {
10778
10806
  SpaceHeader.displayName = "SpaceHeader";
10779
10807
 
10780
10808
  // src/components/space-info-dialog/SpaceInfoDialog.tsx
10781
- import React61, { useState as useState44 } from "react";
10809
+ import React61, { useState as useState45 } from "react";
10782
10810
 
10783
10811
  // src/components/space-info-dialog/ClassicSpaceInfoDialog.tsx
10784
- import React60, { useState as useState43 } from "react";
10812
+ import React60, { useState as useState44 } from "react";
10785
10813
  import { jsx as jsx98, jsxs as jsxs85 } from "react/jsx-runtime";
10786
10814
  var formatDuration4 = (seconds) => {
10787
10815
  const hours = Math.floor(seconds / 3600);
@@ -10792,7 +10820,7 @@ var formatDuration4 = (seconds) => {
10792
10820
  var ClassicSpaceInfoDialog = React60.memo(
10793
10821
  ({ isOpen, onClose, spaceName, spaceId, inviteLink, onCopyLink, isRecording = false, isTranscribing = false, duration = 0, stats = { latency: 28, packetLoss: 0.1, resolution: "1080p \xB7 60fps", region: "Frankfurt, DE" }, className }) => {
10794
10822
  const skin = useSkin();
10795
- const [copied, setCopied] = useState43(false);
10823
+ const [copied, setCopied] = useState44(false);
10796
10824
  const handleCopy = () => {
10797
10825
  onCopyLink();
10798
10826
  setCopied(true);
@@ -10893,7 +10921,7 @@ var formatDuration5 = (seconds) => {
10893
10921
  };
10894
10922
  var ChalkSpaceInfoDialog = React61.memo(({ isOpen, onClose, spaceName, spaceId, inviteLink, onCopyLink, isRecording = false, isTranscribing = false, duration = 0, stats = { latency: 28, packetLoss: 0.1, resolution: "1080p \xB7 60fps", region: "Frankfurt, DE" }, className }) => {
10895
10923
  const skin = useSkin();
10896
- const [copied, setCopied] = useState44(false);
10924
+ const [copied, setCopied] = useState45(false);
10897
10925
  const handleCopy = () => {
10898
10926
  onCopyLink();
10899
10927
  setCopied(true);
@@ -10978,10 +11006,10 @@ var SpaceInfoDialog = React61.memo((props) => {
10978
11006
  SpaceInfoDialog.displayName = "SpaceInfoDialog";
10979
11007
 
10980
11008
  // src/components/transcript-panel/TranscriptPanel.tsx
10981
- import React63, { useMemo as useMemo34, useRef as useRef31, useEffect as useEffect41, useState as useState46, useCallback as useCallback17 } from "react";
11009
+ import React63, { useMemo as useMemo34, useRef as useRef31, useEffect as useEffect42, useState as useState47, useCallback as useCallback17 } from "react";
10982
11010
 
10983
11011
  // src/components/transcript-panel/ClassicTranscriptPanel.tsx
10984
- import React62, { useMemo as useMemo33, useRef as useRef30, useEffect as useEffect40, useState as useState45, useCallback as useCallback16 } from "react";
11012
+ import React62, { useMemo as useMemo33, useRef as useRef30, useEffect as useEffect41, useState as useState46, useCallback as useCallback16 } from "react";
10985
11013
  import { IconButton as IconButton7, Input as Input4 } from "@q9labsai/chalk-ui";
10986
11014
  import { Fragment as Fragment20, jsx as jsx100, jsxs as jsxs87 } from "react/jsx-runtime";
10987
11015
  function groupTranscriptsBySpeaker(transcripts) {
@@ -11014,9 +11042,9 @@ function findSearchMatches(transcripts, query) {
11014
11042
  return matches;
11015
11043
  }
11016
11044
  function ExportDropdown({ onExport, onCopyAll }) {
11017
- const [isOpen, setIsOpen] = useState45(false);
11045
+ const [isOpen, setIsOpen] = useState46(false);
11018
11046
  const dropdownRef = useRef30(null);
11019
- useEffect40(() => {
11047
+ useEffect41(() => {
11020
11048
  function handleClickOutside(event) {
11021
11049
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
11022
11050
  setIsOpen(false);
@@ -11113,9 +11141,9 @@ var TranscriptPanelSurface = React62.memo(
11113
11141
  className
11114
11142
  }) => {
11115
11143
  const prefersReducedMotion = usePrefersReducedMotion2();
11116
- const [searchQuery, setSearchQuery] = useState45("");
11117
- const [currentMatchIndex, setCurrentMatchIndex] = useState45(0);
11118
- const [autoScroll, setAutoScroll] = useState45(true);
11144
+ const [searchQuery, setSearchQuery] = useState46("");
11145
+ const [currentMatchIndex, setCurrentMatchIndex] = useState46(0);
11146
+ const [autoScroll, setAutoScroll] = useState46(true);
11119
11147
  const containerRef = useRef30(null);
11120
11148
  const endRef = useRef30(null);
11121
11149
  const searchInputRef = useRef30(null);
@@ -11142,18 +11170,18 @@ var TranscriptPanelSurface = React62.memo(
11142
11170
  entries: group.entries.filter((e) => matchedIds.has(e.id))
11143
11171
  })).filter((group) => group.entries.length > 0);
11144
11172
  }, [groupedTranscripts, searchQuery, searchMatches]);
11145
- useEffect40(() => {
11173
+ useEffect41(() => {
11146
11174
  if (autoScroll && endRef.current && !searchQuery) {
11147
11175
  endRef.current.scrollIntoView({ behavior: prefersReducedMotion ? "auto" : "smooth" });
11148
11176
  }
11149
11177
  }, [transcripts, autoScroll, prefersReducedMotion, searchQuery]);
11150
- useEffect40(() => {
11178
+ useEffect41(() => {
11151
11179
  if (currentMatch && containerRef.current) {
11152
11180
  const matchElement = containerRef.current.querySelector(`[data-transcript-match="true"]`);
11153
11181
  matchElement?.scrollIntoView({ behavior: "smooth", block: "center" });
11154
11182
  }
11155
11183
  }, [currentMatch, currentMatchIndex]);
11156
- useEffect40(() => {
11184
+ useEffect41(() => {
11157
11185
  function handleKeyDown(event) {
11158
11186
  if ((event.metaKey || event.ctrlKey) && event.key === "f" && searchable) {
11159
11187
  event.preventDefault();
@@ -11414,9 +11442,9 @@ function findSearchMatches2(transcripts, query) {
11414
11442
  return matches;
11415
11443
  }
11416
11444
  function ExportDropdown2({ onExport, onCopyAll }) {
11417
- const [isOpen, setIsOpen] = useState46(false);
11445
+ const [isOpen, setIsOpen] = useState47(false);
11418
11446
  const dropdownRef = useRef31(null);
11419
- useEffect41(() => {
11447
+ useEffect42(() => {
11420
11448
  function handleClickOutside(event) {
11421
11449
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
11422
11450
  setIsOpen(false);
@@ -11508,9 +11536,9 @@ var TranscriptPanelSurface2 = React63.memo(
11508
11536
  className
11509
11537
  }) => {
11510
11538
  const prefersReducedMotion = usePrefersReducedMotion2();
11511
- const [searchQuery, setSearchQuery] = useState46("");
11512
- const [currentMatchIndex, setCurrentMatchIndex] = useState46(0);
11513
- const [autoScroll, setAutoScroll] = useState46(true);
11539
+ const [searchQuery, setSearchQuery] = useState47("");
11540
+ const [currentMatchIndex, setCurrentMatchIndex] = useState47(0);
11541
+ const [autoScroll, setAutoScroll] = useState47(true);
11514
11542
  const containerRef = useRef31(null);
11515
11543
  const endRef = useRef31(null);
11516
11544
  const searchInputRef = useRef31(null);
@@ -11537,18 +11565,18 @@ var TranscriptPanelSurface2 = React63.memo(
11537
11565
  entries: group.entries.filter((e) => matchedIds.has(e.id))
11538
11566
  })).filter((group) => group.entries.length > 0);
11539
11567
  }, [groupedTranscripts, searchQuery, searchMatches]);
11540
- useEffect41(() => {
11568
+ useEffect42(() => {
11541
11569
  if (autoScroll && endRef.current && !searchQuery) {
11542
11570
  endRef.current.scrollIntoView({ behavior: prefersReducedMotion ? "auto" : "smooth" });
11543
11571
  }
11544
11572
  }, [transcripts, autoScroll, prefersReducedMotion, searchQuery]);
11545
- useEffect41(() => {
11573
+ useEffect42(() => {
11546
11574
  if (currentMatch && containerRef.current) {
11547
11575
  const matchElement = containerRef.current.querySelector(`[data-transcript-match="true"]`);
11548
11576
  matchElement?.scrollIntoView({ behavior: "smooth", block: "center" });
11549
11577
  }
11550
11578
  }, [currentMatch, currentMatchIndex]);
11551
- useEffect41(() => {
11579
+ useEffect42(() => {
11552
11580
  function handleKeyDown(event) {
11553
11581
  if ((event.metaKey || event.ctrlKey) && event.key === "f" && searchable) {
11554
11582
  event.preventDefault();
@@ -11771,23 +11799,23 @@ var TranscriptPanel = React63.memo((props) => {
11771
11799
  TranscriptPanel.displayName = "TranscriptPanel";
11772
11800
 
11773
11801
  // src/components/space-view/ClassicSpaceView.tsx
11774
- import React65, { useCallback as useCallback19, useEffect as useEffect45, useMemo as useMemo36, useState as useState48 } from "react";
11802
+ import React65, { useCallback as useCallback19, useEffect as useEffect46, useMemo as useMemo36, useState as useState49 } from "react";
11775
11803
 
11776
11804
  // src/components/space-view/SpaceDrawer.tsx
11777
- import { useEffect as useEffect42, useRef as useRef32 } from "react";
11805
+ import { useEffect as useEffect43, useRef as useRef32 } from "react";
11778
11806
  import { Fragment as Fragment22, jsx as jsx102, jsxs as jsxs89 } from "react/jsx-runtime";
11779
11807
  function SpaceDrawer({ state, onClose, children }) {
11780
11808
  const skin = useSkin();
11781
11809
  const drawerRef = useRef32(null);
11782
11810
  const openerRef = useRef32(null);
11783
- useEffect42(() => {
11811
+ useEffect43(() => {
11784
11812
  if (state !== "open") return;
11785
11813
  const drawer = drawerRef.current;
11786
11814
  if (!drawer || drawer.contains(document.activeElement)) return;
11787
11815
  openerRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
11788
11816
  drawer.focus({ preventScroll: true });
11789
11817
  }, [state]);
11790
- useEffect42(() => {
11818
+ useEffect43(() => {
11791
11819
  if (state !== "closing") return;
11792
11820
  const opener = openerRef.current;
11793
11821
  openerRef.current = null;
@@ -11863,12 +11891,12 @@ function SpaceStage({ tiles, layout, whiteboard, className }) {
11863
11891
  SpaceStage.displayName = "SpaceStage";
11864
11892
 
11865
11893
  // src/components/space-view/useDrawerPresence.ts
11866
- import { useEffect as useEffect43, useState as useState47 } from "react";
11894
+ import { useEffect as useEffect44, useState as useState48 } from "react";
11867
11895
  var DRAWER_EXIT_MS = 200;
11868
11896
  function useDrawerPresence(panel, exitMs) {
11869
- const [retained, setRetained] = useState47(panel);
11870
- const [state, setState] = useState47(panel === null ? "closed" : "open");
11871
- useEffect43(() => {
11897
+ const [retained, setRetained] = useState48(panel);
11898
+ const [state, setState] = useState48(panel === null ? "closed" : "open");
11899
+ useEffect44(() => {
11872
11900
  if (panel !== null) {
11873
11901
  setRetained(panel);
11874
11902
  setState("open");
@@ -11885,10 +11913,10 @@ function useDrawerPresence(panel, exitMs) {
11885
11913
  }
11886
11914
 
11887
11915
  // src/components/space-view/useContentLayoutSwitch.ts
11888
- import { useEffect as useEffect44, useRef as useRef33 } from "react";
11916
+ import { useEffect as useEffect45, useRef as useRef33 } from "react";
11889
11917
  function useContentLayoutSwitch(hasContent, layout, updateLayout) {
11890
11918
  const memoryRef = useRef33({ hasContent: false, layoutBefore: null });
11891
- useEffect44(() => {
11919
+ useEffect45(() => {
11892
11920
  const memory = memoryRef.current;
11893
11921
  if (hasContent === memory.hasContent) return;
11894
11922
  if (hasContent) {
@@ -11937,17 +11965,17 @@ function ClassicSpaceView({
11937
11965
  const canSendReaction = useCan("sendReaction");
11938
11966
  const canDrawWhiteboard = useCan("drawWhiteboard");
11939
11967
  const canManageAdmission = useCan("manageAdmission");
11940
- const [uncontrolledLayout, setUncontrolledLayout] = useState48("focus");
11941
- const [activePanel, setActivePanel] = useState48(initialPanel);
11942
- const [isReactionPickerOpen, setReactionPickerOpen] = useState48(false);
11943
- const [isLeaveDialogOpen, setLeaveDialogOpen] = useState48(false);
11944
- const [commandError, setCommandError] = useState48(null);
11968
+ const [uncontrolledLayout, setUncontrolledLayout] = useState49("focus");
11969
+ const [activePanel, setActivePanel] = useState49(initialPanel);
11970
+ const [isReactionPickerOpen, setReactionPickerOpen] = useState49(false);
11971
+ const [isLeaveDialogOpen, setLeaveDialogOpen] = useState49(false);
11972
+ const [commandError, setCommandError] = useState49(null);
11945
11973
  const layout = controlledLayout ?? uncontrolledLayout;
11946
11974
  const feature = (name) => features?.[name] !== false;
11947
11975
  const localId = self.participantId ?? "local";
11948
11976
  const tiles = useMemo36(() => toVideoParticipants(participantsSlice.roster, media.remote, localId, self.displayName ?? "You", media.local), [localId, media.local, media.remote, participantsSlice.roster, self.displayName]);
11949
- useEffect45(() => setActivePanel(initialPanel), [initialPanel]);
11950
- useEffect45(() => {
11977
+ useEffect46(() => setActivePanel(initialPanel), [initialPanel]);
11978
+ useEffect46(() => {
11951
11979
  if (feature("admission") && canManageAdmission && participantsSlice.admissionQueue.length > 0) setActivePanel("admission");
11952
11980
  }, [canManageAdmission, participantsSlice.admissionQueue.length, features?.admission]);
11953
11981
  const buttons = [
@@ -11987,7 +12015,7 @@ function ClassicSpaceView({
11987
12015
  setActivePanel(null);
11988
12016
  }
11989
12017
  }) : settingsDialog;
11990
- useEffect45(() => {
12018
+ useEffect46(() => {
11991
12019
  if (activePanel !== "settings" || !React65.isValidElement(settingsDialog) || settingsDialog.props.isOpen !== false) return;
11992
12020
  setActivePanel(null);
11993
12021
  }, [activePanel, settingsDialog]);
@@ -12160,17 +12188,17 @@ function ChalkSpaceView({
12160
12188
  const canSendReaction = useCan("sendReaction");
12161
12189
  const canDrawWhiteboard = useCan("drawWhiteboard");
12162
12190
  const canManageAdmission = useCan("manageAdmission");
12163
- const [uncontrolledLayout, setUncontrolledLayout] = useState49("focus");
12164
- const [activePanel, setActivePanel] = useState49(initialPanel);
12165
- const [isReactionPickerOpen, setReactionPickerOpen] = useState49(false);
12166
- const [isLeaveDialogOpen, setLeaveDialogOpen] = useState49(false);
12167
- const [commandError, setCommandError] = useState49(null);
12191
+ const [uncontrolledLayout, setUncontrolledLayout] = useState50("focus");
12192
+ const [activePanel, setActivePanel] = useState50(initialPanel);
12193
+ const [isReactionPickerOpen, setReactionPickerOpen] = useState50(false);
12194
+ const [isLeaveDialogOpen, setLeaveDialogOpen] = useState50(false);
12195
+ const [commandError, setCommandError] = useState50(null);
12168
12196
  const layout = controlledLayout ?? uncontrolledLayout;
12169
12197
  const feature = (name) => features?.[name] !== false;
12170
12198
  const localId = self.participantId ?? "local";
12171
12199
  const tiles = useMemo37(() => toVideoParticipants(participantsSlice.roster, media.remote, localId, self.displayName ?? "You", media.local), [localId, media.local, media.remote, participantsSlice.roster, self.displayName]);
12172
- useEffect46(() => setActivePanel(initialPanel), [initialPanel]);
12173
- useEffect46(() => {
12200
+ useEffect47(() => setActivePanel(initialPanel), [initialPanel]);
12201
+ useEffect47(() => {
12174
12202
  if (feature("admission") && canManageAdmission && participantsSlice.admissionQueue.length > 0) setActivePanel("admission");
12175
12203
  }, [canManageAdmission, participantsSlice.admissionQueue.length, features?.admission]);
12176
12204
  const buttons = [
@@ -12210,7 +12238,7 @@ function ChalkSpaceView({
12210
12238
  setActivePanel(null);
12211
12239
  }
12212
12240
  }) : settingsDialog;
12213
- useEffect46(() => {
12241
+ useEffect47(() => {
12214
12242
  if (activePanel !== "settings" || !React66.isValidElement(settingsDialog) || settingsDialog.props.isOpen !== false) return;
12215
12243
  setActivePanel(null);
12216
12244
  }, [activePanel, settingsDialog]);
@@ -12359,7 +12387,7 @@ function Chalk(props) {
12359
12387
  return createSpaceClient({ space: props.space, getAccess: getLatestAccess });
12360
12388
  }, [getLatestAccess, props.space, suppliedClient]);
12361
12389
  const client = suppliedClient ?? ownedClient;
12362
- useEffect47(() => {
12390
+ useEffect48(() => {
12363
12391
  if (!ownedClient) return;
12364
12392
  return () => {
12365
12393
  void ownedClient.leave().catch(() => void 0).finally(() => ownedClient.dispose());
@@ -12375,7 +12403,7 @@ function SpaceExperience(props) {
12375
12403
  const hasBeenLive = useRef34(connection.status === "live" || connection.status === "reconnecting");
12376
12404
  const autoJoinAttempted = useRef34(false);
12377
12405
  const previousClient = useRef34(client);
12378
- const [joinError, setJoinError] = useState50(null);
12406
+ const [joinError, setJoinError] = useState51(null);
12379
12407
  const entrance = props.entrance ?? true;
12380
12408
  const spaceName = props.spaceName ?? props.space ?? "Space";
12381
12409
  if (previousClient.current !== client) {
@@ -12401,13 +12429,13 @@ function SpaceExperience(props) {
12401
12429
  autoJoinAttempted.current = true;
12402
12430
  void join(defaultJoinOptions(props));
12403
12431
  }, [join, props]);
12404
- useEffect47(() => setJoinError(null), [client]);
12405
- useEffect47(() => {
12432
+ useEffect48(() => setJoinError(null), [client]);
12433
+ useEffect48(() => {
12406
12434
  if (entrance || connection.status !== "idle" || autoJoinAttempted.current) return;
12407
12435
  autoJoinAttempted.current = true;
12408
12436
  void join(defaultJoinOptions(props));
12409
12437
  }, [connection.status, entrance, join, props.defaults?.camera, props.defaults?.microphone, props.displayName]);
12410
- useEffect47(() => {
12438
+ useEffect48(() => {
12411
12439
  const previous = previousStatus.current;
12412
12440
  if (hasObservedStatus.current) {
12413
12441
  if (connection.status === "live" && previous !== "live" && previous !== "reconnecting") props.onJoined?.();
@@ -12435,21 +12463,21 @@ function SpaceSurface(props) {
12435
12463
  const client = useSpaceClient();
12436
12464
  const self = useSelf();
12437
12465
  const media = useMedia();
12466
+ const whiteboardState = useWhiteboard();
12438
12467
  const canEndEpisode = useCan("endEpisode");
12439
12468
  const canDrawWhiteboard = useCan("drawWhiteboard");
12440
- const [settingsOpen, setSettingsOpen] = useState50(false);
12441
- const [settingsInitialSection, setSettingsInitialSection] = useState50();
12442
- const [infoOpen, setInfoOpen] = useState50(false);
12443
- const [whiteboardOpen, setWhiteboardOpen] = useState50(false);
12444
- const [commandError, setCommandError] = useState50(null);
12445
- const [settings, setSettings] = useState50(() => createSettings(self.displayName ?? "", props.layout ?? "focus", props.theme?.skin ?? "classic", props.theme?.palette ?? (props.resolvedColorScheme === "dark" ? "warm-charcoal" : "light"), props.theme?.texture ?? "none"));
12469
+ const [settingsOpen, setSettingsOpen] = useState51(false);
12470
+ const [settingsInitialSection, setSettingsInitialSection] = useState51();
12471
+ const [infoOpen, setInfoOpen] = useState51(false);
12472
+ const [commandError, setCommandError] = useState51(null);
12473
+ const [settings, setSettings] = useState51(() => createSettings(self.displayName ?? "", props.layout ?? "focus", props.theme?.skin ?? "classic", props.theme?.palette ?? (props.resolvedColorScheme === "dark" ? "warm-charcoal" : "light"), props.theme?.texture ?? "none"));
12446
12474
  const resolvedSkin = props.theme?.skin ?? "classic";
12447
12475
  const resolvedPalette = props.theme?.palette ?? (props.resolvedColorScheme === "dark" ? "warm-charcoal" : "light");
12448
12476
  const resolvedTexture = props.theme?.texture ?? "none";
12449
12477
  const appearancePaletteExplicitRef = useRef34(props.theme?.palette !== void 0);
12450
12478
  const settingsRef = useRef34(settings);
12451
12479
  settingsRef.current = settings;
12452
- useEffect47(() => {
12480
+ useEffect48(() => {
12453
12481
  setSettings((current) => ({
12454
12482
  ...current,
12455
12483
  identity: { displayName: self.displayName ?? current.identity.displayName },
@@ -12458,7 +12486,7 @@ function SpaceSurface(props) {
12458
12486
  video: { ...current.video, selectedInput: media.selection.camera ?? void 0 }
12459
12487
  }));
12460
12488
  }, [media.local.camera.state, media.local.microphone.state, media.selection.camera, media.selection.microphone, media.selection.speaker, self.displayName]);
12461
- useEffect47(() => {
12489
+ useEffect48(() => {
12462
12490
  if (!props.theme?.skin && !props.theme?.palette && !props.theme?.texture) return;
12463
12491
  setSettings((current) => ({
12464
12492
  ...current,
@@ -12471,7 +12499,7 @@ function SpaceSurface(props) {
12471
12499
  }
12472
12500
  }));
12473
12501
  }, [props.theme?.palette, props.theme?.skin, props.theme?.texture]);
12474
- useEffect47(() => {
12502
+ useEffect48(() => {
12475
12503
  if (props.theme?.palette || appearancePaletteExplicitRef.current) return;
12476
12504
  const palette = props.resolvedColorScheme === "dark" ? "warm-charcoal" : "light";
12477
12505
  setSettings((current) => current.appearance.palette === palette ? current : { ...current, appearance: { ...current.appearance, palette, theme: palette === "light" ? "light" : "dark" } });
@@ -12485,20 +12513,28 @@ function SpaceSurface(props) {
12485
12513
  }
12486
12514
  }, []);
12487
12515
  const whiteboardTransport = client.whiteboard.transport();
12488
- const whiteboard = props.features?.whiteboard !== false && whiteboardOpen && canDrawWhiteboard && whiteboardTransport ? {
12516
+ const whiteboardAvailable = props.features?.whiteboard !== false;
12517
+ const whiteboardSubscription = useWhiteboardSceneSubscription(whiteboardTransport, whiteboardAvailable);
12518
+ const setWhiteboardPresentation = whiteboardSubscription.status === "ready" ? whiteboardSubscription.transport.setPresentation : void 0;
12519
+ useEffect48(() => {
12520
+ if (whiteboardSubscription.status === "failed") setCommandError(whiteboardSubscription.error.message);
12521
+ else if (whiteboardSubscription.status === "loading" || whiteboardSubscription.status === "ready") setCommandError(null);
12522
+ }, [whiteboardSubscription]);
12523
+ const whiteboard = whiteboardAvailable && whiteboardState.engine.presenting && whiteboardSubscription.status === "ready" ? {
12489
12524
  isOpen: true,
12490
12525
  props: {
12491
12526
  canDraw: canDrawWhiteboard,
12492
12527
  collab: {
12493
12528
  canDraw: canDrawWhiteboard,
12494
- subscribe: (listener) => whiteboardTransport.subscribe((event) => listener(toWhiteboardCollaborationEvent(event))),
12495
- submitUpdate: async (input) => whiteboardTransport.submitUpdate({ sceneId: input.sceneId, syncAll: input.syncAll, elements: input.elements.map(fromWhiteboardWireElement) }),
12496
- sendCursor: (input) => whiteboardTransport.sendCursor(input),
12497
- requestSnapshot: () => whiteboardTransport.requestSnapshot(),
12498
- clear: () => whiteboardTransport.clear(),
12499
- initiateUpload: (input) => whiteboardTransport.files.initiateUpload(input),
12500
- finalizeUpload: (uploadId) => whiteboardTransport.files.finalizeUpload(uploadId),
12501
- presignDownload: (fileId) => whiteboardTransport.files.getDownloadUrl(fileId)
12529
+ subscribe: (listener) => whiteboardSubscription.transport.subscribe((event) => listener(toWhiteboardCollaborationEvent(event))),
12530
+ submitUpdate: async (input) => whiteboardSubscription.transport.submitUpdate({ sceneId: input.sceneId, syncAll: input.syncAll, elements: input.elements.map(fromWhiteboardWireElement) }),
12531
+ sendCursor: (input) => whiteboardSubscription.transport.sendCursor(input),
12532
+ requestSnapshot: () => whiteboardSubscription.transport.requestSnapshot(),
12533
+ onSubmissionError: (cause) => setCommandError(cause instanceof Error ? cause.message : "Whiteboard could not sync."),
12534
+ clear: () => whiteboardSubscription.transport.clear(),
12535
+ initiateUpload: (input) => whiteboardSubscription.transport.files.initiateUpload(input),
12536
+ finalizeUpload: (uploadId) => whiteboardSubscription.transport.files.finalizeUpload(uploadId),
12537
+ presignDownload: (fileId) => whiteboardSubscription.transport.files.getDownloadUrl(fileId)
12502
12538
  }
12503
12539
  }
12504
12540
  } : void 0;
@@ -12520,7 +12556,7 @@ function SpaceSurface(props) {
12520
12556
  features: { ...props.features, sounds: props.features?.sounds !== false && settings.experience.sounds },
12521
12557
  onOpenDiagnostics: props.onOpenDiagnostics,
12522
12558
  whiteboard,
12523
- onToggleWhiteboard: () => setWhiteboardOpen((open) => !open),
12559
+ onToggleWhiteboard: canDrawWhiteboard && setWhiteboardPresentation ? () => void runCommand(() => setWhiteboardPresentation(!whiteboardState.engine.presenting)) : void 0,
12524
12560
  infoDialog: props.features?.info !== false && props.inviteLink ? { isOpen: infoOpen, onOpenChange: setInfoOpen, spaceName: props.spaceName, inviteLink: props.inviteLink, onCopyLink: () => void navigator.clipboard?.writeText(props.inviteLink) } : void 0,
12525
12561
  onOpenSettings: props.features?.settings !== false ? () => {
12526
12562
  setSettingsInitialSection(void 0);
@@ -12594,8 +12630,8 @@ function defaultJoinOptions(props) {
12594
12630
  return { ...displayName ? { displayName } : {}, microphone: props.defaults?.microphone ?? true, camera: props.defaults?.camera ?? true };
12595
12631
  }
12596
12632
  function useResolvedColorScheme(requested = "light") {
12597
- const [resolved, setResolved] = useState50(() => requested === "system" ? readSystemColorScheme() : requested);
12598
- useEffect47(() => {
12633
+ const [resolved, setResolved] = useState51(() => requested === "system" ? readSystemColorScheme() : requested);
12634
+ useEffect48(() => {
12599
12635
  if (requested !== "system") return void setResolved(requested);
12600
12636
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void setResolved("light");
12601
12637
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
@@ -12610,12 +12646,12 @@ function readSystemColorScheme() {
12610
12646
  return typeof window !== "undefined" && window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
12611
12647
  }
12612
12648
  function useClientEvents(client, callbacks) {
12613
- useEffect47(() => client.on("participantJoined", (event) => callbacks.onParticipantJoined?.(event)), [callbacks.onParticipantJoined, client]);
12614
- useEffect47(() => client.on("participantLeft", (event) => callbacks.onParticipantLeft?.(event)), [callbacks.onParticipantLeft, client]);
12615
- useEffect47(() => client.on("episodeEnded", (event) => callbacks.onEpisodeEnded?.(event)), [callbacks.onEpisodeEnded, client]);
12616
- useEffect47(() => client.on("screenShareStarted", (event) => callbacks.onScreenShareStarted?.(event)), [callbacks.onScreenShareStarted, client]);
12617
- useEffect47(() => client.on("screenShareStopped", (event) => callbacks.onScreenShareStopped?.(event)), [callbacks.onScreenShareStopped, client]);
12618
- useEffect47(() => client.on("error", (event) => callbacks.onError?.(event)), [callbacks.onError, client]);
12649
+ useEffect48(() => client.on("participantJoined", (event) => callbacks.onParticipantJoined?.(event)), [callbacks.onParticipantJoined, client]);
12650
+ useEffect48(() => client.on("participantLeft", (event) => callbacks.onParticipantLeft?.(event)), [callbacks.onParticipantLeft, client]);
12651
+ useEffect48(() => client.on("episodeEnded", (event) => callbacks.onEpisodeEnded?.(event)), [callbacks.onEpisodeEnded, client]);
12652
+ useEffect48(() => client.on("screenShareStarted", (event) => callbacks.onScreenShareStarted?.(event)), [callbacks.onScreenShareStarted, client]);
12653
+ useEffect48(() => client.on("screenShareStopped", (event) => callbacks.onScreenShareStopped?.(event)), [callbacks.onScreenShareStopped, client]);
12654
+ useEffect48(() => client.on("error", (event) => callbacks.onError?.(event)), [callbacks.onError, client]);
12619
12655
  }
12620
12656
  function createSettings(displayName, layout, skin, palette, texture) {
12621
12657
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"Chalk.d.ts","sourceRoot":"","sources":["../../../src/components/chalk/Chalk.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Chalk.d.ts","sourceRoot":"","sources":["../../../src/components/chalk/Chalk.tsx"],"names":[],"mappings":"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"}
@@ -35,7 +35,7 @@ import {
35
35
  SettingsPanel,
36
36
  Stage,
37
37
  buildStageItems
38
- } from "../chunk-4SU35WSH.js";
38
+ } from "../chunk-XF5YWLFY.js";
39
39
  import "../chunk-ZEZLA34O.js";
40
40
  export {
41
41
  AdmissionPanel,
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ import {
35
35
  useSelf,
36
36
  useSpaceClient,
37
37
  useWhiteboard
38
- } from "./chunk-4SU35WSH.js";
38
+ } from "./chunk-XF5YWLFY.js";
39
39
  import "./chunk-ZEZLA34O.js";
40
40
  export {
41
41
  COSMIC_CHALK_THEME,
@@ -0,0 +1,13 @@
1
+ import type { ChalkWhiteboardV1Transport } from "@q9labsai/chalk-client";
2
+ type WhiteboardSceneSubscription = {
3
+ readonly status: "closed" | "loading";
4
+ } | {
5
+ readonly status: "ready";
6
+ readonly transport: ChalkWhiteboardV1Transport;
7
+ } | {
8
+ readonly status: "failed";
9
+ readonly error: Error;
10
+ };
11
+ export declare function useWhiteboardSceneSubscription(transport: ChalkWhiteboardV1Transport | null, active: boolean): WhiteboardSceneSubscription;
12
+ export {};
13
+ //# sourceMappingURL=useWhiteboardSceneSubscription.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWhiteboardSceneSubscription.d.ts","sourceRoot":"","sources":["../../src/internal/useWhiteboardSceneSubscription.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAGzE,KAAK,2BAA2B,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,0BAA0B,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAInN,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,0BAA0B,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO,GAAG,2BAA2B,CA6BzI"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q9labsai/chalk-react",
3
- "version": "4.1.3",
3
+ "version": "4.1.5",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -61,10 +61,10 @@
61
61
  "@base-ui/react": "^1.7.0",
62
62
  "@hugeicons/core-free-icons": "^4.2.3",
63
63
  "@hugeicons/react": "^1.1.9",
64
- "@q9labsai/chalk-client": "^4.1.3",
65
- "@q9labsai/chalk-ui": "^4.1.3",
66
- "@q9labsai/chalk-whiteboard": "^4.1.3",
67
- "@q9labsai/facehash": "^4.1.3",
64
+ "@q9labsai/chalk-client": "^4.1.5",
65
+ "@q9labsai/chalk-ui": "^4.1.5",
66
+ "@q9labsai/chalk-whiteboard": "^4.1.5",
67
+ "@q9labsai/facehash": "^4.1.5",
68
68
  "class-variance-authority": "^0.7.1",
69
69
  "clsx": "^2.1.1",
70
70
  "sonner": "^2.0.8",