@q9labsai/chalk-react-native 4.1.15 → 4.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +11 -0
  2. package/dist/android.js +5 -2
  3. package/dist/{chunk-MK6OO4V7.js → chunk-2OS7SSXE.js} +6 -1
  4. package/dist/{chunk-4NLA35HE.js → chunk-ITLUHTVS.js} +1126 -644
  5. package/dist/client.js +1 -1
  6. package/dist/components/Chalk.d.ts +2 -1
  7. package/dist/components/Chalk.d.ts.map +1 -1
  8. package/dist/components/EmbeddedWhiteboard.d.ts.map +1 -1
  9. package/dist/components/SpaceView.d.ts +2 -1
  10. package/dist/components/SpaceView.d.ts.map +1 -1
  11. package/dist/components/SpaceView.shared.d.ts.map +1 -1
  12. package/dist/components/native-space-view/FeedbackSheet.d.ts +12 -0
  13. package/dist/components/native-space-view/FeedbackSheet.d.ts.map +1 -0
  14. package/dist/components/native-space-view/SpaceActionMenu.d.ts +2 -1
  15. package/dist/components/native-space-view/SpaceActionMenu.d.ts.map +1 -1
  16. package/dist/components/native-space-view/SpaceChatAttachment.d.ts +8 -0
  17. package/dist/components/native-space-view/SpaceChatAttachment.d.ts.map +1 -0
  18. package/dist/components/native-space-view/SpaceChatSheet.d.ts.map +1 -1
  19. package/dist/components/native-space-view/SpaceMoreSheet.d.ts +2 -1
  20. package/dist/components/native-space-view/SpaceMoreSheet.d.ts.map +1 -1
  21. package/dist/components/native-space-view/SpaceTopBar.android.d.ts +3 -1
  22. package/dist/components/native-space-view/SpaceTopBar.android.d.ts.map +1 -1
  23. package/dist/components/native-space-view/screen-share-availability.d.ts +4 -1
  24. package/dist/components/native-space-view/screen-share-availability.d.ts.map +1 -1
  25. package/dist/components/native-space-view/space-chat-attachments.d.ts.map +1 -1
  26. package/dist/components/native-space-view/useSpaceViewController.d.ts +8 -2
  27. package/dist/components/native-space-view/useSpaceViewController.d.ts.map +1 -1
  28. package/dist/feedback/native-capture.d.ts +9 -0
  29. package/dist/feedback/native-capture.d.ts.map +1 -0
  30. package/dist/feedback/native-evidence.d.ts +3 -0
  31. package/dist/feedback/native-evidence.d.ts.map +1 -0
  32. package/dist/hooks/space-hooks.d.ts +1 -0
  33. package/dist/hooks/space-hooks.d.ts.map +1 -1
  34. package/dist/index.d.ts +1 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +5 -2
  37. package/dist/ios-pad.js +5 -2
  38. package/dist/ios-phone.js +5 -2
  39. package/dist/ios.js +5 -2
  40. package/dist/macos.js +5 -2
  41. package/dist/space-client/create-native-space-client.d.ts +2 -0
  42. package/dist/space-client/create-native-space-client.d.ts.map +1 -1
  43. package/dist/whiteboard/embedded-whiteboard-viewport.d.ts +3 -0
  44. package/dist/whiteboard/embedded-whiteboard-viewport.d.ts.map +1 -0
  45. package/embedded/chalk-whiteboard/asset-manifest.json +2 -2
  46. package/embedded/chalk-whiteboard/renderer.js +581 -581
  47. package/package.json +8 -6
  48. package/src/components/Chalk.tsx +6 -2
  49. package/src/components/EmbeddedWhiteboard.tsx +14 -5
  50. package/src/components/SpaceView.shared.tsx +58 -47
  51. package/src/components/SpaceView.tsx +2 -1
  52. package/src/components/native-space-view/FeedbackSheet.tsx +296 -0
  53. package/src/components/native-space-view/SpaceActionMenu.tsx +23 -3
  54. package/src/components/native-space-view/SpaceChatAttachment.tsx +105 -0
  55. package/src/components/native-space-view/SpaceChatSheet.tsx +14 -9
  56. package/src/components/native-space-view/SpaceMoreSheet.tsx +35 -6
  57. package/src/components/native-space-view/SpaceTopBar.android.tsx +16 -1
  58. package/src/components/native-space-view/screen-share-availability.test.ts +16 -0
  59. package/src/components/native-space-view/screen-share-availability.ts +4 -1
  60. package/src/components/native-space-view/space-chat-attachments.test.ts +26 -0
  61. package/src/components/native-space-view/space-chat-attachments.ts +2 -4
  62. package/src/components/native-space-view/useSpaceViewController.ts +28 -8
  63. package/src/feedback/native-capture.ts +62 -0
  64. package/src/feedback/native-evidence.ts +37 -0
  65. package/src/hooks/space-hooks.ts +4 -0
  66. package/src/index.ts +1 -1
  67. package/src/space-client/create-native-space-client.ts +7 -0
  68. package/src/whiteboard/embedded-whiteboard-viewport.test.ts +13 -0
  69. package/src/whiteboard/embedded-whiteboard-viewport.ts +6 -0
@@ -12,11 +12,14 @@ import {
12
12
  import {
13
13
  createNativeSpaceClient,
14
14
  getNativeJourneyContext
15
- } from "./chunk-MK6OO4V7.js";
15
+ } from "./chunk-2OS7SSXE.js";
16
+ import {
17
+ getDeviceInfo
18
+ } from "./chunk-F3NPRVHO.js";
16
19
 
17
20
  // src/components/Chalk.tsx
18
- import { useCallback as useCallback9, useEffect as useEffect9, useMemo as useMemo15, useRef as useRef6, useState as useState10 } from "react";
19
- import { Pressable as Pressable17, StyleSheet as StyleSheet25, Text as Text19, View as View24 } from "react-native";
21
+ import { useCallback as useCallback10, useEffect as useEffect11, useMemo as useMemo16, useRef as useRef7, useState as useState13 } from "react";
22
+ import { Pressable as Pressable19, StyleSheet as StyleSheet27, Text as Text21, View as View26 } from "react-native";
20
23
 
21
24
  // src/context/space-client-context.tsx
22
25
  import { createContext, useContext, useMemo } from "react";
@@ -58,6 +61,9 @@ function useChat() {
58
61
  function useReactions() {
59
62
  return useSpaceSlice("reactions");
60
63
  }
64
+ function useRecording() {
65
+ return useSpaceSlice("recording");
66
+ }
61
67
  function useWhiteboard() {
62
68
  return useSpaceSlice("whiteboard");
63
69
  }
@@ -189,7 +195,8 @@ function resolvePlatformVariant() {
189
195
  }
190
196
 
191
197
  // src/components/SpaceView.shared.tsx
192
- import { Alert as Alert3, StyleSheet as StyleSheet20, Text as Text14, View as View19 } from "react-native";
198
+ import { useRef as useRef5, useState as useState12 } from "react";
199
+ import { Alert as Alert3, StyleSheet as StyleSheet22, Text as Text16, View as View21 } from "react-native";
193
200
 
194
201
  // src/utils/ios-simulator.ts
195
202
  import { NativeModules, Platform as Platform2 } from "react-native";
@@ -927,7 +934,7 @@ var styles6 = StyleSheet7.create({
927
934
  // src/components/native-space-view/SpaceActionMenu.tsx
928
935
  import { Modal as Modal2, Pressable as Pressable3, StyleSheet as StyleSheet8, Text as Text4, View as View8 } from "react-native";
929
936
  import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
930
- function SpaceActionMenu({ controller, onOpenDiagnostics }) {
937
+ function SpaceActionMenu({ controller, onOpenDiagnostics, onOpenFeedback }) {
931
938
  const theme = useNativeTheme();
932
939
  const actions = [
933
940
  ...controller.canInvite ? [{ label: "Invite participants", onPress: controller.handleInviteParticipants }] : [],
@@ -945,6 +952,13 @@ function SpaceActionMenu({ controller, onOpenDiagnostics }) {
945
952
  }
946
953
  }
947
954
  ] : [],
955
+ ...controller.canManageRecording ? [
956
+ {
957
+ label: controller.recording?.status === "recording" ? "Stop recording" : "Start recording",
958
+ disabled: !controller.canToggleRecording,
959
+ onPress: controller.toggleRecording
960
+ }
961
+ ] : [],
948
962
  ...controller.canSettings ? [{ label: "Settings", onPress: () => controller.openPanel("settings") }] : [],
949
963
  ...onOpenDiagnostics ? [
950
964
  {
@@ -955,6 +969,15 @@ function SpaceActionMenu({ controller, onOpenDiagnostics }) {
955
969
  }
956
970
  }
957
971
  ] : [],
972
+ ...onOpenFeedback ? [
973
+ {
974
+ label: "Feedback",
975
+ onPress: () => {
976
+ controller.setActionsOpen(false);
977
+ onOpenFeedback();
978
+ }
979
+ }
980
+ ] : [],
958
981
  ...["grid", "focus", "presentation"].map((layout) => ({
959
982
  label: `${layout === "grid" ? "Grid" : layout === "focus" ? "Focus" : "Presentation"} layout${controller.layout.layout === layout ? " (selected)" : ""}`,
960
983
  onPress: () => {
@@ -965,7 +988,7 @@ function SpaceActionMenu({ controller, onOpenDiagnostics }) {
965
988
  ];
966
989
  return /* @__PURE__ */ jsx11(Modal2, { animationType: "slide", onRequestClose: () => controller.setActionsOpen(false), transparent: true, visible: controller.actionsOpen, children: /* @__PURE__ */ jsx11(Pressable3, { onPress: () => controller.setActionsOpen(false), style: styles7.backdrop, children: /* @__PURE__ */ jsxs6(View8, { style: [styles7.sheet, { backgroundColor: theme.colors.background }], children: [
967
990
  /* @__PURE__ */ jsx11(Text4, { style: [styles7.title, { color: theme.colors.foreground }], children: "Space actions" }),
968
- actions.map((action) => /* @__PURE__ */ jsx11(Pressable3, { onPress: action.onPress, style: ({ pressed }) => [styles7.action, { backgroundColor: theme.colors.card }, pressed && styles7.pressed], children: /* @__PURE__ */ jsx11(Text4, { style: [styles7.actionText, { color: theme.colors.foreground }], children: action.label }) }, action.label)),
991
+ actions.map((action) => /* @__PURE__ */ jsx11(Pressable3, { accessibilityRole: "button", accessibilityState: { disabled: action.disabled ?? false }, disabled: action.disabled, onPress: action.onPress, style: ({ pressed }) => [styles7.action, { backgroundColor: theme.colors.card }, pressed && styles7.pressed], children: /* @__PURE__ */ jsx11(Text4, { style: [styles7.actionText, { color: theme.colors.foreground }], children: action.label }) }, action.label)),
969
992
  /* @__PURE__ */ jsx11(Pressable3, { onPress: controller.handleLeave, style: [styles7.action, styles7.dangerAction, { backgroundColor: theme.colors.card, borderColor: theme.colors.error }], children: /* @__PURE__ */ jsx11(Text4, { style: [styles7.actionText, styles7.dangerText, { color: theme.colors.error }], children: "Leave space" }) })
970
993
  ] }) }) });
971
994
  }
@@ -990,62 +1013,376 @@ var styles7 = StyleSheet8.create({
990
1013
  pressed: { opacity: 0.65 }
991
1014
  });
992
1015
 
1016
+ // src/components/native-space-view/FeedbackSheet.tsx
1017
+ import { useCallback as useCallback4, useEffect as useEffect3, useMemo as useMemo8, useState as useState3 } from "react";
1018
+ import { Image as Image2, KeyboardAvoidingView, Modal as Modal3, Platform as Platform6, Pressable as Pressable4, ScrollView, StyleSheet as StyleSheet9, Text as Text5, TextInput, View as View9 } from "react-native";
1019
+
1020
+ // src/feedback/native-evidence.ts
1021
+ import { Platform as Platform4 } from "react-native";
1022
+ function createNativeFeedbackEvidence() {
1023
+ const device = getDeviceInfo({ scriptUrl: null });
1024
+ const kind = feedbackPlatformKind(Platform4.OS);
1025
+ const osName = boundedString(device.systemName ?? device.platform ?? kind);
1026
+ const osVersion = boundedString(device.osVersion);
1027
+ const deviceModel = boundedString(device.model);
1028
+ const reactNativeVersion = boundedString(device.reactNativeVersion);
1029
+ const deviceClass = kind === "macos" ? "desktop" : device.interfaceIdiom === "pad" ? "tablet" : "phone";
1030
+ return {
1031
+ sdk: { client: "@q9labsai/chalk-client", ...reactNativeVersion ? { react_native: reactNativeVersion } : {} },
1032
+ platform: {
1033
+ kind,
1034
+ ...osName ? { os_name: osName } : {},
1035
+ ...osVersion ? { os_version: osVersion } : {},
1036
+ device_class: deviceClass,
1037
+ ...deviceModel ? { device_model: deviceModel } : {}
1038
+ }
1039
+ };
1040
+ }
1041
+ function feedbackPlatformKind(platform) {
1042
+ if (platform === "ios") return "ios";
1043
+ if (platform === "macos") return "macos";
1044
+ return "android";
1045
+ }
1046
+ function boundedString(value) {
1047
+ const normalized = value?.trim();
1048
+ if (!normalized) return void 0;
1049
+ return normalized.slice(0, 64);
1050
+ }
1051
+
1052
+ // src/feedback/native-capture.ts
1053
+ import { Platform as Platform5 } from "react-native";
1054
+ import { captureRef } from "react-native-view-shot";
1055
+ var MAX_SCREENSHOT_BYTES = 450 * 1024;
1056
+ var MAX_SCREENSHOT_WIDTH = 1920;
1057
+ var MAX_SCREENSHOT_HEIGHT = 1080;
1058
+ async function captureNativeFeedbackView(target, size) {
1059
+ if (Platform5.OS === "macos") return { state: "unavailable", failure_code: "unsupported" };
1060
+ if (!target.current) return { state: "unavailable", failure_code: "capture_failed" };
1061
+ const outputSize = boundedOutputSize(size);
1062
+ if (!outputSize) return { state: "unavailable", failure_code: "capture_failed" };
1063
+ try {
1064
+ const captured = await captureRef(target, {
1065
+ format: "jpg",
1066
+ quality: 0.72,
1067
+ result: "base64",
1068
+ ...outputSize
1069
+ });
1070
+ const dataBase64 = normalizeBase64(captured);
1071
+ if (!dataBase64) return { state: "unavailable", failure_code: "capture_failed" };
1072
+ if (base64ByteLength(dataBase64) > MAX_SCREENSHOT_BYTES) return { state: "unavailable", failure_code: "too_large" };
1073
+ return {
1074
+ state: "captured",
1075
+ mime_type: "image/jpeg",
1076
+ width: outputSize.width,
1077
+ height: outputSize.height,
1078
+ captured_at: (/* @__PURE__ */ new Date()).toISOString(),
1079
+ data_base64: dataBase64
1080
+ };
1081
+ } catch {
1082
+ return { state: "unavailable", failure_code: "capture_failed" };
1083
+ }
1084
+ }
1085
+ function boundedOutputSize(size) {
1086
+ if (!Number.isFinite(size.width) || !Number.isFinite(size.height) || size.width <= 0 || size.height <= 0) return void 0;
1087
+ const scale = Math.min(1, MAX_SCREENSHOT_WIDTH / size.width, MAX_SCREENSHOT_HEIGHT / size.height);
1088
+ return {
1089
+ width: Math.max(1, Math.floor(size.width * scale)),
1090
+ height: Math.max(1, Math.floor(size.height * scale))
1091
+ };
1092
+ }
1093
+ function normalizeBase64(value) {
1094
+ return value.replace(/^data:[^;]+;base64,/u, "").replaceAll(/\s/gu, "");
1095
+ }
1096
+ function base64ByteLength(value) {
1097
+ const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
1098
+ return Math.floor(value.length * 3 / 4) - padding;
1099
+ }
1100
+
1101
+ // src/components/native-space-view/FeedbackSheet.tsx
1102
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1103
+ var categories = ["bug", "feature_request", "other"];
1104
+ function FeedbackSheet({ client, requested, captureTarget, captureSize, feedbackEvidence, onClose }) {
1105
+ const theme = useNativeTheme();
1106
+ const [visible, setVisible] = useState3(false);
1107
+ const [preparing, setPreparing] = useState3(false);
1108
+ const [sending, setSending] = useState3(false);
1109
+ const [category, setCategory] = useState3("bug");
1110
+ const [message, setMessage] = useState3("");
1111
+ const [screenshot, setScreenshot] = useState3({ state: "unavailable", failure_code: "capture_failed" });
1112
+ const [prepared, setPrepared] = useState3();
1113
+ const [error, setError] = useState3();
1114
+ const [receiptId, setReceiptId] = useState3();
1115
+ const evidence = useMemo8(() => ({ ...createNativeFeedbackEvidence(), ...feedbackEvidence }), [feedbackEvidence]);
1116
+ const prepareScreenshot = useCallback4((nextScreenshot) => client.feedback.prepare({ evidence, screenshot_provider: () => nextScreenshot }), [client.feedback, evidence]);
1117
+ useEffect3(() => {
1118
+ if (!requested) {
1119
+ setVisible(false);
1120
+ return;
1121
+ }
1122
+ let active = true;
1123
+ setPreparing(true);
1124
+ setSending(false);
1125
+ setCategory("bug");
1126
+ setMessage("");
1127
+ setError(void 0);
1128
+ setReceiptId(void 0);
1129
+ setPrepared(void 0);
1130
+ const prepare = async () => {
1131
+ let captured;
1132
+ try {
1133
+ captured = await captureNativeFeedbackView(captureTarget, captureSize);
1134
+ } catch {
1135
+ captured = { state: "unavailable", failure_code: "capture_failed" };
1136
+ }
1137
+ if (!active) return;
1138
+ setScreenshot(captured);
1139
+ try {
1140
+ const nextPrepared = await prepareScreenshot(captured);
1141
+ if (!active) return;
1142
+ setPrepared(nextPrepared);
1143
+ } catch (cause) {
1144
+ if (!active) return;
1145
+ setError(errorMessage(cause));
1146
+ } finally {
1147
+ if (active) {
1148
+ setPreparing(false);
1149
+ setVisible(true);
1150
+ }
1151
+ }
1152
+ };
1153
+ void prepare();
1154
+ return () => {
1155
+ active = false;
1156
+ };
1157
+ }, [captureSize, captureTarget, prepareScreenshot, requested]);
1158
+ const close = useCallback4(() => {
1159
+ setVisible(false);
1160
+ onClose();
1161
+ }, [onClose]);
1162
+ const refresh = useCallback4(async () => {
1163
+ if (preparing || sending) return;
1164
+ setPreparing(true);
1165
+ setPrepared(void 0);
1166
+ setError(void 0);
1167
+ let captured;
1168
+ try {
1169
+ captured = await captureNativeFeedbackView(captureTarget, captureSize);
1170
+ } catch {
1171
+ captured = { state: "unavailable", failure_code: "capture_failed" };
1172
+ }
1173
+ setScreenshot(captured);
1174
+ try {
1175
+ setPrepared(await prepareScreenshot(captured));
1176
+ } catch (cause) {
1177
+ setError(errorMessage(cause));
1178
+ } finally {
1179
+ setPreparing(false);
1180
+ }
1181
+ }, [captureSize, captureTarget, prepareScreenshot, preparing, sending]);
1182
+ const removeScreenshot = useCallback4(async () => {
1183
+ if (preparing || sending) return;
1184
+ const removed = { state: "removed" };
1185
+ setPreparing(true);
1186
+ setPrepared(void 0);
1187
+ setScreenshot(removed);
1188
+ setError(void 0);
1189
+ try {
1190
+ setPrepared(await prepareScreenshot(removed));
1191
+ } catch (cause) {
1192
+ setError(errorMessage(cause));
1193
+ } finally {
1194
+ setPreparing(false);
1195
+ }
1196
+ }, [prepareScreenshot, preparing, sending]);
1197
+ const submit = useCallback4(async () => {
1198
+ if (sending || !message.trim()) return;
1199
+ setSending(true);
1200
+ setError(void 0);
1201
+ try {
1202
+ const request = prepared ?? await prepareScreenshot(screenshot);
1203
+ setPrepared(request);
1204
+ const receipt = await request.send({ category, message });
1205
+ setReceiptId(receipt.id);
1206
+ } catch (cause) {
1207
+ setError(errorMessage(cause));
1208
+ } finally {
1209
+ setSending(false);
1210
+ }
1211
+ }, [category, message, prepareScreenshot, prepared, screenshot, sending]);
1212
+ const selectCategory = useCallback4((nextCategory) => {
1213
+ setCategory(nextCategory);
1214
+ setPrepared(void 0);
1215
+ }, []);
1216
+ const updateMessage = useCallback4((nextMessage) => {
1217
+ setMessage(nextMessage);
1218
+ setPrepared(void 0);
1219
+ }, []);
1220
+ const screenshotUri = screenshotDataUri(screenshot);
1221
+ const canSubmit = message.trim().length > 0 && !sending && !preparing && !receiptId;
1222
+ return /* @__PURE__ */ jsx12(Modal3, { animationType: "slide", onRequestClose: close, transparent: true, visible, children: /* @__PURE__ */ jsxs7(KeyboardAvoidingView, { behavior: Platform6.OS === "ios" ? "padding" : "height", style: styles8.overlay, children: [
1223
+ /* @__PURE__ */ jsx12(Pressable4, { accessibilityLabel: "Close Feedback", onPress: close, style: styles8.backdrop }),
1224
+ /* @__PURE__ */ jsxs7(View9, { style: [styles8.sheet, { backgroundColor: theme.colors.background }], children: [
1225
+ /* @__PURE__ */ jsxs7(View9, { style: styles8.header, children: [
1226
+ /* @__PURE__ */ jsxs7(View9, { style: styles8.headerCopy, children: [
1227
+ /* @__PURE__ */ jsx12(Text5, { accessibilityRole: "header", style: [styles8.title, { color: theme.colors.foreground }], children: "Feedback" }),
1228
+ /* @__PURE__ */ jsx12(Text5, { style: [styles8.subtitle, { color: theme.colors.mutedForeground }], children: "Tell Chalk what happened. We receive this report with safe diagnostic context." })
1229
+ ] }),
1230
+ /* @__PURE__ */ jsx12(Pressable4, { accessibilityLabel: "Close Feedback", accessibilityRole: "button", disabled: sending, onPress: close, style: styles8.closeButton, children: /* @__PURE__ */ jsx12(Text5, { style: [styles8.closeText, { color: theme.colors.foreground }], children: "\xD7" }) })
1231
+ ] }),
1232
+ receiptId ? /* @__PURE__ */ jsxs7(View9, { style: styles8.success, children: [
1233
+ /* @__PURE__ */ jsx12(Text5, { style: [styles8.successTitle, { color: theme.colors.foreground }], children: "Feedback sent to Chalk" }),
1234
+ /* @__PURE__ */ jsx12(Text5, { style: [styles8.subtitle, { color: theme.colors.mutedForeground }], children: "Thanks. Chalk received your report." }),
1235
+ /* @__PURE__ */ jsx12(Pressable4, { accessibilityRole: "button", onPress: close, style: [styles8.primaryButton, { backgroundColor: theme.colors.primary }], children: /* @__PURE__ */ jsx12(Text5, { style: [styles8.primaryButtonText, { color: theme.colors.primaryForeground }], children: "Done" }) })
1236
+ ] }) : /* @__PURE__ */ jsxs7(ScrollView, { contentContainerStyle: styles8.content, keyboardShouldPersistTaps: "handled", children: [
1237
+ /* @__PURE__ */ jsx12(Text5, { style: [styles8.label, { color: theme.colors.foreground }], children: "Category" }),
1238
+ /* @__PURE__ */ jsx12(View9, { style: styles8.categoryRow, children: categories.map((option) => /* @__PURE__ */ jsx12(
1239
+ Pressable4,
1240
+ {
1241
+ accessibilityRole: "button",
1242
+ accessibilityState: { selected: category === option },
1243
+ onPress: () => selectCategory(option),
1244
+ style: [styles8.categoryButton, { borderColor: theme.colors.border }, category === option && { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary }],
1245
+ children: /* @__PURE__ */ jsx12(Text5, { style: [styles8.categoryText, { color: category === option ? theme.colors.primaryForeground : theme.colors.foreground }], children: categoryLabel(option) })
1246
+ },
1247
+ option
1248
+ )) }),
1249
+ /* @__PURE__ */ jsx12(Text5, { style: [styles8.label, { color: theme.colors.foreground }], children: "Message" }),
1250
+ /* @__PURE__ */ jsx12(
1251
+ TextInput,
1252
+ {
1253
+ accessibilityLabel: "Feedback message",
1254
+ editable: !sending,
1255
+ maxLength: 8e3,
1256
+ multiline: true,
1257
+ onChangeText: updateMessage,
1258
+ placeholder: category === "bug" ? "What went wrong?" : category === "feature_request" ? "What would help?" : "What should Chalk know?",
1259
+ placeholderTextColor: theme.colors.placeholder,
1260
+ style: [styles8.messageInput, { borderColor: theme.colors.border, color: theme.colors.foreground }],
1261
+ textAlignVertical: "top",
1262
+ value: message
1263
+ }
1264
+ ),
1265
+ /* @__PURE__ */ jsx12(Text5, { style: [styles8.label, { color: theme.colors.foreground }], children: "Screenshot" }),
1266
+ screenshotUri ? /* @__PURE__ */ jsxs7(View9, { style: styles8.thumbnailFrame, children: [
1267
+ /* @__PURE__ */ jsx12(Image2, { accessibilityLabel: "Feedback screenshot preview", source: { uri: screenshotUri }, style: styles8.thumbnail }),
1268
+ /* @__PURE__ */ jsxs7(View9, { style: styles8.thumbnailActions, children: [
1269
+ /* @__PURE__ */ jsx12(Pressable4, { accessibilityRole: "button", disabled: preparing || sending, onPress: () => void refresh(), style: styles8.smallButton, children: /* @__PURE__ */ jsx12(Text5, { style: [styles8.smallButtonText, { color: theme.colors.primary }], children: "Refresh" }) }),
1270
+ /* @__PURE__ */ jsx12(Pressable4, { accessibilityRole: "button", disabled: preparing || sending, onPress: () => void removeScreenshot(), style: styles8.smallButton, children: /* @__PURE__ */ jsx12(Text5, { style: [styles8.smallButtonText, { color: theme.colors.error }], children: "Remove" }) })
1271
+ ] })
1272
+ ] }) : /* @__PURE__ */ jsxs7(View9, { style: [styles8.unavailable, { borderColor: theme.colors.border }], children: [
1273
+ /* @__PURE__ */ jsx12(Text5, { style: [styles8.unavailableText, { color: theme.colors.mutedForeground }], children: "Screenshot unavailable. You can still send Feedback." }),
1274
+ /* @__PURE__ */ jsx12(Pressable4, { accessibilityRole: "button", disabled: preparing || sending, onPress: () => void refresh(), style: styles8.smallButton, children: /* @__PURE__ */ jsx12(Text5, { style: [styles8.smallButtonText, { color: theme.colors.primary }], children: "Refresh" }) })
1275
+ ] }),
1276
+ screenshot.state === "partial" ? /* @__PURE__ */ jsx12(Text5, { style: [styles8.notice, { color: theme.colors.mutedForeground }], children: "Some protected content may be missing from this screenshot." }) : null,
1277
+ preparing ? /* @__PURE__ */ jsx12(Text5, { style: [styles8.notice, { color: theme.colors.mutedForeground }], children: "Preparing Feedback\u2026" }) : null,
1278
+ error ? /* @__PURE__ */ jsx12(Text5, { accessibilityLiveRegion: "polite", style: [styles8.error, { color: theme.colors.error }], children: error }) : null,
1279
+ /* @__PURE__ */ jsx12(Pressable4, { accessibilityRole: "button", disabled: !canSubmit, onPress: () => void submit(), style: [styles8.primaryButton, { backgroundColor: theme.colors.primary }, !canSubmit && styles8.disabledButton], children: /* @__PURE__ */ jsx12(Text5, { style: [styles8.primaryButtonText, { color: theme.colors.primaryForeground }], children: sending ? "Sending\u2026" : "Send Feedback" }) }),
1280
+ /* @__PURE__ */ jsx12(Text5, { style: [styles8.footer, { color: theme.colors.mutedForeground }], children: "Chalk includes safe Space state, journey, and diagnostic details. It never includes credentials, names, or message content outside this report. There is no reply channel." })
1281
+ ] })
1282
+ ] })
1283
+ ] }) });
1284
+ }
1285
+ function screenshotDataUri(screenshot) {
1286
+ if (screenshot.state !== "captured" && screenshot.state !== "partial") return void 0;
1287
+ return `data:${screenshot.mime_type};base64,${screenshot.data_base64}`;
1288
+ }
1289
+ function categoryLabel(category) {
1290
+ if (category === "feature_request") return "Feature request";
1291
+ if (category === "bug") return "Bug";
1292
+ return "Other";
1293
+ }
1294
+ function errorMessage(cause) {
1295
+ return cause instanceof Error ? cause.message : "Chalk could not send Feedback.";
1296
+ }
1297
+ var styles8 = StyleSheet9.create({
1298
+ overlay: { flex: 1, justifyContent: "flex-end", backgroundColor: Theme.colors.darkOverlay55 },
1299
+ backdrop: { ...StyleSheet9.absoluteFillObject },
1300
+ sheet: { maxHeight: "92%", borderTopLeftRadius: 24, borderTopRightRadius: 24, padding: 24, paddingBottom: 36 },
1301
+ header: { flexDirection: "row", alignItems: "flex-start", justifyContent: "space-between", gap: 16, marginBottom: 20 },
1302
+ headerCopy: { flex: 1, gap: 4 },
1303
+ title: { ...Theme.typography.heading },
1304
+ subtitle: { ...Theme.typography.body },
1305
+ closeButton: { alignItems: "center", borderColor: Theme.colors.border, borderRadius: Theme.radius.full, borderWidth: 1, height: 36, justifyContent: "center", width: 36 },
1306
+ closeText: { fontSize: 24, lineHeight: 26 },
1307
+ content: { gap: 12, paddingBottom: 8 },
1308
+ label: { ...Theme.typography.label, marginTop: 4 },
1309
+ categoryRow: { flexDirection: "row", flexWrap: "wrap", gap: 8 },
1310
+ categoryButton: { borderRadius: 14, borderWidth: 1, paddingHorizontal: 13, paddingVertical: 10 },
1311
+ categoryText: { fontSize: 14, fontWeight: "700" },
1312
+ messageInput: { minHeight: 116, borderRadius: 14, borderWidth: 1, padding: 14, fontSize: 15, lineHeight: 21 },
1313
+ thumbnailFrame: { borderRadius: 16, overflow: "hidden", borderWidth: 1, borderColor: Theme.colors.border },
1314
+ thumbnail: { width: "100%", height: 170, backgroundColor: Theme.colors.surfaceMuted },
1315
+ thumbnailActions: { flexDirection: "row", gap: 16, paddingHorizontal: 12, paddingVertical: 8 },
1316
+ unavailable: { borderRadius: 14, borderWidth: 1, padding: 14, gap: 4 },
1317
+ unavailableText: { ...Theme.typography.body },
1318
+ smallButton: { alignSelf: "flex-start", paddingVertical: 6, paddingHorizontal: 2 },
1319
+ smallButtonText: { fontSize: 14, fontWeight: "700" },
1320
+ notice: { ...Theme.typography.meta },
1321
+ error: { ...Theme.typography.meta, fontWeight: "700" },
1322
+ primaryButton: { alignItems: "center", borderRadius: 14, justifyContent: "center", minHeight: 50, marginTop: 8, paddingHorizontal: 16 },
1323
+ primaryButtonText: { fontSize: 16, fontWeight: "800" },
1324
+ disabledButton: { opacity: 0.45 },
1325
+ footer: { ...Theme.typography.meta, marginTop: 4 },
1326
+ success: { gap: 12, paddingVertical: 28 },
1327
+ successTitle: { ...Theme.typography.subheading }
1328
+ });
1329
+
993
1330
  // src/components/native-space-view/SpaceStage.android.tsx
994
1331
  import ComputerScreenShareIcon from "@hugeicons/core-free-icons/dist/esm/ComputerScreenShareIcon";
995
1332
  import MicOff01Icon3 from "@hugeicons/core-free-icons/dist/esm/MicOff01Icon";
996
1333
  import Presentation01Icon from "@hugeicons/core-free-icons/dist/esm/Presentation01Icon";
997
1334
  import WavingHand01Icon from "@hugeicons/core-free-icons/dist/esm/WavingHand01Icon";
998
1335
  import { HugeiconsIcon as HugeiconsIcon3 } from "@hugeicons/react-native";
999
- import { FlatList as FlatList2, StyleSheet as StyleSheet9, Text as Text5, View as View9 } from "react-native";
1000
- import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1336
+ import { FlatList as FlatList2, StyleSheet as StyleSheet10, Text as Text6, View as View10 } from "react-native";
1337
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
1001
1338
  function getParticipantStripTrack(participant) {
1002
1339
  return participant.videoTrack ?? null;
1003
1340
  }
1004
1341
  function StageSurface({ children }) {
1005
1342
  const theme = useNativeTheme();
1006
- return /* @__PURE__ */ jsx12(View9, { style: [styles8.surface, { backgroundColor: theme.colors.stageBackground }], children });
1343
+ return /* @__PURE__ */ jsx13(View10, { style: [styles9.surface, { backgroundColor: theme.colors.stageBackground }], children });
1007
1344
  }
1008
1345
  function InfoChip({ icon, label, align = "left" }) {
1009
1346
  const theme = useNativeTheme();
1010
- return /* @__PURE__ */ jsxs7(View9, { style: [styles8.infoChip, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }, align === "right" ? styles8.infoChipRight : styles8.infoChipLeft], children: [
1011
- /* @__PURE__ */ jsx12(HugeiconsIcon3, { color: theme.colors.foreground, icon, size: 14 }),
1012
- /* @__PURE__ */ jsx12(Text5, { style: [styles8.infoChipText, { color: theme.colors.foreground }], children: label })
1347
+ return /* @__PURE__ */ jsxs8(View10, { style: [styles9.infoChip, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }, align === "right" ? styles9.infoChipRight : styles9.infoChipLeft], children: [
1348
+ /* @__PURE__ */ jsx13(HugeiconsIcon3, { color: theme.colors.foreground, icon, size: 14 }),
1349
+ /* @__PURE__ */ jsx13(Text6, { style: [styles9.infoChipText, { color: theme.colors.foreground }], children: label })
1013
1350
  ] });
1014
1351
  }
1015
1352
  function NativeWhiteboardPlaceholder({ whiteboard }) {
1016
- return /* @__PURE__ */ jsxs7(StageSurface, { children: [
1017
- /* @__PURE__ */ jsx12(GradientSurface, { angle: "diagonal", borderRadius: 24, opacity: 0.6, participantId: "whiteboard-stage" }),
1018
- /* @__PURE__ */ jsxs7(View9, { style: styles8.placeholderCenter, children: [
1019
- /* @__PURE__ */ jsx12(View9, { style: styles8.presentingIconCircle, children: /* @__PURE__ */ jsx12(HugeiconsIcon3, { color: Theme.colors.primary, icon: Presentation01Icon, size: 32 }) }),
1020
- /* @__PURE__ */ jsx12(Text5, { style: styles8.placeholderEyebrow, children: "SHARED CANVAS" }),
1021
- /* @__PURE__ */ jsx12(Text5, { style: styles8.placeholderTitle, children: "Whiteboard active" }),
1022
- /* @__PURE__ */ jsx12(Text5, { style: styles8.placeholderCopy, children: whiteboard.canDraw ? "Collaborative board is open." : "Board is open in view-only mode." })
1353
+ return /* @__PURE__ */ jsxs8(StageSurface, { children: [
1354
+ /* @__PURE__ */ jsx13(GradientSurface, { angle: "diagonal", borderRadius: 24, opacity: 0.6, participantId: "whiteboard-stage" }),
1355
+ /* @__PURE__ */ jsxs8(View10, { style: styles9.placeholderCenter, children: [
1356
+ /* @__PURE__ */ jsx13(View10, { style: styles9.presentingIconCircle, children: /* @__PURE__ */ jsx13(HugeiconsIcon3, { color: Theme.colors.primary, icon: Presentation01Icon, size: 32 }) }),
1357
+ /* @__PURE__ */ jsx13(Text6, { style: styles9.placeholderEyebrow, children: "SHARED CANVAS" }),
1358
+ /* @__PURE__ */ jsx13(Text6, { style: styles9.placeholderTitle, children: "Whiteboard active" }),
1359
+ /* @__PURE__ */ jsx13(Text6, { style: styles9.placeholderCopy, children: whiteboard.canDraw ? "Collaborative board is open." : "Board is open in view-only mode." })
1023
1360
  ] })
1024
1361
  ] });
1025
1362
  }
1026
1363
  function NativeLocalSharePlaceholder() {
1027
- return /* @__PURE__ */ jsxs7(StageSurface, { children: [
1028
- /* @__PURE__ */ jsx12(GradientSurface, { angle: "diagonal", borderRadius: 24, opacity: 0.4, participantId: "local-presenting" }),
1029
- /* @__PURE__ */ jsxs7(View9, { style: styles8.placeholderCenter, children: [
1030
- /* @__PURE__ */ jsx12(View9, { style: styles8.presentingIconCircle, children: /* @__PURE__ */ jsx12(HugeiconsIcon3, { color: Theme.colors.primary, icon: ComputerScreenShareIcon, size: 32 }) }),
1031
- /* @__PURE__ */ jsx12(Text5, { style: styles8.placeholderEyebrow, children: "YOU ARE PRESENTING" }),
1032
- /* @__PURE__ */ jsx12(Text5, { style: styles8.placeholderTitle, children: "Screen sharing active" }),
1033
- /* @__PURE__ */ jsx12(Text5, { style: styles8.placeholderCopy, children: "Your preview is hidden here to prevent an infinite mirror effect. Everyone else can see your screen." })
1364
+ return /* @__PURE__ */ jsxs8(StageSurface, { children: [
1365
+ /* @__PURE__ */ jsx13(GradientSurface, { angle: "diagonal", borderRadius: 24, opacity: 0.4, participantId: "local-presenting" }),
1366
+ /* @__PURE__ */ jsxs8(View10, { style: styles9.placeholderCenter, children: [
1367
+ /* @__PURE__ */ jsx13(View10, { style: styles9.presentingIconCircle, children: /* @__PURE__ */ jsx13(HugeiconsIcon3, { color: Theme.colors.primary, icon: ComputerScreenShareIcon, size: 32 }) }),
1368
+ /* @__PURE__ */ jsx13(Text6, { style: styles9.placeholderEyebrow, children: "YOU ARE PRESENTING" }),
1369
+ /* @__PURE__ */ jsx13(Text6, { style: styles9.placeholderTitle, children: "Screen sharing active" }),
1370
+ /* @__PURE__ */ jsx13(Text6, { style: styles9.placeholderCopy, children: "Your preview is hidden here to prevent an infinite mirror effect. Everyone else can see your screen." })
1034
1371
  ] })
1035
1372
  ] });
1036
1373
  }
1037
1374
  function NativeParticipantStrip({ participants, vertical }) {
1038
- return /* @__PURE__ */ jsx12(
1375
+ return /* @__PURE__ */ jsx13(
1039
1376
  FlatList2,
1040
1377
  {
1041
- contentContainerStyle: [styles8.stripContent, vertical ? styles8.stripVertical : styles8.stripHorizontal],
1378
+ contentContainerStyle: [styles9.stripContent, vertical ? styles9.stripVertical : styles9.stripHorizontal],
1042
1379
  data: participants,
1043
1380
  horizontal: !vertical,
1044
1381
  initialNumToRender: vertical ? 4 : 5,
1045
1382
  keyExtractor: (participant, index) => `${participant.id}-${index}`,
1046
1383
  maxToRenderPerBatch: vertical ? 5 : 6,
1047
1384
  removeClippedSubviews: true,
1048
- renderItem: ({ item: participant }) => /* @__PURE__ */ jsx12(View9, { style: [styles8.stripTile, vertical ? styles8.stripTileVertical : styles8.stripTileHorizontal], children: /* @__PURE__ */ jsx12(MediaView, { emphasizeMuted: true, participant, track: getParticipantStripTrack(participant) }) }),
1385
+ renderItem: ({ item: participant }) => /* @__PURE__ */ jsx13(View10, { style: [styles9.stripTile, vertical ? styles9.stripTileVertical : styles9.stripTileHorizontal], children: /* @__PURE__ */ jsx13(MediaView, { emphasizeMuted: true, participant, track: getParticipantStripTrack(participant) }) }),
1049
1386
  showsHorizontalScrollIndicator: false,
1050
1387
  showsVerticalScrollIndicator: false,
1051
1388
  windowSize: 4
@@ -1057,35 +1394,35 @@ function SpaceStageAndroid({ layoutMode, isCompactViewport, primaryContent, scre
1057
1394
  const verticalStrip = !isCompactViewport && layoutMode === "focus";
1058
1395
  let primaryStage;
1059
1396
  if (primaryContent === "whiteboard") {
1060
- primaryStage = /* @__PURE__ */ jsx12(NativeWhiteboardPlaceholder, { whiteboard });
1397
+ primaryStage = /* @__PURE__ */ jsx13(NativeWhiteboardPlaceholder, { whiteboard });
1061
1398
  } else if (primaryContent === "screen-share-placeholder") {
1062
- primaryStage = /* @__PURE__ */ jsx12(NativeLocalSharePlaceholder, {});
1399
+ primaryStage = /* @__PURE__ */ jsx13(NativeLocalSharePlaceholder, {});
1063
1400
  } else if (primaryContent === "split") {
1064
- primaryStage = /* @__PURE__ */ jsxs7(View9, { style: styles8.splitStage, children: [
1065
- /* @__PURE__ */ jsx12(View9, { style: styles8.splitPanel, children: /* @__PURE__ */ jsx12(StageSurface, { children: /* @__PURE__ */ jsx12(MediaView, { participant: screenSharer, track: screenShareTrack, objectFit: "contain" }) }) }),
1066
- /* @__PURE__ */ jsx12(View9, { style: styles8.splitPanel, children: /* @__PURE__ */ jsx12(NativeWhiteboardPlaceholder, { whiteboard }) })
1401
+ primaryStage = /* @__PURE__ */ jsxs8(View10, { style: styles9.splitStage, children: [
1402
+ /* @__PURE__ */ jsx13(View10, { style: styles9.splitPanel, children: /* @__PURE__ */ jsx13(StageSurface, { children: /* @__PURE__ */ jsx13(MediaView, { participant: screenSharer, track: screenShareTrack, objectFit: "contain" }) }) }),
1403
+ /* @__PURE__ */ jsx13(View10, { style: styles9.splitPanel, children: /* @__PURE__ */ jsx13(NativeWhiteboardPlaceholder, { whiteboard }) })
1067
1404
  ] });
1068
1405
  } else {
1069
- primaryStage = /* @__PURE__ */ jsx12(StageSurface, { children: /* @__PURE__ */ jsx12(MediaView, { participant: screenSharer, track: screenShareTrack, label: screenSharer?.displayName || "Participant", objectFit: "contain" }) });
1406
+ primaryStage = /* @__PURE__ */ jsx13(StageSurface, { children: /* @__PURE__ */ jsx13(MediaView, { participant: screenSharer, track: screenShareTrack, label: screenSharer?.displayName || "Participant", objectFit: "contain" }) });
1070
1407
  }
1071
- return /* @__PURE__ */ jsxs7(View9, { style: [styles8.container, { backgroundColor: theme.colors.darkCanvas }, verticalStrip && styles8.containerVertical], children: [
1072
- /* @__PURE__ */ jsxs7(View9, { style: styles8.primaryFrame, children: [
1408
+ return /* @__PURE__ */ jsxs8(View10, { style: [styles9.container, { backgroundColor: theme.colors.darkCanvas }, verticalStrip && styles9.containerVertical], children: [
1409
+ /* @__PURE__ */ jsxs8(View10, { style: styles9.primaryFrame, children: [
1073
1410
  primaryStage,
1074
- raisedHandCount > 0 ? /* @__PURE__ */ jsx12(InfoChip, { icon: WavingHand01Icon, label: raisedHandCount === 1 ? "1 hand raised" : `${raisedHandCount} hands raised` }) : null,
1075
- activeReactions.length > 0 ? /* @__PURE__ */ jsx12(View9, { style: styles8.reactionRail, children: activeReactions.map((reaction, index) => /* @__PURE__ */ jsxs7(View9, { style: [styles8.reactionBubble, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }], children: [
1076
- /* @__PURE__ */ jsx12(Text5, { style: styles8.reactionEmoji, children: reaction.emoji }),
1077
- /* @__PURE__ */ jsx12(Text5, { numberOfLines: 1, style: [styles8.reactionName, { color: theme.colors.foreground }], children: reaction.participantName })
1411
+ raisedHandCount > 0 ? /* @__PURE__ */ jsx13(InfoChip, { icon: WavingHand01Icon, label: raisedHandCount === 1 ? "1 hand raised" : `${raisedHandCount} hands raised` }) : null,
1412
+ activeReactions.length > 0 ? /* @__PURE__ */ jsx13(View10, { style: styles9.reactionRail, children: activeReactions.map((reaction, index) => /* @__PURE__ */ jsxs8(View10, { style: [styles9.reactionBubble, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }], children: [
1413
+ /* @__PURE__ */ jsx13(Text6, { style: styles9.reactionEmoji, children: reaction.emoji }),
1414
+ /* @__PURE__ */ jsx13(Text6, { numberOfLines: 1, style: [styles9.reactionName, { color: theme.colors.foreground }], children: reaction.participantName })
1078
1415
  ] }, `${reaction.id}-${index}`)) }) : null,
1079
- /* @__PURE__ */ jsxs7(View9, { style: [styles8.identityBar, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }], children: [
1080
- /* @__PURE__ */ jsx12(Text5, { style: [styles8.nameLabel, { color: theme.colors.foreground }], numberOfLines: 1, children: selfName }),
1081
- isMuted ? /* @__PURE__ */ jsx12(View9, { style: styles8.muteIndicator, children: /* @__PURE__ */ jsx12(HugeiconsIcon3, { color: theme.colors.primaryForeground, icon: MicOff01Icon3, size: 10 }) }) : null,
1082
- handRaised ? /* @__PURE__ */ jsx12(View9, { style: styles8.handIndicator, children: /* @__PURE__ */ jsx12(HugeiconsIcon3, { color: theme.colors.primaryForeground, icon: WavingHand01Icon, size: 10 }) }) : null
1416
+ /* @__PURE__ */ jsxs8(View10, { style: [styles9.identityBar, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }], children: [
1417
+ /* @__PURE__ */ jsx13(Text6, { style: [styles9.nameLabel, { color: theme.colors.foreground }], numberOfLines: 1, children: selfName }),
1418
+ isMuted ? /* @__PURE__ */ jsx13(View10, { style: styles9.muteIndicator, children: /* @__PURE__ */ jsx13(HugeiconsIcon3, { color: theme.colors.primaryForeground, icon: MicOff01Icon3, size: 10 }) }) : null,
1419
+ handRaised ? /* @__PURE__ */ jsx13(View10, { style: styles9.handIndicator, children: /* @__PURE__ */ jsx13(HugeiconsIcon3, { color: theme.colors.primaryForeground, icon: WavingHand01Icon, size: 10 }) }) : null
1083
1420
  ] })
1084
1421
  ] }),
1085
- stripParticipants.length > 0 ? /* @__PURE__ */ jsx12(View9, { style: [styles8.stripShell, verticalStrip ? styles8.stripShellVertical : styles8.stripShellHorizontal], children: /* @__PURE__ */ jsx12(NativeParticipantStrip, { participants: stripParticipants, vertical: verticalStrip }) }) : null
1422
+ stripParticipants.length > 0 ? /* @__PURE__ */ jsx13(View10, { style: [styles9.stripShell, verticalStrip ? styles9.stripShellVertical : styles9.stripShellHorizontal], children: /* @__PURE__ */ jsx13(NativeParticipantStrip, { participants: stripParticipants, vertical: verticalStrip }) }) : null
1086
1423
  ] });
1087
1424
  }
1088
- var styles8 = StyleSheet9.create({
1425
+ var styles9 = StyleSheet10.create({
1089
1426
  container: {
1090
1427
  flex: 1,
1091
1428
  width: "100%",
@@ -1276,13 +1613,13 @@ var styles8 = StyleSheet9.create({
1276
1613
  // src/components/native-space-view/SpaceTopBar.android.tsx
1277
1614
  import UserGroupIcon from "@hugeicons/core-free-icons/dist/esm/UserGroupIcon";
1278
1615
  import { HugeiconsIcon as HugeiconsIcon4 } from "@hugeicons/react-native";
1279
- import { Image as Image2, Platform as Platform4, StyleSheet as StyleSheet10, Text as Text6, View as View10 } from "react-native";
1616
+ import { Image as Image3, Platform as Platform7, StyleSheet as StyleSheet11, Text as Text7, View as View11 } from "react-native";
1280
1617
 
1281
1618
  // src/components/logo/Logo.tsx
1282
- import { useEffect as useEffect3, useId, useRef as useRef2, useState as useState3 } from "react";
1283
- import { AccessibilityInfo, Animated, Pressable as Pressable4 } from "react-native";
1619
+ import { useEffect as useEffect4, useId, useRef as useRef2, useState as useState4 } from "react";
1620
+ import { AccessibilityInfo, Animated, Pressable as Pressable5 } from "react-native";
1284
1621
  import Svg, { Defs, Ellipse, G, LinearGradient, Path, Stop, Text as SvgText } from "react-native-svg";
1285
- import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
1622
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
1286
1623
  var AnimatedG = Animated.createAnimatedComponent(G);
1287
1624
  var STICK_MOTIONS = [
1288
1625
  {
@@ -1423,8 +1760,8 @@ function resetStickAnimationValues(values) {
1423
1760
  }
1424
1761
  }
1425
1762
  function Logo({ accessibilityLabel = "Chalk", color = DEFAULT_COLOR, height = DEFAULT_HEIGHT, motion = DEFAULT_MOTION, variant = DEFAULT_VARIANT }) {
1426
- const [reducedMotion, setReducedMotion] = useState3(null);
1427
- const [interaction, setInteraction] = useState3({ focus: false, hover: false, press: false });
1763
+ const [reducedMotion, setReducedMotion] = useState4(null);
1764
+ const [interaction, setInteraction] = useState4({ focus: false, hover: false, press: false });
1428
1765
  const idPrefix = `chalk-logo-${useId().replace(/[^a-zA-Z0-9_-]/gu, "")}`;
1429
1766
  const animationValues = useRef2(null);
1430
1767
  if (animationValues.current === null) {
@@ -1433,7 +1770,7 @@ function Logo({ accessibilityLabel = "Chalk", color = DEFAULT_COLOR, height = DE
1433
1770
  const sticks = animationValues.current;
1434
1771
  const interactionActive = interaction.focus || interaction.hover || interaction.press;
1435
1772
  const animate = motion === "orbit-burst" && reducedMotion === false;
1436
- useEffect3(() => {
1773
+ useEffect4(() => {
1437
1774
  let cancelled = false;
1438
1775
  const subscription = AccessibilityInfo.addEventListener("reduceMotionChanged", setReducedMotion);
1439
1776
  void AccessibilityInfo.isReduceMotionEnabled().then((enabled) => {
@@ -1446,7 +1783,7 @@ function Logo({ accessibilityLabel = "Chalk", color = DEFAULT_COLOR, height = DE
1446
1783
  subscription.remove();
1447
1784
  };
1448
1785
  }, []);
1449
- useEffect3(() => {
1786
+ useEffect4(() => {
1450
1787
  if (!animate) {
1451
1788
  resetStickAnimationValues(sticks);
1452
1789
  return;
@@ -1464,8 +1801,8 @@ function Logo({ accessibilityLabel = "Chalk", color = DEFAULT_COLOR, height = DE
1464
1801
  const width = variant === "wordmark" ? height * 2.5 : height * (68 / 80);
1465
1802
  const viewBox = variant === "wordmark" ? WORDMARK_VIEW_BOX : MARK_VIEW_BOX;
1466
1803
  const accessible = accessibilityLabel !== null;
1467
- return /* @__PURE__ */ jsx13(
1468
- Pressable4,
1804
+ return /* @__PURE__ */ jsx14(
1805
+ Pressable5,
1469
1806
  {
1470
1807
  accessible: false,
1471
1808
  onBlur: () => setInteractionFlag("focus", false),
@@ -1474,69 +1811,77 @@ function Logo({ accessibilityLabel = "Chalk", color = DEFAULT_COLOR, height = DE
1474
1811
  onHoverOut: () => setInteractionFlag("hover", false),
1475
1812
  onPressIn: () => setInteractionFlag("press", true),
1476
1813
  onPressOut: () => setInteractionFlag("press", false),
1477
- children: /* @__PURE__ */ jsxs8(Svg, { accessibilityLabel: accessible ? accessibilityLabel ?? void 0 : void 0, accessible, color, fill: "none", focusable: false, height, viewBox, width, children: [
1478
- /* @__PURE__ */ jsxs8(Defs, { children: [
1479
- /* @__PURE__ */ jsxs8(LinearGradient, { id: `${idPrefix}-green`, x1: "0%", x2: "100%", y1: "0%", y2: "0%", children: [
1480
- /* @__PURE__ */ jsx13(Stop, { offset: "0%", stopColor: "#C5E5C0" }),
1481
- /* @__PURE__ */ jsx13(Stop, { offset: "100%", stopColor: "#80B879" })
1814
+ children: /* @__PURE__ */ jsxs9(Svg, { accessibilityLabel: accessible ? accessibilityLabel ?? void 0 : void 0, accessible, color, fill: "none", focusable: false, height, viewBox, width, children: [
1815
+ /* @__PURE__ */ jsxs9(Defs, { children: [
1816
+ /* @__PURE__ */ jsxs9(LinearGradient, { id: `${idPrefix}-green`, x1: "0%", x2: "100%", y1: "0%", y2: "0%", children: [
1817
+ /* @__PURE__ */ jsx14(Stop, { offset: "0%", stopColor: "#C5E5C0" }),
1818
+ /* @__PURE__ */ jsx14(Stop, { offset: "100%", stopColor: "#80B879" })
1482
1819
  ] }),
1483
- /* @__PURE__ */ jsxs8(LinearGradient, { id: `${idPrefix}-yellow`, x1: "0%", x2: "100%", y1: "0%", y2: "0%", children: [
1484
- /* @__PURE__ */ jsx13(Stop, { offset: "0%", stopColor: "#FCEAB3" }),
1485
- /* @__PURE__ */ jsx13(Stop, { offset: "100%", stopColor: "#D9B641" })
1820
+ /* @__PURE__ */ jsxs9(LinearGradient, { id: `${idPrefix}-yellow`, x1: "0%", x2: "100%", y1: "0%", y2: "0%", children: [
1821
+ /* @__PURE__ */ jsx14(Stop, { offset: "0%", stopColor: "#FCEAB3" }),
1822
+ /* @__PURE__ */ jsx14(Stop, { offset: "100%", stopColor: "#D9B641" })
1486
1823
  ] }),
1487
- /* @__PURE__ */ jsxs8(LinearGradient, { id: `${idPrefix}-blue`, x1: "0%", x2: "100%", y1: "0%", y2: "0%", children: [
1488
- /* @__PURE__ */ jsx13(Stop, { offset: "0%", stopColor: "#B2E0F0" }),
1489
- /* @__PURE__ */ jsx13(Stop, { offset: "100%", stopColor: "#55AAC9" })
1824
+ /* @__PURE__ */ jsxs9(LinearGradient, { id: `${idPrefix}-blue`, x1: "0%", x2: "100%", y1: "0%", y2: "0%", children: [
1825
+ /* @__PURE__ */ jsx14(Stop, { offset: "0%", stopColor: "#B2E0F0" }),
1826
+ /* @__PURE__ */ jsx14(Stop, { offset: "100%", stopColor: "#55AAC9" })
1490
1827
  ] }),
1491
- /* @__PURE__ */ jsxs8(LinearGradient, { id: `${idPrefix}-pink`, x1: "0%", x2: "100%", y1: "0%", y2: "0%", children: [
1492
- /* @__PURE__ */ jsx13(Stop, { offset: "0%", stopColor: "#F8CACA" }),
1493
- /* @__PURE__ */ jsx13(Stop, { offset: "100%", stopColor: "#D67B7B" })
1828
+ /* @__PURE__ */ jsxs9(LinearGradient, { id: `${idPrefix}-pink`, x1: "0%", x2: "100%", y1: "0%", y2: "0%", children: [
1829
+ /* @__PURE__ */ jsx14(Stop, { offset: "0%", stopColor: "#F8CACA" }),
1830
+ /* @__PURE__ */ jsx14(Stop, { offset: "100%", stopColor: "#D67B7B" })
1494
1831
  ] })
1495
1832
  ] }),
1496
- /* @__PURE__ */ jsxs8(G, { transform: "translate(2, 2) scale(0.95)", children: [
1497
- /* @__PURE__ */ jsxs8(AnimatedG, { originX: STICK_MOTIONS[0].originX, originY: STICK_MOTIONS[0].originY, rotation: sticks[0].rotation, scaleX: sticks[0].scaleX, scaleY: sticks[0].scaleY, transform: STICK_MOTIONS[0].transform, translateX: sticks[0].translateX, translateY: sticks[0].translateY, children: [
1498
- /* @__PURE__ */ jsx13(Path, { d: "M9,20 L21,20 L22,63 A7,7 0 0 1 8,63 Z", fill: `url(#${idPrefix}-green)` }),
1499
- /* @__PURE__ */ jsx13(Ellipse, { cx: "15", cy: "20", fill: "#D8ECD4", rx: "6", ry: "2.5" })
1833
+ /* @__PURE__ */ jsxs9(G, { transform: "translate(2, 2) scale(0.95)", children: [
1834
+ /* @__PURE__ */ jsxs9(AnimatedG, { originX: STICK_MOTIONS[0].originX, originY: STICK_MOTIONS[0].originY, rotation: sticks[0].rotation, scaleX: sticks[0].scaleX, scaleY: sticks[0].scaleY, transform: STICK_MOTIONS[0].transform, translateX: sticks[0].translateX, translateY: sticks[0].translateY, children: [
1835
+ /* @__PURE__ */ jsx14(Path, { d: "M9,20 L21,20 L22,63 A7,7 0 0 1 8,63 Z", fill: `url(#${idPrefix}-green)` }),
1836
+ /* @__PURE__ */ jsx14(Ellipse, { cx: "15", cy: "20", fill: "#D8ECD4", rx: "6", ry: "2.5" })
1500
1837
  ] }),
1501
- /* @__PURE__ */ jsxs8(AnimatedG, { originX: STICK_MOTIONS[1].originX, originY: STICK_MOTIONS[1].originY, rotation: sticks[1].rotation, scaleX: sticks[1].scaleX, scaleY: sticks[1].scaleY, transform: STICK_MOTIONS[1].transform, translateX: sticks[1].translateX, translateY: sticks[1].translateY, children: [
1502
- /* @__PURE__ */ jsx13(Path, { d: "M23,15 L35,15 L36,60 A7,7 0 0 1 22,60 Z", fill: `url(#${idPrefix}-yellow)` }),
1503
- /* @__PURE__ */ jsx13(Ellipse, { cx: "29", cy: "15", fill: "#FEF3D1", rx: "6", ry: "2.5" })
1838
+ /* @__PURE__ */ jsxs9(AnimatedG, { originX: STICK_MOTIONS[1].originX, originY: STICK_MOTIONS[1].originY, rotation: sticks[1].rotation, scaleX: sticks[1].scaleX, scaleY: sticks[1].scaleY, transform: STICK_MOTIONS[1].transform, translateX: sticks[1].translateX, translateY: sticks[1].translateY, children: [
1839
+ /* @__PURE__ */ jsx14(Path, { d: "M23,15 L35,15 L36,60 A7,7 0 0 1 22,60 Z", fill: `url(#${idPrefix}-yellow)` }),
1840
+ /* @__PURE__ */ jsx14(Ellipse, { cx: "29", cy: "15", fill: "#FEF3D1", rx: "6", ry: "2.5" })
1504
1841
  ] }),
1505
- /* @__PURE__ */ jsxs8(AnimatedG, { originX: STICK_MOTIONS[2].originX, originY: STICK_MOTIONS[2].originY, rotation: sticks[2].rotation, scaleX: sticks[2].scaleX, scaleY: sticks[2].scaleY, transform: STICK_MOTIONS[2].transform, translateX: sticks[2].translateX, translateY: sticks[2].translateY, children: [
1506
- /* @__PURE__ */ jsx13(Path, { d: "M36,8 L48,8 L49,56 A7,7 0 0 1 35,56 Z", fill: `url(#${idPrefix}-blue)` }),
1507
- /* @__PURE__ */ jsx13(Ellipse, { cx: "42", cy: "8", fill: "#D0EDF8", rx: "6", ry: "2.5" })
1842
+ /* @__PURE__ */ jsxs9(AnimatedG, { originX: STICK_MOTIONS[2].originX, originY: STICK_MOTIONS[2].originY, rotation: sticks[2].rotation, scaleX: sticks[2].scaleX, scaleY: sticks[2].scaleY, transform: STICK_MOTIONS[2].transform, translateX: sticks[2].translateX, translateY: sticks[2].translateY, children: [
1843
+ /* @__PURE__ */ jsx14(Path, { d: "M36,8 L48,8 L49,56 A7,7 0 0 1 35,56 Z", fill: `url(#${idPrefix}-blue)` }),
1844
+ /* @__PURE__ */ jsx14(Ellipse, { cx: "42", cy: "8", fill: "#D0EDF8", rx: "6", ry: "2.5" })
1508
1845
  ] }),
1509
- /* @__PURE__ */ jsxs8(AnimatedG, { originX: STICK_MOTIONS[3].originX, originY: STICK_MOTIONS[3].originY, rotation: sticks[3].rotation, scaleX: sticks[3].scaleX, scaleY: sticks[3].scaleY, transform: STICK_MOTIONS[3].transform, translateX: sticks[3].translateX, translateY: sticks[3].translateY, children: [
1510
- /* @__PURE__ */ jsx13(Path, { d: "M49,70 L61,70 L62,29 A7,7 0 0 0 48,29 Z", fill: `url(#${idPrefix}-pink)` }),
1511
- /* @__PURE__ */ jsx13(Ellipse, { cx: "55", cy: "70", fill: "#FBE4E4", rx: "6", ry: "2.5" })
1846
+ /* @__PURE__ */ jsxs9(AnimatedG, { originX: STICK_MOTIONS[3].originX, originY: STICK_MOTIONS[3].originY, rotation: sticks[3].rotation, scaleX: sticks[3].scaleX, scaleY: sticks[3].scaleY, transform: STICK_MOTIONS[3].transform, translateX: sticks[3].translateX, translateY: sticks[3].translateY, children: [
1847
+ /* @__PURE__ */ jsx14(Path, { d: "M49,70 L61,70 L62,29 A7,7 0 0 0 48,29 Z", fill: `url(#${idPrefix}-pink)` }),
1848
+ /* @__PURE__ */ jsx14(Ellipse, { cx: "55", cy: "70", fill: "#FBE4E4", rx: "6", ry: "2.5" })
1512
1849
  ] })
1513
1850
  ] }),
1514
- variant === "wordmark" ? /* @__PURE__ */ jsx13(SvgText, { fill: "currentColor", fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, sans-serif", fontSize: "38", fontWeight: "600", letterSpacing: "-0.02em", x: "90", y: "52", children: "chalk" }) : null
1851
+ variant === "wordmark" ? /* @__PURE__ */ jsx14(SvgText, { fill: "currentColor", fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, sans-serif", fontSize: "38", fontWeight: "600", letterSpacing: "-0.02em", x: "90", y: "52", children: "chalk" }) : null
1515
1852
  ] })
1516
1853
  }
1517
1854
  );
1518
1855
  }
1519
1856
 
1520
1857
  // src/components/native-space-view/SpaceTopBar.android.tsx
1521
- import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
1522
- function SpaceTopBarAndroid({ spaceName, participantCount, formattedDuration, logoUrl }) {
1858
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1859
+ function SpaceTopBarAndroid({ spaceName, participantCount, formattedDuration, logoUrl, recording }) {
1523
1860
  const theme = useNativeTheme();
1524
- return /* @__PURE__ */ jsxs9(View10, { style: [styles9.topBar, { backgroundColor: theme.colors.darkCanvas, borderColor: theme.colors.border }], children: [
1525
- /* @__PURE__ */ jsxs9(View10, { style: styles9.topBarLeft, children: [
1526
- logoUrl ? /* @__PURE__ */ jsx14(Image2, { accessibilityLabel: "Chalk", source: { uri: logoUrl }, style: styles9.logo }) : /* @__PURE__ */ jsx14(Logo, { height: 24, variant: "mark" }),
1527
- /* @__PURE__ */ jsx14(View10, { style: [styles9.connectionDot, { backgroundColor: theme.colors.success }] }),
1528
- /* @__PURE__ */ jsx14(Text6, { style: [styles9.topBarSpaceName, { color: theme.colors.foreground }], numberOfLines: 1, children: spaceName }),
1529
- /* @__PURE__ */ jsx14(View10, { style: [styles9.timerBadge, { backgroundColor: theme.colors.surface }], children: /* @__PURE__ */ jsx14(Text6, { style: [styles9.timerText, { color: theme.colors.mutedForeground }], children: formattedDuration }) })
1861
+ return /* @__PURE__ */ jsxs10(View11, { style: [styles10.topBar, { backgroundColor: theme.colors.darkCanvas, borderColor: theme.colors.border }], children: [
1862
+ /* @__PURE__ */ jsxs10(View11, { style: styles10.topBarLeft, children: [
1863
+ logoUrl ? /* @__PURE__ */ jsx15(Image3, { accessibilityLabel: "Chalk", source: { uri: logoUrl }, style: styles10.logo }) : /* @__PURE__ */ jsx15(Logo, { height: 24, variant: "mark" }),
1864
+ /* @__PURE__ */ jsx15(View11, { style: [styles10.connectionDot, { backgroundColor: theme.colors.success }] }),
1865
+ /* @__PURE__ */ jsx15(Text7, { style: [styles10.topBarSpaceName, { color: theme.colors.foreground }], numberOfLines: 1, children: spaceName }),
1866
+ /* @__PURE__ */ jsx15(View11, { style: [styles10.timerBadge, { backgroundColor: theme.colors.surface }], children: /* @__PURE__ */ jsx15(Text7, { style: [styles10.timerText, { color: theme.colors.mutedForeground }], children: formattedDuration }) })
1530
1867
  ] }),
1531
- /* @__PURE__ */ jsxs9(View10, { style: [styles9.topBarRight, { backgroundColor: theme.colors.surface }], children: [
1532
- /* @__PURE__ */ jsx14(HugeiconsIcon4, { icon: UserGroupIcon, size: 14, color: theme.colors.foreground }),
1533
- /* @__PURE__ */ jsx14(Text6, { style: [styles9.topBarCount, { color: theme.colors.foreground }], children: participantCount })
1868
+ recording && recording.status !== "stopped" ? /* @__PURE__ */ jsx15(Text7, { accessibilityLiveRegion: "polite", style: [styles10.timerText, { color: theme.colors.error }], children: recordingLabels[recording.status] }) : null,
1869
+ /* @__PURE__ */ jsxs10(View11, { style: [styles10.topBarRight, { backgroundColor: theme.colors.surface }], children: [
1870
+ /* @__PURE__ */ jsx15(HugeiconsIcon4, { icon: UserGroupIcon, size: 14, color: theme.colors.foreground }),
1871
+ /* @__PURE__ */ jsx15(Text7, { style: [styles10.topBarCount, { color: theme.colors.foreground }], children: participantCount })
1534
1872
  ] })
1535
1873
  ] });
1536
1874
  }
1537
- var styles9 = StyleSheet10.create({
1875
+ var recordingLabels = {
1876
+ starting: "Starting recording\u2026",
1877
+ recording: "Recording",
1878
+ stopping: "Stopping recording\u2026",
1879
+ stopped: "Recording stopped",
1880
+ failed: "Recording failed"
1881
+ };
1882
+ var styles10 = StyleSheet11.create({
1538
1883
  topBar: {
1539
- paddingTop: Platform4.OS === "ios" ? 54 : 42,
1884
+ paddingTop: Platform7.OS === "ios" ? 54 : 42,
1540
1885
  paddingBottom: 14,
1541
1886
  paddingHorizontal: 24,
1542
1887
  backgroundColor: Theme.colors.darkCanvas,
@@ -1596,23 +1941,23 @@ var styles9 = StyleSheet10.create({
1596
1941
  });
1597
1942
 
1598
1943
  // src/components/native-space-view/SpaceWhiteboardSurface.tsx
1599
- import { useCallback as useCallback5 } from "react";
1600
- import { StyleSheet as StyleSheet12 } from "react-native";
1944
+ import { useCallback as useCallback6 } from "react";
1945
+ import { StyleSheet as StyleSheet13 } from "react-native";
1601
1946
 
1602
1947
  // src/components/EmbeddedWhiteboard.tsx
1603
1948
  import { ChalkWhiteboardController } from "@q9labsai/chalk-whiteboard/embedded";
1604
- import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo8, useRef as useRef3, useState as useState4 } from "react";
1605
- import { ActivityIndicator, Pressable as Pressable5, StyleSheet as StyleSheet11, Text as Text7, useWindowDimensions as useWindowDimensions2, View as View11 } from "react-native";
1949
+ import { useCallback as useCallback5, useEffect as useEffect5, useMemo as useMemo9, useRef as useRef3, useState as useState5 } from "react";
1950
+ import { ActivityIndicator, Pressable as Pressable6, StyleSheet as StyleSheet12, Text as Text8, useWindowDimensions as useWindowDimensions2, View as View12 } from "react-native";
1606
1951
  import WebView from "react-native-webview";
1607
1952
 
1608
1953
  // src/whiteboard/embedded-whiteboard-assets.ts
1609
- import { NativeModules as NativeModules2, Platform as Platform5 } from "react-native";
1954
+ import { NativeModules as NativeModules2, Platform as Platform8 } from "react-native";
1610
1955
  var ANDROID_RENDERER_URL = "file:///android_asset/chalk-whiteboard/index.html";
1611
1956
  async function resolveEmbeddedWhiteboardRendererURL(override) {
1612
1957
  if (override) return requireLocalRendererURL(override);
1613
- if (Platform5.OS === "android") return ANDROID_RENDERER_URL;
1958
+ if (Platform8.OS === "android") return ANDROID_RENDERER_URL;
1614
1959
  const module = NativeModules2.ChalkWhiteboardAssets;
1615
- if (!module?.rendererURL) throw new Error(`Chalk embedded whiteboard assets are unavailable on ${Platform5.OS}`);
1960
+ if (!module?.rendererURL) throw new Error(`Chalk embedded whiteboard assets are unavailable on ${Platform8.OS}`);
1616
1961
  return requireLocalRendererURL(await module.rendererURL());
1617
1962
  }
1618
1963
  function rendererURLWithContext(rendererURL, context) {
@@ -1638,8 +1983,14 @@ function requireLocalRendererURL(value) {
1638
1983
  return value;
1639
1984
  }
1640
1985
 
1986
+ // src/whiteboard/embedded-whiteboard-viewport.ts
1987
+ function createEmbeddedWhiteboardViewport(width, height, scale) {
1988
+ if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0 || !Number.isFinite(scale) || scale <= 0) return null;
1989
+ return { width, height, scale };
1990
+ }
1991
+
1641
1992
  // src/components/EmbeddedWhiteboard.tsx
1642
- import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1993
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
1643
1994
  var embeddedWhiteboardWebViewSecurityPolicy = Object.freeze({
1644
1995
  allowFileAccess: true,
1645
1996
  allowFileAccessFromFileURLs: false,
@@ -1662,16 +2013,20 @@ function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, can
1662
2013
  const onMetricRef = useRef3(onMetric);
1663
2014
  const onErrorRef = useRef3(onError);
1664
2015
  const onUserExportRef = useRef3(onUserExport);
1665
- const [rendererURL, setRendererURL] = useState4(null);
1666
- const [rendererGeneration, setRendererGeneration] = useState4(createRendererGeneration);
1667
- const [loadAttempt, setLoadAttempt] = useState4(0);
1668
- const [loadError, setLoadError] = useState4(null);
1669
- const [compatibilityNotice, setCompatibilityNotice] = useState4(null);
1670
- const { width, height, scale } = useWindowDimensions2();
2016
+ const [rendererURL, setRendererURL] = useState5(null);
2017
+ const [rendererGeneration, setRendererGeneration] = useState5(createRendererGeneration);
2018
+ const [loadAttempt, setLoadAttempt] = useState5(0);
2019
+ const [loadError, setLoadError] = useState5(null);
2020
+ const [compatibilityNotice, setCompatibilityNotice] = useState5(null);
2021
+ const [layout, setLayout] = useState5({ width: 0, height: 0 });
2022
+ const { scale } = useWindowDimensions2();
2023
+ const viewport = useMemo9(() => createEmbeddedWhiteboardViewport(layout.width, layout.height, scale), [layout.height, layout.width, scale]);
2024
+ const latestViewportRef = useRef3(viewport);
2025
+ latestViewportRef.current = viewport;
1671
2026
  onMetricRef.current = onMetric;
1672
2027
  onErrorRef.current = onError;
1673
2028
  onUserExportRef.current = onUserExport;
1674
- const rendererPort = useMemo8(
2029
+ const rendererPort = useMemo9(
1675
2030
  () => ({
1676
2031
  postMessage: (message) => webViewRef.current?.postMessage(message),
1677
2032
  subscribe: (listener) => {
@@ -1681,10 +2036,10 @@ function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, can
1681
2036
  }),
1682
2037
  []
1683
2038
  );
1684
- const handleControllerError = useCallback4((error) => onErrorRef.current?.(error), []);
1685
- const handleControllerMetric = useCallback4((metric) => onMetricRef.current?.(metric), []);
1686
- const handleControllerUserExport = useCallback4((value) => onUserExportRef.current?.(value), []);
1687
- useEffect4(() => {
2039
+ const handleControllerError = useCallback5((error) => onErrorRef.current?.(error), []);
2040
+ const handleControllerMetric = useCallback5((metric) => onMetricRef.current?.(metric), []);
2041
+ const handleControllerUserExport = useCallback5((value) => onUserExportRef.current?.(value), []);
2042
+ useEffect5(() => {
1688
2043
  let active = true;
1689
2044
  setLoadError(null);
1690
2045
  void resolveEmbeddedWhiteboardRendererURL(rendererURLOverride).then((url) => {
@@ -1699,7 +2054,7 @@ function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, can
1699
2054
  active = false;
1700
2055
  };
1701
2056
  }, [loadAttempt, onError, rendererURLOverride]);
1702
- useEffect4(() => {
2057
+ useEffect5(() => {
1703
2058
  setCompatibilityNotice(null);
1704
2059
  const controller = new ChalkWhiteboardController({
1705
2060
  renderer: rendererPort,
@@ -1717,19 +2072,23 @@ function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, can
1717
2072
  onUserExport: handleControllerUserExport
1718
2073
  });
1719
2074
  controller.start();
2075
+ if (latestViewportRef.current) controller.setViewport(latestViewportRef.current);
1720
2076
  controllerRef.current = controller;
1721
2077
  return () => {
1722
2078
  if (controllerRef.current === controller) controllerRef.current = null;
1723
2079
  controller.stop();
1724
2080
  };
1725
2081
  }, [handleControllerError, handleControllerMetric, handleControllerUserExport, journeyId, localParticipantColor, rendererPort, theme, traceparent, tracestate, transport]);
1726
- useEffect4(() => {
2082
+ useEffect5(() => {
1727
2083
  controllerRef.current?.setCapabilities({ canDraw, canClear });
1728
2084
  }, [canClear, canDraw]);
1729
- const viewport = useMemo8(() => ({ width, height, scale }), [height, scale, width]);
1730
- useEffect4(() => {
1731
- controllerRef.current?.setViewport(viewport);
2085
+ useEffect5(() => {
2086
+ if (viewport) controllerRef.current?.setViewport(viewport);
1732
2087
  }, [viewport]);
2088
+ const handleLayout = useCallback5((event) => {
2089
+ const next = { width: event.nativeEvent.layout.width, height: event.nativeEvent.layout.height };
2090
+ setLayout((current) => current.width === next.width && current.height === next.height ? current : next);
2091
+ }, []);
1733
2092
  const sourceURL = rendererURL ? rendererURLWithContext(rendererURL, { journeyId, rendererGeneration }) : null;
1734
2093
  const handleMessage = (event) => {
1735
2094
  const message = event.nativeEvent.data;
@@ -1755,20 +2114,20 @@ function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, can
1755
2114
  reloadRenderer();
1756
2115
  };
1757
2116
  if (loadError) {
1758
- return /* @__PURE__ */ jsxs10(View11, { style: [styles10.status, { backgroundColor: nativeTheme.colors.lightSurface }, style], testID, children: [
1759
- /* @__PURE__ */ jsx15(Text7, { style: [styles10.errorTitle, { color: nativeTheme.colors.lightText }], children: "Whiteboard unavailable" }),
1760
- /* @__PURE__ */ jsx15(Text7, { style: [styles10.errorMessage, { color: nativeTheme.colors.lightSubtleText }], children: loadError }),
1761
- /* @__PURE__ */ jsx15(Pressable5, { accessibilityRole: "button", onPress: retryRenderer, style: ({ pressed }) => [styles10.retryButton, { backgroundColor: nativeTheme.colors.info }, pressed && styles10.retryButtonPressed], children: /* @__PURE__ */ jsx15(Text7, { style: [styles10.retryButtonText, { color: nativeTheme.colors.onDark }], children: "Retry" }) })
2117
+ return /* @__PURE__ */ jsxs11(View12, { style: [styles11.status, { backgroundColor: nativeTheme.colors.lightSurface }, style], testID, children: [
2118
+ /* @__PURE__ */ jsx16(Text8, { style: [styles11.errorTitle, { color: nativeTheme.colors.lightText }], children: "Whiteboard unavailable" }),
2119
+ /* @__PURE__ */ jsx16(Text8, { style: [styles11.errorMessage, { color: nativeTheme.colors.lightSubtleText }], children: loadError }),
2120
+ /* @__PURE__ */ jsx16(Pressable6, { accessibilityRole: "button", onPress: retryRenderer, style: ({ pressed }) => [styles11.retryButton, { backgroundColor: nativeTheme.colors.info }, pressed && styles11.retryButtonPressed], children: /* @__PURE__ */ jsx16(Text8, { style: [styles11.retryButtonText, { color: nativeTheme.colors.onDark }], children: "Retry" }) })
1762
2121
  ] });
1763
2122
  }
1764
2123
  if (!sourceURL || !rendererURL) {
1765
- return /* @__PURE__ */ jsxs10(View11, { style: [styles10.status, { backgroundColor: nativeTheme.colors.lightSurface }, style], testID, children: [
1766
- /* @__PURE__ */ jsx15(ActivityIndicator, { color: nativeTheme.colors.info }),
1767
- /* @__PURE__ */ jsx15(Text7, { style: [styles10.loadingMessage, { color: nativeTheme.colors.lightMutedText }], children: "Loading whiteboard\u2026" })
2124
+ return /* @__PURE__ */ jsxs11(View12, { style: [styles11.status, { backgroundColor: nativeTheme.colors.lightSurface }, style], testID, children: [
2125
+ /* @__PURE__ */ jsx16(ActivityIndicator, { color: nativeTheme.colors.info }),
2126
+ /* @__PURE__ */ jsx16(Text8, { style: [styles11.loadingMessage, { color: nativeTheme.colors.lightMutedText }], children: "Loading whiteboard\u2026" })
1768
2127
  ] });
1769
2128
  }
1770
- return /* @__PURE__ */ jsxs10(View11, { style: [styles10.container, style], testID, children: [
1771
- /* @__PURE__ */ jsx15(
2129
+ return /* @__PURE__ */ jsxs11(View12, { onLayout: handleLayout, style: [styles11.container, style], testID, children: [
2130
+ /* @__PURE__ */ jsx16(
1772
2131
  WebView,
1773
2132
  {
1774
2133
  ref: webViewRef,
@@ -1788,18 +2147,18 @@ function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, can
1788
2147
  pullToRefreshEnabled: false,
1789
2148
  scrollEnabled: false,
1790
2149
  source: { uri: sourceURL },
1791
- style: [styles10.webView, { backgroundColor: nativeTheme.colors.lightSurface }],
2150
+ style: [styles11.webView, { backgroundColor: nativeTheme.colors.lightSurface }],
1792
2151
  webviewDebuggingEnabled: typeof __DEV__ !== "undefined" && __DEV__
1793
2152
  },
1794
2153
  rendererGeneration
1795
2154
  ),
1796
- compatibilityNotice ? /* @__PURE__ */ jsx15(View11, { pointerEvents: "none", style: [styles10.compatibilityNotice, { backgroundColor: nativeTheme.colors.dangerSurfaceOverlay94 }], children: /* @__PURE__ */ jsx15(Text7, { style: [styles10.compatibilityNoticeText, { color: nativeTheme.colors.onDark }], children: compatibilityNotice }) }) : null
2155
+ compatibilityNotice ? /* @__PURE__ */ jsx16(View12, { pointerEvents: "none", style: [styles11.compatibilityNotice, { backgroundColor: nativeTheme.colors.dangerSurfaceOverlay94 }], children: /* @__PURE__ */ jsx16(Text8, { style: [styles11.compatibilityNoticeText, { color: nativeTheme.colors.onDark }], children: compatibilityNotice }) }) : null
1797
2156
  ] });
1798
2157
  }
1799
2158
  function createRendererGeneration() {
1800
2159
  return globalThis.crypto?.randomUUID?.() ?? `whiteboard-${Date.now()}-${Math.random().toString(36).slice(2)}`;
1801
2160
  }
1802
- var styles10 = StyleSheet11.create({
2161
+ var styles11 = StyleSheet12.create({
1803
2162
  container: {
1804
2163
  flex: 1,
1805
2164
  overflow: "hidden"
@@ -1855,7 +2214,7 @@ var styles10 = StyleSheet11.create({
1855
2214
  });
1856
2215
 
1857
2216
  // src/components/native-space-view/SpaceWhiteboardSurface.tsx
1858
- import { jsx as jsx16 } from "react/jsx-runtime";
2217
+ import { jsx as jsx17 } from "react/jsx-runtime";
1859
2218
  function shouldRenderNativeSpaceWhiteboard(whiteboard) {
1860
2219
  return whiteboard.isOpen && whiteboard.transport !== null;
1861
2220
  }
@@ -1871,20 +2230,20 @@ function forwardNativeSpaceWhiteboardFailure(error, onMetric) {
1871
2230
  }
1872
2231
  function SpaceWhiteboardSurface({ whiteboard }) {
1873
2232
  const nativeTheme = useNativeTheme();
1874
- const handleError = useCallback5(
2233
+ const handleError = useCallback6(
1875
2234
  (error) => {
1876
2235
  forwardNativeSpaceWhiteboardFailure(error, whiteboard.onMetric);
1877
2236
  },
1878
2237
  [whiteboard.onMetric]
1879
2238
  );
1880
- const handleMetric = useCallback5(
2239
+ const handleMetric = useCallback6(
1881
2240
  (metric) => {
1882
2241
  forwardNativeSpaceWhiteboardMetric(metric, whiteboard.onMetric);
1883
2242
  },
1884
2243
  [whiteboard.onMetric]
1885
2244
  );
1886
2245
  if (!shouldRenderNativeSpaceWhiteboard(whiteboard)) return null;
1887
- return /* @__PURE__ */ jsx16(
2246
+ return /* @__PURE__ */ jsx17(
1888
2247
  EmbeddedWhiteboard,
1889
2248
  {
1890
2249
  canClear: whiteboard.canClear,
@@ -1892,7 +2251,7 @@ function SpaceWhiteboardSurface({ whiteboard }) {
1892
2251
  journeyId: whiteboard.journeyId,
1893
2252
  onError: handleError,
1894
2253
  onMetric: handleMetric,
1895
- style: styles11.surface,
2254
+ style: styles12.surface,
1896
2255
  theme: nativeTheme.colorScheme,
1897
2256
  transport: whiteboard.transport,
1898
2257
  ...whiteboard.traceparent ? { traceparent: whiteboard.traceparent } : {},
@@ -1900,7 +2259,7 @@ function SpaceWhiteboardSurface({ whiteboard }) {
1900
2259
  }
1901
2260
  );
1902
2261
  }
1903
- var styles11 = StyleSheet12.create({
2262
+ var styles12 = StyleSheet13.create({
1904
2263
  surface: {
1905
2264
  flex: 1,
1906
2265
  width: "100%"
@@ -1915,39 +2274,39 @@ import Speaker01Icon from "@hugeicons/core-free-icons/dist/esm/Speaker01Icon";
1915
2274
  import Video01Icon2 from "@hugeicons/core-free-icons/dist/esm/Video01Icon";
1916
2275
  import VideoOffIcon2 from "@hugeicons/core-free-icons/dist/esm/VideoOffIcon";
1917
2276
  import { HugeiconsIcon as HugeiconsIcon7 } from "@hugeicons/react-native";
1918
- import { useEffect as useEffect5, useState as useState5 } from "react";
1919
- import { Modal as Modal3, Platform as Platform6, Pressable as Pressable8, ScrollView, StyleSheet as StyleSheet15, Text as Text10, View as View14 } from "react-native";
2277
+ import { useEffect as useEffect6, useState as useState6 } from "react";
2278
+ import { Modal as Modal4, Platform as Platform9, Pressable as Pressable9, ScrollView as ScrollView2, StyleSheet as StyleSheet16, Text as Text11, View as View15 } from "react-native";
1920
2279
 
1921
2280
  // src/components/native-space-view/SpaceSurfacePrimitives.tsx
1922
2281
  import { HugeiconsIcon as HugeiconsIcon5 } from "@hugeicons/react-native";
1923
- import { Pressable as Pressable6, StyleSheet as StyleSheet13, Text as Text8, View as View12 } from "react-native";
1924
- import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
2282
+ import { Pressable as Pressable7, StyleSheet as StyleSheet14, Text as Text9, View as View13 } from "react-native";
2283
+ import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
1925
2284
  function SheetGrip() {
1926
- return /* @__PURE__ */ jsx17(View12, { accessibilityElementsHidden: true, style: styles12.grip });
2285
+ return /* @__PURE__ */ jsx18(View13, { accessibilityElementsHidden: true, style: styles13.grip });
1927
2286
  }
1928
2287
  function CloseButton({ label, onPress }) {
1929
- return /* @__PURE__ */ jsx17(Pressable6, { accessibilityLabel: label, accessibilityRole: "button", hitSlop: 6, onPress, style: ({ pressed }) => [styles12.closeButton, pressed && styles12.pressed], children: /* @__PURE__ */ jsx17(Text8, { style: styles12.closeGlyph, children: "\xD7" }) });
2288
+ return /* @__PURE__ */ jsx18(Pressable7, { accessibilityLabel: label, accessibilityRole: "button", hitSlop: 6, onPress, style: ({ pressed }) => [styles13.closeButton, pressed && styles13.pressed], children: /* @__PURE__ */ jsx18(Text9, { style: styles13.closeGlyph, children: "\xD7" }) });
1930
2289
  }
1931
2290
  function SurfaceHeader({ title, count, subtitle, onClose, closeLabel }) {
1932
- return /* @__PURE__ */ jsxs11(View12, { style: styles12.header, children: [
1933
- /* @__PURE__ */ jsxs11(View12, { style: styles12.headerCopy, children: [
1934
- /* @__PURE__ */ jsxs11(View12, { style: styles12.titleRow, children: [
1935
- /* @__PURE__ */ jsx17(Text8, { style: styles12.title, children: title }),
1936
- count !== void 0 ? /* @__PURE__ */ jsx17(View12, { style: styles12.countPill, children: /* @__PURE__ */ jsx17(Text8, { style: styles12.countText, children: count }) }) : null
2291
+ return /* @__PURE__ */ jsxs12(View13, { style: styles13.header, children: [
2292
+ /* @__PURE__ */ jsxs12(View13, { style: styles13.headerCopy, children: [
2293
+ /* @__PURE__ */ jsxs12(View13, { style: styles13.titleRow, children: [
2294
+ /* @__PURE__ */ jsx18(Text9, { style: styles13.title, children: title }),
2295
+ count !== void 0 ? /* @__PURE__ */ jsx18(View13, { style: styles13.countPill, children: /* @__PURE__ */ jsx18(Text9, { style: styles13.countText, children: count }) }) : null
1937
2296
  ] }),
1938
- subtitle ? /* @__PURE__ */ jsx17(Text8, { style: styles12.subtitle, children: subtitle }) : null
2297
+ subtitle ? /* @__PURE__ */ jsx18(Text9, { style: styles13.subtitle, children: subtitle }) : null
1939
2298
  ] }),
1940
- /* @__PURE__ */ jsx17(CloseButton, { label: closeLabel, onPress: onClose })
2299
+ /* @__PURE__ */ jsx18(CloseButton, { label: closeLabel, onPress: onClose })
1941
2300
  ] });
1942
2301
  }
1943
2302
  function InitialsAvatar({ name, size = 52, style }) {
1944
2303
  const color = getParticipantColor(name);
1945
- return /* @__PURE__ */ jsx17(View12, { style: [styles12.avatar, { backgroundColor: color.primary, borderRadius: size / 2, height: size, width: size }, style], children: /* @__PURE__ */ jsx17(Text8, { allowFontScaling: false, style: [styles12.avatarText, { fontSize: Math.max(16, Math.round(size * 0.34)) }], children: getParticipantInitials(name) }) });
2304
+ return /* @__PURE__ */ jsx18(View13, { style: [styles13.avatar, { backgroundColor: color.primary, borderRadius: size / 2, height: size, width: size }, style], children: /* @__PURE__ */ jsx18(Text9, { allowFontScaling: false, style: [styles13.avatarText, { fontSize: Math.max(16, Math.round(size * 0.34)) }], children: getParticipantInitials(name) }) });
1946
2305
  }
1947
2306
  function IconTile({ icon, symbol, color = Theme.colors.ink, wash = Theme.colors.surface }) {
1948
- return /* @__PURE__ */ jsx17(View12, { style: [styles12.iconTile, { backgroundColor: wash }], children: icon ? /* @__PURE__ */ jsx17(HugeiconsIcon5, { color, icon, size: 22 }) : /* @__PURE__ */ jsx17(Text8, { style: [styles12.symbol, { color }], children: symbol }) });
2307
+ return /* @__PURE__ */ jsx18(View13, { style: [styles13.iconTile, { backgroundColor: wash }], children: icon ? /* @__PURE__ */ jsx18(HugeiconsIcon5, { color, icon, size: 22 }) : /* @__PURE__ */ jsx18(Text9, { style: [styles13.symbol, { color }], children: symbol }) });
1949
2308
  }
1950
- var styles12 = StyleSheet13.create({
2309
+ var styles13 = StyleSheet14.create({
1951
2310
  grip: { alignSelf: "center", backgroundColor: Theme.colors.lineStrong, borderRadius: Theme.radius.full, height: 5, marginTop: Theme.spacing.sm, width: 48 },
1952
2311
  closeButton: { alignItems: "center", borderColor: Theme.colors.line, borderRadius: Theme.radius.full, borderWidth: 1, height: 46, justifyContent: "center", width: 46 },
1953
2312
  closeGlyph: { color: Theme.colors.ink, fontSize: 28, fontWeight: "400", lineHeight: 30 },
@@ -1968,29 +2327,29 @@ var styles12 = StyleSheet13.create({
1968
2327
  // src/components/native-space-view/AppearanceSettings.tsx
1969
2328
  import CheckmarkCircle01Icon from "@hugeicons/core-free-icons/dist/esm/CheckmarkCircle01Icon";
1970
2329
  import { HugeiconsIcon as HugeiconsIcon6 } from "@hugeicons/react-native";
1971
- import { Pressable as Pressable7, StyleSheet as StyleSheet14, Text as Text9, View as View13 } from "react-native";
1972
- import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
2330
+ import { Pressable as Pressable8, StyleSheet as StyleSheet15, Text as Text10, View as View14 } from "react-native";
2331
+ import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
1973
2332
  function AppearanceSettings() {
1974
2333
  const { appearance, setPalette, setTexture } = useNativeAppearance();
1975
2334
  const theme = useNativeTheme();
1976
- return /* @__PURE__ */ jsxs12(View13, { style: styles13.section, children: [
1977
- /* @__PURE__ */ jsx18(Text9, { style: [styles13.intro, { color: theme.colors.ink2 }], children: "Choose a complete color family, then layer in a material texture. Every combination is available on mobile." }),
1978
- ["light", "dark"].map((mode) => /* @__PURE__ */ jsx18(PaletteGroup, { mode, selectedPalette: appearance.palette, theme, onSelect: setPalette }, mode)),
1979
- /* @__PURE__ */ jsxs12(View13, { style: styles13.textureSection, children: [
1980
- /* @__PURE__ */ jsx18(Text9, { style: styles13.groupLabel, children: "Texture" }),
1981
- /* @__PURE__ */ jsx18(View13, { style: styles13.textureGrid, children: THEME_TEXTURES.map((texture) => {
2335
+ return /* @__PURE__ */ jsxs13(View14, { style: styles14.section, children: [
2336
+ /* @__PURE__ */ jsx19(Text10, { style: [styles14.intro, { color: theme.colors.ink2 }], children: "Choose a complete color family, then layer in a material texture. Every combination is available on mobile." }),
2337
+ ["light", "dark"].map((mode) => /* @__PURE__ */ jsx19(PaletteGroup, { mode, selectedPalette: appearance.palette, theme, onSelect: setPalette }, mode)),
2338
+ /* @__PURE__ */ jsxs13(View14, { style: styles14.textureSection, children: [
2339
+ /* @__PURE__ */ jsx19(Text10, { style: styles14.groupLabel, children: "Texture" }),
2340
+ /* @__PURE__ */ jsx19(View14, { style: styles14.textureGrid, children: THEME_TEXTURES.map((texture) => {
1982
2341
  const selected = texture.value === appearance.texture;
1983
- return /* @__PURE__ */ jsxs12(
1984
- Pressable7,
2342
+ return /* @__PURE__ */ jsxs13(
2343
+ Pressable8,
1985
2344
  {
1986
2345
  accessibilityLabel: `Use ${texture.label} texture`,
1987
2346
  accessibilityRole: "button",
1988
2347
  accessibilityState: { selected },
1989
2348
  onPress: () => setTexture(texture.value),
1990
- style: ({ pressed }) => [styles13.texture, { backgroundColor: theme.colors.surfaceMuted, borderColor: theme.colors.line }, selected && [styles13.selected, { borderColor: theme.colors.primary }], pressed && styles13.pressed],
2349
+ style: ({ pressed }) => [styles14.texture, { backgroundColor: theme.colors.surfaceMuted, borderColor: theme.colors.line }, selected && [styles14.selected, { borderColor: theme.colors.primary }], pressed && styles14.pressed],
1991
2350
  children: [
1992
- /* @__PURE__ */ jsx18(TexturePreview, { kind: texture.value, background: appearance.tokens.stage, foreground: appearance.tokens.textMuted }),
1993
- /* @__PURE__ */ jsx18(Text9, { numberOfLines: 1, style: [styles13.textureLabel, { color: theme.colors.ink }], children: texture.label })
2351
+ /* @__PURE__ */ jsx19(TexturePreview, { kind: texture.value, background: appearance.tokens.stage, foreground: appearance.tokens.textMuted }),
2352
+ /* @__PURE__ */ jsx19(Text10, { numberOfLines: 1, style: [styles14.textureLabel, { color: theme.colors.ink }], children: texture.label })
1994
2353
  ]
1995
2354
  },
1996
2355
  texture.value
@@ -2000,25 +2359,25 @@ function AppearanceSettings() {
2000
2359
  ] });
2001
2360
  }
2002
2361
  function PaletteGroup({ mode, selectedPalette, theme, onSelect }) {
2003
- return /* @__PURE__ */ jsxs12(View13, { style: styles13.group, children: [
2004
- /* @__PURE__ */ jsx18(Text9, { style: styles13.groupLabel, children: mode === "light" ? "Light palettes" : "Dark palettes" }),
2005
- /* @__PURE__ */ jsx18(View13, { style: styles13.paletteGrid, children: THEME_PALETTES.filter((palette) => palette.mode === mode).map((palette) => {
2362
+ return /* @__PURE__ */ jsxs13(View14, { style: styles14.group, children: [
2363
+ /* @__PURE__ */ jsx19(Text10, { style: styles14.groupLabel, children: mode === "light" ? "Light palettes" : "Dark palettes" }),
2364
+ /* @__PURE__ */ jsx19(View14, { style: styles14.paletteGrid, children: THEME_PALETTES.filter((palette) => palette.mode === mode).map((palette) => {
2006
2365
  const selected = palette.value === selectedPalette;
2007
- return /* @__PURE__ */ jsxs12(
2008
- Pressable7,
2366
+ return /* @__PURE__ */ jsxs13(
2367
+ Pressable8,
2009
2368
  {
2010
2369
  accessibilityLabel: `Use ${palette.label} palette`,
2011
2370
  accessibilityRole: "button",
2012
2371
  accessibilityState: { selected },
2013
2372
  onPress: () => onSelect(palette.value),
2014
- style: ({ pressed }) => [styles13.palette, { backgroundColor: theme.colors.surfaceMuted, borderColor: theme.colors.line }, selected && [styles13.selected, { borderColor: theme.colors.primary }], pressed && styles13.pressed],
2373
+ style: ({ pressed }) => [styles14.palette, { backgroundColor: theme.colors.surfaceMuted, borderColor: theme.colors.line }, selected && [styles14.selected, { borderColor: theme.colors.primary }], pressed && styles14.pressed],
2015
2374
  children: [
2016
- /* @__PURE__ */ jsx18(View13, { style: styles13.swatches, children: palette.swatch.map((color) => /* @__PURE__ */ jsx18(View13, { style: [styles13.swatch, { backgroundColor: color }] }, color)) }),
2017
- /* @__PURE__ */ jsxs12(View13, { style: styles13.paletteCopy, children: [
2018
- /* @__PURE__ */ jsx18(Text9, { numberOfLines: 1, style: [styles13.paletteLabel, { color: theme.colors.ink }], children: palette.label }),
2019
- /* @__PURE__ */ jsx18(Text9, { numberOfLines: 1, style: [styles13.family, { color: theme.colors.ink3 }], children: palette.family })
2375
+ /* @__PURE__ */ jsx19(View14, { style: styles14.swatches, children: palette.swatch.map((color) => /* @__PURE__ */ jsx19(View14, { style: [styles14.swatch, { backgroundColor: color }] }, color)) }),
2376
+ /* @__PURE__ */ jsxs13(View14, { style: styles14.paletteCopy, children: [
2377
+ /* @__PURE__ */ jsx19(Text10, { numberOfLines: 1, style: [styles14.paletteLabel, { color: theme.colors.ink }], children: palette.label }),
2378
+ /* @__PURE__ */ jsx19(Text10, { numberOfLines: 1, style: [styles14.family, { color: theme.colors.ink3 }], children: palette.family })
2020
2379
  ] }),
2021
- selected ? /* @__PURE__ */ jsx18(HugeiconsIcon6, { color: theme.colors.success, icon: CheckmarkCircle01Icon, size: 18 }) : null
2380
+ selected ? /* @__PURE__ */ jsx19(HugeiconsIcon6, { color: theme.colors.success, icon: CheckmarkCircle01Icon, size: 18 }) : null
2022
2381
  ]
2023
2382
  },
2024
2383
  palette.value
@@ -2027,12 +2386,12 @@ function PaletteGroup({ mode, selectedPalette, theme, onSelect }) {
2027
2386
  ] });
2028
2387
  }
2029
2388
  function TexturePreview({ background, foreground, kind }) {
2030
- return /* @__PURE__ */ jsxs12(View13, { style: [styles13.texturePreview, { backgroundColor: background }], children: [
2031
- kind === "paper" ? Array.from({ length: 11 }, (_, index) => /* @__PURE__ */ jsx18(View13, { style: [styles13.grain, { backgroundColor: foreground, left: `${index * 29 % 91}%`, top: `${index * 43 % 88}%` }] }, index)) : null,
2032
- kind === "slate" ? Array.from({ length: 5 }, (_, index) => /* @__PURE__ */ jsx18(View13, { style: [styles13.slateLine, { backgroundColor: foreground, top: 4 + index * 8 }] }, index)) : null
2389
+ return /* @__PURE__ */ jsxs13(View14, { style: [styles14.texturePreview, { backgroundColor: background }], children: [
2390
+ kind === "paper" ? Array.from({ length: 11 }, (_, index) => /* @__PURE__ */ jsx19(View14, { style: [styles14.grain, { backgroundColor: foreground, left: `${index * 29 % 91}%`, top: `${index * 43 % 88}%` }] }, index)) : null,
2391
+ kind === "slate" ? Array.from({ length: 5 }, (_, index) => /* @__PURE__ */ jsx19(View14, { style: [styles14.slateLine, { backgroundColor: foreground, top: 4 + index * 8 }] }, index)) : null
2033
2392
  ] });
2034
2393
  }
2035
- var styles13 = StyleSheet14.create({
2394
+ var styles14 = StyleSheet15.create({
2036
2395
  section: { gap: Theme.spacing.xl },
2037
2396
  intro: { color: Theme.colors.ink2, fontSize: 14, lineHeight: 20 },
2038
2397
  group: { gap: Theme.spacing.sm },
@@ -2056,82 +2415,82 @@ var styles13 = StyleSheet14.create({
2056
2415
  });
2057
2416
 
2058
2417
  // src/components/native-space-view/SettingsSheet.tsx
2059
- import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
2418
+ import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
2060
2419
  function SettingsSheet({ controller, isOpen, onClose }) {
2061
- const [tab, setTab] = useState5("devices");
2062
- useEffect5(() => {
2420
+ const [tab, setTab] = useState6("devices");
2421
+ useEffect6(() => {
2063
2422
  if (!isOpen) setTab("devices");
2064
2423
  }, [isOpen]);
2065
- return /* @__PURE__ */ jsx19(Modal3, { animationType: "slide", onRequestClose: onClose, transparent: true, visible: isOpen, children: /* @__PURE__ */ jsxs13(View14, { style: styles14.modalRoot, children: [
2066
- /* @__PURE__ */ jsx19(Pressable8, { accessibilityLabel: "Close Settings", onPress: onClose, style: styles14.backdrop }),
2067
- /* @__PURE__ */ jsxs13(View14, { style: styles14.sheet, children: [
2068
- /* @__PURE__ */ jsx19(SheetGrip, {}),
2069
- /* @__PURE__ */ jsxs13(View14, { style: styles14.header, children: [
2070
- /* @__PURE__ */ jsx19(Text10, { style: styles14.title, children: "Settings" }),
2071
- /* @__PURE__ */ jsx19(CloseButton, { label: "Close Settings", onPress: onClose })
2424
+ return /* @__PURE__ */ jsx20(Modal4, { animationType: "slide", onRequestClose: onClose, transparent: true, visible: isOpen, children: /* @__PURE__ */ jsxs14(View15, { style: styles15.modalRoot, children: [
2425
+ /* @__PURE__ */ jsx20(Pressable9, { accessibilityLabel: "Close Settings", onPress: onClose, style: styles15.backdrop }),
2426
+ /* @__PURE__ */ jsxs14(View15, { style: styles15.sheet, children: [
2427
+ /* @__PURE__ */ jsx20(SheetGrip, {}),
2428
+ /* @__PURE__ */ jsxs14(View15, { style: styles15.header, children: [
2429
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.title, children: "Settings" }),
2430
+ /* @__PURE__ */ jsx20(CloseButton, { label: "Close Settings", onPress: onClose })
2072
2431
  ] }),
2073
- /* @__PURE__ */ jsx19(View14, { accessibilityRole: "tablist", style: styles14.tabs, children: ["devices", "appearance", "space"].map((nextTab) => /* @__PURE__ */ jsx19(Pressable8, { accessibilityRole: "tab", accessibilityState: { selected: tab === nextTab }, onPress: () => setTab(nextTab), style: ({ pressed }) => [styles14.tab, tab === nextTab && styles14.tabSelected, pressed && styles14.pressed], children: /* @__PURE__ */ jsx19(Text10, { style: [styles14.tabText, tab === nextTab && styles14.tabTextSelected], children: nextTab[0].toUpperCase() + nextTab.slice(1) }) }, nextTab)) }),
2074
- /* @__PURE__ */ jsxs13(ScrollView, { contentContainerStyle: styles14.content, showsVerticalScrollIndicator: false, children: [
2075
- tab === "devices" ? /* @__PURE__ */ jsx19(DevicesSettings, { controller }) : null,
2076
- tab === "appearance" ? /* @__PURE__ */ jsx19(AppearanceSettings, {}) : null,
2077
- tab === "space" ? /* @__PURE__ */ jsx19(SpaceSettings, { controller }) : null
2432
+ /* @__PURE__ */ jsx20(View15, { accessibilityRole: "tablist", style: styles15.tabs, children: ["devices", "appearance", "space"].map((nextTab) => /* @__PURE__ */ jsx20(Pressable9, { accessibilityRole: "tab", accessibilityState: { selected: tab === nextTab }, onPress: () => setTab(nextTab), style: ({ pressed }) => [styles15.tab, tab === nextTab && styles15.tabSelected, pressed && styles15.pressed], children: /* @__PURE__ */ jsx20(Text11, { style: [styles15.tabText, tab === nextTab && styles15.tabTextSelected], children: nextTab[0].toUpperCase() + nextTab.slice(1) }) }, nextTab)) }),
2433
+ /* @__PURE__ */ jsxs14(ScrollView2, { contentContainerStyle: styles15.content, showsVerticalScrollIndicator: false, children: [
2434
+ tab === "devices" ? /* @__PURE__ */ jsx20(DevicesSettings, { controller }) : null,
2435
+ tab === "appearance" ? /* @__PURE__ */ jsx20(AppearanceSettings, {}) : null,
2436
+ tab === "space" ? /* @__PURE__ */ jsx20(SpaceSettings, { controller }) : null
2078
2437
  ] }),
2079
- /* @__PURE__ */ jsx19(Pressable8, { accessibilityRole: "button", onPress: onClose, style: ({ pressed }) => [styles14.doneButton, pressed && styles14.pressed], children: /* @__PURE__ */ jsx19(Text10, { style: styles14.doneText, children: "Done" }) })
2438
+ /* @__PURE__ */ jsx20(Pressable9, { accessibilityRole: "button", onPress: onClose, style: ({ pressed }) => [styles15.doneButton, pressed && styles15.pressed], children: /* @__PURE__ */ jsx20(Text11, { style: styles15.doneText, children: "Done" }) })
2080
2439
  ] })
2081
2440
  ] }) });
2082
2441
  }
2083
2442
  function DevicesSettings({ controller }) {
2084
2443
  const microphoneEnabled = !controller.isMuted;
2085
2444
  const cameraEnabled = !controller.isCameraOff;
2086
- return /* @__PURE__ */ jsxs13(View14, { style: styles14.section, children: [
2087
- /* @__PURE__ */ jsx19(Text10, { style: styles14.sectionIntro, children: "Use the controls below to set what you share in this Episode." }),
2088
- /* @__PURE__ */ jsx19(DeviceControl, { disabled: controller.simulatorMediaDisabled, enabled: microphoneEnabled, icon: microphoneEnabled ? Mic01Icon2 : MicOff01Icon4, label: "Microphone", onPress: controller.toggleAudio, value: microphoneEnabled ? "On" : "Off" }),
2089
- /* @__PURE__ */ jsx19(DeviceControl, { disabled: controller.simulatorMediaDisabled, enabled: cameraEnabled, icon: cameraEnabled ? Video01Icon2 : VideoOffIcon2, label: "Camera", onPress: controller.toggleVideo, value: cameraEnabled ? "On" : "Off" }),
2090
- /* @__PURE__ */ jsxs13(View14, { style: styles14.deviceRow, children: [
2091
- /* @__PURE__ */ jsx19(IconTile, { icon: Speaker01Icon }),
2092
- /* @__PURE__ */ jsxs13(View14, { style: styles14.rowCopy, children: [
2093
- /* @__PURE__ */ jsx19(Text10, { style: styles14.rowLabel, children: "Speaker" }),
2094
- /* @__PURE__ */ jsx19(Text10, { style: styles14.rowMeta, children: "System audio output" })
2445
+ return /* @__PURE__ */ jsxs14(View15, { style: styles15.section, children: [
2446
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.sectionIntro, children: "Use the controls below to set what you share in this Episode." }),
2447
+ /* @__PURE__ */ jsx20(DeviceControl, { disabled: controller.simulatorMediaDisabled, enabled: microphoneEnabled, icon: microphoneEnabled ? Mic01Icon2 : MicOff01Icon4, label: "Microphone", onPress: controller.toggleAudio, value: microphoneEnabled ? "On" : "Off" }),
2448
+ /* @__PURE__ */ jsx20(DeviceControl, { disabled: controller.simulatorMediaDisabled, enabled: cameraEnabled, icon: cameraEnabled ? Video01Icon2 : VideoOffIcon2, label: "Camera", onPress: controller.toggleVideo, value: cameraEnabled ? "On" : "Off" }),
2449
+ /* @__PURE__ */ jsxs14(View15, { style: styles15.deviceRow, children: [
2450
+ /* @__PURE__ */ jsx20(IconTile, { icon: Speaker01Icon }),
2451
+ /* @__PURE__ */ jsxs14(View15, { style: styles15.rowCopy, children: [
2452
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.rowLabel, children: "Speaker" }),
2453
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.rowMeta, children: "System audio output" })
2095
2454
  ] }),
2096
- /* @__PURE__ */ jsx19(Text10, { style: styles14.rowValue, children: "Automatic" })
2455
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.rowValue, children: "Automatic" })
2097
2456
  ] }),
2098
- /* @__PURE__ */ jsxs13(View14, { style: styles14.readyCard, children: [
2099
- /* @__PURE__ */ jsx19(HugeiconsIcon7, { color: Theme.colors.success, icon: CheckmarkCircle01Icon2, size: 22 }),
2100
- /* @__PURE__ */ jsx19(Text10, { style: styles14.readyText, children: controller.simulatorMediaDisabled ? "Device controls are unavailable here" : "Devices are ready" })
2457
+ /* @__PURE__ */ jsxs14(View15, { style: styles15.readyCard, children: [
2458
+ /* @__PURE__ */ jsx20(HugeiconsIcon7, { color: Theme.colors.success, icon: CheckmarkCircle01Icon2, size: 22 }),
2459
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.readyText, children: controller.simulatorMediaDisabled ? "Device controls are unavailable here" : "Devices are ready" })
2101
2460
  ] })
2102
2461
  ] });
2103
2462
  }
2104
2463
  function DeviceControl({ disabled, enabled, icon, label, onPress, value }) {
2105
- return /* @__PURE__ */ jsxs13(Pressable8, { accessibilityLabel: `${label} ${value}`, accessibilityRole: "button", disabled, onPress, style: ({ pressed }) => [styles14.deviceRow, disabled && styles14.disabled, pressed && styles14.pressed], children: [
2106
- /* @__PURE__ */ jsx19(IconTile, { icon, color: enabled ? Theme.colors.ink : Theme.colors.error, wash: enabled ? Theme.colors.surface : Theme.colors.washPink }),
2107
- /* @__PURE__ */ jsxs13(View14, { style: styles14.rowCopy, children: [
2108
- /* @__PURE__ */ jsx19(Text10, { style: styles14.rowLabel, children: label }),
2109
- /* @__PURE__ */ jsx19(Text10, { style: styles14.rowMeta, children: disabled ? "Unavailable on this device" : "Tap to change state" })
2464
+ return /* @__PURE__ */ jsxs14(Pressable9, { accessibilityLabel: `${label} ${value}`, accessibilityRole: "button", disabled, onPress, style: ({ pressed }) => [styles15.deviceRow, disabled && styles15.disabled, pressed && styles15.pressed], children: [
2465
+ /* @__PURE__ */ jsx20(IconTile, { icon, color: enabled ? Theme.colors.ink : Theme.colors.error, wash: enabled ? Theme.colors.surface : Theme.colors.washPink }),
2466
+ /* @__PURE__ */ jsxs14(View15, { style: styles15.rowCopy, children: [
2467
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.rowLabel, children: label }),
2468
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.rowMeta, children: disabled ? "Unavailable on this device" : "Tap to change state" })
2110
2469
  ] }),
2111
- /* @__PURE__ */ jsx19(Text10, { style: [styles14.rowValue, !enabled && styles14.valueOff], children: value })
2470
+ /* @__PURE__ */ jsx20(Text11, { style: [styles15.rowValue, !enabled && styles15.valueOff], children: value })
2112
2471
  ] });
2113
2472
  }
2114
2473
  function SpaceSettings({ controller }) {
2115
- return /* @__PURE__ */ jsxs13(View14, { style: styles14.section, children: [
2116
- /* @__PURE__ */ jsx19(Text10, { style: styles14.sectionIntro, children: "Canonical information about this Space and its current Episode." }),
2117
- /* @__PURE__ */ jsx19(InfoRow, { label: "Space", value: "Current Space" }),
2118
- /* @__PURE__ */ jsx19(InfoRow, { label: "Episode", value: controller.formattedDuration }),
2119
- /* @__PURE__ */ jsx19(InfoRow, { label: "People", value: String(controller.participantCount) }),
2120
- /* @__PURE__ */ jsxs13(View14, { style: styles14.infoCard, children: [
2121
- /* @__PURE__ */ jsx19(Text10, { style: styles14.infoTitle, children: "Space content stays here" }),
2122
- /* @__PURE__ */ jsx19(Text10, { style: styles14.infoText, children: "Chat and Board content belong to this Space and remain available across Episodes." })
2474
+ return /* @__PURE__ */ jsxs14(View15, { style: styles15.section, children: [
2475
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.sectionIntro, children: "Canonical information about this Space and its current Episode." }),
2476
+ /* @__PURE__ */ jsx20(InfoRow, { label: "Space", value: "Current Space" }),
2477
+ /* @__PURE__ */ jsx20(InfoRow, { label: "Episode", value: controller.formattedDuration }),
2478
+ /* @__PURE__ */ jsx20(InfoRow, { label: "People", value: String(controller.participantCount) }),
2479
+ /* @__PURE__ */ jsxs14(View15, { style: styles15.infoCard, children: [
2480
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.infoTitle, children: "Space content stays here" }),
2481
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.infoText, children: "Chat and Board content belong to this Space and remain available across Episodes." })
2123
2482
  ] })
2124
2483
  ] });
2125
2484
  }
2126
2485
  function InfoRow({ label, value }) {
2127
- return /* @__PURE__ */ jsxs13(View14, { style: styles14.infoRow, children: [
2128
- /* @__PURE__ */ jsx19(Text10, { style: styles14.rowLabel, children: label }),
2129
- /* @__PURE__ */ jsx19(Text10, { numberOfLines: 1, style: styles14.infoValue, children: value || "\u2014" })
2486
+ return /* @__PURE__ */ jsxs14(View15, { style: styles15.infoRow, children: [
2487
+ /* @__PURE__ */ jsx20(Text11, { style: styles15.rowLabel, children: label }),
2488
+ /* @__PURE__ */ jsx20(Text11, { numberOfLines: 1, style: styles15.infoValue, children: value || "\u2014" })
2130
2489
  ] });
2131
2490
  }
2132
- var styles14 = StyleSheet15.create({
2491
+ var styles15 = StyleSheet16.create({
2133
2492
  modalRoot: { flex: 1, justifyContent: "flex-end" },
2134
- backdrop: { ...StyleSheet15.absoluteFillObject, backgroundColor: Theme.colors.darkOverlay22 },
2493
+ backdrop: { ...StyleSheet16.absoluteFillObject, backgroundColor: Theme.colors.darkOverlay22 },
2135
2494
  sheet: {
2136
2495
  backgroundColor: Theme.colors.surface,
2137
2496
  borderColor: Theme.colors.line,
@@ -2141,7 +2500,7 @@ var styles14 = StyleSheet15.create({
2141
2500
  flex: 1,
2142
2501
  marginTop: 72,
2143
2502
  overflow: "hidden",
2144
- paddingBottom: Platform6.OS === "ios" ? Theme.spacing.md : Theme.spacing.xs,
2503
+ paddingBottom: Platform9.OS === "ios" ? Theme.spacing.md : Theme.spacing.xs,
2145
2504
  shadowColor: Theme.colors.ink,
2146
2505
  shadowOffset: { height: -8, width: 0 },
2147
2506
  shadowOpacity: 0.12,
@@ -2177,14 +2536,14 @@ var styles14 = StyleSheet15.create({
2177
2536
  });
2178
2537
 
2179
2538
  // src/components/native-space-view/SpacePanelSheet.tsx
2180
- import { Modal as Modal5, Platform as Platform9, Pressable as Pressable12, SafeAreaView, StyleSheet as StyleSheet19, View as View18 } from "react-native";
2539
+ import { Modal as Modal6, Platform as Platform12, Pressable as Pressable14, SafeAreaView, StyleSheet as StyleSheet21, View as View20 } from "react-native";
2181
2540
 
2182
2541
  // src/components/native-space-view/SpaceChatSheet.tsx
2183
2542
  import Message01Icon from "@hugeicons/core-free-icons/dist/esm/Message01Icon";
2184
2543
  import Navigation03Icon from "@hugeicons/core-free-icons/dist/esm/Navigation03Icon";
2185
2544
  import { HugeiconsIcon as HugeiconsIcon8 } from "@hugeicons/react-native";
2186
- import { useMemo as useMemo9 } from "react";
2187
- import { FlatList as FlatList3, KeyboardAvoidingView, Platform as Platform7, Pressable as Pressable9, StyleSheet as StyleSheet16, Text as Text11, TextInput, View as View15 } from "react-native";
2545
+ import { useMemo as useMemo10 } from "react";
2546
+ import { FlatList as FlatList3, KeyboardAvoidingView as KeyboardAvoidingView2, Platform as Platform10, Pressable as Pressable11, StyleSheet as StyleSheet18, Text as Text13, TextInput as TextInput2, View as View17 } from "react-native";
2188
2547
 
2189
2548
  // src/components/native-space-view/space-progressive-surface-helpers.ts
2190
2549
  function buildParticipantActionDescriptors(availability) {
@@ -2204,54 +2563,146 @@ function formatChatTimestamp(timestamp) {
2204
2563
  return new Date(timestamp).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
2205
2564
  }
2206
2565
 
2566
+ // src/components/native-space-view/SpaceChatAttachment.tsx
2567
+ import { useEffect as useEffect7, useState as useState7 } from "react";
2568
+ import { Image as Image4, Pressable as Pressable10, StyleSheet as StyleSheet17, Text as Text12, View as View16 } from "react-native";
2569
+ import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
2570
+ function SpaceChatAttachment({ attachment, isLocal, onOpen, resolveUrl }) {
2571
+ const isImage = attachment.mimeType.startsWith("image/");
2572
+ const [previewUrl, setPreviewUrl] = useState7(null);
2573
+ const [previewFailed, setPreviewFailed] = useState7(false);
2574
+ const [retryGeneration, setRetryGeneration] = useState7(0);
2575
+ useEffect7(() => {
2576
+ if (!isImage || previewUrl || previewFailed) return;
2577
+ let cancelled = false;
2578
+ void resolveUrl(attachment.attachmentId).then(
2579
+ (url) => {
2580
+ if (cancelled) return;
2581
+ if (!url) {
2582
+ reportAttachmentPreviewFailure(attachment.attachmentId, "resolve");
2583
+ setPreviewFailed(true);
2584
+ return;
2585
+ }
2586
+ setPreviewUrl(url);
2587
+ setPreviewFailed(false);
2588
+ },
2589
+ () => {
2590
+ if (cancelled) return;
2591
+ reportAttachmentPreviewFailure(attachment.attachmentId, "resolve");
2592
+ setPreviewFailed(true);
2593
+ }
2594
+ );
2595
+ return () => {
2596
+ cancelled = true;
2597
+ };
2598
+ }, [attachment.attachmentId, isImage, previewFailed, previewUrl, resolveUrl, retryGeneration]);
2599
+ if (!isImage) {
2600
+ return /* @__PURE__ */ jsx21(Pressable10, { accessibilityRole: "link", onPress: () => onOpen(attachment.attachmentId), style: ({ pressed }) => [styles16.attachmentLink, pressed && styles16.pressed], children: /* @__PURE__ */ jsx21(Text12, { numberOfLines: 1, style: [styles16.attachment, isLocal && styles16.localText], children: attachment.fileName }) });
2601
+ }
2602
+ if (previewFailed) {
2603
+ return /* @__PURE__ */ jsxs15(View16, { style: styles16.previewError, children: [
2604
+ /* @__PURE__ */ jsx21(Text12, { accessibilityLiveRegion: "polite", style: [styles16.previewErrorText, isLocal && styles16.localText], children: "Image preview unavailable" }),
2605
+ /* @__PURE__ */ jsx21(
2606
+ Pressable10,
2607
+ {
2608
+ accessibilityLabel: `Retry preview for ${attachment.fileName}`,
2609
+ accessibilityRole: "button",
2610
+ style: styles16.retryButton,
2611
+ onPress: () => {
2612
+ setPreviewFailed(false);
2613
+ setPreviewUrl(null);
2614
+ setRetryGeneration((current) => current + 1);
2615
+ },
2616
+ children: /* @__PURE__ */ jsx21(Text12, { style: [styles16.retry, isLocal && styles16.localText], children: "Retry preview" })
2617
+ }
2618
+ )
2619
+ ] });
2620
+ }
2621
+ if (!previewUrl) return /* @__PURE__ */ jsxs15(Text12, { style: [styles16.previewLoading, isLocal && styles16.localText], children: [
2622
+ "Loading ",
2623
+ attachment.fileName,
2624
+ "\u2026"
2625
+ ] });
2626
+ return /* @__PURE__ */ jsx21(Pressable10, { accessibilityLabel: `Open ${attachment.fileName}`, accessibilityRole: "imagebutton", onPress: () => onOpen(attachment.attachmentId), style: ({ pressed }) => [styles16.imagePreviewButton, pressed && styles16.pressed], children: /* @__PURE__ */ jsx21(
2627
+ Image4,
2628
+ {
2629
+ accessibilityLabel: attachment.fileName,
2630
+ onError: () => {
2631
+ reportAttachmentPreviewFailure(attachment.attachmentId, "render");
2632
+ setPreviewFailed(true);
2633
+ setPreviewUrl(null);
2634
+ },
2635
+ resizeMode: "cover",
2636
+ source: { uri: previewUrl },
2637
+ style: styles16.imagePreview
2638
+ }
2639
+ ) });
2640
+ }
2641
+ function reportAttachmentPreviewFailure(attachmentId, operation) {
2642
+ console.warn("Chat attachment preview unavailable.", { attachmentId, operation });
2643
+ }
2644
+ var styles16 = StyleSheet17.create({
2645
+ attachmentLink: { justifyContent: "center", marginTop: 4, maxWidth: "100%", minHeight: 32 },
2646
+ attachment: { color: Theme.colors.information, fontSize: 14 },
2647
+ imagePreviewButton: { borderRadius: Theme.radius.sm, marginTop: Theme.spacing.sm, maxWidth: "100%", overflow: "hidden" },
2648
+ imagePreview: { height: 160, width: 240 },
2649
+ previewLoading: { color: Theme.colors.ink2, fontSize: 13, marginTop: Theme.spacing.sm },
2650
+ previewError: { borderColor: Theme.colors.line, borderRadius: Theme.radius.sm, borderWidth: 1, marginTop: Theme.spacing.sm, width: 240, maxWidth: "100%", minHeight: 160, justifyContent: "center", alignItems: "center", padding: Theme.spacing.md },
2651
+ previewErrorText: { color: Theme.colors.ink2, fontSize: 13 },
2652
+ retryButton: { minHeight: 44, justifyContent: "center", paddingHorizontal: Theme.spacing.sm },
2653
+ retry: { color: Theme.colors.information, fontSize: 13, fontWeight: "700", marginTop: 6 },
2654
+ localText: { color: Theme.colors.surface },
2655
+ pressed: { opacity: 0.72, transform: [{ scale: 0.98 }] }
2656
+ });
2657
+
2207
2658
  // src/components/native-space-view/SpaceChatSheet.tsx
2208
- import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
2659
+ import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
2209
2660
  function SpaceChatSheet({ controller }) {
2210
2661
  const localParticipantId = controller.participants.localParticipant?.id ?? null;
2211
2662
  const sendDisabled = !controller.chatDraft.trim() && controller.chatAttachments.length === 0 || controller.chatAttachmentUploading;
2212
- const messages = useMemo9(() => controller.chat.messages, [controller.chat.messages]);
2213
- return /* @__PURE__ */ jsxs14(View15, { style: styles15.content, children: [
2214
- controller.chat.hasMore ? /* @__PURE__ */ jsx20(Pressable9, { accessibilityRole: "button", disabled: controller.chat.isLoadingOlder, onPress: () => void controller.chat.loadOlderMessages(), style: ({ pressed }) => [styles15.loadOlder, pressed && styles15.pressed], children: /* @__PURE__ */ jsx20(Text11, { style: styles15.loadOlderText, children: controller.chat.isLoadingOlder ? "Loading\u2026" : "Load earlier messages" }) }) : null,
2215
- /* @__PURE__ */ jsx20(
2663
+ const messages = useMemo10(() => controller.chat.messages, [controller.chat.messages]);
2664
+ return /* @__PURE__ */ jsxs16(View17, { style: styles17.content, children: [
2665
+ controller.chat.hasMore ? /* @__PURE__ */ jsx22(Pressable11, { accessibilityRole: "button", disabled: controller.chat.isLoadingOlder, onPress: () => void controller.chat.loadOlderMessages(), style: ({ pressed }) => [styles17.loadOlder, pressed && styles17.pressed], children: /* @__PURE__ */ jsx22(Text13, { style: styles17.loadOlderText, children: controller.chat.isLoadingOlder ? "Loading\u2026" : "Load earlier messages" }) }) : null,
2666
+ /* @__PURE__ */ jsx22(
2216
2667
  FlatList3,
2217
2668
  {
2218
2669
  accessibilityLabel: "Chat messages",
2219
- contentContainerStyle: styles15.messageList,
2670
+ contentContainerStyle: styles17.messageList,
2220
2671
  data: messages,
2221
2672
  keyExtractor: (message) => message.id,
2222
- ListEmptyComponent: /* @__PURE__ */ jsx20(EmptyChat, {}),
2673
+ ListEmptyComponent: /* @__PURE__ */ jsx22(EmptyChat, {}),
2223
2674
  onViewableItemsChanged: ({ viewableItems }) => {
2224
2675
  const sequence = viewableItems.at(-1)?.item.sequence;
2225
2676
  if (sequence) controller.markChatMessageVisible(sequence);
2226
2677
  },
2227
- renderItem: ({ item }) => /* @__PURE__ */ jsx20(ChatMessage, { isLocal: item.senderId === localParticipantId, message: item, onOpenAttachment: controller.openChatAttachment }),
2678
+ renderItem: ({ item }) => /* @__PURE__ */ jsx22(ChatMessage, { isLocal: item.senderId === localParticipantId, message: item, onOpenAttachment: controller.openChatAttachment, resolveAttachmentUrl: controller.resolveChatAttachmentUrl }),
2228
2679
  showsVerticalScrollIndicator: false
2229
2680
  }
2230
2681
  ),
2231
- controller.chat.pendingMessages.map((message) => /* @__PURE__ */ jsxs14(View15, { style: styles15.pendingMessage, children: [
2232
- /* @__PURE__ */ jsx20(Text11, { style: styles15.pendingText, children: message.text }),
2233
- /* @__PURE__ */ jsx20(Text11, { style: styles15.pendingMeta, children: message.state === "sending" ? "Sending\u2026" : message.error?.message ?? "Send failed" }),
2234
- message.state === "failed" ? /* @__PURE__ */ jsx20(Pressable9, { accessibilityRole: "button", onPress: () => void controller.chat.retryMessage(message.clientMessageId), children: /* @__PURE__ */ jsx20(Text11, { style: styles15.retry, children: "Retry" }) }) : null
2682
+ controller.chat.pendingMessages.map((message) => /* @__PURE__ */ jsxs16(View17, { style: styles17.pendingMessage, children: [
2683
+ /* @__PURE__ */ jsx22(Text13, { style: styles17.pendingText, children: message.text }),
2684
+ /* @__PURE__ */ jsx22(Text13, { style: styles17.pendingMeta, children: message.state === "sending" ? "Sending\u2026" : message.error?.message ?? "Send failed" }),
2685
+ message.state === "failed" ? /* @__PURE__ */ jsx22(Pressable11, { accessibilityRole: "button", onPress: () => void controller.chat.retryMessage(message.clientMessageId), children: /* @__PURE__ */ jsx22(Text13, { style: styles17.retry, children: "Retry" }) }) : null
2235
2686
  ] }, message.clientMessageId)),
2236
- controller.chatAttachments.length ? /* @__PURE__ */ jsx20(View15, { accessibilityLabel: "Selected attachments", style: styles15.selectedAttachments, children: controller.chatAttachments.map((attachment, index) => /* @__PURE__ */ jsxs14(View15, { style: styles15.selectedAttachment, children: [
2237
- /* @__PURE__ */ jsx20(Text11, { numberOfLines: 1, style: styles15.selectedAttachmentText, children: attachment.fileName }),
2238
- /* @__PURE__ */ jsx20(Pressable9, { accessibilityLabel: `Remove ${attachment.fileName}`, accessibilityRole: "button", disabled: controller.chatAttachmentUploading, onPress: () => controller.removeChatAttachment(index), children: /* @__PURE__ */ jsx20(Text11, { style: styles15.removeAttachment, children: "Remove" }) })
2687
+ controller.chatAttachments.length ? /* @__PURE__ */ jsx22(View17, { accessibilityLabel: "Selected attachments", style: styles17.selectedAttachments, children: controller.chatAttachments.map((attachment, index) => /* @__PURE__ */ jsxs16(View17, { style: styles17.selectedAttachment, children: [
2688
+ /* @__PURE__ */ jsx22(Text13, { numberOfLines: 1, style: styles17.selectedAttachmentText, children: attachment.fileName }),
2689
+ /* @__PURE__ */ jsx22(Pressable11, { accessibilityLabel: `Remove ${attachment.fileName}`, accessibilityRole: "button", disabled: controller.chatAttachmentUploading, onPress: () => controller.removeChatAttachment(index), children: /* @__PURE__ */ jsx22(Text13, { style: styles17.removeAttachment, children: "Remove" }) })
2239
2690
  ] }, `${attachment.fileName}-${index}`)) }) : null,
2240
- controller.chatAttachmentError ? /* @__PURE__ */ jsx20(Text11, { accessibilityLiveRegion: "polite", style: styles15.attachmentError, children: controller.chatAttachmentError }) : null,
2241
- /* @__PURE__ */ jsx20(KeyboardAvoidingView, { behavior: Platform7.OS === "ios" ? "padding" : void 0, keyboardVerticalOffset: Platform7.OS === "ios" ? 12 : 0, children: /* @__PURE__ */ jsxs14(View15, { style: styles15.composer, children: [
2242
- controller.canPickChatFiles ? /* @__PURE__ */ jsx20(
2243
- Pressable9,
2691
+ controller.chatAttachmentError ? /* @__PURE__ */ jsx22(Text13, { accessibilityLiveRegion: "polite", style: styles17.attachmentError, children: controller.chatAttachmentError }) : null,
2692
+ /* @__PURE__ */ jsx22(KeyboardAvoidingView2, { behavior: Platform10.OS === "ios" ? "padding" : void 0, keyboardVerticalOffset: Platform10.OS === "ios" ? 12 : 0, children: /* @__PURE__ */ jsxs16(View17, { style: styles17.composer, children: [
2693
+ controller.canPickChatFiles ? /* @__PURE__ */ jsx22(
2694
+ Pressable11,
2244
2695
  {
2245
2696
  accessibilityLabel: "Attach file",
2246
2697
  accessibilityRole: "button",
2247
2698
  disabled: controller.chatAttachmentPicking || controller.chatAttachmentUploading,
2248
2699
  onPress: () => void controller.pickChatFiles(),
2249
- style: ({ pressed }) => [styles15.composerButton, (controller.chatAttachmentPicking || controller.chatAttachmentUploading) && styles15.sendDisabled, pressed && styles15.pressed],
2250
- children: /* @__PURE__ */ jsx20(Text11, { style: styles15.composerButtonText, children: controller.chatAttachmentPicking ? "Choosing\u2026" : "Attach" })
2700
+ style: ({ pressed }) => [styles17.composerButton, (controller.chatAttachmentPicking || controller.chatAttachmentUploading) && styles17.sendDisabled, pressed && styles17.pressed],
2701
+ children: /* @__PURE__ */ jsx22(Text13, { style: styles17.composerButtonText, children: controller.chatAttachmentPicking ? "Choosing\u2026" : "Attach" })
2251
2702
  }
2252
2703
  ) : null,
2253
- /* @__PURE__ */ jsx20(
2254
- TextInput,
2704
+ /* @__PURE__ */ jsx22(
2705
+ TextInput2,
2255
2706
  {
2256
2707
  accessibilityLabel: "Message the Space",
2257
2708
  editable: !controller.chatAttachmentUploading,
@@ -2260,41 +2711,46 @@ function SpaceChatSheet({ controller }) {
2260
2711
  onSubmitEditing: controller.sendChatMessage,
2261
2712
  placeholder: "Message the Space",
2262
2713
  placeholderTextColor: Theme.colors.placeholder,
2263
- style: styles15.input,
2714
+ style: styles17.input,
2264
2715
  value: controller.chatDraft
2265
2716
  }
2266
2717
  ),
2267
- /* @__PURE__ */ jsx20(Pressable9, { accessibilityLabel: "Send message", accessibilityRole: "button", disabled: sendDisabled, onPress: controller.sendChatMessage, style: ({ pressed }) => [styles15.sendButton, sendDisabled && styles15.sendDisabled, pressed && styles15.pressed], children: controller.chatAttachmentUploading ? /* @__PURE__ */ jsx20(Text11, { style: styles15.uploadingText, children: "\u2026" }) : /* @__PURE__ */ jsx20(HugeiconsIcon8, { color: Theme.colors.primaryForeground, icon: Navigation03Icon, size: 21 }) })
2718
+ /* @__PURE__ */ jsx22(Pressable11, { accessibilityLabel: "Send message", accessibilityRole: "button", disabled: sendDisabled, onPress: controller.sendChatMessage, style: ({ pressed }) => [styles17.sendButton, sendDisabled && styles17.sendDisabled, pressed && styles17.pressed], children: controller.chatAttachmentUploading ? /* @__PURE__ */ jsx22(Text13, { style: styles17.uploadingText, children: "\u2026" }) : /* @__PURE__ */ jsx22(HugeiconsIcon8, { color: Theme.colors.primaryForeground, icon: Navigation03Icon, size: 21 }) })
2268
2719
  ] }) })
2269
2720
  ] });
2270
2721
  }
2271
- function ChatMessage({ isLocal, message, onOpenAttachment }) {
2722
+ function ChatMessage({
2723
+ isLocal,
2724
+ message,
2725
+ onOpenAttachment,
2726
+ resolveAttachmentUrl
2727
+ }) {
2272
2728
  const timestamp = formatChatTimestamp(message.timestamp);
2273
- return /* @__PURE__ */ jsxs14(View15, { style: [styles15.messageRow, isLocal && styles15.messageRowLocal], children: [
2274
- !isLocal ? /* @__PURE__ */ jsx20(InitialsAvatar, { name: message.senderName, size: 42 }) : null,
2275
- /* @__PURE__ */ jsxs14(View15, { style: [styles15.messageCopy, isLocal && styles15.messageCopyLocal], children: [
2276
- /* @__PURE__ */ jsx20(Text11, { style: [styles15.sender, isLocal && styles15.senderLocal], children: isLocal ? `${message.senderName} (You)` : message.senderName }),
2277
- /* @__PURE__ */ jsxs14(View15, { style: [styles15.bubble, isLocal ? styles15.localBubble : styles15.remoteBubble], children: [
2278
- message.text ? /* @__PURE__ */ jsx20(Text11, { style: [styles15.messageText, isLocal && styles15.localMessageText], children: message.text }) : null,
2279
- message.attachments.map((attachment) => /* @__PURE__ */ jsx20(Pressable9, { accessibilityRole: "link", onPress: () => onOpenAttachment(attachment.attachmentId), style: ({ pressed }) => [styles15.attachmentLink, pressed && styles15.pressed], children: /* @__PURE__ */ jsx20(Text11, { numberOfLines: 1, style: [styles15.attachment, isLocal && styles15.localMessageText], children: attachment.fileName }) }, attachment.attachmentId))
2729
+ return /* @__PURE__ */ jsxs16(View17, { style: [styles17.messageRow, isLocal && styles17.messageRowLocal], children: [
2730
+ !isLocal ? /* @__PURE__ */ jsx22(InitialsAvatar, { name: message.senderName, size: 42 }) : null,
2731
+ /* @__PURE__ */ jsxs16(View17, { style: [styles17.messageCopy, isLocal && styles17.messageCopyLocal], children: [
2732
+ /* @__PURE__ */ jsx22(Text13, { style: [styles17.sender, isLocal && styles17.senderLocal], children: isLocal ? `${message.senderName} (You)` : message.senderName }),
2733
+ /* @__PURE__ */ jsxs16(View17, { style: [styles17.bubble, isLocal ? styles17.localBubble : styles17.remoteBubble], children: [
2734
+ message.text ? /* @__PURE__ */ jsx22(Text13, { style: [styles17.messageText, isLocal && styles17.localMessageText], children: message.text }) : null,
2735
+ message.attachments.map((attachment) => /* @__PURE__ */ jsx22(SpaceChatAttachment, { attachment, isLocal, onOpen: onOpenAttachment, resolveUrl: resolveAttachmentUrl }, attachment.attachmentId))
2280
2736
  ] }),
2281
- /* @__PURE__ */ jsx20(Text11, { style: [styles15.timestamp, isLocal && styles15.timestampLocal], children: timestamp }),
2282
- message.readBy.length ? /* @__PURE__ */ jsxs14(Text11, { style: [styles15.readBy, isLocal && styles15.timestampLocal], children: [
2737
+ /* @__PURE__ */ jsx22(Text13, { style: [styles17.timestamp, isLocal && styles17.timestampLocal], children: timestamp }),
2738
+ message.readBy.length ? /* @__PURE__ */ jsxs16(Text13, { style: [styles17.readBy, isLocal && styles17.timestampLocal], children: [
2283
2739
  "Read by ",
2284
2740
  message.readBy.map((reader) => reader.displayName).join(", ")
2285
2741
  ] }) : null
2286
2742
  ] }),
2287
- isLocal ? /* @__PURE__ */ jsx20(InitialsAvatar, { name: message.senderName, size: 42 }) : null
2743
+ isLocal ? /* @__PURE__ */ jsx22(InitialsAvatar, { name: message.senderName, size: 42 }) : null
2288
2744
  ] });
2289
2745
  }
2290
2746
  function EmptyChat() {
2291
- return /* @__PURE__ */ jsxs14(View15, { style: styles15.emptyState, children: [
2292
- /* @__PURE__ */ jsx20(View15, { style: styles15.emptyIcon, children: /* @__PURE__ */ jsx20(HugeiconsIcon8, { color: Theme.colors.ink2, icon: Message01Icon, size: 26 }) }),
2293
- /* @__PURE__ */ jsx20(Text11, { style: styles15.emptyTitle, children: "No messages yet" }),
2294
- /* @__PURE__ */ jsx20(Text11, { style: styles15.emptyText, children: "Send a message to start the conversation." })
2747
+ return /* @__PURE__ */ jsxs16(View17, { style: styles17.emptyState, children: [
2748
+ /* @__PURE__ */ jsx22(View17, { style: styles17.emptyIcon, children: /* @__PURE__ */ jsx22(HugeiconsIcon8, { color: Theme.colors.ink2, icon: Message01Icon, size: 26 }) }),
2749
+ /* @__PURE__ */ jsx22(Text13, { style: styles17.emptyTitle, children: "No messages yet" }),
2750
+ /* @__PURE__ */ jsx22(Text13, { style: styles17.emptyText, children: "Send a message to start the conversation." })
2295
2751
  ] });
2296
2752
  }
2297
- var styles15 = StyleSheet16.create({
2753
+ var styles17 = StyleSheet18.create({
2298
2754
  content: { flex: 1, minHeight: 0 },
2299
2755
  loadOlder: { alignSelf: "center", minHeight: 44, paddingHorizontal: Theme.spacing.md, paddingVertical: Theme.spacing.sm, justifyContent: "center" },
2300
2756
  loadOlderText: { color: Theme.colors.information, fontSize: 14, fontWeight: "700" },
@@ -2310,8 +2766,6 @@ var styles15 = StyleSheet16.create({
2310
2766
  localBubble: { backgroundColor: Theme.colors.ink, borderColor: Theme.colors.ink, borderTopRightRadius: 5 },
2311
2767
  messageText: { color: Theme.colors.ink, fontSize: 17, lineHeight: 24 },
2312
2768
  localMessageText: { color: Theme.colors.surface },
2313
- attachmentLink: { justifyContent: "center", marginTop: 4, maxWidth: "100%", minHeight: 32 },
2314
- attachment: { color: Theme.colors.information, fontSize: 14 },
2315
2769
  timestamp: { color: Theme.colors.ink3, fontSize: 12, marginTop: 5, paddingHorizontal: 4 },
2316
2770
  timestampLocal: { textAlign: "right" },
2317
2771
  readBy: { color: Theme.colors.ink3, fontSize: 11, marginTop: 3, paddingHorizontal: 4 },
@@ -2345,8 +2799,8 @@ import MoreHorizontalIcon2 from "@hugeicons/core-free-icons/dist/esm/MoreHorizon
2345
2799
  import Video01Icon4 from "@hugeicons/core-free-icons/dist/esm/Video01Icon";
2346
2800
  import VideoOffIcon3 from "@hugeicons/core-free-icons/dist/esm/VideoOffIcon";
2347
2801
  import { HugeiconsIcon as HugeiconsIcon10 } from "@hugeicons/react-native";
2348
- import { useState as useState6 } from "react";
2349
- import { Pressable as Pressable11, ScrollView as ScrollView2, StyleSheet as StyleSheet18, Text as Text13, View as View17 } from "react-native";
2802
+ import { useState as useState8 } from "react";
2803
+ import { Pressable as Pressable13, ScrollView as ScrollView3, StyleSheet as StyleSheet20, Text as Text15, View as View19 } from "react-native";
2350
2804
 
2351
2805
  // src/components/native-space-view/ParticipantActionSheet.tsx
2352
2806
  import CancelCircleIcon from "@hugeicons/core-free-icons/dist/esm/CancelCircleIcon";
@@ -2354,8 +2808,8 @@ import MicOff01Icon5 from "@hugeicons/core-free-icons/dist/esm/MicOff01Icon";
2354
2808
  import UserIcon from "@hugeicons/core-free-icons/dist/esm/UserIcon";
2355
2809
  import Video01Icon3 from "@hugeicons/core-free-icons/dist/esm/Video01Icon";
2356
2810
  import { HugeiconsIcon as HugeiconsIcon9 } from "@hugeicons/react-native";
2357
- import { Modal as Modal4, Platform as Platform8, Pressable as Pressable10, StyleSheet as StyleSheet17, Text as Text12, View as View16 } from "react-native";
2358
- import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
2811
+ import { Modal as Modal5, Platform as Platform11, Pressable as Pressable12, StyleSheet as StyleSheet19, Text as Text14, View as View18 } from "react-native";
2812
+ import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
2359
2813
  function ParticipantActionSheet({ controller, participantId, onClose }) {
2360
2814
  const participant = participantId ? controller.participants.participants.find((item) => item.id === participantId) : void 0;
2361
2815
  const descriptors = buildParticipantActionDescriptors({
@@ -2375,33 +2829,33 @@ function ParticipantActionSheet({ controller, participantId, onClose }) {
2375
2829
  if (descriptor.kind === "stopScreenShare") controller.stopParticipantScreenShare(participantId);
2376
2830
  if (descriptor.kind === "remove") controller.removeParticipant(participantId);
2377
2831
  };
2378
- return /* @__PURE__ */ jsx21(Modal4, { animationType: "fade", onRequestClose: onClose, transparent: true, visible: participantId !== null, children: /* @__PURE__ */ jsxs15(View16, { style: styles16.modalRoot, children: [
2379
- /* @__PURE__ */ jsx21(Pressable10, { accessibilityLabel: "Close Participant actions", onPress: onClose, style: styles16.backdrop }),
2380
- /* @__PURE__ */ jsxs15(View16, { style: styles16.card, children: [
2381
- /* @__PURE__ */ jsxs15(View16, { style: styles16.cardHeader, children: [
2382
- participant ? /* @__PURE__ */ jsx21(InitialsAvatar, { name: participant.displayName, size: 44 }) : /* @__PURE__ */ jsx21(IconTile, { icon: UserIcon }),
2383
- /* @__PURE__ */ jsx21(View16, { style: styles16.headerCopy, children: /* @__PURE__ */ jsx21(Text12, { numberOfLines: 1, style: styles16.name, children: participant?.displayName ?? "Participant" }) }),
2384
- /* @__PURE__ */ jsx21(CloseButton, { label: "Close Participant actions", onPress: onClose })
2832
+ return /* @__PURE__ */ jsx23(Modal5, { animationType: "fade", onRequestClose: onClose, transparent: true, visible: participantId !== null, children: /* @__PURE__ */ jsxs17(View18, { style: styles18.modalRoot, children: [
2833
+ /* @__PURE__ */ jsx23(Pressable12, { accessibilityLabel: "Close Participant actions", onPress: onClose, style: styles18.backdrop }),
2834
+ /* @__PURE__ */ jsxs17(View18, { style: styles18.card, children: [
2835
+ /* @__PURE__ */ jsxs17(View18, { style: styles18.cardHeader, children: [
2836
+ participant ? /* @__PURE__ */ jsx23(InitialsAvatar, { name: participant.displayName, size: 44 }) : /* @__PURE__ */ jsx23(IconTile, { icon: UserIcon }),
2837
+ /* @__PURE__ */ jsx23(View18, { style: styles18.headerCopy, children: /* @__PURE__ */ jsx23(Text14, { numberOfLines: 1, style: styles18.name, children: participant?.displayName ?? "Participant" }) }),
2838
+ /* @__PURE__ */ jsx23(CloseButton, { label: "Close Participant actions", onPress: onClose })
2385
2839
  ] }),
2386
- /* @__PURE__ */ jsxs15(View16, { style: styles16.actions, children: [
2387
- descriptors.filter((descriptor) => !descriptor.destructive).map((descriptor) => /* @__PURE__ */ jsx21(ParticipantActionRow, { descriptor, onPress: () => run(descriptor) }, descriptor.kind)),
2388
- descriptors.some((descriptor) => descriptor.destructive) ? /* @__PURE__ */ jsx21(View16, { style: styles16.divider }) : null,
2389
- descriptors.filter((descriptor) => descriptor.destructive).map((descriptor) => /* @__PURE__ */ jsx21(ParticipantActionRow, { descriptor, onPress: () => run(descriptor) }, descriptor.kind))
2840
+ /* @__PURE__ */ jsxs17(View18, { style: styles18.actions, children: [
2841
+ descriptors.filter((descriptor) => !descriptor.destructive).map((descriptor) => /* @__PURE__ */ jsx23(ParticipantActionRow, { descriptor, onPress: () => run(descriptor) }, descriptor.kind)),
2842
+ descriptors.some((descriptor) => descriptor.destructive) ? /* @__PURE__ */ jsx23(View18, { style: styles18.divider }) : null,
2843
+ descriptors.filter((descriptor) => descriptor.destructive).map((descriptor) => /* @__PURE__ */ jsx23(ParticipantActionRow, { descriptor, onPress: () => run(descriptor) }, descriptor.kind))
2390
2844
  ] }),
2391
- !descriptors.length ? /* @__PURE__ */ jsx21(Text12, { style: styles16.emptyText, children: "No actions are available for this Participant." }) : null
2845
+ !descriptors.length ? /* @__PURE__ */ jsx23(Text14, { style: styles18.emptyText, children: "No actions are available for this Participant." }) : null
2392
2846
  ] })
2393
2847
  ] }) });
2394
2848
  }
2395
2849
  function ParticipantActionRow({ descriptor, onPress }) {
2396
2850
  const icon = descriptor.kind === "mute" || descriptor.kind === "requestUnmute" ? MicOff01Icon5 : descriptor.kind === "requestCamera" || descriptor.kind === "stopCamera" ? Video01Icon3 : CancelCircleIcon;
2397
- return /* @__PURE__ */ jsxs15(Pressable10, { accessibilityLabel: descriptor.label, accessibilityRole: "button", onPress, style: ({ pressed }) => [styles16.actionRow, descriptor.destructive && styles16.destructiveRow, pressed && styles16.pressed], children: [
2398
- /* @__PURE__ */ jsx21(HugeiconsIcon9, { color: descriptor.destructive ? Theme.colors.error : Theme.colors.ink, icon, size: 21 }),
2399
- /* @__PURE__ */ jsx21(Text12, { style: [styles16.actionLabel, descriptor.destructive && styles16.destructiveText], children: descriptor.label })
2851
+ return /* @__PURE__ */ jsxs17(Pressable12, { accessibilityLabel: descriptor.label, accessibilityRole: "button", onPress, style: ({ pressed }) => [styles18.actionRow, descriptor.destructive && styles18.destructiveRow, pressed && styles18.pressed], children: [
2852
+ /* @__PURE__ */ jsx23(HugeiconsIcon9, { color: descriptor.destructive ? Theme.colors.error : Theme.colors.ink, icon, size: 21 }),
2853
+ /* @__PURE__ */ jsx23(Text14, { style: [styles18.actionLabel, descriptor.destructive && styles18.destructiveText], children: descriptor.label })
2400
2854
  ] });
2401
2855
  }
2402
- var styles16 = StyleSheet17.create({
2403
- modalRoot: { alignItems: "center", flex: 1, justifyContent: "flex-end", paddingBottom: Platform8.OS === "ios" ? Theme.spacing["2xl"] : Theme.spacing.lg, paddingHorizontal: Theme.spacing.lg, paddingTop: Theme.spacing.lg },
2404
- backdrop: { ...StyleSheet17.absoluteFillObject, backgroundColor: Theme.colors.darkOverlay22 },
2856
+ var styles18 = StyleSheet19.create({
2857
+ modalRoot: { alignItems: "center", flex: 1, justifyContent: "flex-end", paddingBottom: Platform11.OS === "ios" ? Theme.spacing["2xl"] : Theme.spacing.lg, paddingHorizontal: Theme.spacing.lg, paddingTop: Theme.spacing.lg },
2858
+ backdrop: { ...StyleSheet19.absoluteFillObject, backgroundColor: Theme.colors.darkOverlay22 },
2405
2859
  card: { backgroundColor: Theme.colors.surface, borderColor: Theme.colors.line, borderRadius: Theme.radius.lg, elevation: 8, maxHeight: "78%", overflow: "hidden", shadowColor: Theme.colors.ink, shadowOffset: { height: 4, width: 0 }, shadowOpacity: 0.14, shadowRadius: 20, width: "100%" },
2406
2860
  cardHeader: { alignItems: "center", borderBottomColor: Theme.colors.line, borderBottomWidth: 1, flexDirection: "row", gap: Theme.spacing.md, minHeight: 78, paddingHorizontal: Theme.spacing.md },
2407
2861
  headerCopy: { flex: 1, minWidth: 0 },
@@ -2417,63 +2871,63 @@ var styles16 = StyleSheet17.create({
2417
2871
  });
2418
2872
 
2419
2873
  // src/components/native-space-view/SpacePeopleSheet.tsx
2420
- import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
2874
+ import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
2421
2875
  function SpacePeopleSheet({ controller }) {
2422
- const [actionParticipantId, setActionParticipantId] = useState6(null);
2876
+ const [actionParticipantId, setActionParticipantId] = useState8(null);
2423
2877
  const closeActions = () => {
2424
2878
  setActionParticipantId(null);
2425
2879
  };
2426
2880
  const openActions = (participantId) => {
2427
2881
  setActionParticipantId(participantId);
2428
2882
  };
2429
- return /* @__PURE__ */ jsxs16(View17, { style: styles17.content, children: [
2430
- /* @__PURE__ */ jsxs16(ScrollView2, { contentContainerStyle: styles17.list, showsVerticalScrollIndicator: false, children: [
2431
- controller.admissionRequests.map((request) => /* @__PURE__ */ jsxs16(View17, { style: styles17.admissionRequest, children: [
2432
- /* @__PURE__ */ jsx22(InitialsAvatar, { name: request.displayName, size: 48 }),
2433
- /* @__PURE__ */ jsxs16(View17, { style: styles17.rowCopy, children: [
2434
- /* @__PURE__ */ jsx22(Text13, { numberOfLines: 1, style: styles17.name, children: request.displayName }),
2435
- /* @__PURE__ */ jsx22(Text13, { style: styles17.meta, children: "At the Entrance" })
2883
+ return /* @__PURE__ */ jsxs18(View19, { style: styles19.content, children: [
2884
+ /* @__PURE__ */ jsxs18(ScrollView3, { contentContainerStyle: styles19.list, showsVerticalScrollIndicator: false, children: [
2885
+ controller.admissionRequests.map((request) => /* @__PURE__ */ jsxs18(View19, { style: styles19.admissionRequest, children: [
2886
+ /* @__PURE__ */ jsx24(InitialsAvatar, { name: request.displayName, size: 48 }),
2887
+ /* @__PURE__ */ jsxs18(View19, { style: styles19.rowCopy, children: [
2888
+ /* @__PURE__ */ jsx24(Text15, { numberOfLines: 1, style: styles19.name, children: request.displayName }),
2889
+ /* @__PURE__ */ jsx24(Text15, { style: styles19.meta, children: "At the Entrance" })
2436
2890
  ] }),
2437
- controller.canManageAdmission ? /* @__PURE__ */ jsxs16(View17, { style: styles17.admissionActions, children: [
2438
- /* @__PURE__ */ jsx22(Pressable11, { accessibilityRole: "button", onPress: () => controller.denyAdmission(request.requestId), style: ({ pressed }) => [styles17.denyButton, pressed && styles17.pressed], children: /* @__PURE__ */ jsx22(Text13, { style: styles17.denyText, children: "Deny" }) }),
2439
- /* @__PURE__ */ jsx22(Pressable11, { accessibilityRole: "button", onPress: () => controller.admitParticipant(request.requestId), style: ({ pressed }) => [styles17.admitButton, pressed && styles17.pressed], children: /* @__PURE__ */ jsx22(Text13, { style: styles17.admitText, children: "Admit" }) })
2891
+ controller.canManageAdmission ? /* @__PURE__ */ jsxs18(View19, { style: styles19.admissionActions, children: [
2892
+ /* @__PURE__ */ jsx24(Pressable13, { accessibilityRole: "button", onPress: () => controller.denyAdmission(request.requestId), style: ({ pressed }) => [styles19.denyButton, pressed && styles19.pressed], children: /* @__PURE__ */ jsx24(Text15, { style: styles19.denyText, children: "Deny" }) }),
2893
+ /* @__PURE__ */ jsx24(Pressable13, { accessibilityRole: "button", onPress: () => controller.admitParticipant(request.requestId), style: ({ pressed }) => [styles19.admitButton, pressed && styles19.pressed], children: /* @__PURE__ */ jsx24(Text15, { style: styles19.admitText, children: "Admit" }) })
2440
2894
  ] }) : null
2441
2895
  ] }, request.requestId)),
2442
2896
  controller.participants.participants.map((participant) => {
2443
2897
  const local = participant.id === controller.participants.localParticipant?.id;
2444
2898
  const canAct = !local && canActOnParticipant(controller);
2445
- return /* @__PURE__ */ jsxs16(View17, { style: styles17.participantRow, children: [
2446
- /* @__PURE__ */ jsx22(InitialsAvatar, { name: participant.displayName, size: 54 }),
2447
- /* @__PURE__ */ jsx22(View17, { style: styles17.rowCopy, children: /* @__PURE__ */ jsxs16(Text13, { numberOfLines: 1, style: styles17.name, children: [
2899
+ return /* @__PURE__ */ jsxs18(View19, { style: styles19.participantRow, children: [
2900
+ /* @__PURE__ */ jsx24(InitialsAvatar, { name: participant.displayName, size: 54 }),
2901
+ /* @__PURE__ */ jsx24(View19, { style: styles19.rowCopy, children: /* @__PURE__ */ jsxs18(Text15, { numberOfLines: 1, style: styles19.name, children: [
2448
2902
  participant.displayName,
2449
2903
  local ? " (You)" : ""
2450
2904
  ] }) }),
2451
- /* @__PURE__ */ jsxs16(View17, { style: styles17.mediaStatus, children: [
2452
- /* @__PURE__ */ jsx22(HugeiconsIcon10, { color: participant.audioEnabled ? Theme.colors.success : Theme.colors.error, icon: participant.audioEnabled ? Mic01Icon3 : MicOff01Icon6, size: 22 }),
2453
- /* @__PURE__ */ jsx22(View17, { style: [styles17.statusDot, { backgroundColor: participant.audioEnabled ? Theme.colors.chalkGreen : Theme.colors.chalkPink }] })
2905
+ /* @__PURE__ */ jsxs18(View19, { style: styles19.mediaStatus, children: [
2906
+ /* @__PURE__ */ jsx24(HugeiconsIcon10, { color: participant.audioEnabled ? Theme.colors.success : Theme.colors.error, icon: participant.audioEnabled ? Mic01Icon3 : MicOff01Icon6, size: 22 }),
2907
+ /* @__PURE__ */ jsx24(View19, { style: [styles19.statusDot, { backgroundColor: participant.audioEnabled ? Theme.colors.chalkGreen : Theme.colors.chalkPink }] })
2454
2908
  ] }),
2455
- /* @__PURE__ */ jsxs16(View17, { style: styles17.mediaStatus, children: [
2456
- /* @__PURE__ */ jsx22(HugeiconsIcon10, { color: participant.videoEnabled ? Theme.colors.success : Theme.colors.error, icon: participant.videoEnabled ? Video01Icon4 : VideoOffIcon3, size: 22 }),
2457
- /* @__PURE__ */ jsx22(View17, { style: [styles17.statusDot, { backgroundColor: participant.videoEnabled ? Theme.colors.chalkGreen : Theme.colors.chalkPink }] })
2909
+ /* @__PURE__ */ jsxs18(View19, { style: styles19.mediaStatus, children: [
2910
+ /* @__PURE__ */ jsx24(HugeiconsIcon10, { color: participant.videoEnabled ? Theme.colors.success : Theme.colors.error, icon: participant.videoEnabled ? Video01Icon4 : VideoOffIcon3, size: 22 }),
2911
+ /* @__PURE__ */ jsx24(View19, { style: [styles19.statusDot, { backgroundColor: participant.videoEnabled ? Theme.colors.chalkGreen : Theme.colors.chalkPink }] })
2458
2912
  ] }),
2459
- canAct ? /* @__PURE__ */ jsx22(Pressable11, { accessibilityLabel: `Actions for ${participant.displayName}`, accessibilityRole: "button", onPress: () => openActions(participant.id), style: ({ pressed }) => [styles17.moreButton, pressed && styles17.pressed], children: /* @__PURE__ */ jsx22(HugeiconsIcon10, { color: Theme.colors.ink, icon: MoreHorizontalIcon2, size: 22 }) }) : null
2913
+ canAct ? /* @__PURE__ */ jsx24(Pressable13, { accessibilityLabel: `Actions for ${participant.displayName}`, accessibilityRole: "button", onPress: () => openActions(participant.id), style: ({ pressed }) => [styles19.moreButton, pressed && styles19.pressed], children: /* @__PURE__ */ jsx24(HugeiconsIcon10, { color: Theme.colors.ink, icon: MoreHorizontalIcon2, size: 22 }) }) : null
2460
2914
  ] }, participant.id);
2461
2915
  }),
2462
- !controller.participants.participants.length && !controller.admissionRequests.length ? /* @__PURE__ */ jsx22(EmptyPeople, {}) : null
2916
+ !controller.participants.participants.length && !controller.admissionRequests.length ? /* @__PURE__ */ jsx24(EmptyPeople, {}) : null
2463
2917
  ] }),
2464
- /* @__PURE__ */ jsx22(ParticipantActionSheet, { controller, onClose: closeActions, participantId: actionParticipantId })
2918
+ /* @__PURE__ */ jsx24(ParticipantActionSheet, { controller, onClose: closeActions, participantId: actionParticipantId })
2465
2919
  ] });
2466
2920
  }
2467
2921
  function canActOnParticipant(controller) {
2468
2922
  return controller.canMuteParticipants || controller.canRequestMedia || controller.canStopParticipantCamera || controller.canStopParticipantScreenShare || controller.canRemoveParticipants;
2469
2923
  }
2470
2924
  function EmptyPeople() {
2471
- return /* @__PURE__ */ jsxs16(View17, { style: styles17.emptyState, children: [
2472
- /* @__PURE__ */ jsx22(Text13, { style: styles17.emptyTitle, children: "No People yet" }),
2473
- /* @__PURE__ */ jsx22(Text13, { style: styles17.emptyText, children: "People will appear here as they join the Space." })
2925
+ return /* @__PURE__ */ jsxs18(View19, { style: styles19.emptyState, children: [
2926
+ /* @__PURE__ */ jsx24(Text15, { style: styles19.emptyTitle, children: "No People yet" }),
2927
+ /* @__PURE__ */ jsx24(Text15, { style: styles19.emptyText, children: "People will appear here as they join the Space." })
2474
2928
  ] });
2475
2929
  }
2476
- var styles17 = StyleSheet18.create({
2930
+ var styles19 = StyleSheet20.create({
2477
2931
  content: { flex: 1, minHeight: 0 },
2478
2932
  list: { paddingHorizontal: Theme.spacing.lg, paddingVertical: Theme.spacing.sm },
2479
2933
  participantRow: { alignItems: "center", borderBottomColor: Theme.colors.line, borderBottomWidth: 1, flexDirection: "row", gap: Theme.spacing.sm, minHeight: 84, paddingVertical: Theme.spacing.md },
@@ -2496,23 +2950,23 @@ var styles17 = StyleSheet18.create({
2496
2950
  });
2497
2951
 
2498
2952
  // src/components/native-space-view/SpacePanelSheet.tsx
2499
- import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
2953
+ import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
2500
2954
  function SpacePanelSheet({ controller }) {
2501
2955
  const visible = controller.panel !== null;
2502
2956
  const close = controller.closePanel;
2503
2957
  const isChat = controller.panel === "chat";
2504
- return /* @__PURE__ */ jsx23(Modal5, { animationType: "slide", onRequestClose: close, transparent: true, visible, children: /* @__PURE__ */ jsxs17(View18, { style: styles18.modalRoot, children: [
2505
- /* @__PURE__ */ jsx23(Pressable12, { accessibilityLabel: "Close panel", onPress: close, style: styles18.backdrop }),
2506
- /* @__PURE__ */ jsxs17(SafeAreaView, { style: styles18.sheet, children: [
2507
- /* @__PURE__ */ jsx23(SheetGrip, {}),
2508
- /* @__PURE__ */ jsx23(SurfaceHeader, { closeLabel: `Close ${isChat ? "Chat" : "People"}`, count: !isChat ? controller.participantCount : void 0, onClose: close, title: isChat ? "Chat" : "People" }),
2509
- isChat ? /* @__PURE__ */ jsx23(SpaceChatSheet, { controller }) : /* @__PURE__ */ jsx23(SpacePeopleSheet, { controller })
2958
+ return /* @__PURE__ */ jsx25(Modal6, { animationType: "slide", onRequestClose: close, transparent: true, visible, children: /* @__PURE__ */ jsxs19(View20, { style: styles20.modalRoot, children: [
2959
+ /* @__PURE__ */ jsx25(Pressable14, { accessibilityLabel: "Close panel", onPress: close, style: styles20.backdrop }),
2960
+ /* @__PURE__ */ jsxs19(SafeAreaView, { style: styles20.sheet, children: [
2961
+ /* @__PURE__ */ jsx25(SheetGrip, {}),
2962
+ /* @__PURE__ */ jsx25(SurfaceHeader, { closeLabel: `Close ${isChat ? "Chat" : "People"}`, count: !isChat ? controller.participantCount : void 0, onClose: close, title: isChat ? "Chat" : "People" }),
2963
+ isChat ? /* @__PURE__ */ jsx25(SpaceChatSheet, { controller }) : /* @__PURE__ */ jsx25(SpacePeopleSheet, { controller })
2510
2964
  ] })
2511
2965
  ] }) });
2512
2966
  }
2513
- var styles18 = StyleSheet19.create({
2967
+ var styles20 = StyleSheet21.create({
2514
2968
  modalRoot: { flex: 1, justifyContent: "flex-end" },
2515
- backdrop: { ...StyleSheet19.absoluteFillObject, backgroundColor: Theme.colors.darkOverlay22 },
2969
+ backdrop: { ...StyleSheet21.absoluteFillObject, backgroundColor: Theme.colors.darkOverlay22 },
2516
2970
  sheet: {
2517
2971
  backgroundColor: Theme.colors.surface,
2518
2972
  borderColor: Theme.colors.line,
@@ -2522,7 +2976,7 @@ var styles18 = StyleSheet19.create({
2522
2976
  flex: 1,
2523
2977
  marginTop: 78,
2524
2978
  overflow: "hidden",
2525
- paddingBottom: Platform9.OS === "android" ? Theme.spacing.sm : 0,
2979
+ paddingBottom: Platform12.OS === "android" ? Theme.spacing.sm : 0,
2526
2980
  shadowColor: Theme.colors.ink,
2527
2981
  shadowOffset: { height: -8, width: 0 },
2528
2982
  shadowOpacity: 0.12,
@@ -2531,8 +2985,9 @@ var styles18 = StyleSheet19.create({
2531
2985
  });
2532
2986
 
2533
2987
  // src/components/native-space-view/useSpaceViewController.ts
2534
- import { useCallback as useCallback8, useEffect as useEffect8, useMemo as useMemo12, useState as useState9 } from "react";
2535
- import { Alert as Alert2, Linking } from "react-native";
2988
+ import { useCallback as useCallback9, useEffect as useEffect10, useMemo as useMemo13, useState as useState11 } from "react";
2989
+ import { Alert as Alert2, Linking, Platform as Platform13 } from "react-native";
2990
+ import { mediaDevices as mediaDevices2 } from "@cloudflare/react-native-webrtc";
2536
2991
 
2537
2992
  // src/components/native-space-view/diagnostics.ts
2538
2993
  function buildSpaceViewDiagnosticsSnapshot(input) {
@@ -2570,7 +3025,7 @@ function disabledAction(detail) {
2570
3025
  }
2571
3026
 
2572
3027
  // src/components/native-space-view/useSpaceViewDerived.ts
2573
- import { useMemo as useMemo10 } from "react";
3028
+ import { useMemo as useMemo11 } from "react";
2574
3029
  import { useWindowDimensions as useWindowDimensions3 } from "react-native";
2575
3030
 
2576
3031
  // src/utils/native-space-layout.ts
@@ -2655,7 +3110,7 @@ function resolveNativeSpaceLayout({ participants, localParticipant, screenShare,
2655
3110
  // src/components/native-space-view/useSpaceViewDerived.ts
2656
3111
  function useSpaceViewDerived({ participants, localParticipant, screenShare, isWhiteboardOpen }) {
2657
3112
  const { width } = useWindowDimensions3();
2658
- return useMemo10(
3113
+ return useMemo11(
2659
3114
  () => resolveNativeSpaceLayout({
2660
3115
  participants,
2661
3116
  localParticipant,
@@ -2668,27 +3123,27 @@ function useSpaceViewDerived({ participants, localParticipant, screenShare, isWh
2668
3123
  }
2669
3124
 
2670
3125
  // src/components/native-space-view/useSpaceViewPanels.ts
2671
- import { useCallback as useCallback7, useEffect as useEffect7, useMemo as useMemo11, useRef as useRef4, useState as useState8 } from "react";
3126
+ import { useCallback as useCallback8, useEffect as useEffect9, useMemo as useMemo12, useRef as useRef4, useState as useState10 } from "react";
2672
3127
  import { Alert, Share } from "react-native";
2673
3128
 
2674
3129
  // src/hooks/useLayout.ts
2675
- import { useCallback as useCallback6, useEffect as useEffect6, useState as useState7 } from "react";
3130
+ import { useCallback as useCallback7, useEffect as useEffect8, useState as useState9 } from "react";
2676
3131
  function useLayout({ layout: controlledLayout, onLayoutChange } = {}) {
2677
- const [uncontrolledLayout, setUncontrolledLayout] = useState7(controlledLayout ?? "focus");
2678
- const [isFullscreen, setFullscreen] = useState7(false);
3132
+ const [uncontrolledLayout, setUncontrolledLayout] = useState9(controlledLayout ?? "focus");
3133
+ const [isFullscreen, setFullscreen] = useState9(false);
2679
3134
  const layout = controlledLayout ?? uncontrolledLayout;
2680
- useEffect6(() => {
3135
+ useEffect8(() => {
2681
3136
  if (controlledLayout) setUncontrolledLayout(controlledLayout);
2682
3137
  }, [controlledLayout]);
2683
- const setLayout = useCallback6(
3138
+ const setLayout = useCallback7(
2684
3139
  (nextLayout) => {
2685
3140
  if (!controlledLayout) setUncontrolledLayout(nextLayout);
2686
3141
  onLayoutChange?.(nextLayout);
2687
3142
  },
2688
3143
  [controlledLayout, onLayoutChange]
2689
3144
  );
2690
- const toggleLayout = useCallback6(() => setLayout(layout === "grid" ? "focus" : "grid"), [layout, setLayout]);
2691
- const toggleFullscreen = useCallback6(async () => setFullscreen((current) => !current), []);
3145
+ const toggleLayout = useCallback7(() => setLayout(layout === "grid" ? "focus" : "grid"), [layout, setLayout]);
3146
+ const toggleFullscreen = useCallback7(async () => setFullscreen((current) => !current), []);
2692
3147
  return { layout, isMobileView: true, isFullscreen, setLayout, toggleLayout, toggleFullscreen };
2693
3148
  }
2694
3149
 
@@ -2703,14 +3158,14 @@ var emptyParticipants = Object.freeze([]);
2703
3158
  function useSpaceViewPanels({ spaceName, inviteLink, layout: controlledLayout, onLayoutChange, canWhiteboard, canDraw, canClear, canEndEpisode, transport, onLeave, onEndEpisode, run, journeyContext, initialState, controlledState }) {
2704
3159
  const fixtureLayout = controlledState?.layout ?? initialState?.layout ?? controlledLayout;
2705
3160
  const layout = useLayout({ layout: fixtureLayout, onLayoutChange });
2706
- const [panel, setPanel] = useState8(initialState?.panel ?? null);
2707
- const [actionsOpen, setActionsOpen] = useState8(initialState?.actionsOpen ?? false);
2708
- const [reactionPickerOpen, setReactionPickerOpen] = useState8(initialState?.reactionPickerOpen ?? false);
2709
- const [secondsElapsed, setSecondsElapsed] = useState8(0);
2710
- const [settingsOpen, setSettingsOpen] = useState8(initialState?.settingsOpen ?? false);
2711
- const [whiteboardOpen, setWhiteboardOpen] = useState8(initialState?.whiteboardOpen ?? false);
3161
+ const [panel, setPanel] = useState10(initialState?.panel ?? null);
3162
+ const [actionsOpen, setActionsOpen] = useState10(initialState?.actionsOpen ?? false);
3163
+ const [reactionPickerOpen, setReactionPickerOpen] = useState10(initialState?.reactionPickerOpen ?? false);
3164
+ const [secondsElapsed, setSecondsElapsed] = useState10(0);
3165
+ const [settingsOpen, setSettingsOpen] = useState10(initialState?.settingsOpen ?? false);
3166
+ const [whiteboardOpen, setWhiteboardOpen] = useState10(initialState?.whiteboardOpen ?? false);
2712
3167
  const generatedJourneyId = useRef4(globalThis.crypto?.randomUUID?.() ?? `native-whiteboard-${Date.now()}-${Math.random().toString(36).slice(2)}`);
2713
- useEffect7(() => {
3168
+ useEffect9(() => {
2714
3169
  const durationSeconds = Math.max(0, Math.floor(controlledState?.durationSeconds ?? initialState?.durationSeconds ?? 0));
2715
3170
  const startedAt = Date.now() - durationSeconds * 1e3;
2716
3171
  const update = () => setSecondsElapsed(Math.max(0, Math.floor((Date.now() - startedAt) / 1e3)));
@@ -2718,14 +3173,14 @@ function useSpaceViewPanels({ spaceName, inviteLink, layout: controlledLayout, o
2718
3173
  const timer = globalThis.setInterval(update, 1e3);
2719
3174
  return () => globalThis.clearInterval(timer);
2720
3175
  }, [controlledState?.durationSeconds, initialState?.durationSeconds]);
2721
- useEffect7(() => {
3176
+ useEffect9(() => {
2722
3177
  if (controlledState?.panel !== void 0) setPanel(controlledState.panel ?? null);
2723
3178
  if (controlledState?.actionsOpen !== void 0) setActionsOpen(controlledState.actionsOpen);
2724
3179
  if (controlledState?.reactionPickerOpen !== void 0) setReactionPickerOpen(controlledState.reactionPickerOpen);
2725
3180
  if (controlledState?.settingsOpen !== void 0) setSettingsOpen(controlledState.settingsOpen);
2726
3181
  if (controlledState?.whiteboardOpen !== void 0) setWhiteboardOpen(controlledState.whiteboardOpen);
2727
3182
  }, [controlledState]);
2728
- const whiteboard = useMemo11(
3183
+ const whiteboard = useMemo12(
2729
3184
  () => ({
2730
3185
  isOpen: canWhiteboard && whiteboardOpen,
2731
3186
  canDraw: canWhiteboard && canDraw,
@@ -2745,7 +3200,7 @@ function useSpaceViewPanels({ spaceName, inviteLink, layout: controlledLayout, o
2745
3200
  }),
2746
3201
  [canClear, canDraw, canWhiteboard, journeyContext, run, transport, whiteboardOpen]
2747
3202
  );
2748
- const handleLeave = useCallback7(() => {
3203
+ const handleLeave = useCallback8(() => {
2749
3204
  const buttons = [
2750
3205
  { text: "Cancel", style: "cancel" },
2751
3206
  { text: "Leave", style: "destructive", onPress: () => void run(onLeave) }
@@ -2759,7 +3214,7 @@ function useSpaceViewPanels({ spaceName, inviteLink, layout: controlledLayout, o
2759
3214
  }
2760
3215
  Alert.alert("Leave Space?", "Choose how you want to leave.", buttons);
2761
3216
  }, [canEndEpisode, onEndEpisode, onLeave, run]);
2762
- const handleInviteParticipants = useCallback7(() => {
3217
+ const handleInviteParticipants = useCallback8(() => {
2763
3218
  void run(async () => {
2764
3219
  if (!inviteLink) throw new Error("The Space invite is not ready yet.");
2765
3220
  await Share.share({ message: inviteLink, title: spaceName || "Chalk Space", url: inviteLink });
@@ -2788,7 +3243,7 @@ function useSpaceViewPanels({ spaceName, inviteLink, layout: controlledLayout, o
2788
3243
  }
2789
3244
 
2790
3245
  // src/components/native-space-view/screen-share-availability.ts
2791
- function resolveNativeScreenShareAvailability({ featureEnabled }) {
3246
+ function resolveNativeScreenShareAvailability({ featureEnabled, platform, simulator, captureAvailable }) {
2792
3247
  if (!featureEnabled) {
2793
3248
  return {
2794
3249
  enabled: false,
@@ -2796,6 +3251,8 @@ function resolveNativeScreenShareAvailability({ featureEnabled }) {
2796
3251
  detail: "features.screenShare=false in SpaceView props"
2797
3252
  };
2798
3253
  }
3254
+ if (simulator) return { enabled: false, reason: "simulator", detail: "Screen sharing requires a physical device." };
3255
+ if (platform !== "ios" && platform !== "android" || !captureAvailable) return { enabled: false, reason: "runtime-unsupported", detail: "Screen sharing is unavailable in this app runtime. Use a supported native build or share from the web app." };
2799
3256
  return {
2800
3257
  enabled: true,
2801
3258
  reason: null,
@@ -2808,10 +3265,8 @@ import { CHALK_CHAT_ATTACHMENT_LIMITS, CHALK_CHAT_ATTACHMENT_MIME_TYPES } from "
2808
3265
  var allowedMimeTypes = new Set(CHALK_CHAT_ATTACHMENT_MIME_TYPES);
2809
3266
  var encoder = new TextEncoder();
2810
3267
  function describeChatUploadFile(file) {
2811
- if ("bytes" in file) {
2812
- return { file, fileName: file.fileName, mimeType: file.mimeType, byteLength: file.bytes.byteLength };
2813
- }
2814
- return { file, fileName: file.name, mimeType: file.type, byteLength: file.size };
3268
+ if ("arrayBuffer" in file) return { file, fileName: file.name, mimeType: file.type, byteLength: file.size };
3269
+ return { file, fileName: file.fileName, mimeType: file.mimeType, byteLength: file.bytes.byteLength };
2815
3270
  }
2816
3271
  function validateChatFileDraft(draft) {
2817
3272
  if (!draft.fileName || encoder.encode(draft.fileName).byteLength > CHALK_CHAT_ATTACHMENT_LIMITS.maximumFileNameBytes) return "This file name is too long.";
@@ -2842,15 +3297,17 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
2842
3297
  const chatSlice = useChat();
2843
3298
  const reactionSlice = useReactions();
2844
3299
  const whiteboardSlice = useWhiteboard();
3300
+ const recording = useRecording().current;
3301
+ const connection = useConnection();
2845
3302
  const journeyContext = getNativeJourneyContext(client);
2846
- const [actionsOpen, setActionsOpen] = useState9(false);
2847
- const [reactionPickerOpen, setReactionPickerOpen] = useState9(false);
2848
- const [chatDraft, setChatDraft] = useState9("");
2849
- const [chatAttachments, setChatAttachments] = useState9([]);
2850
- const [chatAttachmentError, setChatAttachmentError] = useState9(null);
2851
- const [chatAttachmentPicking, setChatAttachmentPicking] = useState9(false);
2852
- const [chatAttachmentUploading, setChatAttachmentUploading] = useState9(false);
2853
- const run = useCallback8(async (action) => {
3303
+ const [actionsOpen, setActionsOpen] = useState11(false);
3304
+ const [reactionPickerOpen, setReactionPickerOpen] = useState11(false);
3305
+ const [chatDraft, setChatDraft] = useState11("");
3306
+ const [chatAttachments, setChatAttachments] = useState11([]);
3307
+ const [chatAttachmentError, setChatAttachmentError] = useState11(null);
3308
+ const [chatAttachmentPicking, setChatAttachmentPicking] = useState11(false);
3309
+ const [chatAttachmentUploading, setChatAttachmentUploading] = useState11(false);
3310
+ const run = useCallback9(async (action) => {
2854
3311
  try {
2855
3312
  await action();
2856
3313
  } catch (cause) {
@@ -2858,14 +3315,14 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
2858
3315
  }
2859
3316
  }, []);
2860
3317
  const localParticipantId = self.participantId;
2861
- const participants = useMemo12(
3318
+ const participants = useMemo13(
2862
3319
  () => participantSlice.roster.map((participant) => {
2863
3320
  const local = participant.participantId === localParticipantId;
2864
3321
  const remoteMedia = media.remote.filter((publication) => publication.participantId === participant.participantId);
2865
3322
  return {
2866
3323
  ...participant,
2867
3324
  id: participant.participantId,
2868
- audioEnabled: local ? media.local.microphone.state === "enabled" || media.local.microphone.state === "requesting" : participant.media.microphone === "active",
3325
+ audioEnabled: local ? media.local.microphone.state === "enabled" : participant.media.microphone === "active",
2869
3326
  videoEnabled: local ? media.local.camera.state === "enabled" || media.local.camera.state === "requesting" : participant.media.camera === "active",
2870
3327
  audioTrack: local ? media.local.microphone.track : remoteMedia.find((publication) => publication.source === "microphone")?.track ?? null,
2871
3328
  videoTrack: local ? media.local.camera.track : remoteMedia.find((publication) => publication.source === "camera")?.track ?? null,
@@ -2874,8 +3331,8 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
2874
3331
  }),
2875
3332
  [localParticipantId, media.local.camera, media.local.microphone, media.remote, media.screenShare.track, participantSlice.roster]
2876
3333
  );
2877
- const localParticipant = useMemo12(() => participants.find((participant) => participant.id === localParticipantId) ?? null, [localParticipantId, participants]);
2878
- const spaceParticipants = useMemo12(
3334
+ const localParticipant = useMemo13(() => participants.find((participant) => participant.id === localParticipantId) ?? null, [localParticipantId, participants]);
3335
+ const spaceParticipants = useMemo13(
2879
3336
  () => ({
2880
3337
  participants,
2881
3338
  localParticipant,
@@ -2889,8 +3346,8 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
2889
3346
  [client.participants, localParticipant, localParticipantId, participants]
2890
3347
  );
2891
3348
  const isLocalSharing = media.screenShare.state === "enabled" || media.screenShare.state === "requesting";
2892
- const remoteScreenShare = useMemo12(() => media.remote.find((publication) => publication.source === "screen") ?? null, [media.remote]);
2893
- const screenShare = useMemo12(
3349
+ const remoteScreenShare = useMemo13(() => media.remote.find((publication) => publication.source === "screen") ?? null, [media.remote]);
3350
+ const screenShare = useMemo13(
2894
3351
  () => ({
2895
3352
  isActive: isLocalSharing || remoteScreenShare !== null,
2896
3353
  isStarting: media.screenShare.state === "requesting",
@@ -2911,7 +3368,7 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
2911
3368
  }),
2912
3369
  [client.media, isLocalSharing, localParticipantId, media.screenShare.state, media.screenShare.track, remoteScreenShare]
2913
3370
  );
2914
- const interactionState = useMemo12(() => {
3371
+ const interactionState = useMemo13(() => {
2915
3372
  const raisedHands = participantSlice.roster.filter((participant) => participant.handRaised).map((participant) => participant.participantId);
2916
3373
  const activeReactions = reactionSlice.active.map((reaction) => ({
2917
3374
  id: reaction.eventId,
@@ -2931,7 +3388,7 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
2931
3388
  sendReaction: (reaction) => client.reactions.send(reaction)
2932
3389
  };
2933
3390
  }, [client.participants, client.reactions, participantSlice.roster, reactionSlice.active, self]);
2934
- const chat = useMemo12(() => {
3391
+ const chat = useMemo13(() => {
2935
3392
  const messages = chatSlice.messages.map((message) => ({
2936
3393
  id: message.messageId,
2937
3394
  sequence: message.sequence,
@@ -2977,10 +3434,10 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
2977
3434
  const canWhiteboard = features?.whiteboard !== false && whiteboardSlice.engine.status !== "unsubscribed";
2978
3435
  const canDraw = canWhiteboard && self.can("drawWhiteboard");
2979
3436
  const canClear = canWhiteboard && self.can("manageWhiteboard");
2980
- const whiteboardTransport = useMemo12(() => client.whiteboard.transport(), [client.whiteboard, whiteboardSlice.engine.status]);
3437
+ const whiteboardTransport = useMemo13(() => client.whiteboard.transport(), [client.whiteboard, whiteboardSlice.engine.status]);
2981
3438
  const canEndEpisode = self.can("endEpisode");
2982
- const screenShareAvailability = useMemo12(() => resolveNativeScreenShareAvailability({ featureEnabled: features?.screenShare !== false }), [features?.screenShare]);
2983
- const capabilities = useMemo12(
3439
+ const screenShareAvailability = useMemo13(() => resolveNativeScreenShareAvailability({ featureEnabled: features?.screenShare !== false, platform: Platform13.OS, simulator: isIosSimulator(), captureAvailable: typeof mediaDevices2.getDisplayMedia === "function" }), [features?.screenShare]);
3440
+ const capabilities = useMemo13(
2984
3441
  () => ({
2985
3442
  canEndEpisode,
2986
3443
  canChat: features?.chat !== false && self.can("sendChat"),
@@ -3018,7 +3475,7 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
3018
3475
  journeyContext
3019
3476
  });
3020
3477
  const derived = useSpaceViewDerived({ participants, localParticipant, screenShare, isWhiteboardOpen: spacePanels.whiteboard.isOpen });
3021
- useEffect8(() => {
3478
+ useEffect10(() => {
3022
3479
  const request = media.incomingRequests[0];
3023
3480
  if (!request) return;
3024
3481
  Alert2.alert(request.kind === "unmute" ? "Unmute request" : "Camera request", `${request.actorDisplayName ?? "A Space organizer"} is asking you to ${request.kind === "unmute" ? "unmute" : "start your camera"}.`, [
@@ -3026,7 +3483,7 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
3026
3483
  { text: "Allow", onPress: () => void run(() => client.media.acceptRequest(request.requestId)) }
3027
3484
  ]);
3028
3485
  }, [client.media, media.incomingRequests, run]);
3029
- const spaceDiagnostics = useMemo12(
3486
+ const spaceDiagnostics = useMemo13(
3030
3487
  () => buildSpaceViewDiagnosticsSnapshot({
3031
3488
  featureFlags: {
3032
3489
  chat: capabilities.canChat,
@@ -3048,8 +3505,8 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
3048
3505
  }),
3049
3506
  [capabilities, chat.unreadCount, interactionState.raisedHandCount, spaceParticipants.participantCount, screenShare.isActive, screenShare.isLocalSharing, screenShare.sharerParticipantId, screenShareAvailability]
3050
3507
  );
3051
- useEffect8(() => onDiagnosticsChange?.(spaceDiagnostics), [onDiagnosticsChange, spaceDiagnostics]);
3052
- const pickChatFiles = useCallback8(async () => {
3508
+ useEffect10(() => onDiagnosticsChange?.(spaceDiagnostics), [onDiagnosticsChange, spaceDiagnostics]);
3509
+ const pickChatFiles = useCallback9(async () => {
3053
3510
  if (!pickChatFilesInput) return;
3054
3511
  setChatAttachmentPicking(true);
3055
3512
  try {
@@ -3071,11 +3528,11 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
3071
3528
  setChatAttachmentPicking(false);
3072
3529
  }
3073
3530
  }, [chatAttachments, pickChatFilesInput]);
3074
- const removeChatAttachment = useCallback8((index) => {
3531
+ const removeChatAttachment = useCallback9((index) => {
3075
3532
  setChatAttachments((current) => current.filter((_, currentIndex) => currentIndex !== index));
3076
3533
  setChatAttachmentError(null);
3077
3534
  }, []);
3078
- const sendChatMessage = useCallback8(() => {
3535
+ const sendChatMessage = useCallback9(() => {
3079
3536
  const text = chatDraft.trim();
3080
3537
  if (!text && chatAttachments.length === 0) return;
3081
3538
  void run(async () => {
@@ -3093,12 +3550,23 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
3093
3550
  }
3094
3551
  });
3095
3552
  }, [chat, chatAttachments, chatDraft, client.chat.files, run]);
3553
+ const resolveChatAttachmentUrl = useCallback9(
3554
+ async (attachmentId) => {
3555
+ const attachment = chatSlice.messages.flatMap((message) => message.attachments).find((candidate) => candidate.attachmentId === attachmentId);
3556
+ return attachment ? client.chat.files.resolveUrl(attachment) : null;
3557
+ },
3558
+ [chatSlice.messages, client.chat.files]
3559
+ );
3096
3560
  return {
3561
+ recording,
3562
+ canManageRecording: self.can("manageRecording"),
3563
+ canToggleRecording: connection.status === "live" && recording?.status !== "starting" && recording?.status !== "stopping",
3564
+ toggleRecording: () => void run(() => recording?.status === "recording" ? client.recording.stop() : client.recording.start()),
3097
3565
  simulatorMediaDisabled: isIosSimulator(),
3098
3566
  spaceName: spaceName || "Space",
3099
3567
  panel: spacePanels.panel,
3100
3568
  selfName: self.displayName || "Participant",
3101
- isMuted: !(media.local.microphone.state === "enabled" || media.local.microphone.state === "requesting"),
3569
+ isMuted: media.local.microphone.state !== "enabled",
3102
3570
  isCameraOff: !(media.local.camera.state === "enabled" || media.local.camera.state === "requesting"),
3103
3571
  handRaised: interactionState.isHandRaised,
3104
3572
  raisedHandCount: interactionState.raisedHandCount,
@@ -3117,6 +3585,7 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
3117
3585
  canChat: capabilities.canChat,
3118
3586
  canParticipants: capabilities.canParticipants,
3119
3587
  canScreenShare: capabilities.canScreenShare,
3588
+ screenShareUnavailableReason: features?.screenShare !== false && self.can("publishScreen") ? screenShareAvailability.detail : null,
3120
3589
  canReactions: capabilities.canReactions,
3121
3590
  canHandRaise: capabilities.canHandRaise,
3122
3591
  canInvite: capabilities.canInvite,
@@ -3133,7 +3602,7 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
3133
3602
  participants: spaceParticipants,
3134
3603
  settings: {
3135
3604
  displayName: self.displayName ?? "",
3136
- microphoneEnabled: media.local.microphone.state === "enabled" || media.local.microphone.state === "requesting",
3605
+ microphoneEnabled: media.local.microphone.state === "enabled",
3137
3606
  cameraEnabled: media.local.camera.state === "enabled" || media.local.camera.state === "requesting",
3138
3607
  devices: media.devices,
3139
3608
  selection: media.selection,
@@ -3169,9 +3638,12 @@ function useSpaceViewController({ spaceName, inviteLink, layout: controlledLayou
3169
3638
  void run(() => interactionState.sendReaction(reaction));
3170
3639
  },
3171
3640
  sendChatMessage,
3641
+ resolveChatAttachmentUrl,
3172
3642
  openChatAttachment: (attachmentId) => {
3173
- const attachment = chat.messages.flatMap((message) => message.attachments).find((candidate) => candidate.attachmentId === attachmentId);
3174
- if (attachment) void run(() => Linking.openURL(client.chat.files.url(attachment)));
3643
+ void run(async () => {
3644
+ const url = await resolveChatAttachmentUrl(attachmentId);
3645
+ if (url) await Linking.openURL(url);
3646
+ });
3175
3647
  },
3176
3648
  markChatMessageVisible: (sequence) => void run(() => chat.markAsRead(sequence)),
3177
3649
  admitParticipant: (requestId) => void run(() => client.participants.admit(requestId)),
@@ -3191,10 +3663,14 @@ function sequenceAtOrAfter(value, floor) {
3191
3663
  }
3192
3664
 
3193
3665
  // src/components/SpaceView.shared.tsx
3194
- import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
3666
+ import { Fragment as Fragment2, jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
3195
3667
  function SpaceViewShared(props) {
3196
3668
  const controller = useSpaceViewController(props);
3669
+ const client = useSpaceClient();
3197
3670
  const theme = useNativeTheme();
3671
+ const captureTarget = useRef5(null);
3672
+ const [captureSize, setCaptureSize] = useState12({ width: 0, height: 0 });
3673
+ const [feedbackRequested, setFeedbackRequested] = useState12(false);
3198
3674
  const toggleMedia = (action) => {
3199
3675
  if (controller.simulatorMediaDisabled) {
3200
3676
  Alert3.alert("Media unavailable", getIosSimulatorMediaMessage());
@@ -3202,51 +3678,54 @@ function SpaceViewShared(props) {
3202
3678
  }
3203
3679
  action();
3204
3680
  };
3205
- return /* @__PURE__ */ jsxs18(View19, { style: [styles19.space, { backgroundColor: theme.colors.darkCanvas }], children: [
3206
- /* @__PURE__ */ jsx24(SpaceTopBarAndroid, { formattedDuration: controller.formattedDuration, logoUrl: props.logoUrl, participantCount: controller.participantCount, spaceName: controller.spaceName }),
3207
- props.reconnecting ? /* @__PURE__ */ jsx24(View19, { accessibilityLiveRegion: "polite", style: [styles19.recovery, { backgroundColor: theme.colors.primary }], children: /* @__PURE__ */ jsx24(Text14, { style: [styles19.recoveryText, { color: theme.colors.primaryForeground }], children: "Reconnecting\u2026 controls will resume shortly." }) }) : null,
3208
- /* @__PURE__ */ jsx24(View19, { style: styles19.stage, children: controller.whiteboard.isOpen ? /* @__PURE__ */ jsx24(SpaceWhiteboardSurface, { whiteboard: controller.whiteboard }) : controller.derived.isStageMode || controller.layout.layout !== "grid" ? /* @__PURE__ */ jsx24(
3209
- SpaceStageAndroid,
3210
- {
3211
- activeReactions: controller.activeReactions,
3212
- handRaised: controller.handRaised,
3213
- isCompactViewport: controller.derived.isCompactViewport,
3214
- isMuted: controller.isMuted,
3215
- layoutMode: controller.layout.layout,
3216
- primaryContent: controller.derived.primaryContent,
3217
- raisedHandCount: controller.raisedHandCount,
3218
- screenShareTrack: controller.derived.screenShareTrack,
3219
- screenSharer: controller.derived.screenSharer,
3220
- selfName: controller.selfName,
3221
- stripParticipants: controller.derived.allParticipants,
3222
- whiteboard: {
3223
- isOpen: controller.whiteboard.isOpen,
3224
- canDraw: controller.whiteboard.canDraw,
3225
- elementCount: controller.whiteboard.elements.length,
3226
- participantCount: controller.whiteboard.openParticipants.length
3681
+ return /* @__PURE__ */ jsxs20(Fragment2, { children: [
3682
+ /* @__PURE__ */ jsxs20(View21, { collapsable: false, onLayout: (event) => setCaptureSize({ width: event.nativeEvent.layout.width, height: event.nativeEvent.layout.height }), ref: captureTarget, style: [styles21.space, { backgroundColor: theme.colors.darkCanvas }], children: [
3683
+ /* @__PURE__ */ jsx26(SpaceTopBarAndroid, { recording: controller.recording, formattedDuration: controller.formattedDuration, logoUrl: props.logoUrl, participantCount: controller.participantCount, spaceName: controller.spaceName }),
3684
+ props.reconnecting ? /* @__PURE__ */ jsx26(View21, { accessibilityLiveRegion: "polite", style: [styles21.recovery, { backgroundColor: theme.colors.primary }], children: /* @__PURE__ */ jsx26(Text16, { style: [styles21.recoveryText, { color: theme.colors.primaryForeground }], children: "Reconnecting\u2026 controls will resume shortly." }) }) : null,
3685
+ /* @__PURE__ */ jsx26(View21, { style: styles21.stage, children: controller.whiteboard.isOpen ? /* @__PURE__ */ jsx26(SpaceWhiteboardSurface, { whiteboard: controller.whiteboard }) : controller.derived.isStageMode || controller.layout.layout !== "grid" ? /* @__PURE__ */ jsx26(
3686
+ SpaceStageAndroid,
3687
+ {
3688
+ activeReactions: controller.activeReactions,
3689
+ handRaised: controller.handRaised,
3690
+ isCompactViewport: controller.derived.isCompactViewport,
3691
+ isMuted: controller.isMuted,
3692
+ layoutMode: controller.layout.layout,
3693
+ primaryContent: controller.derived.primaryContent,
3694
+ raisedHandCount: controller.raisedHandCount,
3695
+ screenShareTrack: controller.derived.screenShareTrack,
3696
+ screenSharer: controller.derived.screenSharer,
3697
+ selfName: controller.selfName,
3698
+ stripParticipants: controller.derived.allParticipants,
3699
+ whiteboard: {
3700
+ isOpen: controller.whiteboard.isOpen,
3701
+ canDraw: controller.whiteboard.canDraw,
3702
+ elementCount: controller.whiteboard.elements.length,
3703
+ participantCount: controller.whiteboard.openParticipants.length
3704
+ }
3227
3705
  }
3228
- }
3229
- ) : /* @__PURE__ */ jsx24(SpaceGridAndroid, { gridPages: controller.derived.gridPages, participants: controller.derived.allParticipants }) }),
3230
- /* @__PURE__ */ jsx24(
3231
- SpaceBottomDockAndroid,
3232
- {
3233
- isCameraOff: controller.isCameraOff,
3234
- isMuted: controller.isMuted,
3235
- onLeave: controller.handleLeave,
3236
- onOpenChat: controller.canChat ? () => controller.openPanel("chat") : void 0,
3237
- onOpenMore: () => controller.setActionsOpen(true),
3238
- onToggleAudio: () => toggleMedia(controller.toggleAudio),
3239
- onToggleVideo: () => toggleMedia(controller.toggleVideo),
3240
- simulatorMediaDisabled: controller.simulatorMediaDisabled,
3241
- unreadChatCount: controller.chat.unreadCount
3242
- }
3243
- ),
3244
- /* @__PURE__ */ jsx24(SpaceActionMenu, { controller, onOpenDiagnostics: props.onOpenDiagnostics }),
3245
- controller.panel === "settings" ? /* @__PURE__ */ jsx24(SettingsSheet, { controller, isOpen: true, onClose: controller.closePanel }) : /* @__PURE__ */ jsx24(SpacePanelSheet, { controller }),
3246
- /* @__PURE__ */ jsx24(ReactionPicker, { isOpen: controller.reactionPickerOpen, onClose: () => controller.setReactionPickerOpen(false), onSelect: (reaction) => selectSpaceReaction(controller, reaction) })
3706
+ ) : /* @__PURE__ */ jsx26(SpaceGridAndroid, { gridPages: controller.derived.gridPages, participants: controller.derived.allParticipants }) }),
3707
+ /* @__PURE__ */ jsx26(
3708
+ SpaceBottomDockAndroid,
3709
+ {
3710
+ isCameraOff: controller.isCameraOff,
3711
+ isMuted: controller.isMuted,
3712
+ onLeave: controller.handleLeave,
3713
+ onOpenChat: controller.canChat ? () => controller.openPanel("chat") : void 0,
3714
+ onOpenMore: () => controller.setActionsOpen(true),
3715
+ onToggleAudio: () => toggleMedia(controller.toggleAudio),
3716
+ onToggleVideo: () => toggleMedia(controller.toggleVideo),
3717
+ simulatorMediaDisabled: controller.simulatorMediaDisabled,
3718
+ unreadChatCount: controller.chat.unreadCount
3719
+ }
3720
+ ),
3721
+ /* @__PURE__ */ jsx26(SpaceActionMenu, { controller, onOpenDiagnostics: props.onOpenDiagnostics, onOpenFeedback: () => setFeedbackRequested(true) }),
3722
+ controller.panel === "settings" ? /* @__PURE__ */ jsx26(SettingsSheet, { controller, isOpen: true, onClose: controller.closePanel }) : /* @__PURE__ */ jsx26(SpacePanelSheet, { controller }),
3723
+ /* @__PURE__ */ jsx26(ReactionPicker, { isOpen: controller.reactionPickerOpen, onClose: () => controller.setReactionPickerOpen(false), onSelect: (reaction) => selectSpaceReaction(controller, reaction) })
3724
+ ] }),
3725
+ /* @__PURE__ */ jsx26(FeedbackSheet, { client, captureSize, captureTarget, feedbackEvidence: props.feedbackEvidence, onClose: () => setFeedbackRequested(false), requested: feedbackRequested })
3247
3726
  ] });
3248
3727
  }
3249
- var styles19 = StyleSheet20.create({
3728
+ var styles21 = StyleSheet22.create({
3250
3729
  space: { flex: 1, backgroundColor: Theme.colors.darkCanvas },
3251
3730
  stage: { flex: 1, width: "100%", overflow: "hidden", justifyContent: "center" },
3252
3731
  recovery: { alignItems: "center", paddingHorizontal: 16, paddingVertical: 8 },
@@ -3254,19 +3733,19 @@ var styles19 = StyleSheet20.create({
3254
3733
  });
3255
3734
 
3256
3735
  // src/components/SpaceView.tsx
3257
- import { jsx as jsx25 } from "react/jsx-runtime";
3736
+ import { jsx as jsx27 } from "react/jsx-runtime";
3258
3737
  function SpaceView(props) {
3259
3738
  switch (resolvePlatformVariant()) {
3260
3739
  case "ios-pad":
3261
- return /* @__PURE__ */ jsx25(SpaceViewShared, { ...props });
3740
+ return /* @__PURE__ */ jsx27(SpaceViewShared, { ...props });
3262
3741
  case "ios-phone":
3263
- return /* @__PURE__ */ jsx25(SpaceViewShared, { ...props });
3742
+ return /* @__PURE__ */ jsx27(SpaceViewShared, { ...props });
3264
3743
  case "macos":
3265
- return /* @__PURE__ */ jsx25(SpaceViewShared, { ...props });
3744
+ return /* @__PURE__ */ jsx27(SpaceViewShared, { ...props });
3266
3745
  case "tvos":
3267
3746
  case "android":
3268
3747
  default:
3269
- return /* @__PURE__ */ jsx25(SpaceViewShared, { ...props });
3748
+ return /* @__PURE__ */ jsx27(SpaceViewShared, { ...props });
3270
3749
  }
3271
3750
  }
3272
3751
 
@@ -3278,13 +3757,13 @@ import UserIcon2 from "@hugeicons/core-free-icons/dist/esm/UserIcon";
3278
3757
  import Video01Icon5 from "@hugeicons/core-free-icons/dist/esm/Video01Icon";
3279
3758
  import VideoOffIcon4 from "@hugeicons/core-free-icons/dist/esm/VideoOffIcon";
3280
3759
  import { HugeiconsIcon as HugeiconsIcon11 } from "@hugeicons/react-native";
3281
- import { KeyboardAvoidingView as KeyboardAvoidingView2, Platform as Platform10, Pressable as Pressable13, StyleSheet as StyleSheet21, Text as Text15, TextInput as TextInput2, View as View20 } from "react-native";
3760
+ import { KeyboardAvoidingView as KeyboardAvoidingView3, Platform as Platform14, Pressable as Pressable15, StyleSheet as StyleSheet23, Text as Text17, TextInput as TextInput3, View as View22 } from "react-native";
3282
3761
 
3283
3762
  // src/components/native-entrance/useEntranceController.ts
3284
- import { useMemo as useMemo14, useSyncExternalStore as useSyncExternalStore4 } from "react";
3763
+ import { useMemo as useMemo15, useSyncExternalStore as useSyncExternalStore4 } from "react";
3285
3764
 
3286
3765
  // src/hooks/useEntrancePreview.ts
3287
- import { useMemo as useMemo13, useSyncExternalStore as useSyncExternalStore3 } from "react";
3766
+ import { useMemo as useMemo14, useSyncExternalStore as useSyncExternalStore3 } from "react";
3288
3767
 
3289
3768
  // src/hooks/entrance-preview-store.ts
3290
3769
  function stopPreviewTracks(stream) {
@@ -3359,7 +3838,7 @@ function createEntrancePreviewStore(options) {
3359
3838
  // src/hooks/useEntrancePreview.ts
3360
3839
  function useEntrancePreview(enabled) {
3361
3840
  const simulatorVideoDisabled = isIosSimulator();
3362
- const store = useMemo13(
3841
+ const store = useMemo14(
3363
3842
  () => createEntrancePreviewStore({
3364
3843
  enabled,
3365
3844
  simulatorVideoDisabled,
@@ -3449,7 +3928,7 @@ var EntranceControllerStore = class {
3449
3928
  // src/components/native-entrance/useEntranceController.ts
3450
3929
  function useEntranceController({ displayName = "", initialAudioEnabled = false, initialVideoEnabled = false, joinDisabled = false, onJoin }) {
3451
3930
  const simulatorMediaDisabled = isIosSimulator();
3452
- const store = useMemo14(
3931
+ const store = useMemo15(
3453
3932
  () => new EntranceControllerStore({
3454
3933
  displayName,
3455
3934
  initialAudioEnabled,
@@ -3485,34 +3964,34 @@ function useEntranceController({ displayName = "", initialAudioEnabled = false,
3485
3964
  }
3486
3965
 
3487
3966
  // src/components/EntranceView.android.tsx
3488
- import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
3967
+ import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
3489
3968
  function EntranceViewAndroid({ spaceName, error, joinDisabled = false, onCancel, ...props }) {
3490
3969
  const controller = useEntranceController({ ...props, joinDisabled });
3491
3970
  const theme = useNativeTheme();
3492
3971
  const canJoin = controller.displayName.trim().length > 0 && !joinDisabled && !controller.isSubmitting;
3493
- return /* @__PURE__ */ jsx26(KeyboardAvoidingView2, { behavior: Platform10.OS === "ios" ? "padding" : "height", style: [styles20.screen, { backgroundColor: theme.colors.background }], children: /* @__PURE__ */ jsxs19(View20, { style: styles20.content, children: [
3494
- /* @__PURE__ */ jsxs19(View20, { style: styles20.previewContainer, children: [
3495
- /* @__PURE__ */ jsxs19(View20, { style: [styles20.previewSurface, { backgroundColor: theme.colors.raisedSurface, borderColor: theme.colors.border }], children: [
3496
- controller.previewStream && controller.videoEnabled ? /* @__PURE__ */ jsx26(RTCView, { mirror: true, objectFit: "cover", streamURL: controller.previewStream.toURL(), style: styles20.previewVideo, zOrder: 0 }) : /* @__PURE__ */ jsx26(View20, { style: [styles20.avatarContainer, { backgroundColor: theme.colors.insetSurface }], children: /* @__PURE__ */ jsx26(FaceAvatar, { name: controller.displayName, size: 140, textSize: 52 }) }),
3497
- onCancel ? /* @__PURE__ */ jsx26(Pressable13, { accessibilityLabel: "Cancel and leave Entrance", accessibilityRole: "button", onPress: onCancel, style: ({ pressed }) => [styles20.floatingBack, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }, pressed && styles20.topIconButtonPressed], children: /* @__PURE__ */ jsx26(HugeiconsIcon11, { icon: ArrowLeft01Icon, size: 22, color: theme.colors.foreground }) }) : null
3972
+ return /* @__PURE__ */ jsx28(KeyboardAvoidingView3, { behavior: Platform14.OS === "ios" ? "padding" : "height", style: [styles22.screen, { backgroundColor: theme.colors.background }], children: /* @__PURE__ */ jsxs21(View22, { style: styles22.content, children: [
3973
+ /* @__PURE__ */ jsxs21(View22, { style: styles22.previewContainer, children: [
3974
+ /* @__PURE__ */ jsxs21(View22, { style: [styles22.previewSurface, { backgroundColor: theme.colors.raisedSurface, borderColor: theme.colors.border }], children: [
3975
+ controller.previewStream && controller.videoEnabled ? /* @__PURE__ */ jsx28(RTCView, { mirror: true, objectFit: "cover", streamURL: controller.previewStream.toURL(), style: styles22.previewVideo, zOrder: 0 }) : /* @__PURE__ */ jsx28(View22, { style: [styles22.avatarContainer, { backgroundColor: theme.colors.insetSurface }], children: /* @__PURE__ */ jsx28(FaceAvatar, { name: controller.displayName, size: 140, textSize: 52 }) }),
3976
+ onCancel ? /* @__PURE__ */ jsx28(Pressable15, { accessibilityLabel: "Cancel and leave Entrance", accessibilityRole: "button", onPress: onCancel, style: ({ pressed }) => [styles22.floatingBack, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }, pressed && styles22.topIconButtonPressed], children: /* @__PURE__ */ jsx28(HugeiconsIcon11, { icon: ArrowLeft01Icon, size: 22, color: theme.colors.foreground }) }) : null
3498
3977
  ] }),
3499
- controller.previewError && controller.videoEnabled ? /* @__PURE__ */ jsx26(Text15, { style: styles20.previewError, children: controller.previewError }) : null,
3500
- controller.simulatorMediaDisabled ? /* @__PURE__ */ jsx26(Text15, { style: styles20.previewHint, children: getIosSimulatorMediaMessage() }) : null
3978
+ controller.previewError && controller.videoEnabled ? /* @__PURE__ */ jsx28(Text17, { style: styles22.previewError, children: controller.previewError }) : null,
3979
+ controller.simulatorMediaDisabled ? /* @__PURE__ */ jsx28(Text17, { style: styles22.previewHint, children: getIosSimulatorMediaMessage() }) : null
3501
3980
  ] }),
3502
- /* @__PURE__ */ jsxs19(View20, { style: [styles20.sheetContainer, { backgroundColor: theme.colors.card, borderColor: theme.colors.border, shadowColor: theme.colors.darkCanvas }], children: [
3503
- /* @__PURE__ */ jsx26(View20, { style: styles20.sheetHandle }),
3504
- /* @__PURE__ */ jsx26(View20, { style: styles20.sheetHeader, children: /* @__PURE__ */ jsx26(Text15, { style: [styles20.spaceName, { color: theme.colors.foreground }], numberOfLines: 1, children: spaceName }) }),
3505
- /* @__PURE__ */ jsxs19(View20, { style: [styles20.inputCard, { backgroundColor: theme.colors.surface, borderColor: controller.isInputFocused ? theme.colors.ring : theme.colors.border }], children: [
3506
- /* @__PURE__ */ jsx26(HugeiconsIcon11, { icon: UserIcon2, size: 18, color: controller.isInputFocused ? theme.colors.primary : theme.colors.mutedForeground, style: styles20.inputIcon }),
3507
- /* @__PURE__ */ jsx26(
3508
- TextInput2,
3981
+ /* @__PURE__ */ jsxs21(View22, { style: [styles22.sheetContainer, { backgroundColor: theme.colors.card, borderColor: theme.colors.border, shadowColor: theme.colors.darkCanvas }], children: [
3982
+ /* @__PURE__ */ jsx28(View22, { style: styles22.sheetHandle }),
3983
+ /* @__PURE__ */ jsx28(View22, { style: styles22.sheetHeader, children: /* @__PURE__ */ jsx28(Text17, { style: [styles22.spaceName, { color: theme.colors.foreground }], numberOfLines: 1, children: spaceName }) }),
3984
+ /* @__PURE__ */ jsxs21(View22, { style: [styles22.inputCard, { backgroundColor: theme.colors.surface, borderColor: controller.isInputFocused ? theme.colors.ring : theme.colors.border }], children: [
3985
+ /* @__PURE__ */ jsx28(HugeiconsIcon11, { icon: UserIcon2, size: 18, color: controller.isInputFocused ? theme.colors.primary : theme.colors.mutedForeground, style: styles22.inputIcon }),
3986
+ /* @__PURE__ */ jsx28(
3987
+ TextInput3,
3509
3988
  {
3510
3989
  onChangeText: controller.setDisplayName,
3511
3990
  onFocus: () => controller.setInputFocused(true),
3512
3991
  onBlur: () => controller.setInputFocused(false),
3513
3992
  placeholder: "Enter your name",
3514
3993
  placeholderTextColor: theme.colors.mutedForeground,
3515
- style: [styles20.nameInput, { color: theme.colors.foreground }],
3994
+ style: [styles22.nameInput, { color: theme.colors.foreground }],
3516
3995
  value: controller.displayName,
3517
3996
  maxLength: 30,
3518
3997
  returnKeyType: "join",
@@ -3520,32 +3999,32 @@ function EntranceViewAndroid({ spaceName, error, joinDisabled = false, onCancel,
3520
3999
  }
3521
4000
  )
3522
4001
  ] }),
3523
- /* @__PURE__ */ jsxs19(View20, { style: styles20.mediaRow, children: [
3524
- /* @__PURE__ */ jsx26(
3525
- Pressable13,
4002
+ /* @__PURE__ */ jsxs21(View22, { style: styles22.mediaRow, children: [
4003
+ /* @__PURE__ */ jsx28(
4004
+ Pressable15,
3526
4005
  {
3527
4006
  disabled: controller.simulatorMediaDisabled,
3528
4007
  onPress: controller.toggleAudio,
3529
- style: ({ pressed }) => [styles20.controlCircle, { backgroundColor: controller.audioEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles20.toggleCircleDisabled, pressed && styles20.togglePressed],
3530
- children: /* @__PURE__ */ jsx26(HugeiconsIcon11, { icon: controller.audioEnabled ? Mic01Icon4 : MicOff01Icon7, size: 24, color: theme.colors.primaryForeground })
4008
+ style: ({ pressed }) => [styles22.controlCircle, { backgroundColor: controller.audioEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles22.toggleCircleDisabled, pressed && styles22.togglePressed],
4009
+ children: /* @__PURE__ */ jsx28(HugeiconsIcon11, { icon: controller.audioEnabled ? Mic01Icon4 : MicOff01Icon7, size: 24, color: theme.colors.primaryForeground })
3531
4010
  }
3532
4011
  ),
3533
- /* @__PURE__ */ jsx26(
3534
- Pressable13,
4012
+ /* @__PURE__ */ jsx28(
4013
+ Pressable15,
3535
4014
  {
3536
4015
  disabled: controller.simulatorMediaDisabled,
3537
4016
  onPress: controller.toggleVideo,
3538
- style: ({ pressed }) => [styles20.controlCircle, { backgroundColor: controller.videoEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles20.toggleCircleDisabled, pressed && styles20.togglePressed],
3539
- children: /* @__PURE__ */ jsx26(HugeiconsIcon11, { icon: controller.videoEnabled ? Video01Icon5 : VideoOffIcon4, size: 24, color: theme.colors.primaryForeground })
4017
+ style: ({ pressed }) => [styles22.controlCircle, { backgroundColor: controller.videoEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles22.toggleCircleDisabled, pressed && styles22.togglePressed],
4018
+ children: /* @__PURE__ */ jsx28(HugeiconsIcon11, { icon: controller.videoEnabled ? Video01Icon5 : VideoOffIcon4, size: 24, color: theme.colors.primaryForeground })
3540
4019
  }
3541
4020
  )
3542
4021
  ] }),
3543
- error ? /* @__PURE__ */ jsx26(Text15, { style: [styles20.globalError, { color: theme.colors.error }], children: error }) : null,
3544
- /* @__PURE__ */ jsx26(Pressable13, { disabled: !canJoin, onPress: controller.handleJoin, style: ({ pressed }) => [styles20.joinButton, { backgroundColor: canJoin ? theme.colors.primary : theme.colors.muted }, !canJoin && styles20.joinButtonDisabled, pressed && styles20.togglePressed], children: /* @__PURE__ */ jsx26(Text15, { style: [styles20.joinButtonText, { color: theme.colors.primaryForeground }], children: controller.isSubmitting || joinDisabled ? "Joining..." : "Enter Space" }) })
4022
+ error ? /* @__PURE__ */ jsx28(Text17, { style: [styles22.globalError, { color: theme.colors.error }], children: error }) : null,
4023
+ /* @__PURE__ */ jsx28(Pressable15, { disabled: !canJoin, onPress: controller.handleJoin, style: ({ pressed }) => [styles22.joinButton, { backgroundColor: canJoin ? theme.colors.primary : theme.colors.muted }, !canJoin && styles22.joinButtonDisabled, pressed && styles22.togglePressed], children: /* @__PURE__ */ jsx28(Text17, { style: [styles22.joinButtonText, { color: theme.colors.primaryForeground }], children: controller.isSubmitting || joinDisabled ? "Joining..." : "Enter Space" }) })
3545
4024
  ] })
3546
4025
  ] }) });
3547
4026
  }
3548
- var styles20 = StyleSheet21.create({
4027
+ var styles22 = StyleSheet23.create({
3549
4028
  screen: {
3550
4029
  flex: 1,
3551
4030
  backgroundColor: Theme.colors.background
@@ -3555,7 +4034,7 @@ var styles20 = StyleSheet21.create({
3555
4034
  },
3556
4035
  floatingBack: {
3557
4036
  position: "absolute",
3558
- top: Platform10.OS === "ios" ? 24 : 20,
4037
+ top: Platform14.OS === "ios" ? 24 : 20,
3559
4038
  left: 20,
3560
4039
  width: 42,
3561
4040
  height: 42,
@@ -3570,7 +4049,7 @@ var styles20 = StyleSheet21.create({
3570
4049
  previewContainer: {
3571
4050
  flex: 1,
3572
4051
  justifyContent: "center",
3573
- paddingTop: Platform10.OS === "ios" ? 10 : 0,
4052
+ paddingTop: Platform14.OS === "ios" ? 10 : 0,
3574
4053
  marginBottom: 0
3575
4054
  },
3576
4055
  previewSurface: {
@@ -3585,10 +4064,10 @@ var styles20 = StyleSheet21.create({
3585
4064
  borderColor: Theme.colors.whiteOverlay06
3586
4065
  },
3587
4066
  previewVideo: {
3588
- ...StyleSheet21.absoluteFillObject
4067
+ ...StyleSheet23.absoluteFillObject
3589
4068
  },
3590
4069
  avatarContainer: {
3591
- ...StyleSheet21.absoluteFillObject,
4070
+ ...StyleSheet23.absoluteFillObject,
3592
4071
  alignItems: "center",
3593
4072
  justifyContent: "center",
3594
4073
  backgroundColor: Theme.colors.insetSurface
@@ -3619,7 +4098,7 @@ var styles20 = StyleSheet21.create({
3619
4098
  borderTopRightRadius: 32,
3620
4099
  paddingHorizontal: 24,
3621
4100
  paddingTop: 16,
3622
- paddingBottom: Platform10.OS === "ios" ? 44 : 32,
4101
+ paddingBottom: Platform14.OS === "ios" ? 44 : 32,
3623
4102
  gap: 20,
3624
4103
  borderTopWidth: 1,
3625
4104
  borderColor: Theme.colors.whiteOverlay08,
@@ -3730,7 +4209,7 @@ import VideoOffIcon5 from "@hugeicons/core-free-icons/dist/esm/VideoOffIcon";
3730
4209
  import ArrowRight02Icon from "@hugeicons/core-free-icons/dist/esm/ArrowRight02Icon";
3731
4210
  import CancelCircleIcon2 from "@hugeicons/core-free-icons/dist/esm/CancelCircleIcon";
3732
4211
  import { HugeiconsIcon as HugeiconsIcon12 } from "@hugeicons/react-native";
3733
- import { KeyboardAvoidingView as KeyboardAvoidingView3, Platform as Platform11, Pressable as Pressable14, StyleSheet as StyleSheet22, Text as Text16, TextInput as TextInput3, View as View21, Animated as Animated2, ActivityIndicator as ActivityIndicator2 } from "react-native";
4212
+ import { KeyboardAvoidingView as KeyboardAvoidingView4, Platform as Platform15, Pressable as Pressable16, StyleSheet as StyleSheet24, Text as Text18, TextInput as TextInput4, View as View23, Animated as Animated2, ActivityIndicator as ActivityIndicator2 } from "react-native";
3734
4213
 
3735
4214
  // src/components/native-animation-controller.ts
3736
4215
  function createAnimationRefController(createAnimations) {
@@ -3760,15 +4239,15 @@ function createAnimationRefController(createAnimations) {
3760
4239
  }
3761
4240
 
3762
4241
  // src/components/EntranceView.ios-pad.tsx
3763
- import { useRef as useRef5 } from "react";
3764
- import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
4242
+ import { useRef as useRef6 } from "react";
4243
+ import { jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
3765
4244
  function EntranceViewIosPad({ spaceName, error, joinDisabled = false, onCancel, ...props }) {
3766
4245
  const controller = useEntranceController({ ...props, joinDisabled });
3767
4246
  const theme = useNativeTheme();
3768
4247
  const canRenderPreview = hasRtcVideoView();
3769
- const entryAnim = useRef5(new Animated2.Value(0)).current;
3770
- const islandAnim = useRef5(new Animated2.Value(0)).current;
3771
- const animationRef = useRef5(null);
4248
+ const entryAnim = useRef6(new Animated2.Value(0)).current;
4249
+ const islandAnim = useRef6(new Animated2.Value(0)).current;
4250
+ const animationRef = useRef6(null);
3772
4251
  const attachEntryAnimation = animationRef.current ?? (animationRef.current = createAnimationRefController(() => [
3773
4252
  Animated2.stagger(300, [
3774
4253
  Animated2.spring(entryAnim, {
@@ -3788,61 +4267,61 @@ function EntranceViewIosPad({ spaceName, error, joinDisabled = false, onCancel,
3788
4267
  const canJoin = controller.displayName.trim().length > 0 && !joinDisabled && !controller.isSubmitting;
3789
4268
  const showPreview = Boolean(controller.previewStream && controller.videoEnabled && canRenderPreview);
3790
4269
  const previewStreamURL = showPreview && controller.previewStream ? controller.previewStream.toURL() : null;
3791
- return /* @__PURE__ */ jsxs20(KeyboardAvoidingView3, { behavior: Platform11.OS === "ios" ? "padding" : "height", style: [styles21.screen, { backgroundColor: theme.colors.background }], children: [
3792
- /* @__PURE__ */ jsxs20(View21, { style: [styles21.immersiveContainer, { backgroundColor: theme.colors.darkCanvas }], children: [
3793
- previewStreamURL ? /* @__PURE__ */ jsx27(RtcVideoView, { mirror: true, objectFit: "cover", streamURL: previewStreamURL, style: styles21.fullScreenVideo, zOrder: -1 }) : /* @__PURE__ */ jsx27(View21, { style: [styles21.immersiveAvatarContainer, { backgroundColor: theme.colors.background }], children: /* @__PURE__ */ jsx27(FaceAvatar, { name: controller.displayName, size: 200, textSize: 80 }) }),
3794
- showPreview ? /* @__PURE__ */ jsx27(View21, { style: styles21.frostOverlay }) : null
4270
+ return /* @__PURE__ */ jsxs22(KeyboardAvoidingView4, { behavior: Platform15.OS === "ios" ? "padding" : "height", style: [styles23.screen, { backgroundColor: theme.colors.background }], children: [
4271
+ /* @__PURE__ */ jsxs22(View23, { style: [styles23.immersiveContainer, { backgroundColor: theme.colors.darkCanvas }], children: [
4272
+ previewStreamURL ? /* @__PURE__ */ jsx29(RtcVideoView, { mirror: true, objectFit: "cover", streamURL: previewStreamURL, style: styles23.fullScreenVideo, zOrder: -1 }) : /* @__PURE__ */ jsx29(View23, { style: [styles23.immersiveAvatarContainer, { backgroundColor: theme.colors.background }], children: /* @__PURE__ */ jsx29(FaceAvatar, { name: controller.displayName, size: 200, textSize: 80 }) }),
4273
+ showPreview ? /* @__PURE__ */ jsx29(View23, { style: styles23.frostOverlay }) : null
3795
4274
  ] }),
3796
- /* @__PURE__ */ jsxs20(View21, { style: styles21.hudLayer, children: [
3797
- /* @__PURE__ */ jsxs20(View21, { style: styles21.topHud, children: [
3798
- onCancel ? /* @__PURE__ */ jsx27(Pressable14, { accessibilityLabel: "Cancel and leave Entrance", accessibilityRole: "button", onPress: onCancel, style: ({ pressed }) => [styles21.backPuck, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }, pressed && styles21.pressed], children: /* @__PURE__ */ jsx27(HugeiconsIcon12, { icon: ArrowLeft01Icon2, size: 22, color: theme.colors.foreground }) }) : null,
3799
- /* @__PURE__ */ jsx27(View21, { style: styles21.spaceInfo, children: /* @__PURE__ */ jsx27(Text16, { style: [styles21.spaceTitle, { color: theme.colors.foreground }], numberOfLines: 1, children: spaceName }) }),
3800
- /* @__PURE__ */ jsx27(View21, { style: styles21.topHudSpacer })
4275
+ /* @__PURE__ */ jsxs22(View23, { style: styles23.hudLayer, children: [
4276
+ /* @__PURE__ */ jsxs22(View23, { style: styles23.topHud, children: [
4277
+ onCancel ? /* @__PURE__ */ jsx29(Pressable16, { accessibilityLabel: "Cancel and leave Entrance", accessibilityRole: "button", onPress: onCancel, style: ({ pressed }) => [styles23.backPuck, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }, pressed && styles23.pressed], children: /* @__PURE__ */ jsx29(HugeiconsIcon12, { icon: ArrowLeft01Icon2, size: 22, color: theme.colors.foreground }) }) : null,
4278
+ /* @__PURE__ */ jsx29(View23, { style: styles23.spaceInfo, children: /* @__PURE__ */ jsx29(Text18, { style: [styles23.spaceTitle, { color: theme.colors.foreground }], numberOfLines: 1, children: spaceName }) }),
4279
+ /* @__PURE__ */ jsx29(View23, { style: styles23.topHudSpacer })
3801
4280
  ] }),
3802
- /* @__PURE__ */ jsx27(View21, { style: styles21.flexFill }),
3803
- /* @__PURE__ */ jsxs20(
4281
+ /* @__PURE__ */ jsx29(View23, { style: styles23.flexFill }),
4282
+ /* @__PURE__ */ jsxs22(
3804
4283
  Animated2.View,
3805
4284
  {
3806
4285
  ref: attachEntryAnimation,
3807
4286
  style: [
3808
- styles21.bottomHud,
4287
+ styles23.bottomHud,
3809
4288
  {
3810
4289
  opacity: islandAnim,
3811
4290
  transform: [{ translateY: islandAnim.interpolate({ inputRange: [0, 1], outputRange: [40, 0] }) }]
3812
4291
  }
3813
4292
  ],
3814
4293
  children: [
3815
- /* @__PURE__ */ jsxs20(View21, { style: [styles21.launchPad, { backgroundColor: theme.colors.card, borderColor: theme.colors.border, shadowColor: theme.colors.darkCanvas }], children: [
3816
- /* @__PURE__ */ jsxs20(View21, { style: styles21.mediaGroup, children: [
3817
- /* @__PURE__ */ jsx27(
3818
- Pressable14,
4294
+ /* @__PURE__ */ jsxs22(View23, { style: [styles23.launchPad, { backgroundColor: theme.colors.card, borderColor: theme.colors.border, shadowColor: theme.colors.darkCanvas }], children: [
4295
+ /* @__PURE__ */ jsxs22(View23, { style: styles23.mediaGroup, children: [
4296
+ /* @__PURE__ */ jsx29(
4297
+ Pressable16,
3819
4298
  {
3820
4299
  accessibilityLabel: controller.audioEnabled ? "Mute microphone" : "Unmute microphone",
3821
4300
  accessibilityRole: "button",
3822
4301
  accessibilityState: { disabled: controller.simulatorMediaDisabled, selected: controller.audioEnabled },
3823
4302
  disabled: controller.simulatorMediaDisabled,
3824
4303
  onPress: controller.toggleAudio,
3825
- style: ({ pressed }) => [styles21.mediaToggle, { backgroundColor: controller.audioEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, pressed && styles21.pressed],
3826
- children: /* @__PURE__ */ jsx27(HugeiconsIcon12, { icon: controller.audioEnabled ? Mic01Icon5 : MicOff01Icon8, size: 22, color: theme.colors.primaryForeground })
4304
+ style: ({ pressed }) => [styles23.mediaToggle, { backgroundColor: controller.audioEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, pressed && styles23.pressed],
4305
+ children: /* @__PURE__ */ jsx29(HugeiconsIcon12, { icon: controller.audioEnabled ? Mic01Icon5 : MicOff01Icon8, size: 22, color: theme.colors.primaryForeground })
3827
4306
  }
3828
4307
  ),
3829
- /* @__PURE__ */ jsx27(
3830
- Pressable14,
4308
+ /* @__PURE__ */ jsx29(
4309
+ Pressable16,
3831
4310
  {
3832
4311
  accessibilityLabel: controller.videoEnabled ? "Turn camera off" : "Turn camera on",
3833
4312
  accessibilityRole: "button",
3834
4313
  accessibilityState: { disabled: controller.simulatorMediaDisabled, selected: controller.videoEnabled },
3835
4314
  disabled: controller.simulatorMediaDisabled,
3836
4315
  onPress: controller.toggleVideo,
3837
- style: ({ pressed }) => [styles21.mediaToggle, { backgroundColor: controller.videoEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, pressed && styles21.pressed],
3838
- children: /* @__PURE__ */ jsx27(HugeiconsIcon12, { icon: controller.videoEnabled ? Video01Icon6 : VideoOffIcon5, size: 22, color: theme.colors.primaryForeground })
4316
+ style: ({ pressed }) => [styles23.mediaToggle, { backgroundColor: controller.videoEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, pressed && styles23.pressed],
4317
+ children: /* @__PURE__ */ jsx29(HugeiconsIcon12, { icon: controller.videoEnabled ? Video01Icon6 : VideoOffIcon5, size: 22, color: theme.colors.primaryForeground })
3839
4318
  }
3840
4319
  )
3841
4320
  ] }),
3842
- /* @__PURE__ */ jsx27(View21, { style: styles21.islandDivider }),
3843
- /* @__PURE__ */ jsxs20(View21, { style: [styles21.identityArea, { backgroundColor: theme.colors.surface, borderColor: controller.isInputFocused ? theme.colors.ring : theme.colors.border }, controller.isInputFocused && styles21.identityAreaFocused], children: [
3844
- /* @__PURE__ */ jsx27(
3845
- TextInput3,
4321
+ /* @__PURE__ */ jsx29(View23, { style: styles23.islandDivider }),
4322
+ /* @__PURE__ */ jsxs22(View23, { style: [styles23.identityArea, { backgroundColor: theme.colors.surface, borderColor: controller.isInputFocused ? theme.colors.ring : theme.colors.border }, controller.isInputFocused && styles23.identityAreaFocused], children: [
4323
+ /* @__PURE__ */ jsx29(
4324
+ TextInput4,
3846
4325
  {
3847
4326
  accessibilityLabel: "Your name",
3848
4327
  onChangeText: controller.setDisplayName,
@@ -3850,17 +4329,17 @@ function EntranceViewIosPad({ spaceName, error, joinDisabled = false, onCancel,
3850
4329
  onBlur: () => controller.setInputFocused(false),
3851
4330
  placeholder: "Enter your name to join",
3852
4331
  placeholderTextColor: theme.colors.mutedForeground,
3853
- style: [styles21.immersiveInput, { color: theme.colors.foreground }],
4332
+ style: [styles23.immersiveInput, { color: theme.colors.foreground }],
3854
4333
  value: controller.displayName,
3855
4334
  maxLength: 30,
3856
4335
  returnKeyType: "join",
3857
4336
  onSubmitEditing: controller.handleJoin
3858
4337
  }
3859
4338
  ),
3860
- controller.displayName.length > 0 && /* @__PURE__ */ jsx27(Pressable14, { accessibilityLabel: "Clear name", accessibilityRole: "button", onPress: () => controller.setDisplayName(""), style: styles21.clearAction, children: /* @__PURE__ */ jsx27(HugeiconsIcon12, { icon: CancelCircleIcon2, size: 18, color: theme.colors.mutedForeground }) })
4339
+ controller.displayName.length > 0 && /* @__PURE__ */ jsx29(Pressable16, { accessibilityLabel: "Clear name", accessibilityRole: "button", onPress: () => controller.setDisplayName(""), style: styles23.clearAction, children: /* @__PURE__ */ jsx29(HugeiconsIcon12, { icon: CancelCircleIcon2, size: 18, color: theme.colors.mutedForeground }) })
3861
4340
  ] }),
3862
- /* @__PURE__ */ jsx27(
3863
- Pressable14,
4341
+ /* @__PURE__ */ jsx29(
4342
+ Pressable16,
3864
4343
  {
3865
4344
  accessibilityLabel: "Enter Space",
3866
4345
  accessibilityRole: "button",
@@ -3868,7 +4347,7 @@ function EntranceViewIosPad({ spaceName, error, joinDisabled = false, onCancel,
3868
4347
  disabled: !canJoin,
3869
4348
  onPress: controller.handleJoin,
3870
4349
  style: ({ pressed }) => [
3871
- styles21.joinArrow,
4350
+ styles23.joinArrow,
3872
4351
  canJoin && {
3873
4352
  backgroundColor: theme.colors.primary,
3874
4353
  shadowColor: theme.colors.primary,
@@ -3876,41 +4355,41 @@ function EntranceViewIosPad({ spaceName, error, joinDisabled = false, onCancel,
3876
4355
  shadowOpacity: 0.3,
3877
4356
  shadowRadius: 8
3878
4357
  },
3879
- pressed && canJoin && styles21.pressed,
3880
- controller.isSubmitting && styles21.disabled
4358
+ pressed && canJoin && styles23.pressed,
4359
+ controller.isSubmitting && styles23.disabled
3881
4360
  ],
3882
- children: controller.isSubmitting ? /* @__PURE__ */ jsx27(ActivityIndicator2, { color: theme.colors.primaryForeground, size: "small" }) : /* @__PURE__ */ jsx27(HugeiconsIcon12, { icon: ArrowRight02Icon, size: 28, color: canJoin ? theme.colors.primaryForeground : theme.colors.mutedForeground })
4361
+ children: controller.isSubmitting ? /* @__PURE__ */ jsx29(ActivityIndicator2, { color: theme.colors.primaryForeground, size: "small" }) : /* @__PURE__ */ jsx29(HugeiconsIcon12, { icon: ArrowRight02Icon, size: 28, color: canJoin ? theme.colors.primaryForeground : theme.colors.mutedForeground })
3883
4362
  }
3884
4363
  )
3885
4364
  ] }),
3886
- error ? /* @__PURE__ */ jsx27(Text16, { style: [styles21.immersiveError, { color: theme.colors.error }], children: error }) : null,
3887
- controller.simulatorMediaDisabled && /* @__PURE__ */ jsx27(Text16, { style: [styles21.simulatorHintText, { color: theme.colors.mutedForeground }], children: getIosSimulatorMediaMessage() })
4365
+ error ? /* @__PURE__ */ jsx29(Text18, { style: [styles23.immersiveError, { color: theme.colors.error }], children: error }) : null,
4366
+ controller.simulatorMediaDisabled && /* @__PURE__ */ jsx29(Text18, { style: [styles23.simulatorHintText, { color: theme.colors.mutedForeground }], children: getIosSimulatorMediaMessage() })
3888
4367
  ]
3889
4368
  }
3890
4369
  )
3891
4370
  ] })
3892
4371
  ] });
3893
4372
  }
3894
- var styles21 = StyleSheet22.create({
4373
+ var styles23 = StyleSheet24.create({
3895
4374
  screen: {
3896
4375
  flex: 1,
3897
4376
  backgroundColor: Theme.colors.darkCanvas
3898
4377
  },
3899
4378
  immersiveContainer: {
3900
- ...StyleSheet22.absoluteFillObject,
4379
+ ...StyleSheet24.absoluteFillObject,
3901
4380
  backgroundColor: Theme.colors.darkCanvas
3902
4381
  },
3903
4382
  fullScreenVideo: {
3904
- ...StyleSheet22.absoluteFillObject
4383
+ ...StyleSheet24.absoluteFillObject
3905
4384
  },
3906
4385
  immersiveAvatarContainer: {
3907
- ...StyleSheet22.absoluteFillObject,
4386
+ ...StyleSheet24.absoluteFillObject,
3908
4387
  alignItems: "center",
3909
4388
  justifyContent: "center",
3910
4389
  backgroundColor: Theme.colors.background
3911
4390
  },
3912
4391
  frostOverlay: {
3913
- ...StyleSheet22.absoluteFillObject,
4392
+ ...StyleSheet24.absoluteFillObject,
3914
4393
  backgroundColor: Theme.colors.darkOverlay30
3915
4394
  },
3916
4395
  hudLayer: {
@@ -4052,35 +4531,35 @@ import UserIcon3 from "@hugeicons/core-free-icons/dist/esm/UserIcon";
4052
4531
  import Video01Icon7 from "@hugeicons/core-free-icons/dist/esm/Video01Icon";
4053
4532
  import VideoOffIcon6 from "@hugeicons/core-free-icons/dist/esm/VideoOffIcon";
4054
4533
  import { HugeiconsIcon as HugeiconsIcon13 } from "@hugeicons/react-native";
4055
- import { KeyboardAvoidingView as KeyboardAvoidingView4, Platform as Platform12, Pressable as Pressable15, StyleSheet as StyleSheet23, Text as Text17, TextInput as TextInput4, View as View22 } from "react-native";
4056
- import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
4534
+ import { KeyboardAvoidingView as KeyboardAvoidingView5, Platform as Platform16, Pressable as Pressable17, StyleSheet as StyleSheet25, Text as Text19, TextInput as TextInput5, View as View24 } from "react-native";
4535
+ import { jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
4057
4536
  function EntranceViewIosPhone({ spaceName, error, joinDisabled = false, onCancel, ...props }) {
4058
4537
  const controller = useEntranceController({ ...props, joinDisabled });
4059
4538
  const theme = useNativeTheme();
4060
4539
  const canJoin = controller.displayName.trim().length > 0 && !joinDisabled && !controller.isSubmitting;
4061
- return /* @__PURE__ */ jsx28(KeyboardAvoidingView4, { behavior: Platform12.OS === "ios" ? "padding" : "height", style: [styles22.screen, { backgroundColor: theme.colors.background }], children: /* @__PURE__ */ jsxs21(View22, { style: styles22.content, children: [
4062
- /* @__PURE__ */ jsxs21(View22, { style: styles22.previewContainer, children: [
4063
- /* @__PURE__ */ jsxs21(View22, { style: [styles22.previewSurface, { backgroundColor: theme.colors.raisedSurface, borderColor: theme.colors.border }], children: [
4064
- controller.previewStream && controller.videoEnabled ? /* @__PURE__ */ jsx28(RTCView, { mirror: true, objectFit: "cover", streamURL: controller.previewStream.toURL(), style: styles22.previewVideo, zOrder: 0 }) : /* @__PURE__ */ jsx28(View22, { style: [styles22.avatarContainer, { backgroundColor: theme.colors.insetSurface }], children: /* @__PURE__ */ jsx28(FaceAvatar, { name: controller.displayName, size: 140, textSize: 52 }) }),
4065
- onCancel ? /* @__PURE__ */ jsx28(Pressable15, { accessibilityLabel: "Cancel and leave Entrance", accessibilityRole: "button", onPress: onCancel, style: ({ pressed }) => [styles22.floatingBack, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }, pressed && styles22.topIconButtonPressed], children: /* @__PURE__ */ jsx28(HugeiconsIcon13, { icon: ArrowLeft01Icon3, size: 22, color: theme.colors.foreground }) }) : null
4540
+ return /* @__PURE__ */ jsx30(KeyboardAvoidingView5, { behavior: Platform16.OS === "ios" ? "padding" : "height", style: [styles24.screen, { backgroundColor: theme.colors.background }], children: /* @__PURE__ */ jsxs23(View24, { style: styles24.content, children: [
4541
+ /* @__PURE__ */ jsxs23(View24, { style: styles24.previewContainer, children: [
4542
+ /* @__PURE__ */ jsxs23(View24, { style: [styles24.previewSurface, { backgroundColor: theme.colors.raisedSurface, borderColor: theme.colors.border }], children: [
4543
+ controller.previewStream && controller.videoEnabled ? /* @__PURE__ */ jsx30(RTCView, { mirror: true, objectFit: "cover", streamURL: controller.previewStream.toURL(), style: styles24.previewVideo, zOrder: 0 }) : /* @__PURE__ */ jsx30(View24, { style: [styles24.avatarContainer, { backgroundColor: theme.colors.insetSurface }], children: /* @__PURE__ */ jsx30(FaceAvatar, { name: controller.displayName, size: 140, textSize: 52 }) }),
4544
+ onCancel ? /* @__PURE__ */ jsx30(Pressable17, { accessibilityLabel: "Cancel and leave Entrance", accessibilityRole: "button", onPress: onCancel, style: ({ pressed }) => [styles24.floatingBack, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }, pressed && styles24.topIconButtonPressed], children: /* @__PURE__ */ jsx30(HugeiconsIcon13, { icon: ArrowLeft01Icon3, size: 22, color: theme.colors.foreground }) }) : null
4066
4545
  ] }),
4067
- controller.previewError && controller.videoEnabled ? /* @__PURE__ */ jsx28(Text17, { style: styles22.previewError, children: controller.previewError }) : null,
4068
- controller.simulatorMediaDisabled ? /* @__PURE__ */ jsx28(Text17, { style: styles22.previewHint, children: getIosSimulatorMediaMessage() }) : null
4546
+ controller.previewError && controller.videoEnabled ? /* @__PURE__ */ jsx30(Text19, { style: styles24.previewError, children: controller.previewError }) : null,
4547
+ controller.simulatorMediaDisabled ? /* @__PURE__ */ jsx30(Text19, { style: styles24.previewHint, children: getIosSimulatorMediaMessage() }) : null
4069
4548
  ] }),
4070
- /* @__PURE__ */ jsxs21(View22, { style: [styles22.sheetContainer, { backgroundColor: theme.colors.card, borderColor: theme.colors.border, shadowColor: theme.colors.darkCanvas }], children: [
4071
- /* @__PURE__ */ jsx28(View22, { style: styles22.sheetHandle }),
4072
- /* @__PURE__ */ jsx28(View22, { style: styles22.sheetHeader, children: /* @__PURE__ */ jsx28(Text17, { style: [styles22.spaceName, { color: theme.colors.foreground }], numberOfLines: 1, children: spaceName }) }),
4073
- /* @__PURE__ */ jsxs21(View22, { style: [styles22.inputCard, { backgroundColor: theme.colors.surface, borderColor: controller.isInputFocused ? theme.colors.ring : theme.colors.border }], children: [
4074
- /* @__PURE__ */ jsx28(HugeiconsIcon13, { icon: UserIcon3, size: 18, color: controller.isInputFocused ? theme.colors.primary : theme.colors.mutedForeground, style: styles22.inputIcon }),
4075
- /* @__PURE__ */ jsx28(
4076
- TextInput4,
4549
+ /* @__PURE__ */ jsxs23(View24, { style: [styles24.sheetContainer, { backgroundColor: theme.colors.card, borderColor: theme.colors.border, shadowColor: theme.colors.darkCanvas }], children: [
4550
+ /* @__PURE__ */ jsx30(View24, { style: styles24.sheetHandle }),
4551
+ /* @__PURE__ */ jsx30(View24, { style: styles24.sheetHeader, children: /* @__PURE__ */ jsx30(Text19, { style: [styles24.spaceName, { color: theme.colors.foreground }], numberOfLines: 1, children: spaceName }) }),
4552
+ /* @__PURE__ */ jsxs23(View24, { style: [styles24.inputCard, { backgroundColor: theme.colors.surface, borderColor: controller.isInputFocused ? theme.colors.ring : theme.colors.border }], children: [
4553
+ /* @__PURE__ */ jsx30(HugeiconsIcon13, { icon: UserIcon3, size: 18, color: controller.isInputFocused ? theme.colors.primary : theme.colors.mutedForeground, style: styles24.inputIcon }),
4554
+ /* @__PURE__ */ jsx30(
4555
+ TextInput5,
4077
4556
  {
4078
4557
  onChangeText: controller.setDisplayName,
4079
4558
  onFocus: () => controller.setInputFocused(true),
4080
4559
  onBlur: () => controller.setInputFocused(false),
4081
4560
  placeholder: "Enter your name",
4082
4561
  placeholderTextColor: theme.colors.mutedForeground,
4083
- style: [styles22.nameInput, { color: theme.colors.foreground }],
4562
+ style: [styles24.nameInput, { color: theme.colors.foreground }],
4084
4563
  value: controller.displayName,
4085
4564
  maxLength: 30,
4086
4565
  returnKeyType: "join",
@@ -4088,32 +4567,32 @@ function EntranceViewIosPhone({ spaceName, error, joinDisabled = false, onCancel
4088
4567
  }
4089
4568
  )
4090
4569
  ] }),
4091
- /* @__PURE__ */ jsxs21(View22, { style: styles22.mediaRow, children: [
4092
- /* @__PURE__ */ jsx28(
4093
- Pressable15,
4570
+ /* @__PURE__ */ jsxs23(View24, { style: styles24.mediaRow, children: [
4571
+ /* @__PURE__ */ jsx30(
4572
+ Pressable17,
4094
4573
  {
4095
4574
  disabled: controller.simulatorMediaDisabled,
4096
4575
  onPress: controller.toggleAudio,
4097
- style: ({ pressed }) => [styles22.controlCircle, { backgroundColor: controller.audioEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles22.toggleCircleDisabled, pressed && styles22.togglePressed],
4098
- children: /* @__PURE__ */ jsx28(HugeiconsIcon13, { icon: controller.audioEnabled ? Mic01Icon6 : MicOff01Icon9, size: 24, color: theme.colors.primaryForeground })
4576
+ style: ({ pressed }) => [styles24.controlCircle, { backgroundColor: controller.audioEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles24.toggleCircleDisabled, pressed && styles24.togglePressed],
4577
+ children: /* @__PURE__ */ jsx30(HugeiconsIcon13, { icon: controller.audioEnabled ? Mic01Icon6 : MicOff01Icon9, size: 24, color: theme.colors.primaryForeground })
4099
4578
  }
4100
4579
  ),
4101
- /* @__PURE__ */ jsx28(
4102
- Pressable15,
4580
+ /* @__PURE__ */ jsx30(
4581
+ Pressable17,
4103
4582
  {
4104
4583
  disabled: controller.simulatorMediaDisabled,
4105
4584
  onPress: controller.toggleVideo,
4106
- style: ({ pressed }) => [styles22.controlCircle, { backgroundColor: controller.videoEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles22.toggleCircleDisabled, pressed && styles22.togglePressed],
4107
- children: /* @__PURE__ */ jsx28(HugeiconsIcon13, { icon: controller.videoEnabled ? Video01Icon7 : VideoOffIcon6, size: 24, color: theme.colors.primaryForeground })
4585
+ style: ({ pressed }) => [styles24.controlCircle, { backgroundColor: controller.videoEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles24.toggleCircleDisabled, pressed && styles24.togglePressed],
4586
+ children: /* @__PURE__ */ jsx30(HugeiconsIcon13, { icon: controller.videoEnabled ? Video01Icon7 : VideoOffIcon6, size: 24, color: theme.colors.primaryForeground })
4108
4587
  }
4109
4588
  )
4110
4589
  ] }),
4111
- error ? /* @__PURE__ */ jsx28(Text17, { style: [styles22.globalError, { color: theme.colors.error }], children: error }) : null,
4112
- /* @__PURE__ */ jsx28(Pressable15, { disabled: !canJoin, onPress: controller.handleJoin, style: ({ pressed }) => [styles22.joinButton, { backgroundColor: canJoin ? theme.colors.primary : theme.colors.muted }, !canJoin && styles22.joinButtonDisabled, pressed && styles22.togglePressed], children: /* @__PURE__ */ jsx28(Text17, { style: [styles22.joinButtonText, { color: theme.colors.primaryForeground }], children: controller.isSubmitting || joinDisabled ? "Joining..." : "Enter Space" }) })
4590
+ error ? /* @__PURE__ */ jsx30(Text19, { style: [styles24.globalError, { color: theme.colors.error }], children: error }) : null,
4591
+ /* @__PURE__ */ jsx30(Pressable17, { disabled: !canJoin, onPress: controller.handleJoin, style: ({ pressed }) => [styles24.joinButton, { backgroundColor: canJoin ? theme.colors.primary : theme.colors.muted }, !canJoin && styles24.joinButtonDisabled, pressed && styles24.togglePressed], children: /* @__PURE__ */ jsx30(Text19, { style: [styles24.joinButtonText, { color: theme.colors.primaryForeground }], children: controller.isSubmitting || joinDisabled ? "Joining..." : "Enter Space" }) })
4113
4592
  ] })
4114
4593
  ] }) });
4115
4594
  }
4116
- var styles22 = StyleSheet23.create({
4595
+ var styles24 = StyleSheet25.create({
4117
4596
  screen: {
4118
4597
  flex: 1,
4119
4598
  backgroundColor: Theme.colors.background
@@ -4137,7 +4616,7 @@ var styles22 = StyleSheet23.create({
4137
4616
  previewContainer: {
4138
4617
  flex: 1,
4139
4618
  justifyContent: "center",
4140
- paddingTop: Platform12.OS === "ios" ? 10 : 0,
4619
+ paddingTop: Platform16.OS === "ios" ? 10 : 0,
4141
4620
  marginBottom: 0
4142
4621
  },
4143
4622
  previewSurface: {
@@ -4152,10 +4631,10 @@ var styles22 = StyleSheet23.create({
4152
4631
  borderColor: Theme.colors.whiteOverlay06
4153
4632
  },
4154
4633
  previewVideo: {
4155
- ...StyleSheet23.absoluteFillObject
4634
+ ...StyleSheet25.absoluteFillObject
4156
4635
  },
4157
4636
  avatarContainer: {
4158
- ...StyleSheet23.absoluteFillObject,
4637
+ ...StyleSheet25.absoluteFillObject,
4159
4638
  alignItems: "center",
4160
4639
  justifyContent: "center",
4161
4640
  backgroundColor: Theme.colors.insetSurface
@@ -4186,7 +4665,7 @@ var styles22 = StyleSheet23.create({
4186
4665
  borderTopRightRadius: 32,
4187
4666
  paddingHorizontal: 24,
4188
4667
  paddingTop: 16,
4189
- paddingBottom: Platform12.OS === "ios" ? 44 : 32,
4668
+ paddingBottom: Platform16.OS === "ios" ? 44 : 32,
4190
4669
  gap: 20,
4191
4670
  borderTopWidth: 1,
4192
4671
  borderColor: Theme.colors.whiteOverlay08,
@@ -4296,8 +4775,8 @@ import UserIcon4 from "@hugeicons/core-free-icons/dist/esm/UserIcon";
4296
4775
  import Video01Icon8 from "@hugeicons/core-free-icons/dist/esm/Video01Icon";
4297
4776
  import VideoOffIcon7 from "@hugeicons/core-free-icons/dist/esm/VideoOffIcon";
4298
4777
  import { HugeiconsIcon as HugeiconsIcon14 } from "@hugeicons/react-native";
4299
- import { KeyboardAvoidingView as KeyboardAvoidingView5, Platform as Platform13, Pressable as Pressable16, StyleSheet as StyleSheet24, Text as Text18, TextInput as TextInput5, View as View23 } from "react-native";
4300
- import { jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
4778
+ import { KeyboardAvoidingView as KeyboardAvoidingView6, Platform as Platform17, Pressable as Pressable18, StyleSheet as StyleSheet26, Text as Text20, TextInput as TextInput6, View as View25 } from "react-native";
4779
+ import { jsx as jsx31, jsxs as jsxs24 } from "react/jsx-runtime";
4301
4780
  function EntranceViewMacos({ spaceName, error, joinDisabled = false, onCancel, ...props }) {
4302
4781
  const controller = useEntranceController({ ...props, joinDisabled });
4303
4782
  const theme = useNativeTheme();
@@ -4306,29 +4785,29 @@ function EntranceViewMacos({ spaceName, error, joinDisabled = false, onCancel, .
4306
4785
  const showPreview = Boolean(controller.previewStream && controller.videoEnabled && canRenderPreview);
4307
4786
  const previewStreamURL = showPreview && controller.previewStream ? controller.previewStream.toURL() : null;
4308
4787
  const previewStatusMessage = controller.videoEnabled && controller.previewStream && !canRenderPreview ? "Camera preview is unavailable on this device." : controller.previewError;
4309
- return /* @__PURE__ */ jsx29(KeyboardAvoidingView5, { behavior: Platform13.OS === "ios" ? "padding" : "height", style: [styles23.screen, { backgroundColor: theme.colors.background }], children: /* @__PURE__ */ jsxs22(View23, { style: styles23.content, children: [
4310
- /* @__PURE__ */ jsxs22(View23, { style: styles23.previewContainer, children: [
4311
- /* @__PURE__ */ jsxs22(View23, { style: [styles23.previewSurface, { backgroundColor: theme.colors.raisedSurface, borderColor: theme.colors.border }], children: [
4312
- previewStreamURL ? /* @__PURE__ */ jsx29(RtcVideoView, { mirror: true, objectFit: "cover", streamURL: previewStreamURL, style: styles23.previewVideo, zOrder: 0 }) : /* @__PURE__ */ jsx29(View23, { style: [styles23.avatarContainer, { backgroundColor: theme.colors.insetSurface }], children: /* @__PURE__ */ jsx29(FaceAvatar, { name: controller.displayName, size: 140, textSize: 52 }) }),
4313
- onCancel ? /* @__PURE__ */ jsx29(Pressable16, { accessibilityLabel: "Cancel and leave Entrance", accessibilityRole: "button", onPress: onCancel, style: ({ pressed }) => [styles23.floatingBack, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }, pressed && styles23.topIconButtonPressed], children: /* @__PURE__ */ jsx29(HugeiconsIcon14, { icon: ArrowLeft01Icon4, size: 22, color: theme.colors.foreground }) }) : null
4788
+ return /* @__PURE__ */ jsx31(KeyboardAvoidingView6, { behavior: Platform17.OS === "ios" ? "padding" : "height", style: [styles25.screen, { backgroundColor: theme.colors.background }], children: /* @__PURE__ */ jsxs24(View25, { style: styles25.content, children: [
4789
+ /* @__PURE__ */ jsxs24(View25, { style: styles25.previewContainer, children: [
4790
+ /* @__PURE__ */ jsxs24(View25, { style: [styles25.previewSurface, { backgroundColor: theme.colors.raisedSurface, borderColor: theme.colors.border }], children: [
4791
+ previewStreamURL ? /* @__PURE__ */ jsx31(RtcVideoView, { mirror: true, objectFit: "cover", streamURL: previewStreamURL, style: styles25.previewVideo, zOrder: 0 }) : /* @__PURE__ */ jsx31(View25, { style: [styles25.avatarContainer, { backgroundColor: theme.colors.insetSurface }], children: /* @__PURE__ */ jsx31(FaceAvatar, { name: controller.displayName, size: 140, textSize: 52 }) }),
4792
+ onCancel ? /* @__PURE__ */ jsx31(Pressable18, { accessibilityLabel: "Cancel and leave Entrance", accessibilityRole: "button", onPress: onCancel, style: ({ pressed }) => [styles25.floatingBack, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }, pressed && styles25.topIconButtonPressed], children: /* @__PURE__ */ jsx31(HugeiconsIcon14, { icon: ArrowLeft01Icon4, size: 22, color: theme.colors.foreground }) }) : null
4314
4793
  ] }),
4315
- previewStatusMessage ? /* @__PURE__ */ jsx29(Text18, { style: styles23.previewError, children: previewStatusMessage }) : null,
4316
- controller.simulatorMediaDisabled ? /* @__PURE__ */ jsx29(Text18, { style: styles23.previewHint, children: getIosSimulatorMediaMessage() }) : null
4794
+ previewStatusMessage ? /* @__PURE__ */ jsx31(Text20, { style: styles25.previewError, children: previewStatusMessage }) : null,
4795
+ controller.simulatorMediaDisabled ? /* @__PURE__ */ jsx31(Text20, { style: styles25.previewHint, children: getIosSimulatorMediaMessage() }) : null
4317
4796
  ] }),
4318
- /* @__PURE__ */ jsxs22(View23, { style: [styles23.sheetContainer, { backgroundColor: theme.colors.card, borderColor: theme.colors.border, shadowColor: theme.colors.darkCanvas }], children: [
4319
- /* @__PURE__ */ jsx29(View23, { style: styles23.sheetHandle }),
4320
- /* @__PURE__ */ jsx29(View23, { style: styles23.sheetHeader, children: /* @__PURE__ */ jsx29(Text18, { style: [styles23.spaceName, { color: theme.colors.foreground }], numberOfLines: 1, children: spaceName }) }),
4321
- /* @__PURE__ */ jsxs22(View23, { style: [styles23.inputCard, { backgroundColor: theme.colors.surface, borderColor: controller.isInputFocused ? theme.colors.ring : theme.colors.border }], children: [
4322
- /* @__PURE__ */ jsx29(HugeiconsIcon14, { icon: UserIcon4, size: 18, color: controller.isInputFocused ? theme.colors.primary : theme.colors.mutedForeground, style: styles23.inputIcon }),
4323
- /* @__PURE__ */ jsx29(
4324
- TextInput5,
4797
+ /* @__PURE__ */ jsxs24(View25, { style: [styles25.sheetContainer, { backgroundColor: theme.colors.card, borderColor: theme.colors.border, shadowColor: theme.colors.darkCanvas }], children: [
4798
+ /* @__PURE__ */ jsx31(View25, { style: styles25.sheetHandle }),
4799
+ /* @__PURE__ */ jsx31(View25, { style: styles25.sheetHeader, children: /* @__PURE__ */ jsx31(Text20, { style: [styles25.spaceName, { color: theme.colors.foreground }], numberOfLines: 1, children: spaceName }) }),
4800
+ /* @__PURE__ */ jsxs24(View25, { style: [styles25.inputCard, { backgroundColor: theme.colors.surface, borderColor: controller.isInputFocused ? theme.colors.ring : theme.colors.border }], children: [
4801
+ /* @__PURE__ */ jsx31(HugeiconsIcon14, { icon: UserIcon4, size: 18, color: controller.isInputFocused ? theme.colors.primary : theme.colors.mutedForeground, style: styles25.inputIcon }),
4802
+ /* @__PURE__ */ jsx31(
4803
+ TextInput6,
4325
4804
  {
4326
4805
  onChangeText: controller.setDisplayName,
4327
4806
  onFocus: () => controller.setInputFocused(true),
4328
4807
  onBlur: () => controller.setInputFocused(false),
4329
4808
  placeholder: "Enter your name",
4330
4809
  placeholderTextColor: theme.colors.mutedForeground,
4331
- style: [styles23.nameInput, { color: theme.colors.foreground }],
4810
+ style: [styles25.nameInput, { color: theme.colors.foreground }],
4332
4811
  value: controller.displayName,
4333
4812
  maxLength: 30,
4334
4813
  returnKeyType: "join",
@@ -4336,32 +4815,32 @@ function EntranceViewMacos({ spaceName, error, joinDisabled = false, onCancel, .
4336
4815
  }
4337
4816
  )
4338
4817
  ] }),
4339
- /* @__PURE__ */ jsxs22(View23, { style: styles23.mediaRow, children: [
4340
- /* @__PURE__ */ jsx29(
4341
- Pressable16,
4818
+ /* @__PURE__ */ jsxs24(View25, { style: styles25.mediaRow, children: [
4819
+ /* @__PURE__ */ jsx31(
4820
+ Pressable18,
4342
4821
  {
4343
4822
  disabled: controller.simulatorMediaDisabled,
4344
4823
  onPress: controller.toggleAudio,
4345
- style: ({ pressed }) => [styles23.controlCircle, { backgroundColor: controller.audioEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles23.toggleCircleDisabled, pressed && styles23.togglePressed],
4346
- children: /* @__PURE__ */ jsx29(HugeiconsIcon14, { icon: controller.audioEnabled ? Mic01Icon7 : MicOff01Icon10, size: 24, color: theme.colors.primaryForeground })
4824
+ style: ({ pressed }) => [styles25.controlCircle, { backgroundColor: controller.audioEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles25.toggleCircleDisabled, pressed && styles25.togglePressed],
4825
+ children: /* @__PURE__ */ jsx31(HugeiconsIcon14, { icon: controller.audioEnabled ? Mic01Icon7 : MicOff01Icon10, size: 24, color: theme.colors.primaryForeground })
4347
4826
  }
4348
4827
  ),
4349
- /* @__PURE__ */ jsx29(
4350
- Pressable16,
4828
+ /* @__PURE__ */ jsx31(
4829
+ Pressable18,
4351
4830
  {
4352
4831
  disabled: controller.simulatorMediaDisabled,
4353
4832
  onPress: controller.toggleVideo,
4354
- style: ({ pressed }) => [styles23.controlCircle, { backgroundColor: controller.videoEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles23.toggleCircleDisabled, pressed && styles23.togglePressed],
4355
- children: /* @__PURE__ */ jsx29(HugeiconsIcon14, { icon: controller.videoEnabled ? Video01Icon8 : VideoOffIcon7, size: 24, color: theme.colors.primaryForeground })
4833
+ style: ({ pressed }) => [styles25.controlCircle, { backgroundColor: controller.videoEnabled ? theme.colors.controlsBackground : theme.colors.error, borderColor: theme.colors.border }, controller.simulatorMediaDisabled && styles25.toggleCircleDisabled, pressed && styles25.togglePressed],
4834
+ children: /* @__PURE__ */ jsx31(HugeiconsIcon14, { icon: controller.videoEnabled ? Video01Icon8 : VideoOffIcon7, size: 24, color: theme.colors.primaryForeground })
4356
4835
  }
4357
4836
  )
4358
4837
  ] }),
4359
- error ? /* @__PURE__ */ jsx29(Text18, { style: [styles23.globalError, { color: theme.colors.error }], children: error }) : null,
4360
- /* @__PURE__ */ jsx29(Pressable16, { disabled: !canJoin, onPress: controller.handleJoin, style: ({ pressed }) => [styles23.joinButton, { backgroundColor: canJoin ? theme.colors.primary : theme.colors.muted }, !canJoin && styles23.joinButtonDisabled, pressed && styles23.togglePressed], children: /* @__PURE__ */ jsx29(Text18, { style: [styles23.joinButtonText, { color: theme.colors.primaryForeground }], children: controller.isSubmitting || joinDisabled ? "Joining..." : "Enter Space" }) })
4838
+ error ? /* @__PURE__ */ jsx31(Text20, { style: [styles25.globalError, { color: theme.colors.error }], children: error }) : null,
4839
+ /* @__PURE__ */ jsx31(Pressable18, { disabled: !canJoin, onPress: controller.handleJoin, style: ({ pressed }) => [styles25.joinButton, { backgroundColor: canJoin ? theme.colors.primary : theme.colors.muted }, !canJoin && styles25.joinButtonDisabled, pressed && styles25.togglePressed], children: /* @__PURE__ */ jsx31(Text20, { style: [styles25.joinButtonText, { color: theme.colors.primaryForeground }], children: controller.isSubmitting || joinDisabled ? "Joining..." : "Enter Space" }) })
4361
4840
  ] })
4362
4841
  ] }) });
4363
4842
  }
4364
- var styles23 = StyleSheet24.create({
4843
+ var styles25 = StyleSheet26.create({
4365
4844
  screen: {
4366
4845
  flex: 1,
4367
4846
  backgroundColor: Theme.colors.background
@@ -4371,7 +4850,7 @@ var styles23 = StyleSheet24.create({
4371
4850
  },
4372
4851
  floatingBack: {
4373
4852
  position: "absolute",
4374
- top: Platform13.OS === "ios" ? 24 : 20,
4853
+ top: Platform17.OS === "ios" ? 24 : 20,
4375
4854
  left: 20,
4376
4855
  width: 42,
4377
4856
  height: 42,
@@ -4386,7 +4865,7 @@ var styles23 = StyleSheet24.create({
4386
4865
  previewContainer: {
4387
4866
  flex: 1,
4388
4867
  justifyContent: "center",
4389
- paddingTop: Platform13.OS === "ios" ? 10 : 0,
4868
+ paddingTop: Platform17.OS === "ios" ? 10 : 0,
4390
4869
  marginBottom: 0
4391
4870
  },
4392
4871
  previewSurface: {
@@ -4401,10 +4880,10 @@ var styles23 = StyleSheet24.create({
4401
4880
  borderColor: Theme.colors.whiteOverlay06
4402
4881
  },
4403
4882
  previewVideo: {
4404
- ...StyleSheet24.absoluteFillObject
4883
+ ...StyleSheet26.absoluteFillObject
4405
4884
  },
4406
4885
  avatarContainer: {
4407
- ...StyleSheet24.absoluteFillObject,
4886
+ ...StyleSheet26.absoluteFillObject,
4408
4887
  alignItems: "center",
4409
4888
  justifyContent: "center",
4410
4889
  backgroundColor: Theme.colors.insetSurface
@@ -4435,7 +4914,7 @@ var styles23 = StyleSheet24.create({
4435
4914
  borderTopRightRadius: 32,
4436
4915
  paddingHorizontal: 24,
4437
4916
  paddingTop: 16,
4438
- paddingBottom: Platform13.OS === "ios" ? 44 : 32,
4917
+ paddingBottom: Platform17.OS === "ios" ? 44 : 32,
4439
4918
  gap: 20,
4440
4919
  borderTopWidth: 1,
4441
4920
  borderColor: Theme.colors.whiteOverlay08,
@@ -4538,34 +5017,34 @@ var styles23 = StyleSheet24.create({
4538
5017
  });
4539
5018
 
4540
5019
  // src/components/EntranceView.tsx
4541
- import { jsx as jsx30 } from "react/jsx-runtime";
5020
+ import { jsx as jsx32 } from "react/jsx-runtime";
4542
5021
  function EntranceView(props) {
4543
5022
  switch (resolvePlatformVariant()) {
4544
5023
  case "ios-pad":
4545
- return /* @__PURE__ */ jsx30(EntranceViewIosPad, { ...props });
5024
+ return /* @__PURE__ */ jsx32(EntranceViewIosPad, { ...props });
4546
5025
  case "ios-phone":
4547
- return /* @__PURE__ */ jsx30(EntranceViewIosPhone, { ...props });
5026
+ return /* @__PURE__ */ jsx32(EntranceViewIosPhone, { ...props });
4548
5027
  case "macos":
4549
- return /* @__PURE__ */ jsx30(EntranceViewMacos, { ...props });
5028
+ return /* @__PURE__ */ jsx32(EntranceViewMacos, { ...props });
4550
5029
  case "tvos":
4551
5030
  case "android":
4552
5031
  default:
4553
- return /* @__PURE__ */ jsx30(EntranceViewAndroid, { ...props });
5032
+ return /* @__PURE__ */ jsx32(EntranceViewAndroid, { ...props });
4554
5033
  }
4555
5034
  }
4556
5035
 
4557
5036
  // src/components/Entrance.tsx
4558
- import { Image as Image3 } from "react-native";
4559
- import { jsx as jsx31 } from "react/jsx-runtime";
5037
+ import { Image as Image5 } from "react-native";
5038
+ import { jsx as jsx33 } from "react/jsx-runtime";
4560
5039
  function Entrance({ spaceName, logoUrl, defaultDisplayName, defaults, error, joining = false, onCancel, onJoin }) {
4561
- return /* @__PURE__ */ jsx31(
5040
+ return /* @__PURE__ */ jsx33(
4562
5041
  EntranceView,
4563
5042
  {
4564
5043
  error,
4565
5044
  initialAudioEnabled: defaults?.microphone ?? true,
4566
5045
  initialVideoEnabled: defaults?.camera ?? true,
4567
5046
  joinDisabled: joining,
4568
- logo: logoUrl ? /* @__PURE__ */ jsx31(Image3, { accessibilityLabel: "Chalk", source: { uri: logoUrl }, style: { height: 32, width: 120 } }) : /* @__PURE__ */ jsx31(Logo, { height: 32, variant: "wordmark" }),
5047
+ logo: logoUrl ? /* @__PURE__ */ jsx33(Image5, { accessibilityLabel: "Chalk", source: { uri: logoUrl }, style: { height: 32, width: 120 } }) : /* @__PURE__ */ jsx33(Logo, { height: 32, variant: "wordmark" }),
4569
5048
  onCancel,
4570
5049
  onJoin: ({ displayName, microphoneEnabled, cameraEnabled }) => void onJoin({ displayName, microphone: microphoneEnabled, camera: cameraEnabled }),
4571
5050
  spaceName,
@@ -4575,20 +5054,20 @@ function Entrance({ spaceName, logoUrl, defaultDisplayName, defaults, error, joi
4575
5054
  }
4576
5055
 
4577
5056
  // src/components/Chalk.tsx
4578
- import { jsx as jsx32, jsxs as jsxs23 } from "react/jsx-runtime";
5057
+ import { jsx as jsx34, jsxs as jsxs25 } from "react/jsx-runtime";
4579
5058
  function Chalk(props) {
4580
5059
  const suppliedClient = props.client;
4581
5060
  const space = props.space;
4582
5061
  const getAccess = props.getAccess;
4583
- const getAccessRef = useRef6(getAccess);
5062
+ const getAccessRef = useRef7(getAccess);
4584
5063
  getAccessRef.current = getAccess;
4585
- const defaults = useRef6(props.defaults).current;
4586
- const getLatestAccess = useCallback9((...args) => {
5064
+ const defaults = useRef7(props.defaults).current;
5065
+ const getLatestAccess = useCallback10((...args) => {
4587
5066
  const currentGetAccess = getAccessRef.current;
4588
5067
  if (!currentGetAccess) throw new Error("Chalk requires getAccess when it creates the SpaceClient.");
4589
5068
  return currentGetAccess(...args);
4590
5069
  }, []);
4591
- const ownedClient = useMemo15(
5070
+ const ownedClient = useMemo16(
4592
5071
  () => suppliedClient ? null : createNativeSpaceClient({
4593
5072
  space,
4594
5073
  getAccess: getLatestAccess,
@@ -4598,27 +5077,27 @@ function Chalk(props) {
4598
5077
  [getLatestAccess, space, suppliedClient]
4599
5078
  );
4600
5079
  const client = suppliedClient ?? ownedClient;
4601
- useEffect9(() => {
5080
+ useEffect11(() => {
4602
5081
  if (!ownedClient) return;
4603
5082
  return () => {
4604
5083
  void ownedClient.leave().catch(() => void 0).finally(() => ownedClient.dispose());
4605
5084
  };
4606
5085
  }, [ownedClient]);
4607
- return /* @__PURE__ */ jsx32(NativeAppearanceProvider, { initialAppearance: { palette: props.theme?.palette, texture: props.theme?.texture }, children: /* @__PURE__ */ jsx32(AppearanceThemeBridge, { theme: props.theme, children: /* @__PURE__ */ jsx32(ChalkProvider, { client, children: /* @__PURE__ */ jsx32(SpaceExperience, { ...props }) }) }) });
5086
+ return /* @__PURE__ */ jsx34(NativeAppearanceProvider, { initialAppearance: { palette: props.theme?.palette, texture: props.theme?.texture }, children: /* @__PURE__ */ jsx34(AppearanceThemeBridge, { theme: props.theme, children: /* @__PURE__ */ jsx34(ChalkProvider, { client, children: /* @__PURE__ */ jsx34(SpaceExperience, { ...props }) }) }) });
4608
5087
  }
4609
5088
  function AppearanceThemeBridge({ children, theme }) {
4610
5089
  const { appearance } = useNativeAppearance();
4611
- return /* @__PURE__ */ jsx32(NativeThemeProvider, { appearance, theme, children });
5090
+ return /* @__PURE__ */ jsx34(NativeThemeProvider, { appearance, theme, children });
4612
5091
  }
4613
5092
  function SpaceExperience(props) {
4614
5093
  const client = useSpaceClient();
4615
5094
  const connection = useConnection();
4616
- const previousStatus = useRef6(connection.status);
4617
- const hasObservedStatus = useRef6(false);
4618
- const hasBeenLive = useRef6(connection.status === "live" || connection.status === "reconnecting");
4619
- const autoJoinAttempted = useRef6(false);
4620
- const previousClient = useRef6(client);
4621
- const [joinError, setJoinError] = useState10(null);
5095
+ const previousStatus = useRef7(connection.status);
5096
+ const hasObservedStatus = useRef7(false);
5097
+ const hasBeenLive = useRef7(connection.status === "live" || connection.status === "reconnecting");
5098
+ const autoJoinAttempted = useRef7(false);
5099
+ const previousClient = useRef7(client);
5100
+ const [joinError, setJoinError] = useState13(null);
4622
5101
  if (previousClient.current !== client) {
4623
5102
  previousClient.current = client;
4624
5103
  previousStatus.current = connection.status;
@@ -4628,7 +5107,7 @@ function SpaceExperience(props) {
4628
5107
  }
4629
5108
  const entrance = props.entrance ?? true;
4630
5109
  const spaceName = props.spaceName ?? props.space ?? "Space";
4631
- const join = useCallback9(
5110
+ const join = useCallback10(
4632
5111
  async (options) => {
4633
5112
  try {
4634
5113
  setJoinError(null);
@@ -4639,14 +5118,14 @@ function SpaceExperience(props) {
4639
5118
  },
4640
5119
  [client]
4641
5120
  );
4642
- const retryAutomaticJoin = useCallback9(() => {
5121
+ const retryAutomaticJoin = useCallback10(() => {
4643
5122
  autoJoinAttempted.current = true;
4644
5123
  void join(defaultJoinOptions(props));
4645
5124
  }, [join, props]);
4646
- useEffect9(() => {
5125
+ useEffect11(() => {
4647
5126
  setJoinError(null);
4648
5127
  }, [client]);
4649
- useEffect9(() => {
5128
+ useEffect11(() => {
4650
5129
  const subscriptions = [
4651
5130
  props.onEpisodeEnded && client.on("episodeEnded", props.onEpisodeEnded),
4652
5131
  props.onParticipantJoined && client.on("participantJoined", props.onParticipantJoined),
@@ -4657,13 +5136,13 @@ function SpaceExperience(props) {
4657
5136
  ].filter((unsubscribe) => Boolean(unsubscribe));
4658
5137
  return () => subscriptions.forEach((unsubscribe) => unsubscribe());
4659
5138
  }, [client, props.onEpisodeEnded, props.onError, props.onParticipantJoined, props.onParticipantLeft, props.onScreenShareStarted, props.onScreenShareStopped]);
4660
- useEffect9(() => {
5139
+ useEffect11(() => {
4661
5140
  if (!entrance && connection.status === "idle" && !autoJoinAttempted.current) {
4662
5141
  autoJoinAttempted.current = true;
4663
5142
  void join(defaultJoinOptions(props));
4664
5143
  }
4665
5144
  }, [connection.status, entrance, join, props.defaults?.camera, props.defaults?.microphone, props.displayName]);
4666
- useEffect9(() => {
5145
+ useEffect11(() => {
4667
5146
  const previous = previousStatus.current;
4668
5147
  if (hasObservedStatus.current) {
4669
5148
  if (connection.status === "live" && previous !== "live" && previous !== "reconnecting") props.onJoined?.();
@@ -4674,27 +5153,27 @@ function SpaceExperience(props) {
4674
5153
  if (connection.status === "live" || connection.status === "reconnecting") hasBeenLive.current = true;
4675
5154
  }, [connection.status, props.onJoined, props.onLeft]);
4676
5155
  if (connection.status === "idle" && entrance) {
4677
- return /* @__PURE__ */ jsx32(AppearanceLayer, { children: /* @__PURE__ */ jsx32(Entrance, { defaultDisplayName: props.displayName, defaults: props.defaults, error: joinError ?? void 0, logoUrl: props.logoUrl, onJoin: join, spaceName }) });
5156
+ return /* @__PURE__ */ jsx34(AppearanceLayer, { children: /* @__PURE__ */ jsx34(Entrance, { defaultDisplayName: props.displayName, defaults: props.defaults, error: joinError ?? void 0, logoUrl: props.logoUrl, onJoin: join, spaceName }) });
4678
5157
  }
4679
5158
  if (connection.status === "idle") {
4680
- return /* @__PURE__ */ jsx32(AppearanceLayer, { children: /* @__PURE__ */ jsx32(SpaceStatus, { message: joinError ?? `Entering ${spaceName}\u2026`, onRetry: joinError ? retryAutomaticJoin : void 0 }) });
5159
+ return /* @__PURE__ */ jsx34(AppearanceLayer, { children: /* @__PURE__ */ jsx34(SpaceStatus, { message: joinError ?? `Entering ${spaceName}\u2026`, onRetry: joinError ? retryAutomaticJoin : void 0 }) });
4681
5160
  }
4682
5161
  if (connection.status === "joining") {
4683
5162
  if (!entrance)
4684
- return /* @__PURE__ */ jsx32(AppearanceLayer, { children: /* @__PURE__ */ jsx32(SpaceStatus, { message: `Entering ${spaceName}\u2026` }) });
4685
- return /* @__PURE__ */ jsx32(AppearanceLayer, { children: /* @__PURE__ */ jsx32(Entrance, { defaultDisplayName: props.displayName, defaults: props.defaults, joining: true, logoUrl: props.logoUrl, onJoin: join, spaceName }) });
5163
+ return /* @__PURE__ */ jsx34(AppearanceLayer, { children: /* @__PURE__ */ jsx34(SpaceStatus, { message: `Entering ${spaceName}\u2026` }) });
5164
+ return /* @__PURE__ */ jsx34(AppearanceLayer, { children: /* @__PURE__ */ jsx34(Entrance, { defaultDisplayName: props.displayName, defaults: props.defaults, joining: true, logoUrl: props.logoUrl, onJoin: join, spaceName }) });
4686
5165
  }
4687
5166
  if (connection.status === "failed") {
4688
5167
  if (!hasBeenLive.current && entrance) {
4689
- return /* @__PURE__ */ jsx32(AppearanceLayer, { children: /* @__PURE__ */ jsx32(Entrance, { defaultDisplayName: props.displayName, defaults: props.defaults, error: connection.lastError?.message ?? "Unable to enter this Space.", logoUrl: props.logoUrl, onJoin: join, spaceName }) });
5168
+ return /* @__PURE__ */ jsx34(AppearanceLayer, { children: /* @__PURE__ */ jsx34(Entrance, { defaultDisplayName: props.displayName, defaults: props.defaults, error: connection.lastError?.message ?? "Unable to enter this Space.", logoUrl: props.logoUrl, onJoin: join, spaceName }) });
4690
5169
  }
4691
- return /* @__PURE__ */ jsx32(AppearanceLayer, { children: /* @__PURE__ */ jsx32(SpaceStatus, { message: connection.lastError?.message ?? "This Space is unavailable.", onRetry: () => void join(defaultJoinOptions(props)) }) });
5170
+ return /* @__PURE__ */ jsx34(AppearanceLayer, { children: /* @__PURE__ */ jsx34(SpaceStatus, { message: connection.lastError?.message ?? "This Space is unavailable.", onRetry: () => void join(defaultJoinOptions(props)) }) });
4692
5171
  }
4693
5172
  if (connection.status === "leaving")
4694
- return /* @__PURE__ */ jsx32(AppearanceLayer, { children: /* @__PURE__ */ jsx32(SpaceStatus, { message: `Leaving ${spaceName}\u2026` }) });
5173
+ return /* @__PURE__ */ jsx34(AppearanceLayer, { children: /* @__PURE__ */ jsx34(SpaceStatus, { message: `Leaving ${spaceName}\u2026` }) });
4695
5174
  if (connection.status === "left")
4696
- return /* @__PURE__ */ jsx32(AppearanceLayer, { children: /* @__PURE__ */ jsx32(SpaceStatus, { message: "You have left this Space.", onRetry: () => void join(defaultJoinOptions(props)) }) });
4697
- return /* @__PURE__ */ jsx32(
5175
+ return /* @__PURE__ */ jsx34(AppearanceLayer, { children: /* @__PURE__ */ jsx34(SpaceStatus, { message: "You have left this Space.", onRetry: () => void join(defaultJoinOptions(props)) }) });
5176
+ return /* @__PURE__ */ jsx34(
4698
5177
  NativeSpaceView,
4699
5178
  {
4700
5179
  features: props.features,
@@ -4703,6 +5182,7 @@ function SpaceExperience(props) {
4703
5182
  logoUrl: props.logoUrl,
4704
5183
  onLayoutChange: props.onLayoutChange,
4705
5184
  onOpenDiagnostics: props.onOpenDiagnostics,
5185
+ feedbackEvidence: props.feedbackEvidence,
4706
5186
  pickChatFiles: props.pickChatFiles,
4707
5187
  reconnecting: connection.status === "reconnecting",
4708
5188
  spaceName
@@ -4717,11 +5197,11 @@ function defaultJoinOptions(props) {
4717
5197
  camera: props.defaults?.camera ?? true
4718
5198
  };
4719
5199
  }
4720
- function NativeSpaceView({ features, inviteLink, layout, logoUrl, onLayoutChange, onOpenDiagnostics, pickChatFiles, reconnecting, spaceName }) {
5200
+ function NativeSpaceView({ features, inviteLink, layout, logoUrl, onLayoutChange, onOpenDiagnostics, feedbackEvidence, pickChatFiles, reconnecting, spaceName }) {
4721
5201
  const client = useSpaceClient();
4722
5202
  const theme = useNativeTheme();
4723
- return /* @__PURE__ */ jsxs23(View24, { style: [styles24.space, { backgroundColor: theme.colors.background }], children: [
4724
- /* @__PURE__ */ jsx32(
5203
+ return /* @__PURE__ */ jsxs25(View26, { style: [styles26.space, { backgroundColor: theme.colors.background }], children: [
5204
+ /* @__PURE__ */ jsx34(
4725
5205
  SpaceView,
4726
5206
  {
4727
5207
  features,
@@ -4732,29 +5212,30 @@ function NativeSpaceView({ features, inviteLink, layout, logoUrl, onLayoutChange
4732
5212
  onLayoutChange,
4733
5213
  onLeave: () => client.leave(),
4734
5214
  onOpenDiagnostics,
5215
+ feedbackEvidence,
4735
5216
  pickChatFiles,
4736
5217
  reconnecting,
4737
5218
  spaceName
4738
5219
  }
4739
5220
  ),
4740
- /* @__PURE__ */ jsx32(NativeTextureOverlay, {})
5221
+ /* @__PURE__ */ jsx34(NativeTextureOverlay, {})
4741
5222
  ] });
4742
5223
  }
4743
5224
  function AppearanceLayer({ children }) {
4744
5225
  const theme = useNativeTheme();
4745
- return /* @__PURE__ */ jsxs23(View24, { style: [styles24.appearanceLayer, { backgroundColor: theme.colors.background }], children: [
5226
+ return /* @__PURE__ */ jsxs25(View26, { style: [styles26.appearanceLayer, { backgroundColor: theme.colors.background }], children: [
4746
5227
  children,
4747
- /* @__PURE__ */ jsx32(NativeTextureOverlay, {})
5228
+ /* @__PURE__ */ jsx34(NativeTextureOverlay, {})
4748
5229
  ] });
4749
5230
  }
4750
5231
  function SpaceStatus({ message, onRetry }) {
4751
5232
  const theme = useNativeTheme();
4752
- return /* @__PURE__ */ jsxs23(View24, { accessibilityLiveRegion: "polite", style: [styles24.status, { backgroundColor: theme.colors.background }], children: [
4753
- /* @__PURE__ */ jsx32(Text19, { style: [styles24.statusText, { color: theme.colors.foreground }], children: message }),
4754
- onRetry ? /* @__PURE__ */ jsx32(Pressable17, { accessibilityRole: "button", onPress: onRetry, style: [styles24.retry, { backgroundColor: theme.colors.primary }], children: /* @__PURE__ */ jsx32(Text19, { style: [styles24.retryText, { color: theme.colors.primaryForeground }], children: "Try again" }) }) : null
5233
+ return /* @__PURE__ */ jsxs25(View26, { accessibilityLiveRegion: "polite", style: [styles26.status, { backgroundColor: theme.colors.background }], children: [
5234
+ /* @__PURE__ */ jsx34(Text21, { style: [styles26.statusText, { color: theme.colors.foreground }], children: message }),
5235
+ onRetry ? /* @__PURE__ */ jsx34(Pressable19, { accessibilityRole: "button", onPress: onRetry, style: [styles26.retry, { backgroundColor: theme.colors.primary }], children: /* @__PURE__ */ jsx34(Text21, { style: [styles26.retryText, { color: theme.colors.primaryForeground }], children: "Try again" }) }) : null
4755
5236
  ] });
4756
5237
  }
4757
- var styles24 = StyleSheet25.create({
5238
+ var styles26 = StyleSheet27.create({
4758
5239
  space: { flex: 1 },
4759
5240
  appearanceLayer: { flex: 1 },
4760
5241
  status: { flex: 1, alignItems: "center", justifyContent: "center", gap: 16, padding: 24 },
@@ -4780,6 +5261,7 @@ export {
4780
5261
  useMedia,
4781
5262
  useChat,
4782
5263
  useReactions,
5264
+ useRecording,
4783
5265
  useWhiteboard,
4784
5266
  useCan,
4785
5267
  Logo,