@poolse/react-native 2.9.0 → 2.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var react$1 = require('@poolse/react');
4
- var react = require('react');
5
3
  var reactNative = require('react-native');
4
+ var react = require('react');
6
5
  var jsxRuntime = require('react/jsx-runtime');
6
+ var react$1 = require('@poolse/react');
7
7
  var reactNativeSvg = require('react-native-svg');
8
8
  var ImagePicker = require('expo-image-picker');
9
9
  var DocumentPicker = require('expo-document-picker');
@@ -206,6 +206,79 @@ function PoolseTheme({ mode, theme, children }) {
206
206
  function usePoolseTheme() {
207
207
  return react.useContext(ThemeContext) ?? defaultLightTheme;
208
208
  }
209
+ function CallVideoGrid({ participants, livekitReactNative, labelFor }) {
210
+ const theme = usePoolseTheme();
211
+ const label = labelFor ?? ((id) => `User ${id.slice(0, 6)}`);
212
+ const VideoTrack = livekitReactNative?.VideoTrack;
213
+ if (participants.length === 0) return null;
214
+ const columns = participants.length <= 1 ? 1 : 2;
215
+ const basis = columns === 1 ? "100%" : "48%";
216
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.grid, children: participants.map((participant) => /* @__PURE__ */ jsxRuntime.jsxs(
217
+ reactNative.View,
218
+ {
219
+ style: [
220
+ styles.tile,
221
+ {
222
+ flexBasis: basis,
223
+ backgroundColor: theme.colors.surface,
224
+ // A ring rather than a badge: it reads at a glance in a
225
+ // grid, and doesn't cover a face.
226
+ borderColor: participant.speaking ? theme.colors.brand : "transparent"
227
+ }
228
+ ],
229
+ children: [
230
+ participant.videoTrackRef && VideoTrack ? /* @__PURE__ */ jsxRuntime.jsx(
231
+ VideoTrack,
232
+ {
233
+ trackRef: participant.videoTrackRef,
234
+ style: styles.video,
235
+ objectFit: "cover",
236
+ mirror: participant.isSelf,
237
+ zOrder: participant.isSelf ? 1 : 0
238
+ }
239
+ ) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.placeholder, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.initial, { color: theme.colors.ink3 }], children: label(participant.userId).slice(0, 1).toUpperCase() }) }),
240
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.caption, children: [
241
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { numberOfLines: 1, style: [styles.name, { color: theme.colors.onBrand }], children: participant.isSelf ? "You" : participant.name ?? label(participant.userId) }),
242
+ !participant.micEnabled && // Muted is worth showing even for yourself — it is the
243
+ // answer to "why can nobody hear me".
244
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.muted, { color: theme.colors.onBrand }], children: "muted" })
245
+ ] })
246
+ ]
247
+ },
248
+ participant.userId
249
+ )) });
250
+ }
251
+ var styles = reactNative.StyleSheet.create({
252
+ grid: {
253
+ flex: 1,
254
+ flexDirection: "row",
255
+ flexWrap: "wrap",
256
+ justifyContent: "center",
257
+ alignContent: "center",
258
+ gap: 8
259
+ },
260
+ tile: {
261
+ aspectRatio: 3 / 4,
262
+ borderRadius: 16,
263
+ borderWidth: 2,
264
+ overflow: "hidden",
265
+ justifyContent: "flex-end"
266
+ },
267
+ video: { ...reactNative.StyleSheet.absoluteFillObject },
268
+ placeholder: { ...reactNative.StyleSheet.absoluteFillObject, alignItems: "center", justifyContent: "center" },
269
+ initial: { fontSize: 48, fontWeight: "600" },
270
+ caption: {
271
+ flexDirection: "row",
272
+ alignItems: "center",
273
+ gap: 6,
274
+ paddingHorizontal: 10,
275
+ paddingVertical: 6,
276
+ // Legible over both a bright video frame and a flat placeholder.
277
+ backgroundColor: "rgba(0,0,0,0.45)"
278
+ },
279
+ name: { flexShrink: 1, fontSize: 13, fontWeight: "600" },
280
+ muted: { fontSize: 11, opacity: 0.85 }
281
+ });
209
282
 
210
283
  // src/primitives/userColor.ts
211
284
  var PALETTE = [
@@ -244,7 +317,7 @@ function Avatar({ src, name, seed, online, size = "md" }) {
244
317
  reactNative.View,
245
318
  {
246
319
  style: [
247
- styles.root,
320
+ styles2.root,
248
321
  {
249
322
  width: dim,
250
323
  height: dim,
@@ -278,7 +351,7 @@ function Avatar({ src, name, seed, online, size = "md" }) {
278
351
  reactNative.View,
279
352
  {
280
353
  style: [
281
- styles.presence,
354
+ styles2.presence,
282
355
  {
283
356
  backgroundColor: theme.colors.presence,
284
357
  borderColor: theme.colors.surface,
@@ -298,7 +371,7 @@ function computeInitials(name) {
298
371
  const parts = name.trim().split(/\s+/).slice(0, 2);
299
372
  return parts.map((p) => p.charAt(0).toUpperCase()).join("").slice(0, 2) || "?";
300
373
  }
301
- var styles = reactNative.StyleSheet.create({
374
+ var styles2 = reactNative.StyleSheet.create({
302
375
  root: {
303
376
  alignItems: "center",
304
377
  justifyContent: "center",
@@ -508,16 +581,16 @@ function MemberList({
508
581
  );
509
582
  const effectiveOnline = onlineExternalIds ?? presenceOnline;
510
583
  if (loading && members.length === 0) {
511
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles2.placeholder, { backgroundColor: theme.colors.paper }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.brand }) });
584
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles3.placeholder, { backgroundColor: theme.colors.paper }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.brand }) });
512
585
  }
513
586
  if (error) {
514
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles2.placeholder, { backgroundColor: theme.colors.paper }], children: [
587
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles3.placeholder, { backgroundColor: theme.colors.paper }], children: [
515
588
  /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.error, fontFamily: theme.type.fontBody }, children: "Failed to load members." }),
516
- error.message ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.errorDetail, { color: theme.colors.ink3 }], children: error.message }) : null
589
+ error.message ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.errorDetail, { color: theme.colors.ink3 }], children: error.message }) : null
517
590
  ] });
518
591
  }
519
592
  if (members.length === 0) {
520
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles2.placeholder, { backgroundColor: theme.colors.paper }], children: typeof emptyState === "string" || emptyState == null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.ink3, fontFamily: theme.type.fontBody }, children: emptyState ?? "No members." }) : emptyState });
593
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles3.placeholder, { backgroundColor: theme.colors.paper }], children: typeof emptyState === "string" || emptyState == null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.ink3, fontFamily: theme.type.fontBody }, children: emptyState ?? "No members." }) : emptyState });
521
594
  }
522
595
  return /* @__PURE__ */ jsxRuntime.jsx(
523
596
  reactNative.FlatList,
@@ -556,23 +629,23 @@ function MemberRow({
556
629
  const resolved = react$1.useUser(externalId);
557
630
  const name = labelFor?.(externalId) ?? resolved.profile?.displayName ?? externalId;
558
631
  const avatarUrl = avatarFor?.(externalId) ?? resolved.profile?.avatarUrl ?? null;
559
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.row, children: [
632
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.row, children: [
560
633
  /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: avatarUrl, name, seed: externalId, online, size: "md" }),
561
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.body, children: [
634
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.body, children: [
562
635
  /* @__PURE__ */ jsxRuntime.jsx(
563
636
  reactNative.Text,
564
637
  {
565
- style: [styles2.name, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
638
+ style: [styles3.name, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
566
639
  numberOfLines: 1,
567
640
  children: name
568
641
  }
569
642
  ),
570
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.role, { color: theme.colors.ink3 }], children: role })
643
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.role, { color: theme.colors.ink3 }], children: role })
571
644
  ] }),
572
- onRemove ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onRemove, hitSlop: 8, style: styles2.removeBtn, children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 16, color: theme.colors.ink2 }) }) : null
645
+ onRemove ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onRemove, hitSlop: 8, style: styles3.removeBtn, children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 16, color: theme.colors.ink2 }) }) : null
573
646
  ] });
574
647
  }
575
- var styles2 = reactNative.StyleSheet.create({
648
+ var styles3 = reactNative.StyleSheet.create({
576
649
  placeholder: {
577
650
  flex: 1,
578
651
  alignItems: "center",
@@ -675,11 +748,11 @@ function GroupDetailsSheet({
675
748
  animationType: "slide",
676
749
  onRequestClose: onClose,
677
750
  statusBarTranslucent: true,
678
- children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.modalRoot, children: [
751
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.modalRoot, children: [
679
752
  /* @__PURE__ */ jsxRuntime.jsx(
680
753
  reactNative.Pressable,
681
754
  {
682
- style: styles3.backdrop,
755
+ style: styles4.backdrop,
683
756
  onPress: onClose,
684
757
  accessibilityLabel: "Close group details"
685
758
  }
@@ -688,7 +761,7 @@ function GroupDetailsSheet({
688
761
  reactNative.Animated.View,
689
762
  {
690
763
  style: [
691
- styles3.sheet,
764
+ styles4.sheet,
692
765
  {
693
766
  backgroundColor: theme.colors.paper,
694
767
  borderTopLeftRadius: theme.radii.xl,
@@ -698,14 +771,14 @@ function GroupDetailsSheet({
698
771
  theme.shadows.lg
699
772
  ],
700
773
  children: [
701
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { ...panHandlers, style: styles3.dragHandle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles3.dragPill, { backgroundColor: theme.colors.ink3 }] }) }),
702
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.headerRow, children: [
774
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { ...panHandlers, style: styles4.dragHandle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles4.dragPill, { backgroundColor: theme.colors.ink3 }] }) }),
775
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.headerRow, children: [
703
776
  /* @__PURE__ */ jsxRuntime.jsx(
704
777
  reactNative.Pressable,
705
778
  {
706
779
  onPress: onClose,
707
780
  hitSlop: 16,
708
- style: [styles3.closeBtn, { backgroundColor: theme.colors.surface2 }],
781
+ style: [styles4.closeBtn, { backgroundColor: theme.colors.surface2 }],
709
782
  accessibilityLabel: "Close",
710
783
  children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 18, color: theme.colors.ink })
711
784
  }
@@ -714,34 +787,34 @@ function GroupDetailsSheet({
714
787
  reactNative.Text,
715
788
  {
716
789
  style: [
717
- styles3.headerTitle,
790
+ styles4.headerTitle,
718
791
  { color: theme.colors.ink, fontFamily: theme.type.fontDisplay }
719
792
  ],
720
793
  children: "Group details"
721
794
  }
722
795
  )
723
796
  ] }),
724
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.summary, children: [
797
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.summary, children: [
725
798
  /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: null, name: title, seed: conversationId, size: "lg" }),
726
799
  /* @__PURE__ */ jsxRuntime.jsx(
727
800
  reactNative.Text,
728
801
  {
729
802
  style: [
730
- styles3.title,
803
+ styles4.title,
731
804
  { color: theme.colors.ink, fontFamily: theme.type.fontDisplay }
732
805
  ],
733
806
  numberOfLines: 1,
734
807
  children: title
735
808
  }
736
809
  ),
737
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.subtitle, { color: theme.colors.ink3 }], children: subtitle })
810
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.subtitle, { color: theme.colors.ink3 }], children: subtitle })
738
811
  ] }),
739
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles3.divider, { backgroundColor: theme.colors.border }] }),
740
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.sectionLabelRow, children: /* @__PURE__ */ jsxRuntime.jsx(
812
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles4.divider, { backgroundColor: theme.colors.border }] }),
813
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles4.sectionLabelRow, children: /* @__PURE__ */ jsxRuntime.jsx(
741
814
  reactNative.Text,
742
815
  {
743
816
  style: [
744
- styles3.sectionLabel,
817
+ styles4.sectionLabel,
745
818
  { color: theme.colors.ink2, fontFamily: theme.type.fontBody }
746
819
  ],
747
820
  children: "Members"
@@ -764,7 +837,7 @@ function GroupDetailsSheet({
764
837
  }
765
838
  );
766
839
  }
767
- var styles3 = reactNative.StyleSheet.create({
840
+ var styles4 = reactNative.StyleSheet.create({
768
841
  modalRoot: {
769
842
  flex: 1,
770
843
  justifyContent: "flex-end"
@@ -858,7 +931,7 @@ function ChatHeader({
858
931
  reactNative.View,
859
932
  {
860
933
  style: [
861
- styles4.root,
934
+ styles5.root,
862
935
  {
863
936
  backgroundColor: theme.colors.surface,
864
937
  borderBottomColor: theme.colors.border
@@ -883,32 +956,32 @@ function ChatHeader({
883
956
  {
884
957
  ...headerOnPress ? { onPress: headerOnPress } : {},
885
958
  style: [
886
- styles4.root,
959
+ styles5.root,
887
960
  {
888
961
  backgroundColor: theme.colors.surface,
889
962
  borderBottomColor: theme.colors.border
890
963
  }
891
964
  ],
892
965
  children: [
893
- onBack ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onBack, hitSlop: 12, style: styles4.backBtn, accessibilityLabel: "Back", children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "reply", size: 20, color: theme.colors.ink }) }) : null,
966
+ onBack ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onBack, hitSlop: 12, style: styles5.backBtn, accessibilityLabel: "Back", children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "reply", size: 20, color: theme.colors.ink }) }) : null,
894
967
  /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: avatarUrl, name: title, seed: avatarSeed, online: isOnline, size: "md" }),
895
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.titleCol, children: [
968
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.titleCol, children: [
896
969
  /* @__PURE__ */ jsxRuntime.jsx(
897
970
  reactNative.Text,
898
971
  {
899
- style: [styles4.title, { color: theme.colors.ink, fontFamily: theme.type.fontDisplay }],
972
+ style: [styles5.title, { color: theme.colors.ink, fontFamily: theme.type.fontDisplay }],
900
973
  numberOfLines: 1,
901
974
  children: title
902
975
  }
903
976
  ),
904
- subtitle ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.subtitle, { color: theme.colors.ink3 }], numberOfLines: 1, children: subtitle }) : null
977
+ subtitle ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.subtitle, { color: theme.colors.ink3 }], numberOfLines: 1, children: subtitle }) : null
905
978
  ] }),
906
979
  onMembersPress ? /* @__PURE__ */ jsxRuntime.jsx(
907
980
  reactNative.Pressable,
908
981
  {
909
982
  onPress: onMembersPress,
910
983
  hitSlop: 12,
911
- style: styles4.actionBtn,
984
+ style: styles5.actionBtn,
912
985
  accessibilityLabel: "Show members",
913
986
  children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "users", size: 20, color: theme.colors.ink2 })
914
987
  }
@@ -928,7 +1001,7 @@ function ChatHeader({
928
1001
  ) : null
929
1002
  ] });
930
1003
  }
931
- var styles4 = reactNative.StyleSheet.create({
1004
+ var styles5 = reactNative.StyleSheet.create({
932
1005
  root: {
933
1006
  flexDirection: "row",
934
1007
  alignItems: "center",
@@ -986,13 +1059,13 @@ function ConversationList({
986
1059
  const error = isControlled ? controlledError ?? null : auto.error;
987
1060
  const counts = unreadCounts ?? (isControlled ? void 0 : auto.unreadCounts);
988
1061
  if (loading && conversations.length === 0) {
989
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles5.placeholder, { backgroundColor: theme.colors.paper }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.brand }) });
1062
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles6.placeholder, { backgroundColor: theme.colors.paper }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.brand }) });
990
1063
  }
991
1064
  if (error) {
992
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles5.placeholder, { backgroundColor: theme.colors.paper }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.error, fontFamily: theme.type.fontBody }, children: "Failed to load conversations." }) });
1065
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles6.placeholder, { backgroundColor: theme.colors.paper }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.error, fontFamily: theme.type.fontBody }, children: "Failed to load conversations." }) });
993
1066
  }
994
1067
  if (conversations.length === 0) {
995
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles5.placeholder, { backgroundColor: theme.colors.paper }], children: typeof emptyState === "string" || emptyState == null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.ink3, fontFamily: theme.type.fontBody }, children: emptyState ?? "No conversations yet." }) : emptyState });
1068
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles6.placeholder, { backgroundColor: theme.colors.paper }], children: typeof emptyState === "string" || emptyState == null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.ink3, fontFamily: theme.type.fontBody }, children: emptyState ?? "No conversations yet." }) : emptyState });
996
1069
  }
997
1070
  return /* @__PURE__ */ jsxRuntime.jsx(
998
1071
  reactNative.FlatList,
@@ -1042,25 +1115,25 @@ function ConversationRow({
1042
1115
  {
1043
1116
  onPress: () => onSelect?.(conv),
1044
1117
  style: [
1045
- styles5.row,
1118
+ styles6.row,
1046
1119
  {
1047
1120
  backgroundColor: selected ? theme.colors.surface2 : "transparent"
1048
1121
  }
1049
1122
  ],
1050
1123
  children: [
1051
- avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Image, { source: { uri: avatarUrl }, style: styles5.rowAvatar }) : /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: null, name: title, seed: avatarSeed, size: "md" }),
1052
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.body, children: [
1124
+ avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Image, { source: { uri: avatarUrl }, style: styles6.rowAvatar }) : /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: null, name: title, seed: avatarSeed, size: "md" }),
1125
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.body, children: [
1053
1126
  /* @__PURE__ */ jsxRuntime.jsx(
1054
1127
  reactNative.Text,
1055
1128
  {
1056
- style: [styles5.name, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
1129
+ style: [styles6.name, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
1057
1130
  numberOfLines: 1,
1058
1131
  children: title
1059
1132
  }
1060
1133
  ),
1061
- conv.last_message_preview ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.preview, { color: theme.colors.ink3 }], numberOfLines: 1, children: conv.last_message_preview }) : conv.last_message_at ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.preview, { color: theme.colors.ink3 }], numberOfLines: 1, children: formatRelative(conv.last_message_at) }) : null
1134
+ conv.last_message_preview ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.preview, { color: theme.colors.ink3 }], numberOfLines: 1, children: conv.last_message_preview }) : conv.last_message_at ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.preview, { color: theme.colors.ink3 }], numberOfLines: 1, children: formatRelative(conv.last_message_at) }) : null
1062
1135
  ] }),
1063
- unread > 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles5.unreadPill, { backgroundColor: theme.colors.unreadPill }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.unreadText, { color: theme.colors.unreadPillText }], children: unread > 99 ? "99+" : String(unread) }) }) : null
1136
+ unread > 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles6.unreadPill, { backgroundColor: theme.colors.unreadPill }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.unreadText, { color: theme.colors.unreadPillText }], children: unread > 99 ? "99+" : String(unread) }) }) : null
1064
1137
  ]
1065
1138
  }
1066
1139
  );
@@ -1078,7 +1151,7 @@ function formatRelative(iso) {
1078
1151
  return "";
1079
1152
  }
1080
1153
  }
1081
- var styles5 = reactNative.StyleSheet.create({
1154
+ var styles6 = reactNative.StyleSheet.create({
1082
1155
  placeholder: {
1083
1156
  flex: 1,
1084
1157
  alignItems: "center",
@@ -1171,11 +1244,11 @@ function AttachmentPicker({
1171
1244
  onClose();
1172
1245
  }
1173
1246
  };
1174
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible, transparent: true, animationType: "slide", onRequestClose: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles6.backdrop, onPress: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(
1247
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible, transparent: true, animationType: "slide", onRequestClose: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles7.backdrop, onPress: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(
1175
1248
  reactNative.View,
1176
1249
  {
1177
1250
  style: [
1178
- styles6.sheet,
1251
+ styles7.sheet,
1179
1252
  {
1180
1253
  backgroundColor: theme.colors.surface,
1181
1254
  borderTopLeftRadius: theme.radii.lg,
@@ -1184,19 +1257,19 @@ function AttachmentPicker({
1184
1257
  theme.shadows.lg
1185
1258
  ],
1186
1259
  children: [
1187
- camera ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { style: styles6.item, onPress: () => pickFromKind("camera"), children: [
1260
+ camera ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { style: styles7.item, onPress: () => pickFromKind("camera"), children: [
1188
1261
  /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "camera", size: 20, color: theme.colors.ink2 }),
1189
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.itemText, { color: theme.colors.ink }], children: "Camera" })
1262
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.itemText, { color: theme.colors.ink }], children: "Camera" })
1190
1263
  ] }) : null,
1191
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { style: styles6.item, onPress: () => pickFromKind("image"), children: [
1264
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { style: styles7.item, onPress: () => pickFromKind("image"), children: [
1192
1265
  /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "image", size: 20, color: theme.colors.ink2 }),
1193
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.itemText, { color: theme.colors.ink }], children: "Photo or video" })
1266
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.itemText, { color: theme.colors.ink }], children: "Photo or video" })
1194
1267
  ] }),
1195
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { style: styles6.item, onPress: () => pickFromKind("document"), children: [
1268
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { style: styles7.item, onPress: () => pickFromKind("document"), children: [
1196
1269
  /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "attachment", size: 20, color: theme.colors.ink2 }),
1197
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.itemText, { color: theme.colors.ink }], children: "File" })
1270
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.itemText, { color: theme.colors.ink }], children: "File" })
1198
1271
  ] }),
1199
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles6.cancel, onPress: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.itemText, { color: theme.colors.brand }], children: "Cancel" }) })
1272
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles7.cancel, onPress: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.itemText, { color: theme.colors.brand }], children: "Cancel" }) })
1200
1273
  ]
1201
1274
  }
1202
1275
  ) }) });
@@ -1342,7 +1415,7 @@ async function defaultAdapter(kind) {
1342
1415
  })
1343
1416
  );
1344
1417
  }
1345
- var styles6 = reactNative.StyleSheet.create({
1418
+ var styles7 = reactNative.StyleSheet.create({
1346
1419
  backdrop: {
1347
1420
  flex: 1,
1348
1421
  backgroundColor: "rgba(0,0,0,0.35)",
@@ -1372,11 +1445,11 @@ var styles6 = reactNative.StyleSheet.create({
1372
1445
  });
1373
1446
  function DaySeparator({ label }) {
1374
1447
  const theme = usePoolseTheme();
1375
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles7.wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
1448
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
1376
1449
  reactNative.View,
1377
1450
  {
1378
1451
  style: [
1379
- styles7.chip,
1452
+ styles8.chip,
1380
1453
  {
1381
1454
  backgroundColor: theme.colors.surface2,
1382
1455
  borderColor: theme.colors.border
@@ -1386,7 +1459,7 @@ function DaySeparator({ label }) {
1386
1459
  reactNative.Text,
1387
1460
  {
1388
1461
  style: [
1389
- styles7.label,
1462
+ styles8.label,
1390
1463
  {
1391
1464
  color: theme.colors.ink2,
1392
1465
  fontFamily: theme.type.fontBody
@@ -1398,7 +1471,7 @@ function DaySeparator({ label }) {
1398
1471
  }
1399
1472
  ) });
1400
1473
  }
1401
- var styles7 = reactNative.StyleSheet.create({
1474
+ var styles8 = reactNative.StyleSheet.create({
1402
1475
  wrap: {
1403
1476
  alignItems: "center",
1404
1477
  marginVertical: 8
@@ -1425,8 +1498,8 @@ function UploadQueueStrip() {
1425
1498
  {
1426
1499
  horizontal: true,
1427
1500
  showsHorizontalScrollIndicator: false,
1428
- contentContainerStyle: styles8.scroll,
1429
- style: [styles8.scrollStyle, { marginBottom: 8 }],
1501
+ contentContainerStyle: styles9.scroll,
1502
+ style: [styles9.scrollStyle, { marginBottom: 8 }],
1430
1503
  children: upload.queue.map((item) => {
1431
1504
  const isError = item.status === "error";
1432
1505
  const isUploading = item.status === "uploading" || item.status === "pending";
@@ -1437,7 +1510,7 @@ function UploadQueueStrip() {
1437
1510
  if (item.status === "ready" || isError) upload.remove(item.localId);
1438
1511
  else upload.cancel(item.localId);
1439
1512
  };
1440
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.tileWrap, children: [
1513
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.tileWrap, children: [
1441
1514
  isImage && previewUri ? /* @__PURE__ */ jsxRuntime.jsx(ImageTile, { uri: previewUri, uploading: isUploading, error: isError }) : /* @__PURE__ */ jsxRuntime.jsx(
1442
1515
  FileTile,
1443
1516
  {
@@ -1452,13 +1525,13 @@ function UploadQueueStrip() {
1452
1525
  {
1453
1526
  onPress: handleClose,
1454
1527
  hitSlop: 8,
1455
- style: styles8.closeBtn,
1528
+ style: styles9.closeBtn,
1456
1529
  accessibilityLabel: isError ? "Remove failed upload" : "Cancel upload",
1457
1530
  children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 11, color: "#fff" })
1458
1531
  }
1459
1532
  ) : null,
1460
- isUploading ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.progressOverlay, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles8.spinner, { borderColor: theme.colors.onBrand }] }) }) : null,
1461
- isError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles8.errorOverlay, { backgroundColor: "rgba(229,72,77,0.85)" }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.errorText, { color: "#fff" }], children: "Failed" }) }) : null
1533
+ isUploading ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles9.progressOverlay, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles9.spinner, { borderColor: theme.colors.onBrand }] }) }) : null,
1534
+ isError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles9.errorOverlay, { backgroundColor: "rgba(229,72,77,0.85)" }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.errorText, { color: "#fff" }], children: "Failed" }) }) : null
1462
1535
  ] }, item.localId);
1463
1536
  })
1464
1537
  }
@@ -1471,7 +1544,7 @@ function ImageTile({ uri, uploading, error }) {
1471
1544
  {
1472
1545
  source: { uri },
1473
1546
  style: [
1474
- styles8.imageTile,
1547
+ styles9.imageTile,
1475
1548
  {
1476
1549
  backgroundColor: theme.colors.surface2,
1477
1550
  borderColor: error ? theme.colors.error : "transparent",
@@ -1493,24 +1566,24 @@ function FileTile({
1493
1566
  reactNative.View,
1494
1567
  {
1495
1568
  style: [
1496
- styles8.fileTile,
1569
+ styles9.fileTile,
1497
1570
  {
1498
1571
  backgroundColor: theme.colors.surface2,
1499
1572
  borderColor: error ? theme.colors.error : uploading ? theme.colors.brand : theme.colors.border
1500
1573
  }
1501
1574
  ],
1502
1575
  children: [
1503
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles8.fileIconBox, { backgroundColor: theme.colors.brandSoft }], children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "attachment", size: 18, color: theme.colors.brand }) }),
1504
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.fileInfo, children: [
1576
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles9.fileIconBox, { backgroundColor: theme.colors.brandSoft }], children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "attachment", size: 18, color: theme.colors.brand }) }),
1577
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.fileInfo, children: [
1505
1578
  /* @__PURE__ */ jsxRuntime.jsx(
1506
1579
  reactNative.Text,
1507
1580
  {
1508
- style: [styles8.fileName, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
1581
+ style: [styles9.fileName, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
1509
1582
  numberOfLines: 1,
1510
1583
  children: filename
1511
1584
  }
1512
1585
  ),
1513
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.fileSize, { color: theme.colors.ink3 }], children: formatBytes(size) })
1586
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.fileSize, { color: theme.colors.ink3 }], children: formatBytes(size) })
1514
1587
  ] })
1515
1588
  ]
1516
1589
  }
@@ -1524,7 +1597,7 @@ function formatBytes(n) {
1524
1597
  return `${(n / 1024 / 1024 / 1024).toFixed(1)} GB`;
1525
1598
  }
1526
1599
  var TILE = 64;
1527
- var styles8 = reactNative.StyleSheet.create({
1600
+ var styles9 = reactNative.StyleSheet.create({
1528
1601
  scrollStyle: {
1529
1602
  overflow: "visible"
1530
1603
  },
@@ -1740,7 +1813,7 @@ var MessageComposer = react.forwardRef(
1740
1813
  reactNative.View,
1741
1814
  {
1742
1815
  style: [
1743
- styles9.wrap,
1816
+ styles10.wrap,
1744
1817
  {
1745
1818
  backgroundColor: theme.colors.surface,
1746
1819
  borderTopColor: theme.colors.border,
@@ -1763,13 +1836,13 @@ var MessageComposer = react.forwardRef(
1763
1836
  }
1764
1837
  ) : null,
1765
1838
  attachments && !isEditing ? /* @__PURE__ */ jsxRuntime.jsx(UploadQueueStrip, {}) : null,
1766
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.row, children: [
1839
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles10.row, children: [
1767
1840
  attachments && onAttachPress ? /* @__PURE__ */ jsxRuntime.jsx(
1768
1841
  reactNative.Pressable,
1769
1842
  {
1770
1843
  onPress: onAttachPress,
1771
1844
  hitSlop: 8,
1772
- style: styles9.iconBtn,
1845
+ style: styles10.iconBtn,
1773
1846
  accessibilityLabel: "Attach file",
1774
1847
  children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "attachment", size: 22, color: theme.colors.ink2 })
1775
1848
  }
@@ -1788,7 +1861,7 @@ var MessageComposer = react.forwardRef(
1788
1861
  multiline: true,
1789
1862
  editable: !disabled,
1790
1863
  style: [
1791
- styles9.input,
1864
+ styles10.input,
1792
1865
  {
1793
1866
  color: theme.colors.ink,
1794
1867
  backgroundColor: theme.colors.surface2,
@@ -1805,7 +1878,7 @@ var MessageComposer = react.forwardRef(
1805
1878
  onPress: handleSend,
1806
1879
  disabled: submitDisabled,
1807
1880
  style: [
1808
- styles9.sendBtn,
1881
+ styles10.sendBtn,
1809
1882
  {
1810
1883
  backgroundColor: submitDisabled ? theme.colors.ink3 : theme.colors.brand,
1811
1884
  opacity: submitDisabled ? 0.6 : 1
@@ -1827,7 +1900,7 @@ function EditChip({ message, onCancel }) {
1827
1900
  reactNative.View,
1828
1901
  {
1829
1902
  style: [
1830
- styles9.replyChip,
1903
+ styles10.replyChip,
1831
1904
  {
1832
1905
  backgroundColor: theme.colors.surface2,
1833
1906
  borderLeftColor: theme.colors.brand
@@ -1835,10 +1908,10 @@ function EditChip({ message, onCancel }) {
1835
1908
  ],
1836
1909
  children: [
1837
1910
  /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flex: 1 }, children: [
1838
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.replyName, { color: theme.colors.brand }], children: "Editing message" }),
1839
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.replyBody, { color: theme.colors.ink2 }], numberOfLines: 1, children: message.body ?? "\u2026" })
1911
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles10.replyName, { color: theme.colors.brand }], children: "Editing message" }),
1912
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles10.replyBody, { color: theme.colors.ink2 }], numberOfLines: 1, children: message.body ?? "\u2026" })
1840
1913
  ] }),
1841
- onCancel ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onCancel, hitSlop: 8, style: styles9.replyCancel, children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 16, color: theme.colors.ink2 }) }) : null
1914
+ onCancel ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onCancel, hitSlop: 8, style: styles10.replyCancel, children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 16, color: theme.colors.ink2 }) }) : null
1842
1915
  ]
1843
1916
  }
1844
1917
  );
@@ -1855,7 +1928,7 @@ function ReplyChip({
1855
1928
  reactNative.View,
1856
1929
  {
1857
1930
  style: [
1858
- styles9.replyChip,
1931
+ styles10.replyChip,
1859
1932
  {
1860
1933
  backgroundColor: theme.colors.surface2,
1861
1934
  borderLeftColor: theme.colors.brand
@@ -1863,18 +1936,18 @@ function ReplyChip({
1863
1936
  ],
1864
1937
  children: [
1865
1938
  /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flex: 1 }, children: [
1866
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles9.replyName, { color: theme.colors.brand }], children: [
1939
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles10.replyName, { color: theme.colors.brand }], children: [
1867
1940
  "Replying to ",
1868
1941
  senderName
1869
1942
  ] }),
1870
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.replyBody, { color: theme.colors.ink2 }], numberOfLines: 1, children: message.body ?? "\u2026" })
1943
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles10.replyBody, { color: theme.colors.ink2 }], numberOfLines: 1, children: message.body ?? "\u2026" })
1871
1944
  ] }),
1872
- onCancel ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onCancel, hitSlop: 8, style: styles9.replyCancel, children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 16, color: theme.colors.ink2 }) }) : null
1945
+ onCancel ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onCancel, hitSlop: 8, style: styles10.replyCancel, children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 16, color: theme.colors.ink2 }) }) : null
1873
1946
  ]
1874
1947
  }
1875
1948
  );
1876
1949
  }
1877
- var styles9 = reactNative.StyleSheet.create({
1950
+ var styles10 = reactNative.StyleSheet.create({
1878
1951
  wrap: {
1879
1952
  borderTopWidth: reactNative.StyleSheet.hairlineWidth,
1880
1953
  paddingTop: 8,
@@ -1971,11 +2044,11 @@ function MentionInput({ conversationId, onSend, ...composerProps }) {
1971
2044
  transparent: true,
1972
2045
  animationType: "slide",
1973
2046
  onRequestClose: () => setPickerOpen(false),
1974
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles10.backdrop, onPress: () => setPickerOpen(false), children: /* @__PURE__ */ jsxRuntime.jsxs(
2047
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles11.backdrop, onPress: () => setPickerOpen(false), children: /* @__PURE__ */ jsxRuntime.jsxs(
1975
2048
  reactNative.View,
1976
2049
  {
1977
2050
  style: [
1978
- styles10.sheet,
2051
+ styles11.sheet,
1979
2052
  {
1980
2053
  backgroundColor: theme.colors.surface,
1981
2054
  borderTopLeftRadius: theme.radii.lg,
@@ -1986,7 +2059,7 @@ function MentionInput({ conversationId, onSend, ...composerProps }) {
1986
2059
  /* @__PURE__ */ jsxRuntime.jsx(
1987
2060
  reactNative.Text,
1988
2061
  {
1989
- style: [styles10.title, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
2062
+ style: [styles11.title, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
1990
2063
  children: "Mention a member"
1991
2064
  }
1992
2065
  ),
@@ -2017,12 +2090,12 @@ function MentionInput({ conversationId, onSend, ...composerProps }) {
2017
2090
  }
2018
2091
  function MentionRow({ member, onPress }) {
2019
2092
  const theme = usePoolseTheme();
2020
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { onPress, style: styles10.row, children: [
2093
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { onPress, style: styles11.row, children: [
2021
2094
  /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: null, name: member.external_id, seed: member.external_id, size: "sm" }),
2022
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles10.rowText, { color: theme.colors.ink, fontFamily: theme.type.fontBody }], children: member.external_id })
2095
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles11.rowText, { color: theme.colors.ink, fontFamily: theme.type.fontBody }], children: member.external_id })
2023
2096
  ] });
2024
2097
  }
2025
- var styles10 = reactNative.StyleSheet.create({
2098
+ var styles11 = reactNative.StyleSheet.create({
2026
2099
  backdrop: {
2027
2100
  flex: 1,
2028
2101
  backgroundColor: "rgba(0,0,0,0.35)",
@@ -2102,12 +2175,12 @@ function MessageList({
2102
2175
  [renderItem, data.length]
2103
2176
  );
2104
2177
  if (loading && messages.length === 0) {
2105
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles11.placeholder, { backgroundColor: theme.colors.paper }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.brand }) });
2178
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles12.placeholder, { backgroundColor: theme.colors.paper }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.brand }) });
2106
2179
  }
2107
2180
  if (messages.length === 0) {
2108
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles11.placeholder, { backgroundColor: theme.colors.paper }], children: typeof emptyState === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.ink3, fontFamily: theme.type.fontBody }, children: emptyState }) : emptyState ?? null });
2181
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles12.placeholder, { backgroundColor: theme.colors.paper }], children: typeof emptyState === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.ink3, fontFamily: theme.type.fontBody }, children: emptyState }) : emptyState ?? null });
2109
2182
  }
2110
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles11.root, children: [
2183
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles12.root, children: [
2111
2184
  /* @__PURE__ */ jsxRuntime.jsx(
2112
2185
  reactNative.FlatList,
2113
2186
  {
@@ -2134,7 +2207,7 @@ function MessageList({
2134
2207
  {
2135
2208
  onPress: scrollToBottom,
2136
2209
  style: [
2137
- styles11.jumpButton,
2210
+ styles12.jumpButton,
2138
2211
  {
2139
2212
  backgroundColor: theme.colors.brand
2140
2213
  },
@@ -2143,7 +2216,7 @@ function MessageList({
2143
2216
  accessibilityLabel: `${newCount} new ${newCount === 1 ? "message" : "messages"}, jump to latest`,
2144
2217
  children: [
2145
2218
  /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "chevron-down", size: 14, color: theme.colors.onBrand }),
2146
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles11.jumpText, { color: theme.colors.onBrand }], children: [
2219
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles12.jumpText, { color: theme.colors.onBrand }], children: [
2147
2220
  newCount,
2148
2221
  " new ",
2149
2222
  newCount === 1 ? "message" : "messages"
@@ -2153,7 +2226,7 @@ function MessageList({
2153
2226
  ) : null
2154
2227
  ] });
2155
2228
  }
2156
- var styles11 = reactNative.StyleSheet.create({
2229
+ var styles12 = reactNative.StyleSheet.create({
2157
2230
  root: {
2158
2231
  flex: 1
2159
2232
  },
@@ -2204,11 +2277,11 @@ function MessageActions({
2204
2277
  if (isSelf && onDelete)
2205
2278
  items.push({ label: "Delete", icon: "trash", onPress: onDelete, danger: true });
2206
2279
  const showEmojiRow = !!onPickReaction && emojis.length > 0;
2207
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible, transparent: true, animationType: "fade", onRequestClose: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles12.backdrop, onPress: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(
2280
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible, transparent: true, animationType: "fade", onRequestClose: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles13.backdrop, onPress: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(
2208
2281
  reactNative.View,
2209
2282
  {
2210
2283
  style: [
2211
- styles12.sheet,
2284
+ styles13.sheet,
2212
2285
  {
2213
2286
  backgroundColor: theme.colors.surface,
2214
2287
  borderTopLeftRadius: theme.radii.lg,
@@ -2217,21 +2290,21 @@ function MessageActions({
2217
2290
  theme.shadows.lg
2218
2291
  ],
2219
2292
  children: [
2220
- showEmojiRow ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles12.emojiRow, { borderBottomColor: theme.colors.border }], children: emojis.map((emoji) => /* @__PURE__ */ jsxRuntime.jsx(
2293
+ showEmojiRow ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles13.emojiRow, { borderBottomColor: theme.colors.border }], children: emojis.map((emoji) => /* @__PURE__ */ jsxRuntime.jsx(
2221
2294
  reactNative.Pressable,
2222
2295
  {
2223
2296
  onPress: () => {
2224
2297
  onPickReaction(emoji);
2225
2298
  onClose();
2226
2299
  },
2227
- style: styles12.emojiBtn,
2300
+ style: styles13.emojiBtn,
2228
2301
  hitSlop: 6,
2229
2302
  accessibilityLabel: `React with ${emoji}`,
2230
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles12.emoji, children: emoji })
2303
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles13.emoji, children: emoji })
2231
2304
  },
2232
2305
  emoji
2233
2306
  )) }) : null,
2234
- items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { onPress: item.onPress, style: styles12.item, children: [
2307
+ items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { onPress: item.onPress, style: styles13.item, children: [
2235
2308
  /* @__PURE__ */ jsxRuntime.jsx(
2236
2309
  PoolseIcon,
2237
2310
  {
@@ -2244,7 +2317,7 @@ function MessageActions({
2244
2317
  reactNative.Text,
2245
2318
  {
2246
2319
  style: [
2247
- styles12.itemText,
2320
+ styles13.itemText,
2248
2321
  {
2249
2322
  color: item.danger ? theme.colors.error : theme.colors.ink,
2250
2323
  fontFamily: theme.type.fontBody
@@ -2258,7 +2331,7 @@ function MessageActions({
2258
2331
  }
2259
2332
  ) }) });
2260
2333
  }
2261
- var styles12 = reactNative.StyleSheet.create({
2334
+ var styles13 = reactNative.StyleSheet.create({
2262
2335
  backdrop: {
2263
2336
  flex: 1,
2264
2337
  backgroundColor: "rgba(0,0,0,0.35)",
@@ -2323,7 +2396,7 @@ function AttachmentPreview({ attachment, onPress, maxWidth = 280 }) {
2323
2396
  reactNative.View,
2324
2397
  {
2325
2398
  style: [
2326
- styles13.imagePlaceholder,
2399
+ styles14.imagePlaceholder,
2327
2400
  {
2328
2401
  width: maxWidth,
2329
2402
  height: 200,
@@ -2340,7 +2413,7 @@ function AttachmentPreview({ attachment, onPress, maxWidth = 280 }) {
2340
2413
  onPress,
2341
2414
  disabled: !onPress,
2342
2415
  style: [
2343
- styles13.fileCard,
2416
+ styles14.fileCard,
2344
2417
  {
2345
2418
  backgroundColor: theme.colors.surface2,
2346
2419
  borderColor: theme.colors.border,
@@ -2353,12 +2426,12 @@ function AttachmentPreview({ attachment, onPress, maxWidth = 280 }) {
2353
2426
  /* @__PURE__ */ jsxRuntime.jsx(
2354
2427
  reactNative.Text,
2355
2428
  {
2356
- style: [styles13.fileName, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
2429
+ style: [styles14.fileName, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
2357
2430
  numberOfLines: 1,
2358
2431
  children: attachment.original_filename ?? "file"
2359
2432
  }
2360
2433
  ),
2361
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles13.fileSize, { color: theme.colors.ink3 }], children: formatBytes2(attachment.byte_size) })
2434
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles14.fileSize, { color: theme.colors.ink3 }], children: formatBytes2(attachment.byte_size) })
2362
2435
  ] })
2363
2436
  ]
2364
2437
  }
@@ -2370,7 +2443,7 @@ function formatBytes2(n) {
2370
2443
  if (n < 1024 * 1024 * 1024) return `${(n / 1024 / 1024).toFixed(1)} MB`;
2371
2444
  return `${(n / 1024 / 1024 / 1024).toFixed(1)} GB`;
2372
2445
  }
2373
- var styles13 = reactNative.StyleSheet.create({
2446
+ var styles14 = reactNative.StyleSheet.create({
2374
2447
  imagePlaceholder: {},
2375
2448
  fileCard: {
2376
2449
  flexDirection: "row",
@@ -2399,7 +2472,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
2399
2472
  reactNative.View,
2400
2473
  {
2401
2474
  style: [
2402
- styles14.root,
2475
+ styles15.root,
2403
2476
  {
2404
2477
  borderRadius: r,
2405
2478
  ...maxWidth ? { maxWidth } : {}
@@ -2410,17 +2483,17 @@ function ImageMosaic({ images, maxWidth, radius }) {
2410
2483
  Tile,
2411
2484
  {
2412
2485
  attachment: visible[0],
2413
- style: styles14.tileFull,
2486
+ style: styles15.tileFull,
2414
2487
  onPress: () => setViewerIndex(0),
2415
2488
  overlay: null
2416
2489
  }
2417
2490
  ) : null,
2418
- n === 2 ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles14.rowEven, children: [
2491
+ n === 2 ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles15.rowEven, children: [
2419
2492
  /* @__PURE__ */ jsxRuntime.jsx(
2420
2493
  Tile,
2421
2494
  {
2422
2495
  attachment: visible[0],
2423
- style: styles14.tileHalfSquare,
2496
+ style: styles15.tileHalfSquare,
2424
2497
  onPress: () => setViewerIndex(0),
2425
2498
  overlay: null
2426
2499
  }
@@ -2429,7 +2502,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
2429
2502
  Tile,
2430
2503
  {
2431
2504
  attachment: visible[1],
2432
- style: styles14.tileHalfSquare,
2505
+ style: styles15.tileHalfSquare,
2433
2506
  onPress: () => setViewerIndex(1),
2434
2507
  overlay: null
2435
2508
  }
@@ -2440,17 +2513,17 @@ function ImageMosaic({ images, maxWidth, radius }) {
2440
2513
  Tile,
2441
2514
  {
2442
2515
  attachment: visible[0],
2443
- style: styles14.tileHero,
2516
+ style: styles15.tileHero,
2444
2517
  onPress: () => setViewerIndex(0),
2445
2518
  overlay: null
2446
2519
  }
2447
2520
  ),
2448
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles14.rowEven, { marginTop: 2 }], children: [
2521
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles15.rowEven, { marginTop: 2 }], children: [
2449
2522
  /* @__PURE__ */ jsxRuntime.jsx(
2450
2523
  Tile,
2451
2524
  {
2452
2525
  attachment: visible[1],
2453
- style: styles14.tileHalfSquare,
2526
+ style: styles15.tileHalfSquare,
2454
2527
  onPress: () => setViewerIndex(1),
2455
2528
  overlay: null
2456
2529
  }
@@ -2459,7 +2532,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
2459
2532
  Tile,
2460
2533
  {
2461
2534
  attachment: visible[2],
2462
- style: styles14.tileHalfSquare,
2535
+ style: styles15.tileHalfSquare,
2463
2536
  onPress: () => setViewerIndex(2),
2464
2537
  overlay: null
2465
2538
  }
@@ -2467,12 +2540,12 @@ function ImageMosaic({ images, maxWidth, radius }) {
2467
2540
  ] })
2468
2541
  ] }) : null,
2469
2542
  n === 4 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2470
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles14.rowEven, children: [
2543
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles15.rowEven, children: [
2471
2544
  /* @__PURE__ */ jsxRuntime.jsx(
2472
2545
  Tile,
2473
2546
  {
2474
2547
  attachment: visible[0],
2475
- style: styles14.tileHalfSquare,
2548
+ style: styles15.tileHalfSquare,
2476
2549
  onPress: () => setViewerIndex(0),
2477
2550
  overlay: null
2478
2551
  }
@@ -2481,18 +2554,18 @@ function ImageMosaic({ images, maxWidth, radius }) {
2481
2554
  Tile,
2482
2555
  {
2483
2556
  attachment: visible[1],
2484
- style: styles14.tileHalfSquare,
2557
+ style: styles15.tileHalfSquare,
2485
2558
  onPress: () => setViewerIndex(1),
2486
2559
  overlay: null
2487
2560
  }
2488
2561
  )
2489
2562
  ] }),
2490
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles14.rowEven, { marginTop: 2 }], children: [
2563
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles15.rowEven, { marginTop: 2 }], children: [
2491
2564
  /* @__PURE__ */ jsxRuntime.jsx(
2492
2565
  Tile,
2493
2566
  {
2494
2567
  attachment: visible[2],
2495
- style: styles14.tileHalfSquare,
2568
+ style: styles15.tileHalfSquare,
2496
2569
  onPress: () => setViewerIndex(2),
2497
2570
  overlay: null
2498
2571
  }
@@ -2501,7 +2574,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
2501
2574
  Tile,
2502
2575
  {
2503
2576
  attachment: visible[3],
2504
- style: styles14.tileHalfSquare,
2577
+ style: styles15.tileHalfSquare,
2505
2578
  onPress: () => setViewerIndex(3),
2506
2579
  overlay: overflow > 0 ? `+${overflow}` : null
2507
2580
  }
@@ -2537,18 +2610,18 @@ function Tile({
2537
2610
  }) {
2538
2611
  const theme = usePoolseTheme();
2539
2612
  const { url } = react$1.useAttachmentUrl(attachment.id);
2540
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { onPress, style: [styles14.tileBase, style], children: [
2613
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { onPress, style: [styles15.tileBase, style], children: [
2541
2614
  url ? /* @__PURE__ */ jsxRuntime.jsx(
2542
2615
  reactNative.Image,
2543
2616
  {
2544
2617
  source: { uri: url },
2545
- style: [styles14.tileImage, { backgroundColor: theme.colors.surface2 }],
2618
+ style: [styles15.tileImage, { backgroundColor: theme.colors.surface2 }],
2546
2619
  resizeMode: "cover",
2547
2620
  accessible: true,
2548
2621
  accessibilityLabel: attachment.original_filename ?? "image"
2549
2622
  }
2550
- ) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles14.tileImage, { backgroundColor: theme.colors.surface2 }] }),
2551
- overlay ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles14.overflow, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles14.overflowText, children: overlay }) }) : null
2623
+ ) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles15.tileImage, { backgroundColor: theme.colors.surface2 }] }),
2624
+ overlay ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles15.overflow, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles15.overflowText, children: overlay }) }) : null
2552
2625
  ] });
2553
2626
  }
2554
2627
  function FullScreenViewer({
@@ -2557,7 +2630,7 @@ function FullScreenViewer({
2557
2630
  }) {
2558
2631
  const { url } = react$1.useAttachmentUrl(attachment.id);
2559
2632
  const { width, height } = reactNative.Dimensions.get("window");
2560
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { style: styles14.viewer, onPress: onClose, children: [
2633
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { style: styles15.viewer, onPress: onClose, children: [
2561
2634
  url ? /* @__PURE__ */ jsxRuntime.jsx(
2562
2635
  reactNative.Image,
2563
2636
  {
@@ -2573,14 +2646,14 @@ function FullScreenViewer({
2573
2646
  {
2574
2647
  onPress: onClose,
2575
2648
  hitSlop: 12,
2576
- style: styles14.closeBtn,
2649
+ style: styles15.closeBtn,
2577
2650
  accessibilityLabel: "Close viewer",
2578
2651
  children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 20, color: "#ffffff" })
2579
2652
  }
2580
2653
  )
2581
2654
  ] });
2582
2655
  }
2583
- var styles14 = reactNative.StyleSheet.create({
2656
+ var styles15 = reactNative.StyleSheet.create({
2584
2657
  root: {
2585
2658
  width: "100%",
2586
2659
  overflow: "hidden",
@@ -2735,7 +2808,7 @@ function MessageBubble({
2735
2808
  reactNative.View,
2736
2809
  {
2737
2810
  style: [
2738
- styles15.wrap,
2811
+ styles16.wrap,
2739
2812
  {
2740
2813
  alignSelf: isSelf ? "flex-end" : "flex-start",
2741
2814
  // Pixel maxWidth (not percentage) so single-line and
@@ -2749,7 +2822,7 @@ function MessageBubble({
2749
2822
  reactNative.View,
2750
2823
  {
2751
2824
  style: [
2752
- styles15.bubble,
2825
+ styles16.bubble,
2753
2826
  {
2754
2827
  backgroundColor: bubbleColor,
2755
2828
  borderColor: isSelf ? "transparent" : theme.colors.border,
@@ -2771,7 +2844,7 @@ function MessageBubble({
2771
2844
  theme.shadows.sm
2772
2845
  ],
2773
2846
  children: [
2774
- showSenderName && !isSelf && (groupPosition === "first" || groupPosition === "standalone") ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles15.senderName, { color: senderTint, fontFamily: theme.type.fontBody }], children: senderLabel }) : null,
2847
+ showSenderName && !isSelf && (groupPosition === "first" || groupPosition === "standalone") ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles16.senderName, { color: senderTint, fontFamily: theme.type.fontBody }], children: senderLabel }) : null,
2775
2848
  message.quoted_message ? /* @__PURE__ */ jsxRuntime.jsx(
2776
2849
  QuotedCard,
2777
2850
  {
@@ -2787,7 +2860,7 @@ function MessageBubble({
2787
2860
  reactNative.Text,
2788
2861
  {
2789
2862
  style: [
2790
- styles15.body,
2863
+ styles16.body,
2791
2864
  {
2792
2865
  color: theme.colors.ink3,
2793
2866
  fontFamily: theme.type.fontBody,
@@ -2812,7 +2885,7 @@ function MessageBubble({
2812
2885
  reactNative.Text,
2813
2886
  {
2814
2887
  style: [
2815
- styles15.body,
2888
+ styles16.body,
2816
2889
  {
2817
2890
  color: textColor,
2818
2891
  fontFamily: theme.type.fontBody,
@@ -2827,18 +2900,18 @@ function MessageBubble({
2827
2900
  reactNative.Text,
2828
2901
  {
2829
2902
  style: [
2830
- styles15.readMore,
2903
+ styles16.readMore,
2831
2904
  { color: isSelf ? theme.colors.onBrand : theme.colors.brand }
2832
2905
  ],
2833
2906
  children: expanded ? "Show less" : "Read more"
2834
2907
  }
2835
2908
  ) }) : null,
2836
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles15.metaRow, children: [
2909
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles16.metaRow, children: [
2837
2910
  isEdited ? /* @__PURE__ */ jsxRuntime.jsx(
2838
2911
  reactNative.Text,
2839
2912
  {
2840
2913
  style: [
2841
- styles15.editedTag,
2914
+ styles16.editedTag,
2842
2915
  {
2843
2916
  color: isSelf ? theme.colors.onBrand : theme.colors.ink3,
2844
2917
  opacity: 0.7
@@ -2851,7 +2924,7 @@ function MessageBubble({
2851
2924
  reactNative.Text,
2852
2925
  {
2853
2926
  style: [
2854
- styles15.meta,
2927
+ styles16.meta,
2855
2928
  {
2856
2929
  color: isSelf ? theme.colors.onBrand : theme.colors.ink3,
2857
2930
  opacity: isSelf ? 0.85 : 1
@@ -2860,7 +2933,7 @@ function MessageBubble({
2860
2933
  children: time
2861
2934
  }
2862
2935
  ),
2863
- isSelf && readState ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles15.readTick, children: /* @__PURE__ */ jsxRuntime.jsx(
2936
+ isSelf && readState ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles16.readTick, children: /* @__PURE__ */ jsxRuntime.jsx(
2864
2937
  PoolseIcon,
2865
2938
  {
2866
2939
  name: readState === "read" ? "check-double" : "check",
@@ -2869,7 +2942,7 @@ function MessageBubble({
2869
2942
  }
2870
2943
  ) }) : null
2871
2944
  ] }),
2872
- actionsTrigger ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles15.actionsSlot, children: actionsTrigger }) : null
2945
+ actionsTrigger ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles16.actionsSlot, children: actionsTrigger }) : null
2873
2946
  ]
2874
2947
  }
2875
2948
  )
@@ -2894,15 +2967,15 @@ function QuotedCard({
2894
2967
  onPress,
2895
2968
  disabled: !onPress,
2896
2969
  style: [
2897
- styles15.quoted,
2970
+ styles16.quoted,
2898
2971
  {
2899
2972
  backgroundColor: bg,
2900
2973
  borderLeftColor: accent
2901
2974
  }
2902
2975
  ],
2903
2976
  children: [
2904
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles15.quotedSender, { color: accent }], children: senderName }),
2905
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles15.quotedBody, { color: txt }], numberOfLines: 2, children: quoted.body ?? "\u2026" })
2977
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles16.quotedSender, { color: accent }], children: senderName }),
2978
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles16.quotedBody, { color: txt }], numberOfLines: 2, children: quoted.body ?? "\u2026" })
2906
2979
  ]
2907
2980
  }
2908
2981
  );
@@ -2934,7 +3007,7 @@ function formatTime(iso) {
2934
3007
  function isSameDay(a, b) {
2935
3008
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
2936
3009
  }
2937
- var styles15 = reactNative.StyleSheet.create({
3010
+ var styles16 = reactNative.StyleSheet.create({
2938
3011
  wrap: {
2939
3012
  marginBottom: 2
2940
3013
  },
@@ -3014,7 +3087,7 @@ function ReactionStrip({
3014
3087
  });
3015
3088
  const entries = Object.entries(reactions);
3016
3089
  if (entries.length === 0) return null;
3017
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles16.strip, children: entries.map(([emoji, userIds]) => {
3090
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles17.strip, children: entries.map(([emoji, userIds]) => {
3018
3091
  const userArr = Array.isArray(userIds) ? userIds : [];
3019
3092
  const meReacted = meId !== null && userArr.includes(meId);
3020
3093
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3022,7 +3095,7 @@ function ReactionStrip({
3022
3095
  {
3023
3096
  onPress: () => meReacted ? removeReaction(emoji) : addReaction(emoji),
3024
3097
  style: [
3025
- styles16.chip,
3098
+ styles17.chip,
3026
3099
  {
3027
3100
  backgroundColor: meReacted ? theme.colors.brandSoft : theme.colors.surface2,
3028
3101
  borderColor: meReacted ? theme.colors.brand : theme.colors.border,
@@ -3031,12 +3104,12 @@ function ReactionStrip({
3031
3104
  }
3032
3105
  ],
3033
3106
  children: [
3034
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles16.emoji, children: emoji }),
3107
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles17.emoji, children: emoji }),
3035
3108
  /* @__PURE__ */ jsxRuntime.jsx(
3036
3109
  reactNative.Text,
3037
3110
  {
3038
3111
  style: [
3039
- styles16.count,
3112
+ styles17.count,
3040
3113
  {
3041
3114
  color: meReacted ? theme.colors.brand : theme.colors.ink2,
3042
3115
  fontWeight: meReacted ? "700" : "600"
@@ -3058,11 +3131,11 @@ function ReactionPicker({
3058
3131
  emojis = DEFAULT_EMOJIS
3059
3132
  }) {
3060
3133
  const theme = usePoolseTheme();
3061
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible, transparent: true, animationType: "fade", onRequestClose: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles16.backdrop, onPress: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
3134
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible, transparent: true, animationType: "fade", onRequestClose: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles17.backdrop, onPress: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
3062
3135
  reactNative.View,
3063
3136
  {
3064
3137
  style: [
3065
- styles16.sheet,
3138
+ styles17.sheet,
3066
3139
  {
3067
3140
  backgroundColor: theme.colors.surface,
3068
3141
  borderRadius: theme.radii.lg
@@ -3072,19 +3145,19 @@ function ReactionPicker({
3072
3145
  children: emojis.map((emoji) => /* @__PURE__ */ jsxRuntime.jsx(
3073
3146
  reactNative.Pressable,
3074
3147
  {
3075
- style: styles16.emojiBtn,
3148
+ style: styles17.emojiBtn,
3076
3149
  onPress: () => {
3077
3150
  onPick(emoji);
3078
3151
  onClose();
3079
3152
  },
3080
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles16.bigEmoji, children: emoji })
3153
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles17.bigEmoji, children: emoji })
3081
3154
  },
3082
3155
  emoji
3083
3156
  ))
3084
3157
  }
3085
3158
  ) }) });
3086
3159
  }
3087
- var styles16 = reactNative.StyleSheet.create({
3160
+ var styles17 = reactNative.StyleSheet.create({
3088
3161
  strip: {
3089
3162
  flexDirection: "row",
3090
3163
  flexWrap: "wrap",
@@ -3252,15 +3325,15 @@ function MessageRow({
3252
3325
  reactNative.View,
3253
3326
  {
3254
3327
  style: [
3255
- styles17.row,
3328
+ styles18.row,
3256
3329
  { alignSelf: isSelf ? "flex-end" : "flex-start" },
3257
3330
  // Lift this row above the dim backdrop the parent renders
3258
3331
  // during edit mode. zIndex covers iOS / web; elevation does
3259
3332
  // the equivalent on Android.
3260
- isEditing ? styles17.rowEditing : null
3333
+ isEditing ? styles18.rowEditing : null
3261
3334
  ],
3262
3335
  children: [
3263
- showAvatarSlot ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles17.avatarSlot, children: showAvatarRender ? /* @__PURE__ */ jsxRuntime.jsx(
3336
+ showAvatarSlot ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles18.avatarSlot, children: showAvatarRender ? /* @__PURE__ */ jsxRuntime.jsx(
3264
3337
  Avatar,
3265
3338
  {
3266
3339
  src: avatarUrl ?? null,
@@ -3269,14 +3342,14 @@ function MessageRow({
3269
3342
  size: "sm"
3270
3343
  }
3271
3344
  ) : null }) : null,
3272
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles17.bubbleCol, children: [
3345
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles18.bubbleCol, children: [
3273
3346
  swipeEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
3274
3347
  reactNative.Animated.View,
3275
3348
  {
3276
3349
  pointerEvents: "none",
3277
3350
  style: [
3278
- styles17.replyHint,
3279
- isSelf ? styles17.replyHintRight : styles17.replyHintLeft,
3351
+ styles18.replyHint,
3352
+ isSelf ? styles18.replyHintRight : styles18.replyHintLeft,
3280
3353
  {
3281
3354
  opacity: replyIconOpacity,
3282
3355
  transform: [{ scale: replyIconScale }],
@@ -3327,13 +3400,13 @@ function MessageRow({
3327
3400
  )
3328
3401
  }
3329
3402
  ),
3330
- threads && (msg.reply_count ?? 0) > 0 && onOpenThread ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onOpenThread, style: styles17.threadPill, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles17.threadPillText, { color: theme.colors.brand }], children: [
3403
+ threads && (msg.reply_count ?? 0) > 0 && onOpenThread ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onOpenThread, style: styles18.threadPill, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles18.threadPillText, { color: theme.colors.brand }], children: [
3331
3404
  "\u{1F4AC} ",
3332
3405
  msg.reply_count,
3333
3406
  " ",
3334
3407
  msg.reply_count === 1 ? "reply" : "replies"
3335
3408
  ] }) }) : null,
3336
- reactions ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles17.reactionsRow, { alignSelf: isSelf ? "flex-end" : "flex-start" }], children: /* @__PURE__ */ jsxRuntime.jsx(
3409
+ reactions ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles18.reactionsRow, { alignSelf: isSelf ? "flex-end" : "flex-start" }], children: /* @__PURE__ */ jsxRuntime.jsx(
3337
3410
  ReactionStrip,
3338
3411
  {
3339
3412
  messageId: msg.id,
@@ -3392,7 +3465,7 @@ function MessageRow({
3392
3465
  }
3393
3466
  );
3394
3467
  }
3395
- var styles17 = reactNative.StyleSheet.create({
3468
+ var styles18 = reactNative.StyleSheet.create({
3396
3469
  row: {
3397
3470
  flexDirection: "row",
3398
3471
  alignItems: "flex-end",
@@ -3552,13 +3625,13 @@ function ThreadSheet({
3552
3625
  ),
3553
3626
  [rootMessage, meId, labelFor, avatarFor]
3554
3627
  );
3555
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles18.modalRoot, children: [
3556
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles18.backdrop, onPress: onClose, accessibilityLabel: "Close thread" }),
3628
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles19.modalRoot, children: [
3629
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles19.backdrop, onPress: onClose, accessibilityLabel: "Close thread" }),
3557
3630
  /* @__PURE__ */ jsxRuntime.jsxs(
3558
3631
  reactNative.Animated.View,
3559
3632
  {
3560
3633
  style: [
3561
- styles18.sheet,
3634
+ styles19.sheet,
3562
3635
  {
3563
3636
  height: sheetHeight,
3564
3637
  backgroundColor: theme.colors.paper,
@@ -3570,14 +3643,14 @@ function ThreadSheet({
3570
3643
  ],
3571
3644
  children: [
3572
3645
  /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ...panHandlers, children: [
3573
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles18.dragHandle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles18.dragPill, { backgroundColor: theme.colors.ink3 }] }) }),
3574
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles18.header, { borderBottomColor: theme.colors.border }], children: [
3646
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles19.dragHandle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles19.dragPill, { backgroundColor: theme.colors.ink3 }] }) }),
3647
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles19.header, { borderBottomColor: theme.colors.border }], children: [
3575
3648
  /* @__PURE__ */ jsxRuntime.jsx(
3576
3649
  reactNative.Pressable,
3577
3650
  {
3578
3651
  onPress: onClose,
3579
3652
  hitSlop: 16,
3580
- style: [styles18.closeBtn, { backgroundColor: theme.colors.surface2 }],
3653
+ style: [styles19.closeBtn, { backgroundColor: theme.colors.surface2 }],
3581
3654
  accessibilityLabel: "Close thread",
3582
3655
  children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 18, color: theme.colors.ink })
3583
3656
  }
@@ -3586,7 +3659,7 @@ function ThreadSheet({
3586
3659
  reactNative.Text,
3587
3660
  {
3588
3661
  style: [
3589
- styles18.title,
3662
+ styles19.title,
3590
3663
  { color: theme.colors.ink, fontFamily: theme.type.fontDisplay }
3591
3664
  ],
3592
3665
  children: "Thread"
@@ -3597,12 +3670,12 @@ function ThreadSheet({
3597
3670
  /* @__PURE__ */ jsxRuntime.jsxs(
3598
3671
  reactNative.KeyboardAvoidingView,
3599
3672
  {
3600
- style: styles18.kavBody,
3673
+ style: styles19.kavBody,
3601
3674
  behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
3602
3675
  keyboardVerticalOffset: reactNative.Platform.OS === "ios" ? gutter : 0,
3603
3676
  children: [
3604
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles18.rootPreview, { backgroundColor: theme.colors.surface2 }], children: rootRow }),
3605
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles18.listWrap, children: /* @__PURE__ */ jsxRuntime.jsx(
3677
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles19.rootPreview, { backgroundColor: theme.colors.surface2 }], children: rootRow }),
3678
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles19.listWrap, children: /* @__PURE__ */ jsxRuntime.jsx(
3606
3679
  MessageList,
3607
3680
  {
3608
3681
  messages: replies,
@@ -3638,7 +3711,7 @@ function ThreadSheet({
3638
3711
  )
3639
3712
  ] });
3640
3713
  }
3641
- var styles18 = reactNative.StyleSheet.create({
3714
+ var styles19 = reactNative.StyleSheet.create({
3642
3715
  modalRoot: {
3643
3716
  flex: 1,
3644
3717
  justifyContent: "flex-end"
@@ -3710,7 +3783,7 @@ function TypingIndicator({ typing, labelFor }) {
3710
3783
  const ids = Array.from(typing);
3711
3784
  const isTyping = ids.length > 0;
3712
3785
  if (!isTyping) return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { height: 0 } });
3713
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles19.row, children: [
3786
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles20.row, children: [
3714
3787
  /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {}),
3715
3788
  /* @__PURE__ */ jsxRuntime.jsx(TypingLabel, { ids, ...labelFor ? { labelFor } : {} })
3716
3789
  ] });
@@ -3755,7 +3828,7 @@ function TypingDots() {
3755
3828
  ],
3756
3829
  opacity: val.interpolate({ inputRange: [0, 1], outputRange: [0.5, 1] })
3757
3830
  });
3758
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles19.dotsWrap, children: [
3831
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles20.dotsWrap, children: [
3759
3832
  /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: dot(a) }),
3760
3833
  /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: dot(b) }),
3761
3834
  /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: dot(c) })
@@ -3771,9 +3844,9 @@ function TypingLabel({
3771
3844
  const name1 = useDisplayName(id1, labelFor);
3772
3845
  const name2 = useDisplayName(id2, labelFor);
3773
3846
  const text = ids.length === 1 ? `${name1} is typing` : ids.length === 2 ? `${name1} and ${name2} are typing` : `${ids.length} people are typing`;
3774
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles19.label, { color: theme.colors.ink2, fontFamily: theme.type.fontBody }], children: text });
3847
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles20.label, { color: theme.colors.ink2, fontFamily: theme.type.fontBody }], children: text });
3775
3848
  }
3776
- var styles19 = reactNative.StyleSheet.create({
3849
+ var styles20 = reactNative.StyleSheet.create({
3777
3850
  row: {
3778
3851
  flexDirection: "row",
3779
3852
  alignItems: "center",
@@ -4011,12 +4084,12 @@ function ConversationView({
4011
4084
  return /* @__PURE__ */ jsxRuntime.jsx(UploadProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(
4012
4085
  reactNative.KeyboardAvoidingView,
4013
4086
  {
4014
- style: [styles20.root, { backgroundColor: theme.colors.paper }],
4087
+ style: [styles21.root, { backgroundColor: theme.colors.paper }],
4015
4088
  behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
4016
4089
  keyboardVerticalOffset: keyboardOffset,
4017
4090
  children: [
4018
4091
  headerNode,
4019
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles20.listWrap, children: [
4092
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles21.listWrap, children: [
4020
4093
  /* @__PURE__ */ jsxRuntime.jsx(
4021
4094
  MessageList,
4022
4095
  {
@@ -4034,7 +4107,7 @@ function ConversationView({
4034
4107
  editingId ? /* @__PURE__ */ jsxRuntime.jsx(
4035
4108
  reactNative.Pressable,
4036
4109
  {
4037
- style: styles20.editBackdrop,
4110
+ style: styles21.editBackdrop,
4038
4111
  onPress: () => setEditingId(null),
4039
4112
  accessibilityLabel: "Cancel editing"
4040
4113
  }
@@ -4069,7 +4142,7 @@ function readStateForMessage(msg, members, meId, sequenceByMessageId) {
4069
4142
  });
4070
4143
  return anyRead ? "read" : "sent";
4071
4144
  }
4072
- var styles20 = reactNative.StyleSheet.create({
4145
+ var styles21 = reactNative.StyleSheet.create({
4073
4146
  root: {
4074
4147
  flex: 1
4075
4148
  },
@@ -4151,13 +4224,13 @@ function UserPickerSheet({
4151
4224
  animationType: "slide",
4152
4225
  onRequestClose: handleClose,
4153
4226
  statusBarTranslucent: true,
4154
- children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles21.modalRoot, children: [
4155
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles21.backdrop, onPress: handleClose }),
4227
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles22.modalRoot, children: [
4228
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles22.backdrop, onPress: handleClose }),
4156
4229
  /* @__PURE__ */ jsxRuntime.jsxs(
4157
4230
  reactNative.Animated.View,
4158
4231
  {
4159
4232
  style: [
4160
- styles21.sheet,
4233
+ styles22.sheet,
4161
4234
  {
4162
4235
  backgroundColor: theme.colors.paper,
4163
4236
  borderTopLeftRadius: theme.radii.xl,
@@ -4167,14 +4240,14 @@ function UserPickerSheet({
4167
4240
  theme.shadows.lg
4168
4241
  ],
4169
4242
  children: [
4170
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { ...panHandlers, style: styles21.dragHandle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles21.dragPill, { backgroundColor: theme.colors.ink3 }] }) }),
4171
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles21.header, children: [
4243
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { ...panHandlers, style: styles22.dragHandle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles22.dragPill, { backgroundColor: theme.colors.ink3 }] }) }),
4244
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles22.header, children: [
4172
4245
  /* @__PURE__ */ jsxRuntime.jsx(
4173
4246
  reactNative.Pressable,
4174
4247
  {
4175
4248
  onPress: handleClose,
4176
4249
  hitSlop: 16,
4177
- style: [styles21.closeBtn, { backgroundColor: theme.colors.surface2 }],
4250
+ style: [styles22.closeBtn, { backgroundColor: theme.colors.surface2 }],
4178
4251
  accessibilityLabel: "Close picker",
4179
4252
  children: /* @__PURE__ */ jsxRuntime.jsx(PoolseIcon, { name: "close", size: 18, color: theme.colors.ink })
4180
4253
  }
@@ -4183,7 +4256,7 @@ function UserPickerSheet({
4183
4256
  reactNative.Text,
4184
4257
  {
4185
4258
  style: [
4186
- styles21.title,
4259
+ styles22.title,
4187
4260
  { color: theme.colors.ink, fontFamily: theme.type.fontDisplay }
4188
4261
  ],
4189
4262
  numberOfLines: 1,
@@ -4197,7 +4270,7 @@ function UserPickerSheet({
4197
4270
  disabled: !canCreate,
4198
4271
  hitSlop: 6,
4199
4272
  style: [
4200
- styles21.createBtn,
4273
+ styles22.createBtn,
4201
4274
  {
4202
4275
  backgroundColor: canCreate ? theme.colors.brand : theme.colors.surface2,
4203
4276
  opacity: canCreate ? 1 : 0.6
@@ -4228,7 +4301,7 @@ function UserPickerSheet({
4228
4301
  value: groupName,
4229
4302
  onChangeText: setGroupName,
4230
4303
  style: [
4231
- styles21.groupNameInput,
4304
+ styles22.groupNameInput,
4232
4305
  {
4233
4306
  color: theme.colors.ink,
4234
4307
  backgroundColor: theme.colors.surface2,
@@ -4247,7 +4320,7 @@ function UserPickerSheet({
4247
4320
  value: query,
4248
4321
  onChangeText: setQuery,
4249
4322
  style: [
4250
- styles21.searchInput,
4323
+ styles22.searchInput,
4251
4324
  {
4252
4325
  color: theme.colors.ink,
4253
4326
  backgroundColor: theme.colors.surface2,
@@ -4263,7 +4336,7 @@ function UserPickerSheet({
4263
4336
  {
4264
4337
  data: filtered,
4265
4338
  keyExtractor: (u) => u.externalId,
4266
- ListEmptyComponent: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles21.empty, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles21.emptyText, { color: theme.colors.ink3 }], children: query ? "No matches." : "No users to show." }) }),
4339
+ ListEmptyComponent: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles22.empty, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles22.emptyText, { color: theme.colors.ink3 }], children: query ? "No matches." : "No users to show." }) }),
4267
4340
  renderItem: ({ item }) => /* @__PURE__ */ jsxRuntime.jsx(
4268
4341
  UserRow,
4269
4342
  {
@@ -4301,29 +4374,29 @@ function UserRow({
4301
4374
  {
4302
4375
  onPress,
4303
4376
  style: [
4304
- styles21.row,
4377
+ styles22.row,
4305
4378
  {
4306
4379
  backgroundColor: selected ? theme.colors.brandSoft : "transparent"
4307
4380
  }
4308
4381
  ],
4309
4382
  children: [
4310
- user.avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Image, { source: { uri: user.avatarUrl }, style: styles21.avatarImg }) : /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: null, name: user.name, seed: user.externalId, size: "md" }),
4311
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles21.body, children: [
4383
+ user.avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Image, { source: { uri: user.avatarUrl }, style: styles22.avatarImg }) : /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: null, name: user.name, seed: user.externalId, size: "md" }),
4384
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles22.body, children: [
4312
4385
  /* @__PURE__ */ jsxRuntime.jsx(
4313
4386
  reactNative.Text,
4314
4387
  {
4315
- style: [styles21.name, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
4388
+ style: [styles22.name, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
4316
4389
  numberOfLines: 1,
4317
4390
  children: user.name
4318
4391
  }
4319
4392
  ),
4320
- user.subtitle ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles21.subtitle, { color: theme.colors.ink3 }], numberOfLines: 1, children: user.subtitle }) : null
4393
+ user.subtitle ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles22.subtitle, { color: theme.colors.ink3 }], numberOfLines: 1, children: user.subtitle }) : null
4321
4394
  ] }),
4322
4395
  isGroup ? /* @__PURE__ */ jsxRuntime.jsx(
4323
4396
  reactNative.View,
4324
4397
  {
4325
4398
  style: [
4326
- styles21.checkbox,
4399
+ styles22.checkbox,
4327
4400
  {
4328
4401
  borderColor: selected ? theme.colors.brand : theme.colors.border,
4329
4402
  backgroundColor: selected ? theme.colors.brand : "transparent"
@@ -4336,7 +4409,7 @@ function UserRow({
4336
4409
  }
4337
4410
  );
4338
4411
  }
4339
- var styles21 = reactNative.StyleSheet.create({
4412
+ var styles22 = reactNative.StyleSheet.create({
4340
4413
  modalRoot: {
4341
4414
  flex: 1,
4342
4415
  justifyContent: "flex-end"
@@ -4596,7 +4669,7 @@ var PoolseInbox = react.forwardRef(
4596
4669
  },
4597
4670
  [renderConversationRow, meExternalId, labelFor, avatarFor, unreadCounts]
4598
4671
  );
4599
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles22.root, { backgroundColor: theme.colors.paper }], children: [
4672
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles23.root, { backgroundColor: theme.colors.paper }], children: [
4600
4673
  /* @__PURE__ */ jsxRuntime.jsxs(
4601
4674
  reactNative.Animated.View,
4602
4675
  {
@@ -4607,7 +4680,7 @@ var PoolseInbox = react.forwardRef(
4607
4680
  reactNative.View,
4608
4681
  {
4609
4682
  style: [
4610
- styles22.listHeader,
4683
+ styles23.listHeader,
4611
4684
  {
4612
4685
  backgroundColor: theme.colors.surface,
4613
4686
  borderBottomColor: theme.colors.border
@@ -4618,13 +4691,13 @@ var PoolseInbox = react.forwardRef(
4618
4691
  reactNative.Text,
4619
4692
  {
4620
4693
  style: [
4621
- styles22.listTitle,
4694
+ styles23.listTitle,
4622
4695
  { color: theme.colors.ink, fontFamily: theme.type.fontDisplay }
4623
4696
  ],
4624
4697
  children: title
4625
4698
  }
4626
4699
  ),
4627
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles22.headerActions, children: [
4700
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles23.headerActions, children: [
4628
4701
  users ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4629
4702
  /* @__PURE__ */ jsxRuntime.jsx(
4630
4703
  HeaderIconButton,
@@ -4737,7 +4810,7 @@ function HeaderIconButton({
4737
4810
  hitSlop: 10,
4738
4811
  accessibilityLabel: label,
4739
4812
  style: ({ pressed }) => [
4740
- styles22.iconBtn,
4813
+ styles23.iconBtn,
4741
4814
  {
4742
4815
  backgroundColor: pressed ? theme.colors.surface2 : "transparent"
4743
4816
  }
@@ -4767,31 +4840,31 @@ function DefaultConversationRow({
4767
4840
  {
4768
4841
  onPress,
4769
4842
  style: [
4770
- styles22.row,
4843
+ styles23.row,
4771
4844
  {
4772
4845
  backgroundColor: selected ? theme.colors.surface2 : "transparent",
4773
4846
  borderBottomColor: theme.colors.border
4774
4847
  }
4775
4848
  ],
4776
4849
  children: [
4777
- avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Image, { source: { uri: avatarUrl }, style: styles22.rowAvatar }) : /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: null, name: title, seed: avatarSeed, size: "md" }),
4778
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles22.rowBody, children: [
4850
+ avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Image, { source: { uri: avatarUrl }, style: styles23.rowAvatar }) : /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: null, name: title, seed: avatarSeed, size: "md" }),
4851
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles23.rowBody, children: [
4779
4852
  /* @__PURE__ */ jsxRuntime.jsx(
4780
4853
  reactNative.Text,
4781
4854
  {
4782
- style: [styles22.rowTitle, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
4855
+ style: [styles23.rowTitle, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
4783
4856
  numberOfLines: 1,
4784
4857
  children: title
4785
4858
  }
4786
4859
  ),
4787
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles22.rowSubtitle, { color: theme.colors.ink3 }], numberOfLines: 1, children: conv.last_message_preview ?? (isDirect ? otherExtId ?? "" : `${(conv.member_external_ids ?? []).length} members`) })
4860
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles23.rowSubtitle, { color: theme.colors.ink3 }], numberOfLines: 1, children: conv.last_message_preview ?? (isDirect ? otherExtId ?? "" : `${(conv.member_external_ids ?? []).length} members`) })
4788
4861
  ] }),
4789
- unread > 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles22.unreadPill, { backgroundColor: theme.colors.unreadPill }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles22.unreadText, { color: theme.colors.unreadPillText }], children: unread > 99 ? "99+" : String(unread) }) }) : null
4862
+ unread > 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles23.unreadPill, { backgroundColor: theme.colors.unreadPill }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles23.unreadText, { color: theme.colors.unreadPillText }], children: unread > 99 ? "99+" : String(unread) }) }) : null
4790
4863
  ]
4791
4864
  }
4792
4865
  );
4793
4866
  }
4794
- var styles22 = reactNative.StyleSheet.create({
4867
+ var styles23 = reactNative.StyleSheet.create({
4795
4868
  root: {
4796
4869
  flex: 1,
4797
4870
  overflow: "hidden"
@@ -4995,10 +5068,10 @@ function VoiceRoomBar({
4995
5068
  reactNative.View,
4996
5069
  {
4997
5070
  style: [
4998
- styles23.bar,
5071
+ styles24.bar,
4999
5072
  { backgroundColor: theme.colors.surface, borderBottomColor: theme.colors.border }
5000
5073
  ],
5001
- children: unavailableSlot ?? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles23.hint, { color: theme.colors.ink3 }], children: "Voice needs react-native-webrtc and a development build." })
5074
+ children: unavailableSlot ?? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles24.hint, { color: theme.colors.ink3 }], children: "Voice needs react-native-webrtc and a development build." })
5002
5075
  }
5003
5076
  );
5004
5077
  }
@@ -5006,22 +5079,22 @@ function VoiceRoomBar({
5006
5079
  reactNative.View,
5007
5080
  {
5008
5081
  style: [
5009
- styles23.bar,
5082
+ styles24.bar,
5010
5083
  { backgroundColor: theme.colors.surface, borderBottomColor: theme.colors.border }
5011
5084
  ],
5012
5085
  children: [
5013
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles23.row, children: [
5086
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles24.row, children: [
5014
5087
  /* @__PURE__ */ jsxRuntime.jsx(
5015
5088
  reactNative.View,
5016
5089
  {
5017
5090
  style: [
5018
- styles23.dot,
5091
+ styles24.dot,
5019
5092
  { backgroundColor: connected ? theme.colors.brand : theme.colors.ink3 }
5020
5093
  ]
5021
5094
  }
5022
5095
  ),
5023
5096
  connected ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5024
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles23.people, children: participants.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles23.hint, { color: theme.colors.ink3 }], children: "Waiting for others\u2026" }) : participants.map((p) => /* @__PURE__ */ jsxRuntime.jsx(ParticipantChip, { participant: p, label: label(p.userId) }, p.userId)) }),
5097
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles24.people, children: participants.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles24.hint, { color: theme.colors.ink3 }], children: "Waiting for others\u2026" }) : participants.map((p) => /* @__PURE__ */ jsxRuntime.jsx(ParticipantChip, { participant: p, label: label(p.userId) }, p.userId)) }),
5025
5098
  /* @__PURE__ */ jsxRuntime.jsx(
5026
5099
  reactNative.Pressable,
5027
5100
  {
@@ -5029,7 +5102,7 @@ function VoiceRoomBar({
5029
5102
  accessibilityRole: "button",
5030
5103
  accessibilityState: { selected: muted },
5031
5104
  style: [
5032
- styles23.btn,
5105
+ styles24.btn,
5033
5106
  {
5034
5107
  borderColor: muted ? theme.colors.brand : theme.colors.border,
5035
5108
  backgroundColor: muted ? theme.colors.brandSoft : theme.colors.paper
@@ -5043,25 +5116,25 @@ function VoiceRoomBar({
5043
5116
  {
5044
5117
  onPress: leave,
5045
5118
  accessibilityRole: "button",
5046
- style: [styles23.btn, { borderColor: theme.colors.error }],
5119
+ style: [styles24.btn, { borderColor: theme.colors.error }],
5047
5120
  children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.error }, children: "Leave" })
5048
5121
  }
5049
5122
  )
5050
5123
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5051
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles23.hint, { color: theme.colors.ink3 }], children: status === "connecting" ? "Connecting\u2026" : "Talk to everyone here" }),
5124
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles24.hint, { color: theme.colors.ink3 }], children: status === "connecting" ? "Connecting\u2026" : "Talk to everyone here" }),
5052
5125
  /* @__PURE__ */ jsxRuntime.jsx(
5053
5126
  reactNative.Pressable,
5054
5127
  {
5055
5128
  onPress: () => void join(),
5056
5129
  disabled: status === "connecting",
5057
5130
  accessibilityRole: "button",
5058
- style: [styles23.btn, styles23.btnPrimary, { backgroundColor: theme.colors.brand }],
5131
+ style: [styles24.btn, styles24.btnPrimary, { backgroundColor: theme.colors.brand }],
5059
5132
  children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.onBrand, fontWeight: "600" }, children: status === "connecting" ? "Joining\u2026" : "Join Voice" })
5060
5133
  }
5061
5134
  )
5062
5135
  ] })
5063
5136
  ] }),
5064
- error && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles23.error, { color: theme.colors.error }], children: error.message })
5137
+ error && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles24.error, { color: theme.colors.error }], children: error.message })
5065
5138
  ]
5066
5139
  }
5067
5140
  );
@@ -5072,7 +5145,7 @@ function ParticipantChip({ participant, label }) {
5072
5145
  reactNative.View,
5073
5146
  {
5074
5147
  style: [
5075
- styles23.chip,
5148
+ styles24.chip,
5076
5149
  {
5077
5150
  backgroundColor: theme.colors.paper,
5078
5151
  // The speaking ring is a border colour swap rather than an
@@ -5091,7 +5164,7 @@ function ParticipantChip({ participant, label }) {
5091
5164
  }
5092
5165
  );
5093
5166
  }
5094
- var styles23 = reactNative.StyleSheet.create({
5167
+ var styles24 = reactNative.StyleSheet.create({
5095
5168
  bar: { paddingHorizontal: 14, paddingVertical: 8, borderBottomWidth: reactNative.StyleSheet.hairlineWidth },
5096
5169
  row: { flexDirection: "row", alignItems: "center", gap: 8, flexWrap: "wrap" },
5097
5170
  dot: { width: 8, height: 8, borderRadius: 4 },
@@ -5113,42 +5186,77 @@ var styles23 = reactNative.StyleSheet.create({
5113
5186
  function CallScreen({
5114
5187
  userId,
5115
5188
  labelFor,
5116
- calls: external,
5189
+ calls: callsProp,
5117
5190
  webrtc,
5191
+ livekit,
5192
+ livekitReactNative,
5118
5193
  onStatusChange,
5119
- nativeIncomingUi = false
5194
+ onVideoChange,
5195
+ nativeIncomingUi
5120
5196
  }) {
5121
5197
  const theme = usePoolseTheme();
5122
- const own = react$1.useCalls(external ? null : userId);
5123
- const calls = external ?? own;
5124
- const available = isNativeWebRtcAvailable(webrtc);
5198
+ const ownCalls = react$1.useCalls(callsProp ? null : userId);
5199
+ const calls = callsProp ?? ownCalls;
5200
+ const meshAvailable = isNativeWebRtcAvailable(webrtc);
5125
5201
  const opts = react.useMemo(
5126
- () => available && webrtc ? { webrtc: createNativeWebRtcAdapter(webrtc) } : {},
5127
- [available, webrtc]
5128
- );
5129
- const voice = react$1.useVoiceRoom(
5130
- calls.phase === "active" && available ? calls.activeConversationId : null,
5131
- opts
5202
+ () => meshAvailable && webrtc ? { webrtc: createNativeWebRtcAdapter(webrtc) } : {},
5203
+ [meshAvailable, webrtc]
5132
5204
  );
5205
+ const conversationId = calls.phase === "active" ? calls.activeConversationId : null;
5206
+ const sfu = react$1.useCallRoom(livekit ? conversationId : null, {
5207
+ livekit,
5208
+ video: calls.media === "video"
5209
+ });
5210
+ const mesh = react$1.useVoiceRoom(conversationId, opts);
5211
+ const usingSfu = sfu.sfuAvailable === true;
5212
+ const status = usingSfu ? toVoiceStatus(sfu.status) : mesh.status;
5133
5213
  react.useEffect(() => {
5134
- if (calls.phase === "active" && voice.status === "idle") void voice.join();
5135
- }, [calls.phase, voice]);
5214
+ if (calls.phase !== "active" || !conversationId) return;
5215
+ let cancelled = false;
5216
+ void (async () => {
5217
+ const connected2 = livekit ? await sfu.join() : false;
5218
+ if (cancelled || connected2) return;
5219
+ if (meshAvailable) await mesh.join();
5220
+ })();
5221
+ return () => {
5222
+ cancelled = true;
5223
+ };
5224
+ }, [calls.phase, conversationId, livekit, meshAvailable]);
5136
5225
  react.useEffect(() => {
5137
- onStatusChange?.(voice.status);
5138
- }, [voice.status, onStatusChange]);
5226
+ onStatusChange?.(status);
5227
+ }, [status, onStatusChange]);
5228
+ const videoOn = usingSfu && sfu.cameraEnabled;
5229
+ react.useEffect(() => {
5230
+ onVideoChange?.(videoOn);
5231
+ }, [videoOn, onVideoChange]);
5139
5232
  const label = labelFor ?? ((id) => `User ${id.slice(0, 6)}`);
5140
5233
  const ringingIn = calls.phase === "ringing-in";
5141
5234
  const visible = calls.phase !== "idle" && !(nativeIncomingUi && ringingIn);
5142
- const hangUp = () => {
5143
- voice.leave();
5235
+ const hangUp = react.useCallback(() => {
5236
+ sfu.leave();
5237
+ mesh.leave();
5144
5238
  void calls.hangUp();
5145
- };
5146
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible, animationType: "slide", transparent: false, onRequestClose: hangUp, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles24.screen, { backgroundColor: theme.colors.paper }], children: [
5147
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles24.identity, children: [
5148
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles24.who, { color: theme.colors.ink }], children: calls.phase === "ringing-in" && calls.incoming ? label(calls.incoming.callerUserId) : calls.outgoing ? calls.outgoing.calleeUserIds.map(label).join(", ") : "" }),
5149
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles24.state, { color: theme.colors.ink3 }], children: statusLine(calls, voice.status) })
5239
+ }, [sfu, mesh, calls]);
5240
+ const micOn = usingSfu ? sfu.micEnabled : !mesh.muted;
5241
+ const toggleMic = react.useCallback(() => {
5242
+ if (usingSfu) void sfu.toggleMic();
5243
+ else mesh.toggleMute();
5244
+ }, [usingSfu, sfu, mesh]);
5245
+ const error = calls.error ?? (usingSfu ? sfu.error : mesh.error);
5246
+ const connected = calls.phase === "active" && status === "connected";
5247
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible, animationType: "slide", transparent: false, onRequestClose: hangUp, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles25.screen, { backgroundColor: theme.colors.paper }], children: [
5248
+ connected && usingSfu && sfu.participants.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
5249
+ CallVideoGrid,
5250
+ {
5251
+ participants: sfu.participants,
5252
+ livekitReactNative,
5253
+ labelFor
5254
+ }
5255
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles25.identity, children: [
5256
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles25.who, { color: theme.colors.ink }], children: ringingIn && calls.incoming ? label(calls.incoming.callerUserId) : calls.outgoing ? calls.outgoing.calleeUserIds.map(label).join(", ") : "" }),
5257
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles25.state, { color: theme.colors.ink3 }], children: statusLine(calls, status) })
5150
5258
  ] }),
5151
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles24.actions, children: calls.phase === "ringing-in" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5259
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles25.actions, children: ringingIn ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5152
5260
  /* @__PURE__ */ jsxRuntime.jsx(
5153
5261
  CallButton,
5154
5262
  {
@@ -5176,21 +5284,41 @@ function CallScreen({
5176
5284
  /* @__PURE__ */ jsxRuntime.jsx(
5177
5285
  CallButton,
5178
5286
  {
5179
- label: voice.muted ? "Unmute" : "Mute",
5180
- color: theme.colors.ink2,
5181
- onPress: voice.toggleMute
5287
+ label: micOn ? "Mute" : "Unmute",
5288
+ color: micOn ? theme.colors.ink2 : theme.colors.brand,
5289
+ onPress: toggleMic
5290
+ }
5291
+ ),
5292
+ usingSfu && /* @__PURE__ */ jsxRuntime.jsx(
5293
+ CallButton,
5294
+ {
5295
+ label: videoOn ? "Camera off" : "Camera on",
5296
+ color: videoOn ? theme.colors.brand : theme.colors.ink2,
5297
+ onPress: () => void sfu.toggleCamera()
5182
5298
  }
5183
5299
  ),
5184
5300
  /* @__PURE__ */ jsxRuntime.jsx(CallButton, { label: "Hang up", color: theme.colors.error, onPress: hangUp })
5185
5301
  ] }) }),
5186
- !available && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles24.warn, { color: theme.colors.error }], children: "react-native-webrtc is not installed \u2014 this call has no audio." }),
5187
- (calls.error ?? voice.error) && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles24.warn, { color: theme.colors.error }], children: (calls.error ?? voice.error)?.message })
5302
+ !meshAvailable && !livekit && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles25.warn, { color: theme.colors.error }], children: "No WebRTC module supplied \u2014 this call has no audio." }),
5303
+ error && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles25.warn, { color: theme.colors.error }], children: error.message })
5188
5304
  ] }) });
5189
5305
  }
5190
- function statusLine(calls, voiceStatus) {
5306
+ function toVoiceStatus(status) {
5307
+ switch (status) {
5308
+ case "connecting":
5309
+ return "connecting";
5310
+ case "connected":
5311
+ return "connected";
5312
+ case "error":
5313
+ return "error";
5314
+ default:
5315
+ return "idle";
5316
+ }
5317
+ }
5318
+ function statusLine(calls, mediaStatus) {
5191
5319
  switch (calls.phase) {
5192
5320
  case "ringing-in":
5193
- return "Incoming call\u2026";
5321
+ return calls.media === "video" ? "Incoming video call\u2026" : "Incoming call\u2026";
5194
5322
  case "ringing-out":
5195
5323
  return "Ringing\u2026";
5196
5324
  case "declined":
@@ -5200,7 +5328,7 @@ function statusLine(calls, voiceStatus) {
5200
5328
  case "timed-out":
5201
5329
  return "No answer";
5202
5330
  case "active":
5203
- return voiceStatus === "connected" ? "Connected" : "Connecting\u2026";
5331
+ return mediaStatus === "connected" ? "Connected" : "Connecting\u2026";
5204
5332
  default:
5205
5333
  return "";
5206
5334
  }
@@ -5215,22 +5343,22 @@ function CallButton({
5215
5343
  {
5216
5344
  onPress,
5217
5345
  accessibilityRole: "button",
5218
- style: [styles24.callBtn, { backgroundColor: color }],
5219
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles24.callBtnText, children: label })
5346
+ style: [styles25.callBtn, { backgroundColor: color }],
5347
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles25.callBtnText, children: label })
5220
5348
  }
5221
5349
  );
5222
5350
  }
5223
- var styles24 = reactNative.StyleSheet.create({
5351
+ var styles25 = reactNative.StyleSheet.create({
5224
5352
  screen: { flex: 1, justifyContent: "space-between", paddingVertical: 72, paddingHorizontal: 24 },
5225
5353
  identity: { alignItems: "center", gap: 8, marginTop: 48 },
5226
5354
  who: { fontSize: 28, fontWeight: "600", textAlign: "center" },
5227
5355
  state: { fontSize: 15 },
5228
- actions: { flexDirection: "row", justifyContent: "center", gap: 16 },
5356
+ actions: { flexDirection: "row", justifyContent: "center", gap: 12, flexWrap: "wrap" },
5229
5357
  callBtn: {
5230
- paddingHorizontal: 26,
5358
+ paddingHorizontal: 22,
5231
5359
  paddingVertical: 16,
5232
5360
  borderRadius: 999,
5233
- minWidth: 128,
5361
+ minWidth: 108,
5234
5362
  alignItems: "center"
5235
5363
  },
5236
5364
  callBtnText: { color: "#ffffff", fontSize: 16, fontWeight: "600" },
@@ -5282,7 +5410,7 @@ function useVoipCalls({
5282
5410
  call.callerUserId,
5283
5411
  call.callerName,
5284
5412
  "generic",
5285
- false
5413
+ call.media === "video"
5286
5414
  );
5287
5415
  } catch {
5288
5416
  }
@@ -5308,7 +5436,10 @@ function useVoipCalls({
5308
5436
  callId,
5309
5437
  conversationId,
5310
5438
  callerUserId: payload.caller_user_id ?? "",
5311
- callerName: payload.caller_name ?? "Incoming call"
5439
+ callerName: payload.caller_name ?? "Incoming call",
5440
+ // `has_video` is what older servers sent; `media` supersedes
5441
+ // it. Either says video, and the system UI offers video.
5442
+ media: payload.media === "video" || payload.has_video ? "video" : "audio"
5312
5443
  },
5313
5444
  payload.sent_at
5314
5445
  );
@@ -5357,7 +5488,8 @@ function useVoipCalls({
5357
5488
  void handlers.current.calls?.accept({
5358
5489
  callId: call.callId,
5359
5490
  conversationId: call.conversationId,
5360
- callerUserId: call.callerUserId
5491
+ callerUserId: call.callerUserId,
5492
+ media: call.media
5361
5493
  });
5362
5494
  handlers.current.onAnswer?.(call);
5363
5495
  }));
@@ -5373,7 +5505,8 @@ function useVoipCalls({
5373
5505
  void handlers.current.calls?.decline({
5374
5506
  callId: call.callId,
5375
5507
  conversationId: call.conversationId,
5376
- callerUserId: call.callerUserId
5508
+ callerUserId: call.callerUserId,
5509
+ media: call.media
5377
5510
  });
5378
5511
  handlers.current.onDecline?.(call);
5379
5512
  }));
@@ -5395,7 +5528,8 @@ function useVoipCalls({
5395
5528
  callId: incoming.callId,
5396
5529
  conversationId: incoming.conversationId,
5397
5530
  callerUserId: incoming.callerUserId,
5398
- callerName: incoming.callerUserId
5531
+ callerName: incoming.callerUserId,
5532
+ media: incoming.media
5399
5533
  });
5400
5534
  }
5401
5535
  }, [phase, incoming]);
@@ -5412,6 +5546,7 @@ exports.AttachmentPicker = AttachmentPicker;
5412
5546
  exports.AttachmentPreview = AttachmentPreview;
5413
5547
  exports.Avatar = Avatar;
5414
5548
  exports.CallScreen = CallScreen;
5549
+ exports.CallVideoGrid = CallVideoGrid;
5415
5550
  exports.ChatHeader = ChatHeader;
5416
5551
  exports.ConversationList = ConversationList;
5417
5552
  exports.ConversationView = ConversationView;