@poolse/react-native 2.0.13 → 2.1.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 +736 -352
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -16
- package/dist/index.d.ts +76 -16
- package/dist/index.js +739 -355
- package/dist/index.js.map +1 -1
- package/package.json +12 -4
package/dist/index.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import { useUser, useMe, useConversations, useAttachmentUpload, useConversation, useMembers, usePresence, useMessages, useTyping, useReactions, useThread, useAttachmentUrl, usePoolse } from '@poolse/react';
|
|
2
|
-
import { createContext, forwardRef, useRef, useState,
|
|
3
|
-
import { StyleSheet, View, Pressable, TextInput, Text, useWindowDimensions, Animated, Easing, PanResponder, Image, ScrollView, ActivityIndicator, FlatList,
|
|
1
|
+
import { useUser, useMe, useConversations, useAttachmentUpload, useConversation, useMembers, usePresence, useMessages, useTyping, useRealtimeStatus, computeGroupPosition, formatDayLabel, useReactions, sameDay, useThread, useAttachmentUrl, usePoolse } from '@poolse/react';
|
|
2
|
+
import { createContext, forwardRef, useRef, useState, useEffect, useImperativeHandle, useMemo, useCallback, useContext, createElement } from 'react';
|
|
3
|
+
import { StyleSheet, Platform, Keyboard, View, Pressable, TextInput, Text, useWindowDimensions, Animated, Easing, PanResponder, Image, ScrollView, ActivityIndicator, FlatList, AppState, KeyboardAvoidingView, Modal, Linking, Dimensions } from 'react-native';
|
|
4
4
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { SvgXml, Svg, Path, Circle, G } from 'react-native-svg';
|
|
6
6
|
import * as ImagePicker from 'expo-image-picker';
|
|
7
7
|
import * as DocumentPicker from 'expo-document-picker';
|
|
8
8
|
import { manipulateAsync, SaveFormat } from 'expo-image-manipulator';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
11
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
12
|
+
}) : x)(function(x) {
|
|
13
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
14
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
15
|
+
});
|
|
11
16
|
|
|
12
17
|
// src/theme/default.ts
|
|
13
18
|
var lightColors = {
|
|
@@ -1307,6 +1312,51 @@ var styles6 = StyleSheet.create({
|
|
|
1307
1312
|
fontWeight: "500"
|
|
1308
1313
|
}
|
|
1309
1314
|
});
|
|
1315
|
+
function DaySeparator({ label }) {
|
|
1316
|
+
const theme = usePoolseTheme();
|
|
1317
|
+
return /* @__PURE__ */ jsx(View, { style: styles7.wrap, children: /* @__PURE__ */ jsx(
|
|
1318
|
+
View,
|
|
1319
|
+
{
|
|
1320
|
+
style: [
|
|
1321
|
+
styles7.chip,
|
|
1322
|
+
{
|
|
1323
|
+
backgroundColor: theme.colors.surface2,
|
|
1324
|
+
borderColor: theme.colors.border
|
|
1325
|
+
}
|
|
1326
|
+
],
|
|
1327
|
+
children: /* @__PURE__ */ jsx(
|
|
1328
|
+
Text,
|
|
1329
|
+
{
|
|
1330
|
+
style: [
|
|
1331
|
+
styles7.label,
|
|
1332
|
+
{
|
|
1333
|
+
color: theme.colors.ink2,
|
|
1334
|
+
fontFamily: theme.type.fontBody
|
|
1335
|
+
}
|
|
1336
|
+
],
|
|
1337
|
+
children: label
|
|
1338
|
+
}
|
|
1339
|
+
)
|
|
1340
|
+
}
|
|
1341
|
+
) });
|
|
1342
|
+
}
|
|
1343
|
+
var styles7 = StyleSheet.create({
|
|
1344
|
+
wrap: {
|
|
1345
|
+
alignItems: "center",
|
|
1346
|
+
marginVertical: 8
|
|
1347
|
+
},
|
|
1348
|
+
chip: {
|
|
1349
|
+
paddingHorizontal: 12,
|
|
1350
|
+
paddingVertical: 4,
|
|
1351
|
+
borderRadius: 999,
|
|
1352
|
+
borderWidth: StyleSheet.hairlineWidth
|
|
1353
|
+
},
|
|
1354
|
+
label: {
|
|
1355
|
+
fontSize: 11,
|
|
1356
|
+
fontWeight: "600",
|
|
1357
|
+
letterSpacing: 0.3
|
|
1358
|
+
}
|
|
1359
|
+
});
|
|
1310
1360
|
function UploadQueueStrip() {
|
|
1311
1361
|
const theme = usePoolseTheme();
|
|
1312
1362
|
const upload = useSharedUpload();
|
|
@@ -1317,8 +1367,8 @@ function UploadQueueStrip() {
|
|
|
1317
1367
|
{
|
|
1318
1368
|
horizontal: true,
|
|
1319
1369
|
showsHorizontalScrollIndicator: false,
|
|
1320
|
-
contentContainerStyle:
|
|
1321
|
-
style: [
|
|
1370
|
+
contentContainerStyle: styles8.scroll,
|
|
1371
|
+
style: [styles8.scrollStyle, { marginBottom: 8 }],
|
|
1322
1372
|
children: upload.queue.map((item) => {
|
|
1323
1373
|
const isError = item.status === "error";
|
|
1324
1374
|
const isUploading = item.status === "uploading" || item.status === "pending";
|
|
@@ -1329,7 +1379,7 @@ function UploadQueueStrip() {
|
|
|
1329
1379
|
if (item.status === "ready" || isError) upload.remove(item.localId);
|
|
1330
1380
|
else upload.cancel(item.localId);
|
|
1331
1381
|
};
|
|
1332
|
-
return /* @__PURE__ */ jsxs(View, { style:
|
|
1382
|
+
return /* @__PURE__ */ jsxs(View, { style: styles8.tileWrap, children: [
|
|
1333
1383
|
isImage && previewUri ? /* @__PURE__ */ jsx(ImageTile, { uri: previewUri, uploading: isUploading, error: isError }) : /* @__PURE__ */ jsx(
|
|
1334
1384
|
FileTile,
|
|
1335
1385
|
{
|
|
@@ -1344,13 +1394,13 @@ function UploadQueueStrip() {
|
|
|
1344
1394
|
{
|
|
1345
1395
|
onPress: handleClose,
|
|
1346
1396
|
hitSlop: 8,
|
|
1347
|
-
style: [
|
|
1397
|
+
style: [styles8.closeBtn, { backgroundColor: theme.colors.ink }],
|
|
1348
1398
|
accessibilityLabel: isError ? "Remove failed upload" : "Cancel upload",
|
|
1349
1399
|
children: /* @__PURE__ */ jsx(PoolseIcon, { name: "close", size: 11, color: theme.colors.onBrand })
|
|
1350
1400
|
}
|
|
1351
1401
|
) : null,
|
|
1352
|
-
isUploading ? /* @__PURE__ */ jsx(View, { style:
|
|
1353
|
-
isError ? /* @__PURE__ */ jsx(View, { style: [
|
|
1402
|
+
isUploading ? /* @__PURE__ */ jsx(View, { style: styles8.progressOverlay, children: /* @__PURE__ */ jsx(View, { style: [styles8.spinner, { borderColor: theme.colors.onBrand }] }) }) : null,
|
|
1403
|
+
isError ? /* @__PURE__ */ jsx(View, { style: [styles8.errorOverlay, { backgroundColor: "rgba(229,72,77,0.85)" }], children: /* @__PURE__ */ jsx(Text, { style: [styles8.errorText, { color: "#fff" }], children: "Failed" }) }) : null
|
|
1354
1404
|
] }, item.localId);
|
|
1355
1405
|
})
|
|
1356
1406
|
}
|
|
@@ -1363,7 +1413,7 @@ function ImageTile({ uri, uploading, error }) {
|
|
|
1363
1413
|
{
|
|
1364
1414
|
source: { uri },
|
|
1365
1415
|
style: [
|
|
1366
|
-
|
|
1416
|
+
styles8.imageTile,
|
|
1367
1417
|
{
|
|
1368
1418
|
backgroundColor: theme.colors.surface2,
|
|
1369
1419
|
borderColor: error ? theme.colors.error : "transparent",
|
|
@@ -1385,24 +1435,24 @@ function FileTile({
|
|
|
1385
1435
|
View,
|
|
1386
1436
|
{
|
|
1387
1437
|
style: [
|
|
1388
|
-
|
|
1438
|
+
styles8.fileTile,
|
|
1389
1439
|
{
|
|
1390
1440
|
backgroundColor: theme.colors.surface2,
|
|
1391
1441
|
borderColor: error ? theme.colors.error : uploading ? theme.colors.brand : theme.colors.border
|
|
1392
1442
|
}
|
|
1393
1443
|
],
|
|
1394
1444
|
children: [
|
|
1395
|
-
/* @__PURE__ */ jsx(View, { style: [
|
|
1396
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
1445
|
+
/* @__PURE__ */ jsx(View, { style: [styles8.fileIconBox, { backgroundColor: theme.colors.brandSoft }], children: /* @__PURE__ */ jsx(PoolseIcon, { name: "attachment", size: 18, color: theme.colors.brand }) }),
|
|
1446
|
+
/* @__PURE__ */ jsxs(View, { style: styles8.fileInfo, children: [
|
|
1397
1447
|
/* @__PURE__ */ jsx(
|
|
1398
1448
|
Text,
|
|
1399
1449
|
{
|
|
1400
|
-
style: [
|
|
1450
|
+
style: [styles8.fileName, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
|
|
1401
1451
|
numberOfLines: 1,
|
|
1402
1452
|
children: filename
|
|
1403
1453
|
}
|
|
1404
1454
|
),
|
|
1405
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
1455
|
+
/* @__PURE__ */ jsx(Text, { style: [styles8.fileSize, { color: theme.colors.ink3 }], children: formatBytes(size) })
|
|
1406
1456
|
] })
|
|
1407
1457
|
]
|
|
1408
1458
|
}
|
|
@@ -1416,7 +1466,7 @@ function formatBytes(n) {
|
|
|
1416
1466
|
return `${(n / 1024 / 1024 / 1024).toFixed(1)} GB`;
|
|
1417
1467
|
}
|
|
1418
1468
|
var TILE = 64;
|
|
1419
|
-
var
|
|
1469
|
+
var styles8 = StyleSheet.create({
|
|
1420
1470
|
scrollStyle: {
|
|
1421
1471
|
overflow: "visible"
|
|
1422
1472
|
},
|
|
@@ -1516,6 +1566,22 @@ var styles7 = StyleSheet.create({
|
|
|
1516
1566
|
fontWeight: "700"
|
|
1517
1567
|
}
|
|
1518
1568
|
});
|
|
1569
|
+
var FALLBACK = {
|
|
1570
|
+
top: Platform.OS === "ios" ? 50 : 24,
|
|
1571
|
+
bottom: Platform.OS === "ios" ? 34 : 0,
|
|
1572
|
+
left: 0,
|
|
1573
|
+
right: 0
|
|
1574
|
+
};
|
|
1575
|
+
var realHook = null;
|
|
1576
|
+
try {
|
|
1577
|
+
const mod = __require("react-native-safe-area-context");
|
|
1578
|
+
if (mod && typeof mod.useSafeAreaInsets === "function") {
|
|
1579
|
+
realHook = mod.useSafeAreaInsets;
|
|
1580
|
+
}
|
|
1581
|
+
} catch {
|
|
1582
|
+
}
|
|
1583
|
+
var useFallback = () => FALLBACK;
|
|
1584
|
+
var useSafeInsets = realHook ?? useFallback;
|
|
1519
1585
|
var MessageComposer = forwardRef(
|
|
1520
1586
|
function MessageComposer2({
|
|
1521
1587
|
onSend,
|
|
@@ -1527,13 +1593,32 @@ var MessageComposer = forwardRef(
|
|
|
1527
1593
|
labelFor,
|
|
1528
1594
|
attachments = true,
|
|
1529
1595
|
onAttachPress,
|
|
1530
|
-
keyboardOffset: _keyboardOffset = 0
|
|
1596
|
+
keyboardOffset: _keyboardOffset = 0,
|
|
1597
|
+
editingMessage = null,
|
|
1598
|
+
onCancelEdit,
|
|
1599
|
+
onSaveEdit
|
|
1531
1600
|
}, ref) {
|
|
1532
1601
|
const theme = usePoolseTheme();
|
|
1533
1602
|
const inputRef = useRef(null);
|
|
1534
1603
|
const [value, setValue] = useState("");
|
|
1535
1604
|
const [sending, setSending] = useState(false);
|
|
1605
|
+
const [keyboardOpen, setKeyboardOpen] = useState(false);
|
|
1536
1606
|
const upload = useSharedUpload();
|
|
1607
|
+
const insets = useSafeInsets();
|
|
1608
|
+
useEffect(() => {
|
|
1609
|
+
const show = Keyboard.addListener(
|
|
1610
|
+
Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow",
|
|
1611
|
+
() => setKeyboardOpen(true)
|
|
1612
|
+
);
|
|
1613
|
+
const hide = Keyboard.addListener(
|
|
1614
|
+
Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide",
|
|
1615
|
+
() => setKeyboardOpen(false)
|
|
1616
|
+
);
|
|
1617
|
+
return () => {
|
|
1618
|
+
show.remove();
|
|
1619
|
+
hide.remove();
|
|
1620
|
+
};
|
|
1621
|
+
}, []);
|
|
1537
1622
|
useImperativeHandle(
|
|
1538
1623
|
ref,
|
|
1539
1624
|
() => ({
|
|
@@ -1552,36 +1637,65 @@ var MessageComposer = forwardRef(
|
|
|
1552
1637
|
const isUploading = upload.queue.some(
|
|
1553
1638
|
(item) => item.status === "uploading" || item.status === "pending"
|
|
1554
1639
|
);
|
|
1555
|
-
const
|
|
1640
|
+
const previousDraftRef = useRef(null);
|
|
1641
|
+
const editingIdRef = useRef(null);
|
|
1642
|
+
useEffect(() => {
|
|
1643
|
+
const id = editingMessage?.id ?? null;
|
|
1644
|
+
if (id === editingIdRef.current) return;
|
|
1645
|
+
if (id) {
|
|
1646
|
+
previousDraftRef.current = value;
|
|
1647
|
+
setValue(editingMessage?.body ?? "");
|
|
1648
|
+
inputRef.current?.focus();
|
|
1649
|
+
} else {
|
|
1650
|
+
setValue(previousDraftRef.current ?? "");
|
|
1651
|
+
previousDraftRef.current = null;
|
|
1652
|
+
}
|
|
1653
|
+
editingIdRef.current = id;
|
|
1654
|
+
}, [editingMessage?.id, editingMessage?.body]);
|
|
1655
|
+
const isEditing = !!editingMessage;
|
|
1656
|
+
const editChanged = isEditing && value.trim() !== (editingMessage?.body?.trim() ?? "");
|
|
1657
|
+
const submitDisabled = disabled || sending || isUploading || value.trim().length === 0 || (isEditing ? !editChanged : value.trim().length === 0 && readyAttachmentIds.length === 0);
|
|
1556
1658
|
const handleSend = async () => {
|
|
1557
1659
|
if (submitDisabled) return;
|
|
1558
1660
|
const body = value.trim();
|
|
1559
|
-
const replyId = replyingTo?.id;
|
|
1560
|
-
const attachmentIds = readyAttachmentIds;
|
|
1561
|
-
setValue("");
|
|
1562
|
-
upload.reset();
|
|
1563
1661
|
setSending(true);
|
|
1564
1662
|
try {
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1663
|
+
if (isEditing && onSaveEdit) {
|
|
1664
|
+
await onSaveEdit(body);
|
|
1665
|
+
} else {
|
|
1666
|
+
const replyId = replyingTo?.id;
|
|
1667
|
+
const attachmentIds = readyAttachmentIds;
|
|
1668
|
+
setValue("");
|
|
1669
|
+
upload.reset();
|
|
1670
|
+
await onSend(body, {
|
|
1671
|
+
...replyId ? { quoted_message_id: replyId } : {},
|
|
1672
|
+
...attachmentIds.length > 0 ? { attachment_ids: attachmentIds } : {}
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1569
1675
|
} finally {
|
|
1570
1676
|
setSending(false);
|
|
1571
1677
|
}
|
|
1572
1678
|
};
|
|
1679
|
+
const paddingBottom = keyboardOpen ? 10 : Math.max(10, insets.bottom);
|
|
1573
1680
|
return /* @__PURE__ */ jsxs(
|
|
1574
1681
|
View,
|
|
1575
1682
|
{
|
|
1576
1683
|
style: [
|
|
1577
|
-
|
|
1684
|
+
styles9.wrap,
|
|
1578
1685
|
{
|
|
1579
1686
|
backgroundColor: theme.colors.surface,
|
|
1580
|
-
borderTopColor: theme.colors.border
|
|
1687
|
+
borderTopColor: theme.colors.border,
|
|
1688
|
+
paddingBottom
|
|
1581
1689
|
}
|
|
1582
1690
|
],
|
|
1583
1691
|
children: [
|
|
1584
|
-
|
|
1692
|
+
isEditing ? /* @__PURE__ */ jsx(
|
|
1693
|
+
EditChip,
|
|
1694
|
+
{
|
|
1695
|
+
message: editingMessage,
|
|
1696
|
+
...onCancelEdit ? { onCancel: onCancelEdit } : {}
|
|
1697
|
+
}
|
|
1698
|
+
) : replyingTo ? /* @__PURE__ */ jsx(
|
|
1585
1699
|
ReplyChip,
|
|
1586
1700
|
{
|
|
1587
1701
|
message: replyingTo,
|
|
@@ -1589,14 +1703,14 @@ var MessageComposer = forwardRef(
|
|
|
1589
1703
|
...onCancelReply ? { onCancel: onCancelReply } : {}
|
|
1590
1704
|
}
|
|
1591
1705
|
) : null,
|
|
1592
|
-
attachments ? /* @__PURE__ */ jsx(UploadQueueStrip, {}) : null,
|
|
1593
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
1706
|
+
attachments && !isEditing ? /* @__PURE__ */ jsx(UploadQueueStrip, {}) : null,
|
|
1707
|
+
/* @__PURE__ */ jsxs(View, { style: styles9.row, children: [
|
|
1594
1708
|
attachments && onAttachPress ? /* @__PURE__ */ jsx(
|
|
1595
1709
|
Pressable,
|
|
1596
1710
|
{
|
|
1597
1711
|
onPress: onAttachPress,
|
|
1598
1712
|
hitSlop: 8,
|
|
1599
|
-
style:
|
|
1713
|
+
style: styles9.iconBtn,
|
|
1600
1714
|
accessibilityLabel: "Attach file",
|
|
1601
1715
|
children: /* @__PURE__ */ jsx(PoolseIcon, { name: "attachment", size: 22, color: theme.colors.ink2 })
|
|
1602
1716
|
}
|
|
@@ -1615,7 +1729,7 @@ var MessageComposer = forwardRef(
|
|
|
1615
1729
|
multiline: true,
|
|
1616
1730
|
editable: !disabled,
|
|
1617
1731
|
style: [
|
|
1618
|
-
|
|
1732
|
+
styles9.input,
|
|
1619
1733
|
{
|
|
1620
1734
|
color: theme.colors.ink,
|
|
1621
1735
|
backgroundColor: theme.colors.surface2,
|
|
@@ -1632,7 +1746,7 @@ var MessageComposer = forwardRef(
|
|
|
1632
1746
|
onPress: handleSend,
|
|
1633
1747
|
disabled: submitDisabled,
|
|
1634
1748
|
style: [
|
|
1635
|
-
|
|
1749
|
+
styles9.sendBtn,
|
|
1636
1750
|
{
|
|
1637
1751
|
backgroundColor: submitDisabled ? theme.colors.ink3 : theme.colors.brand,
|
|
1638
1752
|
opacity: submitDisabled ? 0.6 : 1
|
|
@@ -1648,6 +1762,28 @@ var MessageComposer = forwardRef(
|
|
|
1648
1762
|
);
|
|
1649
1763
|
}
|
|
1650
1764
|
);
|
|
1765
|
+
function EditChip({ message, onCancel }) {
|
|
1766
|
+
const theme = usePoolseTheme();
|
|
1767
|
+
return /* @__PURE__ */ jsxs(
|
|
1768
|
+
View,
|
|
1769
|
+
{
|
|
1770
|
+
style: [
|
|
1771
|
+
styles9.replyChip,
|
|
1772
|
+
{
|
|
1773
|
+
backgroundColor: theme.colors.surface2,
|
|
1774
|
+
borderLeftColor: theme.colors.brand
|
|
1775
|
+
}
|
|
1776
|
+
],
|
|
1777
|
+
children: [
|
|
1778
|
+
/* @__PURE__ */ jsxs(View, { style: { flex: 1 }, children: [
|
|
1779
|
+
/* @__PURE__ */ jsx(Text, { style: [styles9.replyName, { color: theme.colors.brand }], children: "Editing message" }),
|
|
1780
|
+
/* @__PURE__ */ jsx(Text, { style: [styles9.replyBody, { color: theme.colors.ink2 }], numberOfLines: 1, children: message.body ?? "\u2026" })
|
|
1781
|
+
] }),
|
|
1782
|
+
onCancel ? /* @__PURE__ */ jsx(Pressable, { onPress: onCancel, hitSlop: 8, style: styles9.replyCancel, children: /* @__PURE__ */ jsx(PoolseIcon, { name: "close", size: 16, color: theme.colors.ink2 }) }) : null
|
|
1783
|
+
]
|
|
1784
|
+
}
|
|
1785
|
+
);
|
|
1786
|
+
}
|
|
1651
1787
|
function ReplyChip({
|
|
1652
1788
|
message,
|
|
1653
1789
|
labelFor,
|
|
@@ -1660,7 +1796,7 @@ function ReplyChip({
|
|
|
1660
1796
|
View,
|
|
1661
1797
|
{
|
|
1662
1798
|
style: [
|
|
1663
|
-
|
|
1799
|
+
styles9.replyChip,
|
|
1664
1800
|
{
|
|
1665
1801
|
backgroundColor: theme.colors.surface2,
|
|
1666
1802
|
borderLeftColor: theme.colors.brand
|
|
@@ -1668,27 +1804,26 @@ function ReplyChip({
|
|
|
1668
1804
|
],
|
|
1669
1805
|
children: [
|
|
1670
1806
|
/* @__PURE__ */ jsxs(View, { style: { flex: 1 }, children: [
|
|
1671
|
-
/* @__PURE__ */ jsxs(Text, { style: [
|
|
1807
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles9.replyName, { color: theme.colors.brand }], children: [
|
|
1672
1808
|
"Replying to ",
|
|
1673
1809
|
senderName
|
|
1674
1810
|
] }),
|
|
1675
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
1811
|
+
/* @__PURE__ */ jsx(Text, { style: [styles9.replyBody, { color: theme.colors.ink2 }], numberOfLines: 1, children: message.body ?? "\u2026" })
|
|
1676
1812
|
] }),
|
|
1677
|
-
onCancel ? /* @__PURE__ */ jsx(Pressable, { onPress: onCancel, hitSlop: 8, style:
|
|
1813
|
+
onCancel ? /* @__PURE__ */ jsx(Pressable, { onPress: onCancel, hitSlop: 8, style: styles9.replyCancel, children: /* @__PURE__ */ jsx(PoolseIcon, { name: "close", size: 16, color: theme.colors.ink2 }) }) : null
|
|
1678
1814
|
]
|
|
1679
1815
|
}
|
|
1680
1816
|
);
|
|
1681
1817
|
}
|
|
1682
|
-
var
|
|
1818
|
+
var styles9 = StyleSheet.create({
|
|
1683
1819
|
wrap: {
|
|
1684
1820
|
borderTopWidth: StyleSheet.hairlineWidth,
|
|
1685
1821
|
paddingTop: 8,
|
|
1686
|
-
paddingBottom: 10,
|
|
1687
1822
|
paddingHorizontal: 12
|
|
1688
|
-
//
|
|
1689
|
-
//
|
|
1690
|
-
//
|
|
1691
|
-
//
|
|
1823
|
+
// paddingBottom is applied inline — it follows the keyboard state
|
|
1824
|
+
// (10 px while open, max(10, safeBottomInset) while closed) so the
|
|
1825
|
+
// send/attach buttons stay clear of the home indicator without
|
|
1826
|
+
// double-padding above the keyboard.
|
|
1692
1827
|
},
|
|
1693
1828
|
row: {
|
|
1694
1829
|
flexDirection: "row",
|
|
@@ -1777,11 +1912,11 @@ function MentionInput({ conversationId, onSend, ...composerProps }) {
|
|
|
1777
1912
|
transparent: true,
|
|
1778
1913
|
animationType: "slide",
|
|
1779
1914
|
onRequestClose: () => setPickerOpen(false),
|
|
1780
|
-
children: /* @__PURE__ */ jsx(Pressable, { style:
|
|
1915
|
+
children: /* @__PURE__ */ jsx(Pressable, { style: styles10.backdrop, onPress: () => setPickerOpen(false), children: /* @__PURE__ */ jsxs(
|
|
1781
1916
|
View,
|
|
1782
1917
|
{
|
|
1783
1918
|
style: [
|
|
1784
|
-
|
|
1919
|
+
styles10.sheet,
|
|
1785
1920
|
{
|
|
1786
1921
|
backgroundColor: theme.colors.surface,
|
|
1787
1922
|
borderTopLeftRadius: theme.radii.lg,
|
|
@@ -1792,7 +1927,7 @@ function MentionInput({ conversationId, onSend, ...composerProps }) {
|
|
|
1792
1927
|
/* @__PURE__ */ jsx(
|
|
1793
1928
|
Text,
|
|
1794
1929
|
{
|
|
1795
|
-
style: [
|
|
1930
|
+
style: [styles10.title, { color: theme.colors.ink, fontFamily: theme.type.fontBody }],
|
|
1796
1931
|
children: "Mention a member"
|
|
1797
1932
|
}
|
|
1798
1933
|
),
|
|
@@ -1823,12 +1958,12 @@ function MentionInput({ conversationId, onSend, ...composerProps }) {
|
|
|
1823
1958
|
}
|
|
1824
1959
|
function MentionRow({ member, onPress }) {
|
|
1825
1960
|
const theme = usePoolseTheme();
|
|
1826
|
-
return /* @__PURE__ */ jsxs(Pressable, { onPress, style:
|
|
1961
|
+
return /* @__PURE__ */ jsxs(Pressable, { onPress, style: styles10.row, children: [
|
|
1827
1962
|
/* @__PURE__ */ jsx(Avatar, { src: null, name: member.external_id, seed: member.external_id, size: "sm" }),
|
|
1828
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
1963
|
+
/* @__PURE__ */ jsx(Text, { style: [styles10.rowText, { color: theme.colors.ink, fontFamily: theme.type.fontBody }], children: member.external_id })
|
|
1829
1964
|
] });
|
|
1830
1965
|
}
|
|
1831
|
-
var
|
|
1966
|
+
var styles10 = StyleSheet.create({
|
|
1832
1967
|
backdrop: {
|
|
1833
1968
|
flex: 1,
|
|
1834
1969
|
backgroundColor: "rgba(0,0,0,0.35)",
|
|
@@ -1855,138 +1990,134 @@ var styles9 = StyleSheet.create({
|
|
|
1855
1990
|
fontSize: 14
|
|
1856
1991
|
}
|
|
1857
1992
|
});
|
|
1993
|
+
var AT_BOTTOM_THRESHOLD = 32;
|
|
1858
1994
|
function MessageList({
|
|
1859
1995
|
messages,
|
|
1996
|
+
items,
|
|
1860
1997
|
loading = false,
|
|
1861
1998
|
hasMore = false,
|
|
1862
1999
|
onLoadMore,
|
|
1863
2000
|
renderItem,
|
|
1864
2001
|
ListHeader = null,
|
|
1865
2002
|
ListFooter = null,
|
|
1866
|
-
emptyState
|
|
2003
|
+
emptyState,
|
|
2004
|
+
meId = null
|
|
1867
2005
|
}) {
|
|
1868
2006
|
const theme = usePoolseTheme();
|
|
1869
|
-
const
|
|
2007
|
+
const flatListRef = useRef(null);
|
|
2008
|
+
const [atBottom, setAtBottom] = useState(true);
|
|
2009
|
+
const [newCount, setNewCount] = useState(0);
|
|
2010
|
+
const lastTailIdRef = useRef(null);
|
|
2011
|
+
const sourceItems = items ?? messages.map((msg) => ({ kind: "msg", msg }));
|
|
2012
|
+
const data = [...sourceItems].reverse();
|
|
2013
|
+
useEffect(() => {
|
|
2014
|
+
const tail = messages[messages.length - 1];
|
|
2015
|
+
if (!tail) return;
|
|
2016
|
+
const tailId = tail.id;
|
|
2017
|
+
if (tailId === lastTailIdRef.current) return;
|
|
2018
|
+
const isFirstSet = lastTailIdRef.current === null;
|
|
2019
|
+
lastTailIdRef.current = tailId;
|
|
2020
|
+
if (atBottom || isFirstSet) {
|
|
2021
|
+
setNewCount(0);
|
|
2022
|
+
return;
|
|
2023
|
+
}
|
|
2024
|
+
if (meId !== null && tail.sender_id === meId) return;
|
|
2025
|
+
setNewCount((n) => n + 1);
|
|
2026
|
+
}, [messages, atBottom, meId]);
|
|
2027
|
+
const handleScroll = useCallback((e) => {
|
|
2028
|
+
const y = e.nativeEvent.contentOffset.y;
|
|
2029
|
+
const next = y <= AT_BOTTOM_THRESHOLD;
|
|
2030
|
+
setAtBottom((prev) => prev === next ? prev : next);
|
|
2031
|
+
if (next) setNewCount(0);
|
|
2032
|
+
}, []);
|
|
2033
|
+
const scrollToBottom = useCallback(() => {
|
|
2034
|
+
flatListRef.current?.scrollToOffset({ offset: 0, animated: true });
|
|
2035
|
+
setNewCount(0);
|
|
2036
|
+
}, []);
|
|
1870
2037
|
const handleRender = useCallback(
|
|
1871
|
-
({ item, index }) =>
|
|
1872
|
-
|
|
2038
|
+
({ item, index }) => {
|
|
2039
|
+
if (item.kind === "separator") return item.node;
|
|
2040
|
+
const sourceIndex = data.length - 1 - index;
|
|
2041
|
+
return renderItem(item.msg, sourceIndex);
|
|
2042
|
+
},
|
|
2043
|
+
[renderItem, data.length]
|
|
1873
2044
|
);
|
|
1874
2045
|
if (loading && messages.length === 0) {
|
|
1875
|
-
return /* @__PURE__ */ jsx(View, { style: [
|
|
2046
|
+
return /* @__PURE__ */ jsx(View, { style: [styles11.placeholder, { backgroundColor: theme.colors.paper }], children: /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.brand }) });
|
|
1876
2047
|
}
|
|
1877
2048
|
if (messages.length === 0) {
|
|
1878
|
-
return /* @__PURE__ */ jsx(View, { style: [
|
|
2049
|
+
return /* @__PURE__ */ jsx(View, { style: [styles11.placeholder, { backgroundColor: theme.colors.paper }], children: typeof emptyState === "string" ? /* @__PURE__ */ jsx(Text, { style: { color: theme.colors.ink3, fontFamily: theme.type.fontBody }, children: emptyState }) : emptyState ?? null });
|
|
1879
2050
|
}
|
|
1880
|
-
return /* @__PURE__ */
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
2051
|
+
return /* @__PURE__ */ jsxs(View, { style: styles11.root, children: [
|
|
2052
|
+
/* @__PURE__ */ jsx(
|
|
2053
|
+
FlatList,
|
|
2054
|
+
{
|
|
2055
|
+
ref: flatListRef,
|
|
2056
|
+
inverted: true,
|
|
2057
|
+
data,
|
|
2058
|
+
keyExtractor: (item) => item.kind === "msg" ? item.msg.id : item.id,
|
|
2059
|
+
renderItem: handleRender,
|
|
2060
|
+
onEndReached: hasMore ? onLoadMore : void 0,
|
|
2061
|
+
onEndReachedThreshold: 0.3,
|
|
2062
|
+
onScroll: handleScroll,
|
|
2063
|
+
scrollEventThrottle: 32,
|
|
2064
|
+
ListHeaderComponent: ListHeader,
|
|
2065
|
+
ListFooterComponent: /* @__PURE__ */ jsxs(View, { children: [
|
|
2066
|
+
hasMore && loading ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.ink3, style: { marginVertical: 8 } }) : null,
|
|
2067
|
+
ListFooter
|
|
2068
|
+
] }),
|
|
2069
|
+
style: { backgroundColor: theme.colors.paper },
|
|
2070
|
+
contentContainerStyle: { paddingVertical: 8 }
|
|
2071
|
+
}
|
|
2072
|
+
),
|
|
2073
|
+
!atBottom && newCount > 0 ? /* @__PURE__ */ jsxs(
|
|
2074
|
+
Pressable,
|
|
2075
|
+
{
|
|
2076
|
+
onPress: scrollToBottom,
|
|
2077
|
+
style: [
|
|
2078
|
+
styles11.jumpButton,
|
|
2079
|
+
{
|
|
2080
|
+
backgroundColor: theme.colors.brand
|
|
2081
|
+
},
|
|
2082
|
+
theme.shadows.sm
|
|
2083
|
+
],
|
|
2084
|
+
accessibilityLabel: `${newCount} new ${newCount === 1 ? "message" : "messages"}, jump to latest`,
|
|
2085
|
+
children: [
|
|
2086
|
+
/* @__PURE__ */ jsx(PoolseIcon, { name: "chevron-down", size: 14, color: theme.colors.onBrand }),
|
|
2087
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles11.jumpText, { color: theme.colors.onBrand }], children: [
|
|
2088
|
+
newCount,
|
|
2089
|
+
" new ",
|
|
2090
|
+
newCount === 1 ? "message" : "messages"
|
|
2091
|
+
] })
|
|
2092
|
+
]
|
|
2093
|
+
}
|
|
2094
|
+
) : null
|
|
2095
|
+
] });
|
|
1898
2096
|
}
|
|
1899
|
-
var
|
|
2097
|
+
var styles11 = StyleSheet.create({
|
|
2098
|
+
root: {
|
|
2099
|
+
flex: 1
|
|
2100
|
+
},
|
|
1900
2101
|
placeholder: {
|
|
1901
2102
|
flex: 1,
|
|
1902
2103
|
alignItems: "center",
|
|
1903
2104
|
justifyContent: "center",
|
|
1904
2105
|
padding: 24
|
|
1905
|
-
}
|
|
1906
|
-
});
|
|
1907
|
-
function EditableMessageBubble({
|
|
1908
|
-
message,
|
|
1909
|
-
currentUserId,
|
|
1910
|
-
onCancel,
|
|
1911
|
-
onSave
|
|
1912
|
-
}) {
|
|
1913
|
-
const theme = usePoolseTheme();
|
|
1914
|
-
const isSelf = currentUserId !== null && message.sender_id === currentUserId;
|
|
1915
|
-
const [value, setValue] = useState(message.body ?? "");
|
|
1916
|
-
const [saving, setSaving] = useState(false);
|
|
1917
|
-
const submit = async () => {
|
|
1918
|
-
if (saving || !value.trim()) return;
|
|
1919
|
-
setSaving(true);
|
|
1920
|
-
try {
|
|
1921
|
-
await onSave(value.trim());
|
|
1922
|
-
} finally {
|
|
1923
|
-
setSaving(false);
|
|
1924
|
-
}
|
|
1925
|
-
};
|
|
1926
|
-
const bg = isSelf ? theme.colors.selfBubble : theme.colors.otherBubble;
|
|
1927
|
-
const ink = isSelf ? theme.colors.selfBubbleText : theme.colors.otherBubbleText;
|
|
1928
|
-
return /* @__PURE__ */ jsx(
|
|
1929
|
-
View,
|
|
1930
|
-
{
|
|
1931
|
-
style: [
|
|
1932
|
-
styles11.wrap,
|
|
1933
|
-
{
|
|
1934
|
-
alignSelf: isSelf ? "flex-end" : "flex-start",
|
|
1935
|
-
maxWidth: "80%"
|
|
1936
|
-
}
|
|
1937
|
-
],
|
|
1938
|
-
children: /* @__PURE__ */ jsxs(
|
|
1939
|
-
View,
|
|
1940
|
-
{
|
|
1941
|
-
style: [
|
|
1942
|
-
styles11.bubble,
|
|
1943
|
-
{
|
|
1944
|
-
backgroundColor: bg,
|
|
1945
|
-
borderRadius: theme.radii.bubble,
|
|
1946
|
-
paddingHorizontal: theme.spacing.md,
|
|
1947
|
-
paddingVertical: theme.spacing.sm
|
|
1948
|
-
},
|
|
1949
|
-
theme.shadows.sm
|
|
1950
|
-
],
|
|
1951
|
-
children: [
|
|
1952
|
-
/* @__PURE__ */ jsx(
|
|
1953
|
-
TextInput,
|
|
1954
|
-
{
|
|
1955
|
-
value,
|
|
1956
|
-
onChangeText: setValue,
|
|
1957
|
-
multiline: true,
|
|
1958
|
-
autoFocus: true,
|
|
1959
|
-
style: {
|
|
1960
|
-
color: ink,
|
|
1961
|
-
fontFamily: theme.type.fontBody,
|
|
1962
|
-
fontSize: theme.type.bodySize,
|
|
1963
|
-
minHeight: 24
|
|
1964
|
-
}
|
|
1965
|
-
}
|
|
1966
|
-
),
|
|
1967
|
-
/* @__PURE__ */ jsxs(View, { style: styles11.actions, children: [
|
|
1968
|
-
/* @__PURE__ */ jsx(Pressable, { onPress: onCancel, hitSlop: 6, children: /* @__PURE__ */ jsx(Text, { style: [styles11.btn, { color: ink, opacity: 0.7 }], children: "Cancel" }) }),
|
|
1969
|
-
/* @__PURE__ */ jsx(Pressable, { onPress: submit, disabled: saving, hitSlop: 6, children: /* @__PURE__ */ jsx(Text, { style: [styles11.btn, { color: ink, fontWeight: "700" }], children: saving ? "Saving\u2026" : "Save" }) })
|
|
1970
|
-
] })
|
|
1971
|
-
]
|
|
1972
|
-
}
|
|
1973
|
-
)
|
|
1974
|
-
}
|
|
1975
|
-
);
|
|
1976
|
-
}
|
|
1977
|
-
var styles11 = StyleSheet.create({
|
|
1978
|
-
wrap: {
|
|
1979
|
-
marginBottom: 4
|
|
1980
2106
|
},
|
|
1981
|
-
|
|
1982
|
-
|
|
2107
|
+
jumpButton: {
|
|
2108
|
+
position: "absolute",
|
|
2109
|
+
alignSelf: "center",
|
|
2110
|
+
bottom: 12,
|
|
1983
2111
|
flexDirection: "row",
|
|
1984
|
-
|
|
1985
|
-
gap:
|
|
1986
|
-
|
|
2112
|
+
alignItems: "center",
|
|
2113
|
+
gap: 6,
|
|
2114
|
+
paddingHorizontal: 14,
|
|
2115
|
+
paddingVertical: 8,
|
|
2116
|
+
borderRadius: 999
|
|
1987
2117
|
},
|
|
1988
|
-
|
|
1989
|
-
fontSize: 13
|
|
2118
|
+
jumpText: {
|
|
2119
|
+
fontSize: 13,
|
|
2120
|
+
fontWeight: "600"
|
|
1990
2121
|
}
|
|
1991
2122
|
});
|
|
1992
2123
|
var DEFAULT_REACTION_EMOJIS = ["\u{1F44D}", "\u2764\uFE0F", "\u{1F602}", "\u{1F389}", "\u{1F64F}", "\u{1F525}"];
|
|
@@ -2449,6 +2580,77 @@ var styles14 = StyleSheet.create({
|
|
|
2449
2580
|
borderRadius: 20
|
|
2450
2581
|
}
|
|
2451
2582
|
});
|
|
2583
|
+
var MarkdownModule;
|
|
2584
|
+
var warned = false;
|
|
2585
|
+
function loadMarkdown() {
|
|
2586
|
+
if (MarkdownModule === void 0) {
|
|
2587
|
+
try {
|
|
2588
|
+
MarkdownModule = __require("react-native-markdown-display");
|
|
2589
|
+
} catch {
|
|
2590
|
+
MarkdownModule = null;
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
const fn = MarkdownModule?.default;
|
|
2594
|
+
if (!fn) {
|
|
2595
|
+
if (!warned) {
|
|
2596
|
+
warned = true;
|
|
2597
|
+
console.warn(
|
|
2598
|
+
"[@poolse/react-native] Markdown rendering requires `react-native-markdown-display`. Install it to enable bold/italic/code/links in message bubbles. Falling back to plain text."
|
|
2599
|
+
);
|
|
2600
|
+
}
|
|
2601
|
+
return null;
|
|
2602
|
+
}
|
|
2603
|
+
return fn;
|
|
2604
|
+
}
|
|
2605
|
+
function renderMarkdown(body, args) {
|
|
2606
|
+
const Markdown = loadMarkdown();
|
|
2607
|
+
if (!Markdown) return null;
|
|
2608
|
+
const baseText = {
|
|
2609
|
+
color: args.textColor,
|
|
2610
|
+
fontFamily: args.fontFamily,
|
|
2611
|
+
fontSize: args.fontSize,
|
|
2612
|
+
lineHeight: args.lineHeight
|
|
2613
|
+
};
|
|
2614
|
+
const style = {
|
|
2615
|
+
body: baseText,
|
|
2616
|
+
paragraph: { ...baseText, marginTop: 0, marginBottom: 0 },
|
|
2617
|
+
text: baseText,
|
|
2618
|
+
strong: { ...baseText, fontWeight: "700" },
|
|
2619
|
+
em: { ...baseText, fontStyle: "italic" },
|
|
2620
|
+
s: { ...baseText, textDecorationLine: "line-through" },
|
|
2621
|
+
link: { color: args.linkColor, textDecorationLine: "underline" },
|
|
2622
|
+
code_inline: {
|
|
2623
|
+
...baseText,
|
|
2624
|
+
backgroundColor: "rgba(127,127,127,0.18)",
|
|
2625
|
+
borderRadius: 4,
|
|
2626
|
+
paddingHorizontal: 4
|
|
2627
|
+
},
|
|
2628
|
+
code_block: {
|
|
2629
|
+
...baseText,
|
|
2630
|
+
backgroundColor: "rgba(127,127,127,0.18)",
|
|
2631
|
+
padding: 8,
|
|
2632
|
+
borderRadius: 6
|
|
2633
|
+
},
|
|
2634
|
+
fence: {
|
|
2635
|
+
...baseText,
|
|
2636
|
+
backgroundColor: "rgba(127,127,127,0.18)",
|
|
2637
|
+
padding: 8,
|
|
2638
|
+
borderRadius: 6
|
|
2639
|
+
},
|
|
2640
|
+
bullet_list: { marginTop: 2, marginBottom: 2 },
|
|
2641
|
+
ordered_list: { marginTop: 2, marginBottom: 2 },
|
|
2642
|
+
list_item: baseText,
|
|
2643
|
+
blockquote: {
|
|
2644
|
+
...baseText,
|
|
2645
|
+
borderLeftWidth: 3,
|
|
2646
|
+
borderLeftColor: args.linkColor,
|
|
2647
|
+
paddingLeft: 8,
|
|
2648
|
+
marginVertical: 4,
|
|
2649
|
+
opacity: 0.85
|
|
2650
|
+
}
|
|
2651
|
+
};
|
|
2652
|
+
return createElement(Markdown, { style, onLinkPress: args.onLinkPress }, body);
|
|
2653
|
+
}
|
|
2452
2654
|
function MessageBubble({
|
|
2453
2655
|
message,
|
|
2454
2656
|
currentUserId,
|
|
@@ -2459,7 +2661,8 @@ function MessageBubble({
|
|
|
2459
2661
|
maxBodyLength = 0,
|
|
2460
2662
|
showSenderName = false,
|
|
2461
2663
|
actionsTrigger,
|
|
2462
|
-
showAttachments = true
|
|
2664
|
+
showAttachments = true,
|
|
2665
|
+
markdown = true
|
|
2463
2666
|
}) {
|
|
2464
2667
|
const theme = usePoolseTheme();
|
|
2465
2668
|
const { width: screenWidth } = useWindowDimensions();
|
|
@@ -2544,22 +2747,53 @@ function MessageBubble({
|
|
|
2544
2747
|
) : null,
|
|
2545
2748
|
renderAttachments && images.length > 0 ? /* @__PURE__ */ jsx(ImageMosaic, { images, maxWidth: contentMaxWidth }) : null,
|
|
2546
2749
|
renderAttachments && files.length > 0 ? /* @__PURE__ */ jsx(View, { style: { gap: theme.spacing.xs, marginBottom: theme.spacing.xs }, children: files.map((att) => /* @__PURE__ */ jsx(AttachmentPreview, { attachment: att, maxWidth: contentMaxWidth }, att.id)) }) : null,
|
|
2547
|
-
body.length > 0 ?
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
styles15.body,
|
|
2750
|
+
body.length > 0 ? (() => {
|
|
2751
|
+
if (isDeleted) {
|
|
2752
|
+
return /* @__PURE__ */ jsx(
|
|
2753
|
+
Text,
|
|
2552
2754
|
{
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2755
|
+
style: [
|
|
2756
|
+
styles15.body,
|
|
2757
|
+
{
|
|
2758
|
+
color: theme.colors.ink3,
|
|
2759
|
+
fontFamily: theme.type.fontBody,
|
|
2760
|
+
fontSize: theme.type.bodySize,
|
|
2761
|
+
lineHeight: theme.type.lineHeight,
|
|
2762
|
+
fontStyle: "italic"
|
|
2763
|
+
}
|
|
2764
|
+
],
|
|
2765
|
+
children: "Message deleted"
|
|
2558
2766
|
}
|
|
2559
|
-
|
|
2560
|
-
children: isDeleted ? "Message deleted" : truncated
|
|
2767
|
+
);
|
|
2561
2768
|
}
|
|
2562
|
-
|
|
2769
|
+
const md = markdown ? renderMarkdown(truncated, {
|
|
2770
|
+
textColor,
|
|
2771
|
+
linkColor: isSelf ? theme.colors.onBrand : theme.colors.brand,
|
|
2772
|
+
fontFamily: theme.type.fontBody,
|
|
2773
|
+
fontSize: theme.type.bodySize,
|
|
2774
|
+
lineHeight: theme.type.lineHeight,
|
|
2775
|
+
onLinkPress: (url) => {
|
|
2776
|
+
void Linking.openURL(url).catch(() => void 0);
|
|
2777
|
+
return false;
|
|
2778
|
+
}
|
|
2779
|
+
}) : null;
|
|
2780
|
+
if (md) return md;
|
|
2781
|
+
return /* @__PURE__ */ jsx(
|
|
2782
|
+
Text,
|
|
2783
|
+
{
|
|
2784
|
+
style: [
|
|
2785
|
+
styles15.body,
|
|
2786
|
+
{
|
|
2787
|
+
color: textColor,
|
|
2788
|
+
fontFamily: theme.type.fontBody,
|
|
2789
|
+
fontSize: theme.type.bodySize,
|
|
2790
|
+
lineHeight: theme.type.lineHeight
|
|
2791
|
+
}
|
|
2792
|
+
],
|
|
2793
|
+
children: truncated
|
|
2794
|
+
}
|
|
2795
|
+
);
|
|
2796
|
+
})() : null,
|
|
2563
2797
|
maxBodyLength > 0 && body.length > maxBodyLength ? /* @__PURE__ */ jsx(Pressable, { onPress: () => setExpanded((e) => !e), children: /* @__PURE__ */ jsx(
|
|
2564
2798
|
Text,
|
|
2565
2799
|
{
|
|
@@ -2652,9 +2886,9 @@ function formatTime(iso) {
|
|
|
2652
2886
|
try {
|
|
2653
2887
|
const d = new Date(iso);
|
|
2654
2888
|
const now = /* @__PURE__ */ new Date();
|
|
2655
|
-
const
|
|
2889
|
+
const sameDay2 = isSameDay(d, now);
|
|
2656
2890
|
const time = d.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
|
|
2657
|
-
if (
|
|
2891
|
+
if (sameDay2) return time;
|
|
2658
2892
|
const yesterday = new Date(now);
|
|
2659
2893
|
yesterday.setDate(now.getDate() - 1);
|
|
2660
2894
|
if (isSameDay(d, yesterday)) return `Yesterday ${time}`;
|
|
@@ -2762,12 +2996,26 @@ function ReactionStrip({
|
|
|
2762
2996
|
styles16.chip,
|
|
2763
2997
|
{
|
|
2764
2998
|
backgroundColor: meReacted ? theme.colors.brandSoft : theme.colors.surface2,
|
|
2765
|
-
borderColor: meReacted ? theme.colors.brand : theme.colors.border
|
|
2999
|
+
borderColor: meReacted ? theme.colors.brand : theme.colors.border,
|
|
3000
|
+
borderWidth: meReacted ? 1.5 : 1,
|
|
3001
|
+
transform: meReacted ? [{ scale: 1.04 }] : void 0
|
|
2766
3002
|
}
|
|
2767
3003
|
],
|
|
2768
3004
|
children: [
|
|
2769
3005
|
/* @__PURE__ */ jsx(Text, { style: styles16.emoji, children: emoji }),
|
|
2770
|
-
/* @__PURE__ */ jsx(
|
|
3006
|
+
/* @__PURE__ */ jsx(
|
|
3007
|
+
Text,
|
|
3008
|
+
{
|
|
3009
|
+
style: [
|
|
3010
|
+
styles16.count,
|
|
3011
|
+
{
|
|
3012
|
+
color: meReacted ? theme.colors.brand : theme.colors.ink2,
|
|
3013
|
+
fontWeight: meReacted ? "700" : "600"
|
|
3014
|
+
}
|
|
3015
|
+
],
|
|
3016
|
+
children: userArr.length
|
|
3017
|
+
}
|
|
3018
|
+
)
|
|
2771
3019
|
]
|
|
2772
3020
|
},
|
|
2773
3021
|
emoji
|
|
@@ -2820,7 +3068,6 @@ var styles16 = StyleSheet.create({
|
|
|
2820
3068
|
paddingHorizontal: 9,
|
|
2821
3069
|
paddingVertical: 4,
|
|
2822
3070
|
borderRadius: 14,
|
|
2823
|
-
borderWidth: 1,
|
|
2824
3071
|
gap: 5,
|
|
2825
3072
|
minHeight: 26,
|
|
2826
3073
|
// Subtle elevation so chips lift off the surface
|
|
@@ -2836,7 +3083,6 @@ var styles16 = StyleSheet.create({
|
|
|
2836
3083
|
},
|
|
2837
3084
|
count: {
|
|
2838
3085
|
fontSize: 12,
|
|
2839
|
-
fontWeight: "600",
|
|
2840
3086
|
fontVariant: ["tabular-nums"]
|
|
2841
3087
|
},
|
|
2842
3088
|
backdrop: {
|
|
@@ -2874,11 +3120,10 @@ function MessageRow({
|
|
|
2874
3120
|
actions = true,
|
|
2875
3121
|
threads = true,
|
|
2876
3122
|
quotations = true,
|
|
3123
|
+
markdown = true,
|
|
2877
3124
|
readState,
|
|
2878
|
-
|
|
3125
|
+
isEditing = false,
|
|
2879
3126
|
onStartEdit,
|
|
2880
|
-
onCancelEdit,
|
|
2881
|
-
onSaveEdit,
|
|
2882
3127
|
onDelete,
|
|
2883
3128
|
onOpenThread,
|
|
2884
3129
|
onQuote,
|
|
@@ -2899,7 +3144,7 @@ function MessageRow({
|
|
|
2899
3144
|
...msg.reactions ? { initialReactions: msg.reactions } : {}
|
|
2900
3145
|
});
|
|
2901
3146
|
const translateX = useRef(new Animated.Value(0)).current;
|
|
2902
|
-
const swipeEnabled = quotations && !!onQuote && !
|
|
3147
|
+
const swipeEnabled = quotations && !!onQuote && !isEditing;
|
|
2903
3148
|
const panResponder = useMemo(
|
|
2904
3149
|
() => PanResponder.create({
|
|
2905
3150
|
// Tap / long-press still go to the inner Pressable.
|
|
@@ -2974,137 +3219,149 @@ function MessageRow({
|
|
|
2974
3219
|
const rowSender = useUser(showAvatarSlot ? msg.sender_external_id : null);
|
|
2975
3220
|
const avatarUrl = msg.sender_external_id ? avatarFor?.(msg.sender_external_id) ?? rowSender.profile?.avatarUrl ?? null : null;
|
|
2976
3221
|
const senderLabel = msg.sender_external_id ? labelFor?.(msg.sender_external_id) ?? rowSender.profile?.displayName ?? msg.sender_external_id : null;
|
|
2977
|
-
return /* @__PURE__ */ jsxs(
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
children: /* @__PURE__ */ jsx(PoolseIcon, { name: "reply", size: 16, color: theme.colors.brand })
|
|
3002
|
-
}
|
|
3003
|
-
) : null,
|
|
3004
|
-
/* @__PURE__ */ jsx(
|
|
3005
|
-
Animated.View,
|
|
3006
|
-
{
|
|
3007
|
-
...swipeEnabled ? panResponder.panHandlers : {},
|
|
3008
|
-
style: { transform: [{ translateX }] },
|
|
3009
|
-
children: /* @__PURE__ */ jsx(
|
|
3010
|
-
Pressable,
|
|
3222
|
+
return /* @__PURE__ */ jsxs(
|
|
3223
|
+
View,
|
|
3224
|
+
{
|
|
3225
|
+
style: [
|
|
3226
|
+
styles17.row,
|
|
3227
|
+
{ alignSelf: isSelf ? "flex-end" : "flex-start" },
|
|
3228
|
+
// Lift this row above the dim backdrop the parent renders
|
|
3229
|
+
// during edit mode. zIndex covers iOS / web; elevation does
|
|
3230
|
+
// the equivalent on Android.
|
|
3231
|
+
isEditing ? styles17.rowEditing : null
|
|
3232
|
+
],
|
|
3233
|
+
children: [
|
|
3234
|
+
showAvatarSlot ? /* @__PURE__ */ jsx(View, { style: styles17.avatarSlot, children: showAvatarRender ? /* @__PURE__ */ jsx(
|
|
3235
|
+
Avatar,
|
|
3236
|
+
{
|
|
3237
|
+
src: avatarUrl ?? null,
|
|
3238
|
+
name: senderLabel,
|
|
3239
|
+
seed: msg.sender_external_id ?? null,
|
|
3240
|
+
size: "sm"
|
|
3241
|
+
}
|
|
3242
|
+
) : null }) : null,
|
|
3243
|
+
/* @__PURE__ */ jsxs(View, { style: styles17.bubbleCol, children: [
|
|
3244
|
+
swipeEnabled ? /* @__PURE__ */ jsx(
|
|
3245
|
+
Animated.View,
|
|
3011
3246
|
{
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
accessibilityRole: "button",
|
|
3017
|
-
accessibilityLabel: "Message actions",
|
|
3018
|
-
children: editing ? /* @__PURE__ */ jsx(
|
|
3019
|
-
EditableMessageBubble,
|
|
3247
|
+
pointerEvents: "none",
|
|
3248
|
+
style: [
|
|
3249
|
+
styles17.replyHint,
|
|
3250
|
+
isSelf ? styles17.replyHintRight : styles17.replyHintLeft,
|
|
3020
3251
|
{
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
onSave: onSaveEdit ?? (() => void 0)
|
|
3252
|
+
opacity: replyIconOpacity,
|
|
3253
|
+
transform: [{ scale: replyIconScale }],
|
|
3254
|
+
backgroundColor: theme.colors.surface2
|
|
3025
3255
|
}
|
|
3026
|
-
|
|
3027
|
-
|
|
3256
|
+
],
|
|
3257
|
+
children: /* @__PURE__ */ jsx(PoolseIcon, { name: "reply", size: 16, color: theme.colors.brand })
|
|
3258
|
+
}
|
|
3259
|
+
) : null,
|
|
3260
|
+
/* @__PURE__ */ jsx(
|
|
3261
|
+
Animated.View,
|
|
3262
|
+
{
|
|
3263
|
+
...swipeEnabled ? panResponder.panHandlers : {},
|
|
3264
|
+
style: { transform: [{ translateX }] },
|
|
3265
|
+
children: /* @__PURE__ */ jsx(
|
|
3266
|
+
Pressable,
|
|
3028
3267
|
{
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
showAttachments: attachments,
|
|
3038
|
-
actionsTrigger: actions ? /* @__PURE__ */ jsx(Pressable, { onPress: () => setActionsOpen(true), hitSlop: 8, children: /* @__PURE__ */ jsx(
|
|
3039
|
-
PoolseIcon,
|
|
3268
|
+
onLongPress: () => {
|
|
3269
|
+
if (!actions) return;
|
|
3270
|
+
setActionsOpen(true);
|
|
3271
|
+
},
|
|
3272
|
+
accessibilityRole: "button",
|
|
3273
|
+
accessibilityLabel: "Message actions",
|
|
3274
|
+
children: /* @__PURE__ */ jsx(
|
|
3275
|
+
MessageBubble,
|
|
3040
3276
|
{
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3277
|
+
message: msg,
|
|
3278
|
+
currentUserId: meId,
|
|
3279
|
+
...readState ? { readState } : {},
|
|
3280
|
+
...labelFor ? { labelFor } : {},
|
|
3281
|
+
...onQuotedClick ? { onQuotedClick } : {},
|
|
3282
|
+
groupPosition,
|
|
3283
|
+
maxBodyLength,
|
|
3284
|
+
showSenderName,
|
|
3285
|
+
showAttachments: attachments,
|
|
3286
|
+
markdown,
|
|
3287
|
+
actionsTrigger: actions ? /* @__PURE__ */ jsx(Pressable, { onPress: () => setActionsOpen(true), hitSlop: 8, children: /* @__PURE__ */ jsx(
|
|
3288
|
+
PoolseIcon,
|
|
3289
|
+
{
|
|
3290
|
+
name: "chevron-down",
|
|
3291
|
+
size: 14,
|
|
3292
|
+
color: isSelf ? theme.colors.onBrand : theme.colors.ink3
|
|
3293
|
+
}
|
|
3294
|
+
) }) : null
|
|
3044
3295
|
}
|
|
3045
|
-
)
|
|
3296
|
+
)
|
|
3046
3297
|
}
|
|
3047
3298
|
)
|
|
3048
3299
|
}
|
|
3049
|
-
)
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
}
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3300
|
+
),
|
|
3301
|
+
threads && (msg.reply_count ?? 0) > 0 && onOpenThread ? /* @__PURE__ */ jsx(Pressable, { onPress: onOpenThread, style: styles17.threadPill, children: /* @__PURE__ */ jsxs(Text, { style: [styles17.threadPillText, { color: theme.colors.brand }], children: [
|
|
3302
|
+
"\u{1F4AC} ",
|
|
3303
|
+
msg.reply_count,
|
|
3304
|
+
" ",
|
|
3305
|
+
msg.reply_count === 1 ? "reply" : "replies"
|
|
3306
|
+
] }) }) : null,
|
|
3307
|
+
reactions ? /* @__PURE__ */ jsx(View, { style: [styles17.reactionsRow, { alignSelf: isSelf ? "flex-end" : "flex-start" }], children: /* @__PURE__ */ jsx(
|
|
3308
|
+
ReactionStrip,
|
|
3309
|
+
{
|
|
3310
|
+
messageId: msg.id,
|
|
3311
|
+
conversationId: msg.conversation_id,
|
|
3312
|
+
meId,
|
|
3313
|
+
...msg.reactions ? { initialReactions: msg.reactions } : {}
|
|
3314
|
+
}
|
|
3315
|
+
) }) : null
|
|
3316
|
+
] }),
|
|
3317
|
+
actions && actionsOpen ? /* @__PURE__ */ jsx(
|
|
3318
|
+
MessageActions,
|
|
3319
|
+
{
|
|
3320
|
+
visible: actionsOpen,
|
|
3321
|
+
onClose: () => setActionsOpen(false),
|
|
3322
|
+
isSelf,
|
|
3323
|
+
...reactions ? {
|
|
3324
|
+
// Inline quick-react row at the top of the sheet —
|
|
3325
|
+
// one tap = react + close, no second modal needed.
|
|
3326
|
+
onPickReaction: (emoji) => {
|
|
3327
|
+
void reactionsApi.addReaction(emoji);
|
|
3328
|
+
}
|
|
3329
|
+
} : {},
|
|
3330
|
+
...msg.body && !msg.deleted_at ? {
|
|
3331
|
+
onCopy: () => {
|
|
3332
|
+
setActionsOpen(false);
|
|
3333
|
+
void copyToClipboard(msg.body ?? "");
|
|
3334
|
+
}
|
|
3335
|
+
} : {},
|
|
3336
|
+
...onStartEdit ? {
|
|
3337
|
+
onEdit: () => {
|
|
3338
|
+
setActionsOpen(false);
|
|
3339
|
+
onStartEdit();
|
|
3340
|
+
}
|
|
3341
|
+
} : {},
|
|
3342
|
+
...onDelete ? {
|
|
3343
|
+
onDelete: () => {
|
|
3344
|
+
setActionsOpen(false);
|
|
3345
|
+
onDelete();
|
|
3346
|
+
}
|
|
3347
|
+
} : {},
|
|
3348
|
+
...onOpenThread ? {
|
|
3349
|
+
onReplyInThread: () => {
|
|
3350
|
+
setActionsOpen(false);
|
|
3351
|
+
onOpenThread();
|
|
3352
|
+
}
|
|
3353
|
+
} : {},
|
|
3354
|
+
...quotations && onQuote ? {
|
|
3355
|
+
onQuote: () => {
|
|
3356
|
+
setActionsOpen(false);
|
|
3357
|
+
onQuote();
|
|
3358
|
+
}
|
|
3359
|
+
} : {}
|
|
3103
3360
|
}
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3361
|
+
) : null
|
|
3362
|
+
]
|
|
3363
|
+
}
|
|
3364
|
+
);
|
|
3108
3365
|
}
|
|
3109
3366
|
var styles17 = StyleSheet.create({
|
|
3110
3367
|
row: {
|
|
@@ -3120,6 +3377,12 @@ var styles17 = StyleSheet.create({
|
|
|
3120
3377
|
paddingHorizontal: 10,
|
|
3121
3378
|
maxWidth: "95%"
|
|
3122
3379
|
},
|
|
3380
|
+
rowEditing: {
|
|
3381
|
+
// Above ConversationView's editBackdrop (zIndex 5). Elevation
|
|
3382
|
+
// does the equivalent stacking on Android.
|
|
3383
|
+
zIndex: 10,
|
|
3384
|
+
elevation: 10
|
|
3385
|
+
},
|
|
3123
3386
|
avatarSlot: {
|
|
3124
3387
|
width: 36,
|
|
3125
3388
|
marginRight: 6
|
|
@@ -3159,6 +3422,27 @@ var styles17 = StyleSheet.create({
|
|
|
3159
3422
|
marginTop: 2
|
|
3160
3423
|
}
|
|
3161
3424
|
});
|
|
3425
|
+
var clipboardModule;
|
|
3426
|
+
var clipboardWarned = false;
|
|
3427
|
+
async function copyToClipboard(text) {
|
|
3428
|
+
if (clipboardModule === void 0) {
|
|
3429
|
+
try {
|
|
3430
|
+
clipboardModule = __require("expo-clipboard");
|
|
3431
|
+
} catch {
|
|
3432
|
+
clipboardModule = null;
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
if (!clipboardModule?.setStringAsync) {
|
|
3436
|
+
if (!clipboardWarned) {
|
|
3437
|
+
clipboardWarned = true;
|
|
3438
|
+
console.warn(
|
|
3439
|
+
"[@poolse/react-native] Copy action requires `expo-clipboard`. Install it to enable copy-to-clipboard."
|
|
3440
|
+
);
|
|
3441
|
+
}
|
|
3442
|
+
return;
|
|
3443
|
+
}
|
|
3444
|
+
await clipboardModule.setStringAsync(text);
|
|
3445
|
+
}
|
|
3162
3446
|
var SHEET_HEIGHT_FRACTION = 0.88;
|
|
3163
3447
|
function ThreadView({
|
|
3164
3448
|
visible,
|
|
@@ -3214,31 +3498,34 @@ function ThreadSheet({
|
|
|
3214
3498
|
const [pickerOpen, setPickerOpen] = useState(false);
|
|
3215
3499
|
const [editingId, setEditingId] = useState(null);
|
|
3216
3500
|
const renderReply = useCallback(
|
|
3217
|
-
(msg) =>
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3501
|
+
(msg) => {
|
|
3502
|
+
const isSelf = meId !== null && msg.sender_id === meId;
|
|
3503
|
+
const canEdit = isSelf && !msg.deleted_at;
|
|
3504
|
+
return /* @__PURE__ */ jsx(
|
|
3505
|
+
MessageRow,
|
|
3506
|
+
{
|
|
3507
|
+
msg,
|
|
3508
|
+
meId,
|
|
3509
|
+
reactions: true,
|
|
3510
|
+
attachments: true,
|
|
3511
|
+
actions: true,
|
|
3512
|
+
threads: false,
|
|
3513
|
+
quotations: false,
|
|
3514
|
+
isEditing: editingId === msg.id,
|
|
3515
|
+
...canEdit ? { onStartEdit: () => setEditingId(msg.id) } : {},
|
|
3516
|
+
onDelete: () => {
|
|
3517
|
+
void deleteReply(msg.id);
|
|
3518
|
+
},
|
|
3519
|
+
...labelFor ? { labelFor } : {},
|
|
3520
|
+
...avatarFor ? { avatarFor } : {}
|
|
3521
|
+
}
|
|
3522
|
+
);
|
|
3523
|
+
},
|
|
3524
|
+
[meId, editingId, deleteReply, labelFor, avatarFor]
|
|
3525
|
+
);
|
|
3526
|
+
const editingMessage = useMemo(
|
|
3527
|
+
() => editingId ? replies.find((m) => m.id === editingId) ?? null : null,
|
|
3528
|
+
[editingId, replies]
|
|
3242
3529
|
);
|
|
3243
3530
|
const rootRow = useMemo(
|
|
3244
3531
|
() => /* @__PURE__ */ jsx(
|
|
@@ -3324,7 +3611,14 @@ function ThreadSheet({
|
|
|
3324
3611
|
},
|
|
3325
3612
|
placeholder: "Reply to thread\u2026",
|
|
3326
3613
|
attachments: true,
|
|
3327
|
-
onAttachPress: () => setPickerOpen(true)
|
|
3614
|
+
onAttachPress: () => setPickerOpen(true),
|
|
3615
|
+
editingMessage,
|
|
3616
|
+
onCancelEdit: () => setEditingId(null),
|
|
3617
|
+
onSaveEdit: async (body) => {
|
|
3618
|
+
if (!editingId) return;
|
|
3619
|
+
await edit(editingId, body);
|
|
3620
|
+
setEditingId(null);
|
|
3621
|
+
}
|
|
3328
3622
|
}
|
|
3329
3623
|
)
|
|
3330
3624
|
]
|
|
@@ -3488,6 +3782,7 @@ var styles19 = StyleSheet.create({
|
|
|
3488
3782
|
fontSize: 12
|
|
3489
3783
|
}
|
|
3490
3784
|
});
|
|
3785
|
+
var GROUPING_WINDOW_MS = 5 * 60 * 1e3;
|
|
3491
3786
|
function ConversationView({
|
|
3492
3787
|
conversationId,
|
|
3493
3788
|
emptyState,
|
|
@@ -3504,6 +3799,7 @@ function ConversationView({
|
|
|
3504
3799
|
threads = true,
|
|
3505
3800
|
quotations = true,
|
|
3506
3801
|
readReceipts = true,
|
|
3802
|
+
markdown = true,
|
|
3507
3803
|
maxBodyLength = 200,
|
|
3508
3804
|
senderLabels = "auto",
|
|
3509
3805
|
avatars = "auto",
|
|
@@ -3522,9 +3818,25 @@ function ConversationView({
|
|
|
3522
3818
|
send,
|
|
3523
3819
|
edit,
|
|
3524
3820
|
delete: deleteMsg,
|
|
3525
|
-
markReadUpTo
|
|
3821
|
+
markReadUpTo,
|
|
3822
|
+
refetch
|
|
3526
3823
|
} = useMessages(conversationId);
|
|
3527
3824
|
const { typing, signalTyping } = useTyping(conversationId);
|
|
3825
|
+
const realtimeStatus = useRealtimeStatus();
|
|
3826
|
+
useEffect(() => {
|
|
3827
|
+
const sub = AppState.addEventListener("change", (next) => {
|
|
3828
|
+
if (next === "active") void refetch();
|
|
3829
|
+
});
|
|
3830
|
+
return () => sub.remove();
|
|
3831
|
+
}, [refetch]);
|
|
3832
|
+
const prevStatusRef = useRef(realtimeStatus);
|
|
3833
|
+
useEffect(() => {
|
|
3834
|
+
const prev = prevStatusRef.current;
|
|
3835
|
+
prevStatusRef.current = realtimeStatus;
|
|
3836
|
+
if (realtimeStatus === "connected" && (prev === "reconnecting" || prev === "closed" || prev === "connecting")) {
|
|
3837
|
+
void refetch();
|
|
3838
|
+
}
|
|
3839
|
+
}, [realtimeStatus, refetch]);
|
|
3528
3840
|
const wantsMembers = mentions || senderLabels === "auto" || avatars === "auto";
|
|
3529
3841
|
const { members } = useMembers(wantsMembers ? conversationId : "");
|
|
3530
3842
|
const isGroupChat = members.length > 2;
|
|
@@ -3555,10 +3867,24 @@ function ConversationView({
|
|
|
3555
3867
|
});
|
|
3556
3868
|
onMarkedRead?.(conversationId, latest.id);
|
|
3557
3869
|
}, [messages, meId, readReceipts, markReadUpTo, onMarkedRead, conversationId]);
|
|
3870
|
+
const groupPositionById = useMemo(() => {
|
|
3871
|
+
const map = /* @__PURE__ */ new Map();
|
|
3872
|
+
for (let i = 0; i < messages.length; i++) {
|
|
3873
|
+
const msg = messages[i];
|
|
3874
|
+
if (!msg) continue;
|
|
3875
|
+
const prev = i > 0 ? messages[i - 1] ?? null : null;
|
|
3876
|
+
const next = i < messages.length - 1 ? messages[i + 1] ?? null : null;
|
|
3877
|
+
map.set(msg.id, computeGroupPosition(msg, prev, next, GROUPING_WINDOW_MS));
|
|
3878
|
+
}
|
|
3879
|
+
return map;
|
|
3880
|
+
}, [messages]);
|
|
3558
3881
|
const renderItem = useCallback(
|
|
3559
3882
|
(msg) => {
|
|
3560
3883
|
if (renderMessage) return /* @__PURE__ */ jsx(Fragment, { children: renderMessage(msg, meId) });
|
|
3561
3884
|
const readState = readReceipts && meId !== null && msg.sender_id === meId ? readStateForMessage(msg, members, meId, sequenceByMessageId) : void 0;
|
|
3885
|
+
const isSelf = meId !== null && msg.sender_id === meId;
|
|
3886
|
+
const canEdit = isSelf && !msg.deleted_at && (readState ?? "sent") === "sent";
|
|
3887
|
+
const groupPosition = groupPositionById.get(msg.id) ?? "standalone";
|
|
3562
3888
|
return /* @__PURE__ */ jsx(
|
|
3563
3889
|
MessageRow,
|
|
3564
3890
|
{
|
|
@@ -3570,13 +3896,8 @@ function ConversationView({
|
|
|
3570
3896
|
threads,
|
|
3571
3897
|
quotations,
|
|
3572
3898
|
...readState ? { readState } : {},
|
|
3573
|
-
|
|
3574
|
-
onStartEdit: () => setEditingId(msg.id),
|
|
3575
|
-
onCancelEdit: () => setEditingId(null),
|
|
3576
|
-
onSaveEdit: async (body) => {
|
|
3577
|
-
await edit(msg.id, body);
|
|
3578
|
-
setEditingId(null);
|
|
3579
|
-
},
|
|
3899
|
+
isEditing: editingId === msg.id,
|
|
3900
|
+
...canEdit ? { onStartEdit: () => setEditingId(msg.id) } : {},
|
|
3580
3901
|
onDelete: () => deleteMsg(msg.id),
|
|
3581
3902
|
...threads ? { onOpenThread: () => setThreadRoot(msg) } : {},
|
|
3582
3903
|
...quotations ? { onQuote: () => setReplyingTo(msg) } : {},
|
|
@@ -3584,7 +3905,9 @@ function ConversationView({
|
|
|
3584
3905
|
...avatarFor ? { avatarFor } : {},
|
|
3585
3906
|
showSenderName: showSenderLabels,
|
|
3586
3907
|
showAvatar: showAvatars,
|
|
3587
|
-
maxBodyLength
|
|
3908
|
+
maxBodyLength,
|
|
3909
|
+
groupPosition,
|
|
3910
|
+
markdown
|
|
3588
3911
|
}
|
|
3589
3912
|
);
|
|
3590
3913
|
},
|
|
@@ -3599,16 +3922,38 @@ function ConversationView({
|
|
|
3599
3922
|
threads,
|
|
3600
3923
|
quotations,
|
|
3601
3924
|
editingId,
|
|
3602
|
-
edit,
|
|
3603
3925
|
deleteMsg,
|
|
3604
3926
|
labelFor,
|
|
3605
3927
|
avatarFor,
|
|
3606
3928
|
showSenderLabels,
|
|
3607
3929
|
showAvatars,
|
|
3608
3930
|
maxBodyLength,
|
|
3609
|
-
sequenceByMessageId
|
|
3931
|
+
sequenceByMessageId,
|
|
3932
|
+
groupPositionById,
|
|
3933
|
+
markdown
|
|
3610
3934
|
]
|
|
3611
3935
|
);
|
|
3936
|
+
const editingMessage = useMemo(
|
|
3937
|
+
() => editingId ? messages.find((m) => m.id === editingId) ?? null : null,
|
|
3938
|
+
[editingId, messages]
|
|
3939
|
+
);
|
|
3940
|
+
const listItems = useMemo(() => {
|
|
3941
|
+
const out = [];
|
|
3942
|
+
let prev = null;
|
|
3943
|
+
for (const msg of messages) {
|
|
3944
|
+
if (prev === null || !sameDay(msg.inserted_at, prev.inserted_at)) {
|
|
3945
|
+
const label = formatDayLabel(msg.inserted_at);
|
|
3946
|
+
out.push({
|
|
3947
|
+
kind: "separator",
|
|
3948
|
+
id: `sep-${msg.id}`,
|
|
3949
|
+
node: /* @__PURE__ */ jsx(DaySeparator, { label })
|
|
3950
|
+
});
|
|
3951
|
+
}
|
|
3952
|
+
out.push({ kind: "msg", msg });
|
|
3953
|
+
prev = msg;
|
|
3954
|
+
}
|
|
3955
|
+
return out;
|
|
3956
|
+
}, [messages]);
|
|
3612
3957
|
const composerProps = useMemo(
|
|
3613
3958
|
() => ({
|
|
3614
3959
|
onSend: async (body, opts) => {
|
|
@@ -3622,9 +3967,28 @@ function ConversationView({
|
|
|
3622
3967
|
onCancelReply: () => setReplyingTo(null),
|
|
3623
3968
|
...labelFor ? { labelFor } : {},
|
|
3624
3969
|
attachments,
|
|
3625
|
-
keyboardOffset
|
|
3970
|
+
keyboardOffset,
|
|
3971
|
+
editingMessage,
|
|
3972
|
+
onCancelEdit: () => setEditingId(null),
|
|
3973
|
+
onSaveEdit: async (body) => {
|
|
3974
|
+
if (!editingId) return;
|
|
3975
|
+
await edit(editingId, body);
|
|
3976
|
+
setEditingId(null);
|
|
3977
|
+
}
|
|
3626
3978
|
}),
|
|
3627
|
-
[
|
|
3979
|
+
[
|
|
3980
|
+
send,
|
|
3981
|
+
signalTyping,
|
|
3982
|
+
attachments,
|
|
3983
|
+
replyingTo,
|
|
3984
|
+
labelFor,
|
|
3985
|
+
keyboardOffset,
|
|
3986
|
+
onSent,
|
|
3987
|
+
conversationId,
|
|
3988
|
+
editingMessage,
|
|
3989
|
+
editingId,
|
|
3990
|
+
edit
|
|
3991
|
+
]
|
|
3628
3992
|
);
|
|
3629
3993
|
const headerNode = header === false ? null : header === true ? /* @__PURE__ */ jsx(
|
|
3630
3994
|
ChatHeader,
|
|
@@ -3644,18 +4008,30 @@ function ConversationView({
|
|
|
3644
4008
|
keyboardVerticalOffset: keyboardOffset,
|
|
3645
4009
|
children: [
|
|
3646
4010
|
headerNode,
|
|
3647
|
-
/* @__PURE__ */
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
4011
|
+
/* @__PURE__ */ jsxs(View, { style: styles20.listWrap, children: [
|
|
4012
|
+
/* @__PURE__ */ jsx(
|
|
4013
|
+
MessageList,
|
|
4014
|
+
{
|
|
4015
|
+
messages,
|
|
4016
|
+
items: listItems,
|
|
4017
|
+
meId,
|
|
4018
|
+
loading,
|
|
4019
|
+
hasMore,
|
|
4020
|
+
onLoadMore: loadMore,
|
|
4021
|
+
renderItem,
|
|
4022
|
+
ListHeader: /* @__PURE__ */ jsx(TypingIndicator, { typing, ...labelFor ? { labelFor } : {} }),
|
|
4023
|
+
...emptyState !== void 0 ? { emptyState } : {}
|
|
4024
|
+
}
|
|
4025
|
+
),
|
|
4026
|
+
editingId ? /* @__PURE__ */ jsx(
|
|
4027
|
+
Pressable,
|
|
4028
|
+
{
|
|
4029
|
+
style: styles20.editBackdrop,
|
|
4030
|
+
onPress: () => setEditingId(null),
|
|
4031
|
+
accessibilityLabel: "Cancel editing"
|
|
4032
|
+
}
|
|
4033
|
+
) : null
|
|
4034
|
+
] }),
|
|
3659
4035
|
mentions ? /* @__PURE__ */ jsx(MentionInput, { conversationId, ...composerProps }) : /* @__PURE__ */ jsx(MessageComposer, { ...composerProps }),
|
|
3660
4036
|
attachments ? /* @__PURE__ */ jsx(AttachmentPicker, { visible: pickerOpen, onClose: () => setPickerOpen(false) }) : null,
|
|
3661
4037
|
threads && threadRoot ? /* @__PURE__ */ jsx(
|
|
@@ -3691,6 +4067,14 @@ var styles20 = StyleSheet.create({
|
|
|
3691
4067
|
},
|
|
3692
4068
|
listWrap: {
|
|
3693
4069
|
flex: 1
|
|
4070
|
+
},
|
|
4071
|
+
editBackdrop: {
|
|
4072
|
+
...StyleSheet.absoluteFillObject,
|
|
4073
|
+
backgroundColor: "rgba(0,0,0,0.45)",
|
|
4074
|
+
// Sit above message rows by default but below any row that
|
|
4075
|
+
// explicitly elevates itself (MessageRow bumps zIndex/elevation
|
|
4076
|
+
// when isEditing is true).
|
|
4077
|
+
zIndex: 5
|
|
3694
4078
|
}
|
|
3695
4079
|
});
|
|
3696
4080
|
function UserPickerSheet({
|
|
@@ -4549,6 +4933,6 @@ function useAppStateLifecycle() {
|
|
|
4549
4933
|
}, [poolse]);
|
|
4550
4934
|
}
|
|
4551
4935
|
|
|
4552
|
-
export { AttachmentPicker, AttachmentPreview, Avatar, ChatHeader, ConversationList, ConversationView,
|
|
4936
|
+
export { AttachmentPicker, AttachmentPreview, Avatar, ChatHeader, ConversationList, ConversationView, DaySeparator, GroupDetailsSheet, ImageMosaic, MemberList, MentionInput, MessageActions, MessageBubble, MessageComposer, MessageList, MessageRow, PoolseIcon, PoolseInbox, PoolseLogo, PoolseTheme, primitives as Primitives, ReactionPicker, ReactionStrip, ThreadView, TypingIndicator, UploadQueueStrip, UserName, defaultDarkTheme, defaultLightTheme, useAppStateLifecycle, useDisplayName, usePoolseTheme };
|
|
4553
4937
|
//# sourceMappingURL=index.js.map
|
|
4554
4938
|
//# sourceMappingURL=index.js.map
|