@poolse/react-native 2.9.0 → 2.10.0

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