@q9labsai/chalk-react 4.1.2 → 4.1.4

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.
@@ -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";
@@ -9661,15 +9689,64 @@ function diffSoundCues(previous, next) {
9661
9689
  }
9662
9690
  return cues;
9663
9691
  }
9692
+ var AUTOPLAY_UNLOCK_EVENTS = ["pointerdown", "touchend", "click", "keydown"];
9693
+ function isAutoplayBlocked(cause) {
9694
+ return typeof DOMException !== "undefined" && cause instanceof DOMException && cause.name === "NotAllowedError";
9695
+ }
9696
+ function supportsSinkSelection(element) {
9697
+ return "setSinkId" in element && typeof element.setSinkId === "function";
9698
+ }
9664
9699
  function soundSourceFor(cue, canPlay) {
9665
9700
  const asset = CHALK_SOUND_ASSETS[cue];
9666
9701
  return canPlay(asset.opus.mimeType) ? asset.opus.url : asset.mp3.url;
9667
9702
  }
9668
- function createSoundPlayer({ volume = 0.6, onError } = {}) {
9703
+ function createSoundPlayer({ volume = 0.6, outputDeviceId, onError, unlockTarget = typeof window === "undefined" ? null : window } = {}) {
9669
9704
  const elements = /* @__PURE__ */ new Map();
9670
9705
  const lastPlayed = /* @__PURE__ */ new Map();
9706
+ const blocked = /* @__PURE__ */ new Set();
9707
+ const playbackInFlight = /* @__PURE__ */ new Set();
9671
9708
  const probe = typeof Audio === "undefined" ? null : new Audio();
9672
9709
  const canPlay = (mimeType) => probe !== null && probe.canPlayType(mimeType) !== "";
9710
+ let listeningForUnlock = false;
9711
+ const removeUnlockListeners = () => {
9712
+ if (!unlockTarget || !listeningForUnlock) return;
9713
+ for (const event of AUTOPLAY_UNLOCK_EVENTS) unlockTarget.removeEventListener(event, retryBlocked, true);
9714
+ listeningForUnlock = false;
9715
+ };
9716
+ const addUnlockListeners = () => {
9717
+ if (!unlockTarget || listeningForUnlock) return;
9718
+ for (const event of AUTOPLAY_UNLOCK_EVENTS) unlockTarget.addEventListener(event, retryBlocked, { capture: true, passive: true });
9719
+ listeningForUnlock = true;
9720
+ };
9721
+ const reportPlaybackFailure = (cue, cause) => {
9722
+ if (isAutoplayBlocked(cause)) {
9723
+ blocked.add(cue);
9724
+ addUnlockListeners();
9725
+ }
9726
+ onError?.(cue, cause);
9727
+ };
9728
+ const playElement = (cue, element) => {
9729
+ if (playbackInFlight.has(cue)) return;
9730
+ playbackInFlight.add(cue);
9731
+ element.currentTime = 0;
9732
+ element.play().then(
9733
+ () => {
9734
+ playbackInFlight.delete(cue);
9735
+ blocked.delete(cue);
9736
+ if (blocked.size === 0) removeUnlockListeners();
9737
+ },
9738
+ (cause) => {
9739
+ playbackInFlight.delete(cue);
9740
+ reportPlaybackFailure(cue, cause);
9741
+ }
9742
+ );
9743
+ };
9744
+ function retryBlocked() {
9745
+ for (const cue of blocked) {
9746
+ const element = elements.get(cue);
9747
+ if (element) playElement(cue, element);
9748
+ }
9749
+ }
9673
9750
  return {
9674
9751
  play: (cue) => {
9675
9752
  if (probe === null) return;
@@ -9681,12 +9758,15 @@ function createSoundPlayer({ volume = 0.6, onError } = {}) {
9681
9758
  element = new Audio(soundSourceFor(cue, canPlay));
9682
9759
  element.preload = "auto";
9683
9760
  element.volume = volume;
9761
+ if (outputDeviceId && supportsSinkSelection(element) && element.sinkId !== outputDeviceId) void element.setSinkId(outputDeviceId).catch(() => void 0);
9684
9762
  elements.set(cue, element);
9685
9763
  }
9686
- element.currentTime = 0;
9687
- element.play().catch((cause) => onError?.(cue, cause));
9764
+ playElement(cue, element);
9688
9765
  },
9689
9766
  dispose: () => {
9767
+ removeUnlockListeners();
9768
+ blocked.clear();
9769
+ playbackInFlight.clear();
9690
9770
  for (const element of elements.values()) {
9691
9771
  element.pause();
9692
9772
  element.removeAttribute("src");
@@ -9697,13 +9777,14 @@ function createSoundPlayer({ volume = 0.6, onError } = {}) {
9697
9777
  }
9698
9778
 
9699
9779
  // src/internal/useSoundCues.ts
9700
- function useSoundCues(enabled, createPlayer = () => createSoundPlayer()) {
9780
+ function useSoundCues(enabled, createPlayer = createSoundPlayer) {
9701
9781
  const client = useSpaceClient();
9782
+ const outputDeviceId = useMedia().selection.speaker ?? void 0;
9702
9783
  const createPlayerRef = useRef20(createPlayer);
9703
9784
  createPlayerRef.current = createPlayer;
9704
- useEffect32(() => {
9785
+ useEffect33(() => {
9705
9786
  if (!enabled) return;
9706
- const player = createPlayerRef.current();
9787
+ const player = createPlayerRef.current({ outputDeviceId });
9707
9788
  let previous = client.getSnapshot();
9708
9789
  const unsubscribe = client.subscribe(() => {
9709
9790
  const next = client.getSnapshot();
@@ -9714,29 +9795,29 @@ function useSoundCues(enabled, createPlayer = () => createSoundPlayer()) {
9714
9795
  unsubscribe();
9715
9796
  player.dispose();
9716
9797
  };
9717
- }, [client, enabled]);
9798
+ }, [client, enabled, outputDeviceId]);
9718
9799
  }
9719
9800
 
9720
9801
  // src/components/composite/ReactionPicker.tsx
9721
- 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";
9722
9803
  import { DEFAULT_QUICK_REACTIONS as DEFAULT_QUICK_REACTIONS2, EMOJI_CATEGORIES as EMOJI_CATEGORIES2, EMOJI_KEYWORDS as EMOJI_KEYWORDS2 } from "@q9labsai/chalk-ui/reactions";
9723
9804
 
9724
9805
  // src/components/composite/ClassicReactionPicker.tsx
9725
- 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";
9726
9807
  import { DEFAULT_QUICK_REACTIONS, EMOJI_CATEGORIES, EMOJI_KEYWORDS } from "@q9labsai/chalk-ui/reactions";
9727
9808
 
9728
9809
  // src/components/composite/ReactionTray.tsx
9729
- 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";
9730
9811
  import { Fragment as Fragment17, jsx as jsx86, jsxs as jsxs73 } from "react/jsx-runtime";
9731
9812
  function ReactionTray({ reactions, onSelect, onClose, position = "top", className }) {
9732
9813
  const skin = useSkin();
9733
9814
  const prefersReducedMotion = usePrefersReducedMotion2();
9734
9815
  const { trigger } = useHaptics();
9735
9816
  const listRef = useRef21(null);
9736
- useEffect33(() => {
9817
+ useEffect34(() => {
9737
9818
  listRef.current?.querySelector("button")?.focus();
9738
9819
  }, []);
9739
- useEffect33(() => {
9820
+ useEffect34(() => {
9740
9821
  const handleKeyDown2 = (event) => {
9741
9822
  if (event.key === "Escape") onClose();
9742
9823
  };
@@ -9787,11 +9868,11 @@ import { Fragment as Fragment18, jsx as jsx87, jsxs as jsxs74 } from "react/jsx-
9787
9868
  var ClassicReactionPicker = React49.memo(({ isOpen, onClose, onSelect, recentReactions = [], allowedReactions, position = "top", participantColorSeed, participantGradientPreference, className, size = "default" }) => {
9788
9869
  const prefersReducedMotion = usePrefersReducedMotion2();
9789
9870
  const { trigger } = useHaptics();
9790
- const [activeCategory, setActiveCategory] = useState37("smileys");
9791
- const [searchQuery, setSearchQuery] = useState37("");
9871
+ const [activeCategory, setActiveCategory] = useState38("smileys");
9872
+ const [searchQuery, setSearchQuery] = useState38("");
9792
9873
  const inputRef = useRef22(null);
9793
9874
  const themeVariables = useMemo31(() => getParticipantThemeVariables(participantColorSeed, participantGradientPreference), [participantColorSeed, participantGradientPreference]);
9794
- useEffect34(() => {
9875
+ useEffect35(() => {
9795
9876
  if (isOpen) {
9796
9877
  setTimeout(() => inputRef.current?.focus(), 50);
9797
9878
  setSearchQuery("");
@@ -9806,7 +9887,7 @@ var ClassicReactionPicker = React49.memo(({ isOpen, onClose, onSelect, recentRea
9806
9887
  },
9807
9888
  [onClose, onSelect, trigger]
9808
9889
  );
9809
- useEffect34(() => {
9890
+ useEffect35(() => {
9810
9891
  if (!isOpen || typeof window === "undefined") return;
9811
9892
  const handleKeyDown = (e) => {
9812
9893
  if (e.key === "Escape") onClose();
@@ -9947,11 +10028,11 @@ import { Fragment as Fragment19, jsx as jsx88, jsxs as jsxs75 } from "react/jsx-
9947
10028
  var ChalkReactionPicker = React50.memo(({ isOpen, onClose, onSelect, recentReactions = [], allowedReactions, position = "top", participantColorSeed, participantGradientPreference, className, size = "default" }) => {
9948
10029
  const prefersReducedMotion = usePrefersReducedMotion2();
9949
10030
  const { trigger } = useHaptics();
9950
- const [activeCategory, setActiveCategory] = useState38("smileys");
9951
- const [searchQuery, setSearchQuery] = useState38("");
10031
+ const [activeCategory, setActiveCategory] = useState39("smileys");
10032
+ const [searchQuery, setSearchQuery] = useState39("");
9952
10033
  const inputRef = useRef23(null);
9953
10034
  const themeVariables = useMemo32(() => getParticipantThemeVariables(participantColorSeed, participantGradientPreference), [participantColorSeed, participantGradientPreference]);
9954
- useEffect35(() => {
10035
+ useEffect36(() => {
9955
10036
  if (isOpen) {
9956
10037
  setTimeout(() => inputRef.current?.focus(), 50);
9957
10038
  setSearchQuery("");
@@ -9966,7 +10047,7 @@ var ChalkReactionPicker = React50.memo(({ isOpen, onClose, onSelect, recentReact
9966
10047
  },
9967
10048
  [onClose, onSelect, trigger]
9968
10049
  );
9969
- useEffect35(() => {
10050
+ useEffect36(() => {
9970
10051
  if (!isOpen || typeof window === "undefined") return;
9971
10052
  const handleKeyDown = (e) => {
9972
10053
  if (e.key === "Escape") onClose();
@@ -10092,10 +10173,10 @@ var ReactionPicker = React50.memo((props) => {
10092
10173
  ReactionPicker.displayName = "ReactionPicker";
10093
10174
 
10094
10175
  // src/components/invite-dialog/InviteDialog.tsx
10095
- 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";
10096
10177
 
10097
10178
  // src/components/invite-dialog/ClassicInviteDialog.tsx
10098
- 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";
10099
10180
  import { Input as Input3 } from "@q9labsai/chalk-ui";
10100
10181
  import { jsx as jsx89, jsxs as jsxs76 } from "react/jsx-runtime";
10101
10182
  var ClassicInviteDialog = React51.memo(({ isOpen, onClose, inviteLink, spaceId, onCopyLink, onShareEmail, onShareCalendar, className }) => {
@@ -10103,8 +10184,8 @@ var ClassicInviteDialog = React51.memo(({ isOpen, onClose, inviteLink, spaceId,
10103
10184
  const prefersReducedMotion = usePrefersReducedMotion2();
10104
10185
  const modalRef = useRef24(null);
10105
10186
  const copyResetTimeoutRef = useRef24(null);
10106
- const [isCopyFeedbackVisible, setIsCopyFeedbackVisible] = useState39(false);
10107
- useEffect36(() => {
10187
+ const [isCopyFeedbackVisible, setIsCopyFeedbackVisible] = useState40(false);
10188
+ useEffect37(() => {
10108
10189
  const handleEscape = (e) => {
10109
10190
  if (e.key === "Escape" && isOpen) {
10110
10191
  onClose();
@@ -10113,7 +10194,7 @@ var ClassicInviteDialog = React51.memo(({ isOpen, onClose, inviteLink, spaceId,
10113
10194
  document.addEventListener("keydown", handleEscape);
10114
10195
  return () => document.removeEventListener("keydown", handleEscape);
10115
10196
  }, [isOpen, onClose]);
10116
- useEffect36(() => {
10197
+ useEffect37(() => {
10117
10198
  return () => {
10118
10199
  if (copyResetTimeoutRef.current) {
10119
10200
  window.clearTimeout(copyResetTimeoutRef.current);
@@ -10218,8 +10299,8 @@ var ChalkInviteDialog = React52.memo(({ isOpen, onClose, inviteLink, spaceId, on
10218
10299
  const prefersReducedMotion = usePrefersReducedMotion2();
10219
10300
  const modalRef = useRef25(null);
10220
10301
  const copyResetTimeoutRef = useRef25(null);
10221
- const [isCopyFeedbackVisible, setIsCopyFeedbackVisible] = useState40(false);
10222
- useEffect37(() => {
10302
+ const [isCopyFeedbackVisible, setIsCopyFeedbackVisible] = useState41(false);
10303
+ useEffect38(() => {
10223
10304
  const handleEscape = (e) => {
10224
10305
  if (e.key === "Escape" && isOpen) {
10225
10306
  onClose();
@@ -10228,7 +10309,7 @@ var ChalkInviteDialog = React52.memo(({ isOpen, onClose, inviteLink, spaceId, on
10228
10309
  document.addEventListener("keydown", handleEscape);
10229
10310
  return () => document.removeEventListener("keydown", handleEscape);
10230
10311
  }, [isOpen, onClose]);
10231
- useEffect37(() => {
10312
+ useEffect38(() => {
10232
10313
  return () => {
10233
10314
  if (copyResetTimeoutRef.current) {
10234
10315
  window.clearTimeout(copyResetTimeoutRef.current);
@@ -10339,21 +10420,21 @@ var InviteDialog = React52.memo((props) => {
10339
10420
  InviteDialog.displayName = "InviteDialog";
10340
10421
 
10341
10422
  // src/components/leave-dialog/LeaveDialog.tsx
10342
- 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";
10343
10424
 
10344
10425
  // src/components/leave-dialog/ClassicLeaveDialog.tsx
10345
- 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";
10346
10427
  import { jsx as jsx91, jsxs as jsxs78 } from "react/jsx-runtime";
10347
10428
  var ClassicLeaveDialog = React53.memo(({ isOpen, onClose, onConfirm, onEndEpisode, palette, texture = "none", className }) => {
10348
10429
  const skin = useSkin();
10349
10430
  const prefersReducedMotion = usePrefersReducedMotion2();
10350
10431
  const portalTheme = resolvePortalThemeFromDocument();
10351
10432
  const modalRef = useRef26(null);
10352
- const [confirmingEndEpisode, setConfirmingEndEpisode] = useState41(false);
10353
- useEffect38(() => {
10433
+ const [confirmingEndEpisode, setConfirmingEndEpisode] = useState42(false);
10434
+ useEffect39(() => {
10354
10435
  if (!isOpen) setConfirmingEndEpisode(false);
10355
10436
  }, [isOpen]);
10356
- useEffect38(() => {
10437
+ useEffect39(() => {
10357
10438
  const handleEscape = (e) => {
10358
10439
  if (e.key === "Escape" && isOpen) {
10359
10440
  onClose();
@@ -10447,11 +10528,11 @@ var ChalkLeaveDialog = React54.memo(({ isOpen, onClose, onConfirm, onEndEpisode,
10447
10528
  const prefersReducedMotion = usePrefersReducedMotion2();
10448
10529
  const portalTheme = resolvePortalThemeFromDocument();
10449
10530
  const modalRef = useRef27(null);
10450
- const [confirmingEndEpisode, setConfirmingEndEpisode] = useState42(false);
10451
- useEffect39(() => {
10531
+ const [confirmingEndEpisode, setConfirmingEndEpisode] = useState43(false);
10532
+ useEffect40(() => {
10452
10533
  if (!isOpen) setConfirmingEndEpisode(false);
10453
10534
  }, [isOpen]);
10454
- useEffect39(() => {
10535
+ useEffect40(() => {
10455
10536
  const handleEscape = (e) => {
10456
10537
  if (e.key === "Escape" && isOpen) {
10457
10538
  onClose();
@@ -10725,10 +10806,10 @@ var SpaceHeader = React59.memo((props) => {
10725
10806
  SpaceHeader.displayName = "SpaceHeader";
10726
10807
 
10727
10808
  // src/components/space-info-dialog/SpaceInfoDialog.tsx
10728
- import React61, { useState as useState44 } from "react";
10809
+ import React61, { useState as useState45 } from "react";
10729
10810
 
10730
10811
  // src/components/space-info-dialog/ClassicSpaceInfoDialog.tsx
10731
- import React60, { useState as useState43 } from "react";
10812
+ import React60, { useState as useState44 } from "react";
10732
10813
  import { jsx as jsx98, jsxs as jsxs85 } from "react/jsx-runtime";
10733
10814
  var formatDuration4 = (seconds) => {
10734
10815
  const hours = Math.floor(seconds / 3600);
@@ -10739,7 +10820,7 @@ var formatDuration4 = (seconds) => {
10739
10820
  var ClassicSpaceInfoDialog = React60.memo(
10740
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 }) => {
10741
10822
  const skin = useSkin();
10742
- const [copied, setCopied] = useState43(false);
10823
+ const [copied, setCopied] = useState44(false);
10743
10824
  const handleCopy = () => {
10744
10825
  onCopyLink();
10745
10826
  setCopied(true);
@@ -10840,7 +10921,7 @@ var formatDuration5 = (seconds) => {
10840
10921
  };
10841
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 }) => {
10842
10923
  const skin = useSkin();
10843
- const [copied, setCopied] = useState44(false);
10924
+ const [copied, setCopied] = useState45(false);
10844
10925
  const handleCopy = () => {
10845
10926
  onCopyLink();
10846
10927
  setCopied(true);
@@ -10925,10 +11006,10 @@ var SpaceInfoDialog = React61.memo((props) => {
10925
11006
  SpaceInfoDialog.displayName = "SpaceInfoDialog";
10926
11007
 
10927
11008
  // src/components/transcript-panel/TranscriptPanel.tsx
10928
- 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";
10929
11010
 
10930
11011
  // src/components/transcript-panel/ClassicTranscriptPanel.tsx
10931
- 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";
10932
11013
  import { IconButton as IconButton7, Input as Input4 } from "@q9labsai/chalk-ui";
10933
11014
  import { Fragment as Fragment20, jsx as jsx100, jsxs as jsxs87 } from "react/jsx-runtime";
10934
11015
  function groupTranscriptsBySpeaker(transcripts) {
@@ -10961,9 +11042,9 @@ function findSearchMatches(transcripts, query) {
10961
11042
  return matches;
10962
11043
  }
10963
11044
  function ExportDropdown({ onExport, onCopyAll }) {
10964
- const [isOpen, setIsOpen] = useState45(false);
11045
+ const [isOpen, setIsOpen] = useState46(false);
10965
11046
  const dropdownRef = useRef30(null);
10966
- useEffect40(() => {
11047
+ useEffect41(() => {
10967
11048
  function handleClickOutside(event) {
10968
11049
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
10969
11050
  setIsOpen(false);
@@ -11060,9 +11141,9 @@ var TranscriptPanelSurface = React62.memo(
11060
11141
  className
11061
11142
  }) => {
11062
11143
  const prefersReducedMotion = usePrefersReducedMotion2();
11063
- const [searchQuery, setSearchQuery] = useState45("");
11064
- const [currentMatchIndex, setCurrentMatchIndex] = useState45(0);
11065
- const [autoScroll, setAutoScroll] = useState45(true);
11144
+ const [searchQuery, setSearchQuery] = useState46("");
11145
+ const [currentMatchIndex, setCurrentMatchIndex] = useState46(0);
11146
+ const [autoScroll, setAutoScroll] = useState46(true);
11066
11147
  const containerRef = useRef30(null);
11067
11148
  const endRef = useRef30(null);
11068
11149
  const searchInputRef = useRef30(null);
@@ -11089,18 +11170,18 @@ var TranscriptPanelSurface = React62.memo(
11089
11170
  entries: group.entries.filter((e) => matchedIds.has(e.id))
11090
11171
  })).filter((group) => group.entries.length > 0);
11091
11172
  }, [groupedTranscripts, searchQuery, searchMatches]);
11092
- useEffect40(() => {
11173
+ useEffect41(() => {
11093
11174
  if (autoScroll && endRef.current && !searchQuery) {
11094
11175
  endRef.current.scrollIntoView({ behavior: prefersReducedMotion ? "auto" : "smooth" });
11095
11176
  }
11096
11177
  }, [transcripts, autoScroll, prefersReducedMotion, searchQuery]);
11097
- useEffect40(() => {
11178
+ useEffect41(() => {
11098
11179
  if (currentMatch && containerRef.current) {
11099
11180
  const matchElement = containerRef.current.querySelector(`[data-transcript-match="true"]`);
11100
11181
  matchElement?.scrollIntoView({ behavior: "smooth", block: "center" });
11101
11182
  }
11102
11183
  }, [currentMatch, currentMatchIndex]);
11103
- useEffect40(() => {
11184
+ useEffect41(() => {
11104
11185
  function handleKeyDown(event) {
11105
11186
  if ((event.metaKey || event.ctrlKey) && event.key === "f" && searchable) {
11106
11187
  event.preventDefault();
@@ -11361,9 +11442,9 @@ function findSearchMatches2(transcripts, query) {
11361
11442
  return matches;
11362
11443
  }
11363
11444
  function ExportDropdown2({ onExport, onCopyAll }) {
11364
- const [isOpen, setIsOpen] = useState46(false);
11445
+ const [isOpen, setIsOpen] = useState47(false);
11365
11446
  const dropdownRef = useRef31(null);
11366
- useEffect41(() => {
11447
+ useEffect42(() => {
11367
11448
  function handleClickOutside(event) {
11368
11449
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
11369
11450
  setIsOpen(false);
@@ -11455,9 +11536,9 @@ var TranscriptPanelSurface2 = React63.memo(
11455
11536
  className
11456
11537
  }) => {
11457
11538
  const prefersReducedMotion = usePrefersReducedMotion2();
11458
- const [searchQuery, setSearchQuery] = useState46("");
11459
- const [currentMatchIndex, setCurrentMatchIndex] = useState46(0);
11460
- const [autoScroll, setAutoScroll] = useState46(true);
11539
+ const [searchQuery, setSearchQuery] = useState47("");
11540
+ const [currentMatchIndex, setCurrentMatchIndex] = useState47(0);
11541
+ const [autoScroll, setAutoScroll] = useState47(true);
11461
11542
  const containerRef = useRef31(null);
11462
11543
  const endRef = useRef31(null);
11463
11544
  const searchInputRef = useRef31(null);
@@ -11484,18 +11565,18 @@ var TranscriptPanelSurface2 = React63.memo(
11484
11565
  entries: group.entries.filter((e) => matchedIds.has(e.id))
11485
11566
  })).filter((group) => group.entries.length > 0);
11486
11567
  }, [groupedTranscripts, searchQuery, searchMatches]);
11487
- useEffect41(() => {
11568
+ useEffect42(() => {
11488
11569
  if (autoScroll && endRef.current && !searchQuery) {
11489
11570
  endRef.current.scrollIntoView({ behavior: prefersReducedMotion ? "auto" : "smooth" });
11490
11571
  }
11491
11572
  }, [transcripts, autoScroll, prefersReducedMotion, searchQuery]);
11492
- useEffect41(() => {
11573
+ useEffect42(() => {
11493
11574
  if (currentMatch && containerRef.current) {
11494
11575
  const matchElement = containerRef.current.querySelector(`[data-transcript-match="true"]`);
11495
11576
  matchElement?.scrollIntoView({ behavior: "smooth", block: "center" });
11496
11577
  }
11497
11578
  }, [currentMatch, currentMatchIndex]);
11498
- useEffect41(() => {
11579
+ useEffect42(() => {
11499
11580
  function handleKeyDown(event) {
11500
11581
  if ((event.metaKey || event.ctrlKey) && event.key === "f" && searchable) {
11501
11582
  event.preventDefault();
@@ -11718,23 +11799,23 @@ var TranscriptPanel = React63.memo((props) => {
11718
11799
  TranscriptPanel.displayName = "TranscriptPanel";
11719
11800
 
11720
11801
  // src/components/space-view/ClassicSpaceView.tsx
11721
- 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";
11722
11803
 
11723
11804
  // src/components/space-view/SpaceDrawer.tsx
11724
- import { useEffect as useEffect42, useRef as useRef32 } from "react";
11805
+ import { useEffect as useEffect43, useRef as useRef32 } from "react";
11725
11806
  import { Fragment as Fragment22, jsx as jsx102, jsxs as jsxs89 } from "react/jsx-runtime";
11726
11807
  function SpaceDrawer({ state, onClose, children }) {
11727
11808
  const skin = useSkin();
11728
11809
  const drawerRef = useRef32(null);
11729
11810
  const openerRef = useRef32(null);
11730
- useEffect42(() => {
11811
+ useEffect43(() => {
11731
11812
  if (state !== "open") return;
11732
11813
  const drawer = drawerRef.current;
11733
11814
  if (!drawer || drawer.contains(document.activeElement)) return;
11734
11815
  openerRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
11735
11816
  drawer.focus({ preventScroll: true });
11736
11817
  }, [state]);
11737
- useEffect42(() => {
11818
+ useEffect43(() => {
11738
11819
  if (state !== "closing") return;
11739
11820
  const opener = openerRef.current;
11740
11821
  openerRef.current = null;
@@ -11810,12 +11891,12 @@ function SpaceStage({ tiles, layout, whiteboard, className }) {
11810
11891
  SpaceStage.displayName = "SpaceStage";
11811
11892
 
11812
11893
  // src/components/space-view/useDrawerPresence.ts
11813
- import { useEffect as useEffect43, useState as useState47 } from "react";
11894
+ import { useEffect as useEffect44, useState as useState48 } from "react";
11814
11895
  var DRAWER_EXIT_MS = 200;
11815
11896
  function useDrawerPresence(panel, exitMs) {
11816
- const [retained, setRetained] = useState47(panel);
11817
- const [state, setState] = useState47(panel === null ? "closed" : "open");
11818
- useEffect43(() => {
11897
+ const [retained, setRetained] = useState48(panel);
11898
+ const [state, setState] = useState48(panel === null ? "closed" : "open");
11899
+ useEffect44(() => {
11819
11900
  if (panel !== null) {
11820
11901
  setRetained(panel);
11821
11902
  setState("open");
@@ -11832,10 +11913,10 @@ function useDrawerPresence(panel, exitMs) {
11832
11913
  }
11833
11914
 
11834
11915
  // src/components/space-view/useContentLayoutSwitch.ts
11835
- import { useEffect as useEffect44, useRef as useRef33 } from "react";
11916
+ import { useEffect as useEffect45, useRef as useRef33 } from "react";
11836
11917
  function useContentLayoutSwitch(hasContent, layout, updateLayout) {
11837
11918
  const memoryRef = useRef33({ hasContent: false, layoutBefore: null });
11838
- useEffect44(() => {
11919
+ useEffect45(() => {
11839
11920
  const memory = memoryRef.current;
11840
11921
  if (hasContent === memory.hasContent) return;
11841
11922
  if (hasContent) {
@@ -11884,17 +11965,17 @@ function ClassicSpaceView({
11884
11965
  const canSendReaction = useCan("sendReaction");
11885
11966
  const canDrawWhiteboard = useCan("drawWhiteboard");
11886
11967
  const canManageAdmission = useCan("manageAdmission");
11887
- const [uncontrolledLayout, setUncontrolledLayout] = useState48("focus");
11888
- const [activePanel, setActivePanel] = useState48(initialPanel);
11889
- const [isReactionPickerOpen, setReactionPickerOpen] = useState48(false);
11890
- const [isLeaveDialogOpen, setLeaveDialogOpen] = useState48(false);
11891
- 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);
11892
11973
  const layout = controlledLayout ?? uncontrolledLayout;
11893
11974
  const feature = (name) => features?.[name] !== false;
11894
11975
  const localId = self.participantId ?? "local";
11895
11976
  const tiles = useMemo36(() => toVideoParticipants(participantsSlice.roster, media.remote, localId, self.displayName ?? "You", media.local), [localId, media.local, media.remote, participantsSlice.roster, self.displayName]);
11896
- useEffect45(() => setActivePanel(initialPanel), [initialPanel]);
11897
- useEffect45(() => {
11977
+ useEffect46(() => setActivePanel(initialPanel), [initialPanel]);
11978
+ useEffect46(() => {
11898
11979
  if (feature("admission") && canManageAdmission && participantsSlice.admissionQueue.length > 0) setActivePanel("admission");
11899
11980
  }, [canManageAdmission, participantsSlice.admissionQueue.length, features?.admission]);
11900
11981
  const buttons = [
@@ -11934,7 +12015,7 @@ function ClassicSpaceView({
11934
12015
  setActivePanel(null);
11935
12016
  }
11936
12017
  }) : settingsDialog;
11937
- useEffect45(() => {
12018
+ useEffect46(() => {
11938
12019
  if (activePanel !== "settings" || !React65.isValidElement(settingsDialog) || settingsDialog.props.isOpen !== false) return;
11939
12020
  setActivePanel(null);
11940
12021
  }, [activePanel, settingsDialog]);
@@ -12107,17 +12188,17 @@ function ChalkSpaceView({
12107
12188
  const canSendReaction = useCan("sendReaction");
12108
12189
  const canDrawWhiteboard = useCan("drawWhiteboard");
12109
12190
  const canManageAdmission = useCan("manageAdmission");
12110
- const [uncontrolledLayout, setUncontrolledLayout] = useState49("focus");
12111
- const [activePanel, setActivePanel] = useState49(initialPanel);
12112
- const [isReactionPickerOpen, setReactionPickerOpen] = useState49(false);
12113
- const [isLeaveDialogOpen, setLeaveDialogOpen] = useState49(false);
12114
- 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);
12115
12196
  const layout = controlledLayout ?? uncontrolledLayout;
12116
12197
  const feature = (name) => features?.[name] !== false;
12117
12198
  const localId = self.participantId ?? "local";
12118
12199
  const tiles = useMemo37(() => toVideoParticipants(participantsSlice.roster, media.remote, localId, self.displayName ?? "You", media.local), [localId, media.local, media.remote, participantsSlice.roster, self.displayName]);
12119
- useEffect46(() => setActivePanel(initialPanel), [initialPanel]);
12120
- useEffect46(() => {
12200
+ useEffect47(() => setActivePanel(initialPanel), [initialPanel]);
12201
+ useEffect47(() => {
12121
12202
  if (feature("admission") && canManageAdmission && participantsSlice.admissionQueue.length > 0) setActivePanel("admission");
12122
12203
  }, [canManageAdmission, participantsSlice.admissionQueue.length, features?.admission]);
12123
12204
  const buttons = [
@@ -12157,7 +12238,7 @@ function ChalkSpaceView({
12157
12238
  setActivePanel(null);
12158
12239
  }
12159
12240
  }) : settingsDialog;
12160
- useEffect46(() => {
12241
+ useEffect47(() => {
12161
12242
  if (activePanel !== "settings" || !React66.isValidElement(settingsDialog) || settingsDialog.props.isOpen !== false) return;
12162
12243
  setActivePanel(null);
12163
12244
  }, [activePanel, settingsDialog]);
@@ -12306,7 +12387,7 @@ function Chalk(props) {
12306
12387
  return createSpaceClient({ space: props.space, getAccess: getLatestAccess });
12307
12388
  }, [getLatestAccess, props.space, suppliedClient]);
12308
12389
  const client = suppliedClient ?? ownedClient;
12309
- useEffect47(() => {
12390
+ useEffect48(() => {
12310
12391
  if (!ownedClient) return;
12311
12392
  return () => {
12312
12393
  void ownedClient.leave().catch(() => void 0).finally(() => ownedClient.dispose());
@@ -12322,7 +12403,7 @@ function SpaceExperience(props) {
12322
12403
  const hasBeenLive = useRef34(connection.status === "live" || connection.status === "reconnecting");
12323
12404
  const autoJoinAttempted = useRef34(false);
12324
12405
  const previousClient = useRef34(client);
12325
- const [joinError, setJoinError] = useState50(null);
12406
+ const [joinError, setJoinError] = useState51(null);
12326
12407
  const entrance = props.entrance ?? true;
12327
12408
  const spaceName = props.spaceName ?? props.space ?? "Space";
12328
12409
  if (previousClient.current !== client) {
@@ -12348,13 +12429,13 @@ function SpaceExperience(props) {
12348
12429
  autoJoinAttempted.current = true;
12349
12430
  void join(defaultJoinOptions(props));
12350
12431
  }, [join, props]);
12351
- useEffect47(() => setJoinError(null), [client]);
12352
- useEffect47(() => {
12432
+ useEffect48(() => setJoinError(null), [client]);
12433
+ useEffect48(() => {
12353
12434
  if (entrance || connection.status !== "idle" || autoJoinAttempted.current) return;
12354
12435
  autoJoinAttempted.current = true;
12355
12436
  void join(defaultJoinOptions(props));
12356
12437
  }, [connection.status, entrance, join, props.defaults?.camera, props.defaults?.microphone, props.displayName]);
12357
- useEffect47(() => {
12438
+ useEffect48(() => {
12358
12439
  const previous = previousStatus.current;
12359
12440
  if (hasObservedStatus.current) {
12360
12441
  if (connection.status === "live" && previous !== "live" && previous !== "reconnecting") props.onJoined?.();
@@ -12384,19 +12465,19 @@ function SpaceSurface(props) {
12384
12465
  const media = useMedia();
12385
12466
  const canEndEpisode = useCan("endEpisode");
12386
12467
  const canDrawWhiteboard = useCan("drawWhiteboard");
12387
- const [settingsOpen, setSettingsOpen] = useState50(false);
12388
- const [settingsInitialSection, setSettingsInitialSection] = useState50();
12389
- const [infoOpen, setInfoOpen] = useState50(false);
12390
- const [whiteboardOpen, setWhiteboardOpen] = useState50(false);
12391
- const [commandError, setCommandError] = useState50(null);
12392
- 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"));
12468
+ const [settingsOpen, setSettingsOpen] = useState51(false);
12469
+ const [settingsInitialSection, setSettingsInitialSection] = useState51();
12470
+ const [infoOpen, setInfoOpen] = useState51(false);
12471
+ const [whiteboardOpen, setWhiteboardOpen] = 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"));
12393
12474
  const resolvedSkin = props.theme?.skin ?? "classic";
12394
12475
  const resolvedPalette = props.theme?.palette ?? (props.resolvedColorScheme === "dark" ? "warm-charcoal" : "light");
12395
12476
  const resolvedTexture = props.theme?.texture ?? "none";
12396
12477
  const appearancePaletteExplicitRef = useRef34(props.theme?.palette !== void 0);
12397
12478
  const settingsRef = useRef34(settings);
12398
12479
  settingsRef.current = settings;
12399
- useEffect47(() => {
12480
+ useEffect48(() => {
12400
12481
  setSettings((current) => ({
12401
12482
  ...current,
12402
12483
  identity: { displayName: self.displayName ?? current.identity.displayName },
@@ -12405,7 +12486,7 @@ function SpaceSurface(props) {
12405
12486
  video: { ...current.video, selectedInput: media.selection.camera ?? void 0 }
12406
12487
  }));
12407
12488
  }, [media.local.camera.state, media.local.microphone.state, media.selection.camera, media.selection.microphone, media.selection.speaker, self.displayName]);
12408
- useEffect47(() => {
12489
+ useEffect48(() => {
12409
12490
  if (!props.theme?.skin && !props.theme?.palette && !props.theme?.texture) return;
12410
12491
  setSettings((current) => ({
12411
12492
  ...current,
@@ -12418,7 +12499,7 @@ function SpaceSurface(props) {
12418
12499
  }
12419
12500
  }));
12420
12501
  }, [props.theme?.palette, props.theme?.skin, props.theme?.texture]);
12421
- useEffect47(() => {
12502
+ useEffect48(() => {
12422
12503
  if (props.theme?.palette || appearancePaletteExplicitRef.current) return;
12423
12504
  const palette = props.resolvedColorScheme === "dark" ? "warm-charcoal" : "light";
12424
12505
  setSettings((current) => current.appearance.palette === palette ? current : { ...current, appearance: { ...current.appearance, palette, theme: palette === "light" ? "light" : "dark" } });
@@ -12432,20 +12513,27 @@ function SpaceSurface(props) {
12432
12513
  }
12433
12514
  }, []);
12434
12515
  const whiteboardTransport = client.whiteboard.transport();
12435
- const whiteboard = props.features?.whiteboard !== false && whiteboardOpen && canDrawWhiteboard && whiteboardTransport ? {
12516
+ const whiteboardEnabled = props.features?.whiteboard !== false && whiteboardOpen && canDrawWhiteboard;
12517
+ const whiteboardSubscription = useWhiteboardSceneSubscription(whiteboardTransport, whiteboardEnabled);
12518
+ useEffect48(() => {
12519
+ if (whiteboardSubscription.status === "failed") setCommandError(whiteboardSubscription.error.message);
12520
+ else if (whiteboardSubscription.status === "loading" || whiteboardSubscription.status === "ready") setCommandError(null);
12521
+ }, [whiteboardSubscription]);
12522
+ const whiteboard = whiteboardEnabled && whiteboardSubscription.status === "ready" ? {
12436
12523
  isOpen: true,
12437
12524
  props: {
12438
12525
  canDraw: canDrawWhiteboard,
12439
12526
  collab: {
12440
12527
  canDraw: canDrawWhiteboard,
12441
- subscribe: (listener) => whiteboardTransport.subscribe((event) => listener(toWhiteboardCollaborationEvent(event))),
12442
- submitUpdate: async (input) => whiteboardTransport.submitUpdate({ sceneId: input.sceneId, syncAll: input.syncAll, elements: input.elements.map(fromWhiteboardWireElement) }),
12443
- sendCursor: (input) => whiteboardTransport.sendCursor(input),
12444
- requestSnapshot: () => whiteboardTransport.requestSnapshot(),
12445
- clear: () => whiteboardTransport.clear(),
12446
- initiateUpload: (input) => whiteboardTransport.files.initiateUpload(input),
12447
- finalizeUpload: (uploadId) => whiteboardTransport.files.finalizeUpload(uploadId),
12448
- presignDownload: (fileId) => whiteboardTransport.files.getDownloadUrl(fileId)
12528
+ subscribe: (listener) => whiteboardSubscription.transport.subscribe((event) => listener(toWhiteboardCollaborationEvent(event))),
12529
+ submitUpdate: async (input) => whiteboardSubscription.transport.submitUpdate({ sceneId: input.sceneId, syncAll: input.syncAll, elements: input.elements.map(fromWhiteboardWireElement) }),
12530
+ sendCursor: (input) => whiteboardSubscription.transport.sendCursor(input),
12531
+ requestSnapshot: () => whiteboardSubscription.transport.requestSnapshot(),
12532
+ onSubmissionError: (cause) => setCommandError(cause instanceof Error ? cause.message : "Whiteboard could not sync."),
12533
+ clear: () => whiteboardSubscription.transport.clear(),
12534
+ initiateUpload: (input) => whiteboardSubscription.transport.files.initiateUpload(input),
12535
+ finalizeUpload: (uploadId) => whiteboardSubscription.transport.files.finalizeUpload(uploadId),
12536
+ presignDownload: (fileId) => whiteboardSubscription.transport.files.getDownloadUrl(fileId)
12449
12537
  }
12450
12538
  }
12451
12539
  } : void 0;
@@ -12541,8 +12629,8 @@ function defaultJoinOptions(props) {
12541
12629
  return { ...displayName ? { displayName } : {}, microphone: props.defaults?.microphone ?? true, camera: props.defaults?.camera ?? true };
12542
12630
  }
12543
12631
  function useResolvedColorScheme(requested = "light") {
12544
- const [resolved, setResolved] = useState50(() => requested === "system" ? readSystemColorScheme() : requested);
12545
- useEffect47(() => {
12632
+ const [resolved, setResolved] = useState51(() => requested === "system" ? readSystemColorScheme() : requested);
12633
+ useEffect48(() => {
12546
12634
  if (requested !== "system") return void setResolved(requested);
12547
12635
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void setResolved("light");
12548
12636
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
@@ -12557,12 +12645,12 @@ function readSystemColorScheme() {
12557
12645
  return typeof window !== "undefined" && window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
12558
12646
  }
12559
12647
  function useClientEvents(client, callbacks) {
12560
- useEffect47(() => client.on("participantJoined", (event) => callbacks.onParticipantJoined?.(event)), [callbacks.onParticipantJoined, client]);
12561
- useEffect47(() => client.on("participantLeft", (event) => callbacks.onParticipantLeft?.(event)), [callbacks.onParticipantLeft, client]);
12562
- useEffect47(() => client.on("episodeEnded", (event) => callbacks.onEpisodeEnded?.(event)), [callbacks.onEpisodeEnded, client]);
12563
- useEffect47(() => client.on("screenShareStarted", (event) => callbacks.onScreenShareStarted?.(event)), [callbacks.onScreenShareStarted, client]);
12564
- useEffect47(() => client.on("screenShareStopped", (event) => callbacks.onScreenShareStopped?.(event)), [callbacks.onScreenShareStopped, client]);
12565
- useEffect47(() => client.on("error", (event) => callbacks.onError?.(event)), [callbacks.onError, client]);
12648
+ useEffect48(() => client.on("participantJoined", (event) => callbacks.onParticipantJoined?.(event)), [callbacks.onParticipantJoined, client]);
12649
+ useEffect48(() => client.on("participantLeft", (event) => callbacks.onParticipantLeft?.(event)), [callbacks.onParticipantLeft, client]);
12650
+ useEffect48(() => client.on("episodeEnded", (event) => callbacks.onEpisodeEnded?.(event)), [callbacks.onEpisodeEnded, client]);
12651
+ useEffect48(() => client.on("screenShareStarted", (event) => callbacks.onScreenShareStarted?.(event)), [callbacks.onScreenShareStarted, client]);
12652
+ useEffect48(() => client.on("screenShareStopped", (event) => callbacks.onScreenShareStopped?.(event)), [callbacks.onScreenShareStopped, client]);
12653
+ useEffect48(() => client.on("error", (event) => callbacks.onError?.(event)), [callbacks.onError, client]);
12566
12654
  }
12567
12655
  function createSettings(displayName, layout, skin, palette, texture) {
12568
12656
  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-FTWI75A2.js";
38
+ } from "../chunk-DDIM65MJ.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-FTWI75A2.js";
38
+ } from "./chunk-DDIM65MJ.js";
39
39
  import "./chunk-ZEZLA34O.js";
40
40
  export {
41
41
  COSMIC_CHALK_THEME,
@@ -15,14 +15,18 @@ export interface SoundPlayer {
15
15
  readonly play: (cue: SoundCue) => void;
16
16
  readonly dispose: () => void;
17
17
  }
18
+ type SoundUnlockTarget = Pick<EventTarget, "addEventListener" | "removeEventListener">;
18
19
  /** Picks the Opus file when the browser can decode it, otherwise the MP3. */
19
20
  export declare function soundSourceFor(cue: SoundCue, canPlay: (mimeType: string) => boolean): string;
20
21
  /**
21
22
  * Lazily creates one `HTMLAudioElement` per cue and replays it from the start. Playback failures
22
23
  * (autoplay policy before the first gesture, network) are reported through `onError` and never thrown.
23
24
  */
24
- export declare function createSoundPlayer({ volume, onError }?: {
25
+ export declare function createSoundPlayer({ volume, outputDeviceId, onError, unlockTarget }?: {
25
26
  volume?: number;
27
+ outputDeviceId?: string;
26
28
  onError?: (cue: SoundCue, cause: unknown) => void;
29
+ unlockTarget?: SoundUnlockTarget | null;
27
30
  }): SoundPlayer;
31
+ export {};
28
32
  //# sourceMappingURL=sound-cues.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sound-cues.d.ts","sourceRoot":"","sources":["../../src/internal/sound-cues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,kBAAkB,CAAC;AAEvD,qFAAqF;AACrF,eAAO,MAAM,mBAAmB,iEAAgG,CAAC;AAEjI,8GAA8G;AAC9G,eAAO,MAAM,eAAe,MAAM,CAAC;AAMnC;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,GAAG,SAAS,QAAQ,EAAE,CA2B/F;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,CAG5F;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,MAAY,EAAE,OAAO,EAAE,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAAO,GAAG,WAAW,CA8BrJ"}
1
+ {"version":3,"file":"sound-cues.d.ts","sourceRoot":"","sources":["../../src/internal/sound-cues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,kBAAkB,CAAC;AAEvD,qFAAqF;AACrF,eAAO,MAAM,mBAAmB,iEAAgG,CAAC;AAEjI,8GAA8G;AAC9G,eAAO,MAAM,eAAe,MAAM,CAAC;AAMnC;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,GAAG,SAAS,QAAQ,EAAE,CA2B/F;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AASD,KAAK,iBAAiB,GAAG,IAAI,CAAC,WAAW,EAAE,kBAAkB,GAAG,qBAAqB,CAAC,CAAC;AAUvF,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,CAG5F;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,MAAY,EAAE,cAAc,EAAE,OAAO,EAAE,YAA4D,EAAE,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAAC,YAAY,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAAO,GAAG,WAAW,CAgFrS"}
@@ -1,7 +1,9 @@
1
1
  import { type SoundPlayer } from "./sound-cues";
2
2
  /**
3
3
  * Plays the join / leave / message / hand-raise / reaction cues for snapshot changes on the
4
- * current client while `enabled`. Autoplay refusals before the first user gesture are ignored.
4
+ * current client while `enabled`. Autoplay refusals are retried after the next user gesture.
5
5
  */
6
- export declare function useSoundCues(enabled: boolean, createPlayer?: () => SoundPlayer): void;
6
+ export declare function useSoundCues(enabled: boolean, createPlayer?: (options: {
7
+ readonly outputDeviceId?: string;
8
+ }) => SoundPlayer): void;
7
9
  //# sourceMappingURL=useSoundCues.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSoundCues.d.ts","sourceRoot":"","sources":["../../src/internal/useSoundCues.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoC,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAElF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,GAAE,MAAM,WAAuC,GAAG,IAAI,CAmBhH"}
1
+ {"version":3,"file":"useSoundCues.d.ts","sourceRoot":"","sources":["../../src/internal/useSoundCues.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoC,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAElF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,GAAE,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,WAA+B,GAAG,IAAI,CAoBrJ"}
@@ -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.2",
3
+ "version": "4.1.4",
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.2",
65
- "@q9labsai/chalk-ui": "^4.1.2",
66
- "@q9labsai/chalk-whiteboard": "^4.1.2",
67
- "@q9labsai/facehash": "^4.1.2",
64
+ "@q9labsai/chalk-client": "^4.1.4",
65
+ "@q9labsai/chalk-ui": "^4.1.4",
66
+ "@q9labsai/chalk-whiteboard": "^4.1.4",
67
+ "@q9labsai/facehash": "^4.1.4",
68
68
  "class-variance-authority": "^0.7.1",
69
69
  "clsx": "^2.1.1",
70
70
  "sonner": "^2.0.8",