@poolse/react-native 2.19.0 → 2.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/dist/index.cjs +304 -178
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -3
- package/dist/index.d.ts +37 -3
- package/dist/index.js +304 -178
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -86,7 +86,7 @@ var radii = {
|
|
|
86
86
|
lg: 16,
|
|
87
87
|
xl: 24,
|
|
88
88
|
pill: 999,
|
|
89
|
-
bubble:
|
|
89
|
+
bubble: 18
|
|
90
90
|
};
|
|
91
91
|
var spacing = {
|
|
92
92
|
xs: 4,
|
|
@@ -2318,7 +2318,12 @@ var styles12 = StyleSheet.create({
|
|
|
2318
2318
|
fontWeight: "500"
|
|
2319
2319
|
}
|
|
2320
2320
|
});
|
|
2321
|
-
function AttachmentPreview({
|
|
2321
|
+
function AttachmentPreview({
|
|
2322
|
+
attachment,
|
|
2323
|
+
onPress,
|
|
2324
|
+
maxWidth = 280,
|
|
2325
|
+
tone = "default"
|
|
2326
|
+
}) {
|
|
2322
2327
|
const theme = usePoolseTheme();
|
|
2323
2328
|
const isImage = (attachment.content_type ?? "").startsWith("image/");
|
|
2324
2329
|
const { url } = useAttachmentUrl(attachment.id);
|
|
@@ -2352,6 +2357,9 @@ function AttachmentPreview({ attachment, onPress, maxWidth = 280 }) {
|
|
|
2352
2357
|
}
|
|
2353
2358
|
) });
|
|
2354
2359
|
}
|
|
2360
|
+
const onBrand = tone === "onBrand";
|
|
2361
|
+
const ink = onBrand ? theme.colors.onBrand : theme.colors.ink;
|
|
2362
|
+
const inkSoft = onBrand ? theme.colors.onBrand : theme.colors.ink3;
|
|
2355
2363
|
return /* @__PURE__ */ jsxs(
|
|
2356
2364
|
Pressable,
|
|
2357
2365
|
{
|
|
@@ -2360,23 +2368,23 @@ function AttachmentPreview({ attachment, onPress, maxWidth = 280 }) {
|
|
|
2360
2368
|
style: [
|
|
2361
2369
|
styles13.fileCard,
|
|
2362
2370
|
{
|
|
2363
|
-
backgroundColor: theme.colors.surface2,
|
|
2364
|
-
borderColor: theme.colors.border,
|
|
2371
|
+
backgroundColor: onBrand ? "rgba(255,255,255,0.18)" : theme.colors.surface2,
|
|
2372
|
+
borderColor: onBrand ? "transparent" : theme.colors.border,
|
|
2365
2373
|
borderRadius: theme.radii.md
|
|
2366
2374
|
}
|
|
2367
2375
|
],
|
|
2368
2376
|
children: [
|
|
2369
|
-
/* @__PURE__ */ jsx(PoolseIcon, { name: "attachment", size: 18, color: theme.colors.ink2 }),
|
|
2377
|
+
/* @__PURE__ */ jsx(PoolseIcon, { name: "attachment", size: 18, color: onBrand ? ink : theme.colors.ink2 }),
|
|
2370
2378
|
/* @__PURE__ */ jsxs(View, { style: { flex: 1, marginLeft: 8 }, children: [
|
|
2371
2379
|
/* @__PURE__ */ jsx(
|
|
2372
2380
|
Text,
|
|
2373
2381
|
{
|
|
2374
|
-
style: [styles13.fileName, { color:
|
|
2382
|
+
style: [styles13.fileName, { color: ink, fontFamily: theme.type.fontBody }],
|
|
2375
2383
|
numberOfLines: 1,
|
|
2376
2384
|
children: attachment.original_filename ?? "file"
|
|
2377
2385
|
}
|
|
2378
2386
|
),
|
|
2379
|
-
/* @__PURE__ */ jsx(Text, { style: [styles13.fileSize, { color:
|
|
2387
|
+
/* @__PURE__ */ jsx(Text, { style: [styles13.fileSize, { color: inkSoft, opacity: onBrand ? 0.8 : 1 }], children: formatBytes2(attachment.byte_size) })
|
|
2380
2388
|
] })
|
|
2381
2389
|
]
|
|
2382
2390
|
}
|
|
@@ -2404,9 +2412,16 @@ var styles13 = StyleSheet.create({
|
|
|
2404
2412
|
fontSize: 11
|
|
2405
2413
|
}
|
|
2406
2414
|
});
|
|
2407
|
-
function ImageMosaic({
|
|
2415
|
+
function ImageMosaic({
|
|
2416
|
+
images,
|
|
2417
|
+
maxWidth,
|
|
2418
|
+
radius,
|
|
2419
|
+
squareBottom = false,
|
|
2420
|
+
onLongPress
|
|
2421
|
+
}) {
|
|
2408
2422
|
const theme = usePoolseTheme();
|
|
2409
2423
|
const r = radius ?? theme.radii.md;
|
|
2424
|
+
const rBottom = squareBottom ? 5 : r;
|
|
2410
2425
|
const [viewerIndex, setViewerIndex] = useState(null);
|
|
2411
2426
|
if (images.length === 0) return null;
|
|
2412
2427
|
const visible = images.slice(0, 4);
|
|
@@ -2419,14 +2434,24 @@ function ImageMosaic({ images, maxWidth, radius }) {
|
|
|
2419
2434
|
style: [
|
|
2420
2435
|
styles14.root,
|
|
2421
2436
|
{
|
|
2422
|
-
|
|
2423
|
-
|
|
2437
|
+
borderTopLeftRadius: r,
|
|
2438
|
+
borderTopRightRadius: r,
|
|
2439
|
+
borderBottomLeftRadius: rBottom,
|
|
2440
|
+
borderBottomRightRadius: rBottom,
|
|
2441
|
+
// Explicit pixel width, not just a cap: the mosaic sits
|
|
2442
|
+
// inside an auto-sized bubble, and a percentage width
|
|
2443
|
+
// against an indefinite parent collapses (or, worse,
|
|
2444
|
+
// resolves against the image's intrinsic size and blows
|
|
2445
|
+
// the row open). Media bubbles are fixed-width — the
|
|
2446
|
+
// WhatsApp convention anyway.
|
|
2447
|
+
...maxWidth ? { width: maxWidth } : {}
|
|
2424
2448
|
}
|
|
2425
2449
|
],
|
|
2426
2450
|
children: [
|
|
2427
2451
|
n === 1 ? /* @__PURE__ */ jsx(
|
|
2428
2452
|
Tile,
|
|
2429
2453
|
{
|
|
2454
|
+
onLongPress,
|
|
2430
2455
|
attachment: visible[0],
|
|
2431
2456
|
style: styles14.tileFull,
|
|
2432
2457
|
onPress: () => setViewerIndex(0),
|
|
@@ -2437,6 +2462,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
|
|
|
2437
2462
|
/* @__PURE__ */ jsx(
|
|
2438
2463
|
Tile,
|
|
2439
2464
|
{
|
|
2465
|
+
onLongPress,
|
|
2440
2466
|
attachment: visible[0],
|
|
2441
2467
|
style: styles14.tileHalfSquare,
|
|
2442
2468
|
onPress: () => setViewerIndex(0),
|
|
@@ -2446,6 +2472,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
|
|
|
2446
2472
|
/* @__PURE__ */ jsx(
|
|
2447
2473
|
Tile,
|
|
2448
2474
|
{
|
|
2475
|
+
onLongPress,
|
|
2449
2476
|
attachment: visible[1],
|
|
2450
2477
|
style: styles14.tileHalfSquare,
|
|
2451
2478
|
onPress: () => setViewerIndex(1),
|
|
@@ -2457,6 +2484,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
|
|
|
2457
2484
|
/* @__PURE__ */ jsx(
|
|
2458
2485
|
Tile,
|
|
2459
2486
|
{
|
|
2487
|
+
onLongPress,
|
|
2460
2488
|
attachment: visible[0],
|
|
2461
2489
|
style: styles14.tileHero,
|
|
2462
2490
|
onPress: () => setViewerIndex(0),
|
|
@@ -2467,6 +2495,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
|
|
|
2467
2495
|
/* @__PURE__ */ jsx(
|
|
2468
2496
|
Tile,
|
|
2469
2497
|
{
|
|
2498
|
+
onLongPress,
|
|
2470
2499
|
attachment: visible[1],
|
|
2471
2500
|
style: styles14.tileHalfSquare,
|
|
2472
2501
|
onPress: () => setViewerIndex(1),
|
|
@@ -2476,6 +2505,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
|
|
|
2476
2505
|
/* @__PURE__ */ jsx(
|
|
2477
2506
|
Tile,
|
|
2478
2507
|
{
|
|
2508
|
+
onLongPress,
|
|
2479
2509
|
attachment: visible[2],
|
|
2480
2510
|
style: styles14.tileHalfSquare,
|
|
2481
2511
|
onPress: () => setViewerIndex(2),
|
|
@@ -2489,6 +2519,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
|
|
|
2489
2519
|
/* @__PURE__ */ jsx(
|
|
2490
2520
|
Tile,
|
|
2491
2521
|
{
|
|
2522
|
+
onLongPress,
|
|
2492
2523
|
attachment: visible[0],
|
|
2493
2524
|
style: styles14.tileHalfSquare,
|
|
2494
2525
|
onPress: () => setViewerIndex(0),
|
|
@@ -2498,6 +2529,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
|
|
|
2498
2529
|
/* @__PURE__ */ jsx(
|
|
2499
2530
|
Tile,
|
|
2500
2531
|
{
|
|
2532
|
+
onLongPress,
|
|
2501
2533
|
attachment: visible[1],
|
|
2502
2534
|
style: styles14.tileHalfSquare,
|
|
2503
2535
|
onPress: () => setViewerIndex(1),
|
|
@@ -2509,6 +2541,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
|
|
|
2509
2541
|
/* @__PURE__ */ jsx(
|
|
2510
2542
|
Tile,
|
|
2511
2543
|
{
|
|
2544
|
+
onLongPress,
|
|
2512
2545
|
attachment: visible[2],
|
|
2513
2546
|
style: styles14.tileHalfSquare,
|
|
2514
2547
|
onPress: () => setViewerIndex(2),
|
|
@@ -2518,6 +2551,7 @@ function ImageMosaic({ images, maxWidth, radius }) {
|
|
|
2518
2551
|
/* @__PURE__ */ jsx(
|
|
2519
2552
|
Tile,
|
|
2520
2553
|
{
|
|
2554
|
+
onLongPress,
|
|
2521
2555
|
attachment: visible[3],
|
|
2522
2556
|
style: styles14.tileHalfSquare,
|
|
2523
2557
|
onPress: () => setViewerIndex(3),
|
|
@@ -2551,11 +2585,12 @@ function Tile({
|
|
|
2551
2585
|
attachment,
|
|
2552
2586
|
style,
|
|
2553
2587
|
overlay,
|
|
2554
|
-
onPress
|
|
2588
|
+
onPress,
|
|
2589
|
+
onLongPress
|
|
2555
2590
|
}) {
|
|
2556
2591
|
const theme = usePoolseTheme();
|
|
2557
2592
|
const { url } = useAttachmentUrl(attachment.id);
|
|
2558
|
-
return /* @__PURE__ */ jsxs(Pressable, { onPress, style: [styles14.tileBase, style], children: [
|
|
2593
|
+
return /* @__PURE__ */ jsxs(Pressable, { onPress, onLongPress, style: [styles14.tileBase, style], children: [
|
|
2559
2594
|
url ? /* @__PURE__ */ jsx(
|
|
2560
2595
|
Image,
|
|
2561
2596
|
{
|
|
@@ -2657,6 +2692,27 @@ var styles14 = StyleSheet.create({
|
|
|
2657
2692
|
borderRadius: 20
|
|
2658
2693
|
}
|
|
2659
2694
|
});
|
|
2695
|
+
|
|
2696
|
+
// src/internal/bubbleText.ts
|
|
2697
|
+
function hasMarkdown(body) {
|
|
2698
|
+
return /[*_~`#>|\\]|\[.*\]|^\s*(?:[-+]|\d+[.)])\s|https?:\/\/|www\./ms.test(body);
|
|
2699
|
+
}
|
|
2700
|
+
function emojiOnlyCount(body) {
|
|
2701
|
+
const text = body.trim();
|
|
2702
|
+
if (!text || text.length > 32) return 0;
|
|
2703
|
+
try {
|
|
2704
|
+
const unit = "(?:\\p{Regional_Indicator}{2}|\\p{Extended_Pictographic})[\\u{1F3FB}-\\u{1F3FF}]?\\uFE0F?(?:\\u200D\\p{Extended_Pictographic}[\\u{1F3FB}-\\u{1F3FF}]?\\uFE0F?)*";
|
|
2705
|
+
const whole = new RegExp(`^(?:${unit}){1,3}$`, "u");
|
|
2706
|
+
if (!whole.test(text)) return 0;
|
|
2707
|
+
const each = new RegExp(unit, "gu");
|
|
2708
|
+
return (text.match(each) ?? []).length;
|
|
2709
|
+
} catch {
|
|
2710
|
+
return 0;
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
function emojiFontSize(count) {
|
|
2714
|
+
return count === 1 ? 44 : count === 2 ? 38 : 32;
|
|
2715
|
+
}
|
|
2660
2716
|
var markdownit = MarkdownIt({ typographer: false, linkify: true });
|
|
2661
2717
|
function renderMarkdown(body, args) {
|
|
2662
2718
|
const baseText = {
|
|
@@ -2716,107 +2772,163 @@ function MessageBubble({
|
|
|
2716
2772
|
showSenderName = false,
|
|
2717
2773
|
actionsTrigger,
|
|
2718
2774
|
showAttachments = true,
|
|
2719
|
-
markdown = true
|
|
2775
|
+
markdown = true,
|
|
2776
|
+
onLongPress
|
|
2720
2777
|
}) {
|
|
2721
2778
|
const theme = usePoolseTheme();
|
|
2722
2779
|
const { width: screenWidth } = useWindowDimensions();
|
|
2723
2780
|
const isSelf = currentUserId !== null && message.sender_id === currentUserId;
|
|
2724
2781
|
const [expanded, setExpanded] = useState(false);
|
|
2725
2782
|
const bubbleMaxWidth = Math.floor(screenWidth * 0.78);
|
|
2726
|
-
const
|
|
2783
|
+
const mediaWidth = Math.min(bubbleMaxWidth - 6, 420);
|
|
2727
2784
|
const sender = useUser(!isSelf ? message.sender_external_id : null);
|
|
2728
2785
|
const senderFallbackName = message.sender_external_id ?? "Unknown";
|
|
2729
2786
|
const senderLabel = sender.profile?.displayName ?? (message.sender_external_id ? labelFor?.(message.sender_external_id) ?? senderFallbackName : senderFallbackName);
|
|
2730
2787
|
const senderTint = userColor(message.sender_external_id ?? message.sender_id ?? message.id);
|
|
2731
2788
|
const tailCorner = groupPosition === "last" || groupPosition === "standalone";
|
|
2732
|
-
const
|
|
2789
|
+
const bubbleRadius = theme.radii.bubble;
|
|
2733
2790
|
const textColor = isSelf ? theme.colors.selfBubbleText : theme.colors.otherBubbleText;
|
|
2791
|
+
const mutedOnBubble = isSelf ? theme.colors.onBrand : theme.colors.ink3;
|
|
2734
2792
|
const radii2 = {
|
|
2735
|
-
topLeft:
|
|
2736
|
-
topRight:
|
|
2737
|
-
bottomLeft:
|
|
2738
|
-
bottomRight:
|
|
2793
|
+
topLeft: bubbleRadius,
|
|
2794
|
+
topRight: bubbleRadius,
|
|
2795
|
+
bottomLeft: bubbleRadius,
|
|
2796
|
+
bottomRight: bubbleRadius
|
|
2739
2797
|
};
|
|
2740
2798
|
if (tailCorner) {
|
|
2741
|
-
if (isSelf) radii2.bottomRight =
|
|
2742
|
-
else radii2.bottomLeft =
|
|
2799
|
+
if (isSelf) radii2.bottomRight = 5;
|
|
2800
|
+
else radii2.bottomLeft = 5;
|
|
2743
2801
|
}
|
|
2744
2802
|
const body = message.body ?? "";
|
|
2745
|
-
const truncated = maxBodyLength > 0 && body.length > maxBodyLength && !expanded ? body.slice(0, maxBodyLength) + "\u2026" : body;
|
|
2746
|
-
const time = formatTime(message.inserted_at);
|
|
2747
2803
|
const isDeleted = !!message.deleted_at;
|
|
2748
2804
|
const isEdited = !!message.edited_at && !isDeleted;
|
|
2749
|
-
const
|
|
2750
|
-
const
|
|
2751
|
-
const
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2805
|
+
const trimmable = maxBodyLength > 0 && body.length > maxBodyLength;
|
|
2806
|
+
const truncated = trimmable && !expanded ? body.slice(0, maxBodyLength) + "\u2026" : body;
|
|
2807
|
+
const time = formatTime(message.inserted_at);
|
|
2808
|
+
const images = showAttachments && !isDeleted ? (message.attachments ?? []).filter((a) => isImageContentType(a.content_type)) : [];
|
|
2809
|
+
const files = showAttachments && !isDeleted ? (message.attachments ?? []).filter((a) => !isImageContentType(a.content_type)) : [];
|
|
2810
|
+
const hasMedia = images.length > 0;
|
|
2811
|
+
const hasFiles = files.length > 0;
|
|
2812
|
+
const hasBody = !isDeleted && body.length > 0;
|
|
2813
|
+
const metaOverlay = hasMedia && !hasBody && !hasFiles;
|
|
2814
|
+
const jumboCount = hasBody && !hasMedia && !hasFiles && !message.quoted_message_id ? emojiOnlyCount(body) : 0;
|
|
2815
|
+
const inlineMeta = hasBody && jumboCount === 0 && !trimmable && (!markdown || !hasMarkdown(truncated));
|
|
2816
|
+
const sectionAbove = hasMedia || hasFiles || !!message.quoted_message || isDeleted;
|
|
2817
|
+
const ghost = ` ${isEdited ? "edited " : ""}${time}${isSelf && readState ? " \u2713\u2713" : ""}`;
|
|
2818
|
+
const metaRow = (variant) => {
|
|
2819
|
+
const color = variant === "overlay" ? "#FFFFFF" : variant === "jumbo" ? theme.colors.ink3 : mutedOnBubble;
|
|
2820
|
+
return /* @__PURE__ */ jsxs(
|
|
2821
|
+
View,
|
|
2822
|
+
{
|
|
2823
|
+
style: [
|
|
2824
|
+
styles15.metaRow,
|
|
2825
|
+
variant === "inline" && styles15.metaInline,
|
|
2826
|
+
variant === "overlay" && styles15.metaOverlay,
|
|
2827
|
+
variant === "block" && styles15.metaBlock,
|
|
2828
|
+
// File-only bubble: the meta row follows the cards directly —
|
|
2829
|
+
// give it air so the time doesn't sit glued to the card.
|
|
2830
|
+
variant === "block" && hasFiles && !hasBody && styles15.metaBlockAfterFiles,
|
|
2831
|
+
variant === "jumbo" && styles15.metaJumbo
|
|
2832
|
+
],
|
|
2833
|
+
pointerEvents: "none",
|
|
2834
|
+
children: [
|
|
2835
|
+
isEdited ? /* @__PURE__ */ jsx(Text, { style: [styles15.editedTag, { color, opacity: 0.8 }], children: "edited" }) : null,
|
|
2836
|
+
/* @__PURE__ */ jsx(Text, { style: [styles15.meta, { color, opacity: variant === "overlay" ? 1 : 0.75 }], children: time }),
|
|
2837
|
+
isSelf && readState ? /* @__PURE__ */ jsx(View, { style: styles15.readTick, children: /* @__PURE__ */ jsx(
|
|
2838
|
+
PoolseIcon,
|
|
2839
|
+
{
|
|
2840
|
+
name: readState === "read" ? "check-double" : "check",
|
|
2841
|
+
size: 13,
|
|
2842
|
+
color
|
|
2843
|
+
}
|
|
2844
|
+
) }) : null
|
|
2845
|
+
]
|
|
2846
|
+
}
|
|
2847
|
+
);
|
|
2848
|
+
};
|
|
2849
|
+
return /* @__PURE__ */ jsxs(View, { style: [styles15.wrap, { alignSelf: isSelf ? "flex-end" : "flex-start", maxWidth: bubbleMaxWidth }], children: [
|
|
2850
|
+
/* @__PURE__ */ jsxs(
|
|
2851
|
+
View,
|
|
2852
|
+
{
|
|
2853
|
+
style: [
|
|
2854
|
+
jumboCount === 0 && {
|
|
2855
|
+
backgroundColor: isSelf ? theme.colors.selfBubble : theme.colors.otherBubble,
|
|
2856
|
+
borderColor: isSelf ? "transparent" : theme.colors.border,
|
|
2857
|
+
borderWidth: isSelf ? 0 : StyleSheet.hairlineWidth,
|
|
2858
|
+
borderTopLeftRadius: radii2.topLeft,
|
|
2859
|
+
borderTopRightRadius: radii2.topRight,
|
|
2860
|
+
borderBottomLeftRadius: radii2.bottomLeft,
|
|
2861
|
+
borderBottomRightRadius: radii2.bottomRight
|
|
2862
|
+
},
|
|
2863
|
+
jumboCount === 0 && theme.shadows.sm
|
|
2864
|
+
],
|
|
2865
|
+
children: [
|
|
2866
|
+
showSenderName && !isSelf && jumboCount === 0 && (groupPosition === "first" || groupPosition === "standalone") ? /* @__PURE__ */ jsx(
|
|
2867
|
+
Text,
|
|
2868
|
+
{
|
|
2869
|
+
style: [styles15.senderName, { color: senderTint, fontFamily: theme.type.fontBody }],
|
|
2870
|
+
children: senderLabel
|
|
2871
|
+
}
|
|
2872
|
+
) : null,
|
|
2873
|
+
message.quoted_message ? /* @__PURE__ */ jsx(
|
|
2874
|
+
QuotedCard,
|
|
2875
|
+
{
|
|
2876
|
+
quoted: message.quoted_message,
|
|
2877
|
+
isSelf,
|
|
2878
|
+
...labelFor ? { labelFor } : {},
|
|
2879
|
+
...onQuotedClick ? { onPress: () => onQuotedClick(message.quoted_message.id) } : {}
|
|
2880
|
+
}
|
|
2881
|
+
) : null,
|
|
2882
|
+
hasMedia ? (
|
|
2883
|
+
// 3px of bubble color framing the picture; the mosaic clips
|
|
2884
|
+
// itself 3px tighter than the bubble so the curves stay
|
|
2885
|
+
// concentric.
|
|
2886
|
+
/* @__PURE__ */ jsxs(View, { style: styles15.mediaFrame, children: [
|
|
2887
|
+
/* @__PURE__ */ jsx(
|
|
2888
|
+
ImageMosaic,
|
|
2889
|
+
{
|
|
2890
|
+
images,
|
|
2891
|
+
maxWidth: mediaWidth,
|
|
2892
|
+
radius: Math.max(bubbleRadius - 3, 8),
|
|
2893
|
+
squareBottom: !metaOverlay,
|
|
2894
|
+
...onLongPress ? { onLongPress } : {}
|
|
2895
|
+
}
|
|
2896
|
+
),
|
|
2897
|
+
metaOverlay ? metaRow("overlay") : null
|
|
2898
|
+
] })
|
|
2899
|
+
) : null,
|
|
2900
|
+
hasFiles ? /* @__PURE__ */ jsx(View, { style: styles15.filesBlock, children: files.map((att) => /* @__PURE__ */ jsx(
|
|
2901
|
+
AttachmentPreview,
|
|
2771
2902
|
{
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
borderTopLeftRadius: radii2.topLeft,
|
|
2776
|
-
borderTopRightRadius: radii2.topRight,
|
|
2777
|
-
borderBottomLeftRadius: radii2.bottomLeft,
|
|
2778
|
-
borderBottomRightRadius: radii2.bottomRight,
|
|
2779
|
-
// Slightly more breathing room — 14/10 reads tighter and
|
|
2780
|
-
// matches the iMessage / WhatsApp bubble density.
|
|
2781
|
-
paddingHorizontal: 14,
|
|
2782
|
-
paddingVertical: 10,
|
|
2783
|
-
// Floor the bubble at a width that always fits the meta row
|
|
2784
|
-
// ("edited HH:MM ✓✓" → ~110px). Without this, short bodies
|
|
2785
|
-
// like "ok" produce a bubble too narrow for the meta to lay
|
|
2786
|
-
// out, and `edited` or the time gets clipped.
|
|
2787
|
-
minWidth: isSelf && isEdited ? 130 : 90
|
|
2903
|
+
attachment: att,
|
|
2904
|
+
maxWidth: bubbleMaxWidth - 12,
|
|
2905
|
+
tone: isSelf ? "onBrand" : "default"
|
|
2788
2906
|
},
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
children:
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
fontStyle: "italic"
|
|
2815
|
-
}
|
|
2816
|
-
],
|
|
2817
|
-
children: "Message deleted"
|
|
2818
|
-
}
|
|
2819
|
-
) : markdown ? renderMarkdown(truncated, {
|
|
2907
|
+
att.id
|
|
2908
|
+
)) }) : null,
|
|
2909
|
+
isDeleted ? /* @__PURE__ */ jsx(View, { style: [styles15.textBlock, sectionAbove && styles15.textBlockAfter], children: /* @__PURE__ */ jsx(
|
|
2910
|
+
Text,
|
|
2911
|
+
{
|
|
2912
|
+
style: {
|
|
2913
|
+
color: mutedOnBubble,
|
|
2914
|
+
opacity: 0.7,
|
|
2915
|
+
fontFamily: theme.type.fontBody,
|
|
2916
|
+
fontSize: theme.type.bodySize,
|
|
2917
|
+
lineHeight: theme.type.lineHeight,
|
|
2918
|
+
fontStyle: "italic"
|
|
2919
|
+
},
|
|
2920
|
+
children: "Message deleted"
|
|
2921
|
+
}
|
|
2922
|
+
) }) : null,
|
|
2923
|
+
hasBody && jumboCount > 0 ? /* @__PURE__ */ jsx(View, { style: styles15.jumboBlock, children: /* @__PURE__ */ jsx(
|
|
2924
|
+
Text,
|
|
2925
|
+
{
|
|
2926
|
+
style: { fontSize: emojiFontSize(jumboCount), lineHeight: emojiFontSize(jumboCount) + 8 },
|
|
2927
|
+
children: body
|
|
2928
|
+
}
|
|
2929
|
+
) }) : null,
|
|
2930
|
+
hasBody && jumboCount === 0 ? /* @__PURE__ */ jsxs(View, { style: [styles15.textBlock, sectionAbove && styles15.textBlockAfter], children: [
|
|
2931
|
+
markdown && !inlineMeta ? renderMarkdown(truncated, {
|
|
2820
2932
|
textColor,
|
|
2821
2933
|
linkColor: isSelf ? theme.colors.onBrand : theme.colors.brand,
|
|
2822
2934
|
fontFamily: theme.type.fontBody,
|
|
@@ -2826,22 +2938,29 @@ function MessageBubble({
|
|
|
2826
2938
|
void Linking.openURL(url).catch(() => void 0);
|
|
2827
2939
|
return false;
|
|
2828
2940
|
}
|
|
2829
|
-
}) : /* @__PURE__ */
|
|
2941
|
+
}) : /* @__PURE__ */ jsxs(
|
|
2830
2942
|
Text,
|
|
2831
2943
|
{
|
|
2832
|
-
style:
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2944
|
+
style: {
|
|
2945
|
+
color: textColor,
|
|
2946
|
+
fontFamily: theme.type.fontBody,
|
|
2947
|
+
fontSize: theme.type.bodySize,
|
|
2948
|
+
lineHeight: theme.type.lineHeight
|
|
2949
|
+
},
|
|
2950
|
+
children: [
|
|
2951
|
+
truncated,
|
|
2952
|
+
inlineMeta ? (
|
|
2953
|
+
// The invisible twin: reserves the meta's footprint
|
|
2954
|
+
// at the end of the last line so the absolutely-
|
|
2955
|
+
// positioned real meta never covers a glyph — and
|
|
2956
|
+
// when the line is full, the reservation wraps and
|
|
2957
|
+
// the meta drops down, flush right.
|
|
2958
|
+
/* @__PURE__ */ jsx(Text, { style: styles15.ghost, children: ghost })
|
|
2959
|
+
) : null
|
|
2960
|
+
]
|
|
2842
2961
|
}
|
|
2843
|
-
)
|
|
2844
|
-
|
|
2962
|
+
),
|
|
2963
|
+
trimmable ? /* @__PURE__ */ jsx(Pressable, { onPress: () => setExpanded((e) => !e), children: /* @__PURE__ */ jsx(
|
|
2845
2964
|
Text,
|
|
2846
2965
|
{
|
|
2847
2966
|
style: [
|
|
@@ -2851,48 +2970,15 @@ function MessageBubble({
|
|
|
2851
2970
|
children: expanded ? "Show less" : "Read more"
|
|
2852
2971
|
}
|
|
2853
2972
|
) }) : null,
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
}
|
|
2864
|
-
],
|
|
2865
|
-
children: "edited"
|
|
2866
|
-
}
|
|
2867
|
-
) : null,
|
|
2868
|
-
/* @__PURE__ */ jsx(
|
|
2869
|
-
Text,
|
|
2870
|
-
{
|
|
2871
|
-
style: [
|
|
2872
|
-
styles15.meta,
|
|
2873
|
-
{
|
|
2874
|
-
color: isSelf ? theme.colors.onBrand : theme.colors.ink3,
|
|
2875
|
-
opacity: isSelf ? 0.85 : 1
|
|
2876
|
-
}
|
|
2877
|
-
],
|
|
2878
|
-
children: time
|
|
2879
|
-
}
|
|
2880
|
-
),
|
|
2881
|
-
isSelf && readState ? /* @__PURE__ */ jsx(View, { style: styles15.readTick, children: /* @__PURE__ */ jsx(
|
|
2882
|
-
PoolseIcon,
|
|
2883
|
-
{
|
|
2884
|
-
name: readState === "read" ? "check-double" : "check",
|
|
2885
|
-
size: 13,
|
|
2886
|
-
color: theme.colors.onBrand
|
|
2887
|
-
}
|
|
2888
|
-
) }) : null
|
|
2889
|
-
] }),
|
|
2890
|
-
actionsTrigger ? /* @__PURE__ */ jsx(View, { style: styles15.actionsSlot, children: actionsTrigger }) : null
|
|
2891
|
-
]
|
|
2892
|
-
}
|
|
2893
|
-
)
|
|
2894
|
-
}
|
|
2895
|
-
);
|
|
2973
|
+
inlineMeta ? metaRow("inline") : null
|
|
2974
|
+
] }) : null,
|
|
2975
|
+
!inlineMeta && !metaOverlay && jumboCount === 0 ? metaRow("block") : null,
|
|
2976
|
+
actionsTrigger ? /* @__PURE__ */ jsx(View, { style: styles15.actionsSlot, children: actionsTrigger }) : null
|
|
2977
|
+
]
|
|
2978
|
+
}
|
|
2979
|
+
),
|
|
2980
|
+
jumboCount > 0 ? /* @__PURE__ */ jsx(View, { style: { alignSelf: isSelf ? "flex-end" : "flex-start" }, children: metaRow("jumbo") }) : null
|
|
2981
|
+
] });
|
|
2896
2982
|
}
|
|
2897
2983
|
function QuotedCard({
|
|
2898
2984
|
quoted,
|
|
@@ -2903,7 +2989,7 @@ function QuotedCard({
|
|
|
2903
2989
|
const theme = usePoolseTheme();
|
|
2904
2990
|
const resolved = useUser(quoted.sender_external_id);
|
|
2905
2991
|
const senderName = quoted.sender_external_id ? labelFor?.(quoted.sender_external_id) ?? resolved.profile?.displayName ?? quoted.sender_external_id : "Unknown";
|
|
2906
|
-
const bg = isSelf ? "rgba(
|
|
2992
|
+
const bg = isSelf ? "rgba(0,0,0,0.16)" : theme.colors.surface2;
|
|
2907
2993
|
const accent = isSelf ? theme.colors.onBrand : theme.colors.brand;
|
|
2908
2994
|
const txt = isSelf ? theme.colors.onBrand : theme.colors.ink;
|
|
2909
2995
|
return /* @__PURE__ */ jsxs(
|
|
@@ -2919,8 +3005,8 @@ function QuotedCard({
|
|
|
2919
3005
|
}
|
|
2920
3006
|
],
|
|
2921
3007
|
children: [
|
|
2922
|
-
/* @__PURE__ */ jsx(Text, { style: [styles15.quotedSender, { color: accent }], children: senderName }),
|
|
2923
|
-
/* @__PURE__ */ jsx(Text, { style: [styles15.quotedBody, { color: txt }], numberOfLines: 2, children: quoted.body ?? "\u2026" })
|
|
3008
|
+
/* @__PURE__ */ jsx(Text, { style: [styles15.quotedSender, { color: accent }], numberOfLines: 1, children: senderName }),
|
|
3009
|
+
/* @__PURE__ */ jsx(Text, { style: [styles15.quotedBody, { color: txt }], numberOfLines: 2, children: quoted.deleted_at ? "Original message deleted" : quoted.body ?? "\u2026" })
|
|
2924
3010
|
]
|
|
2925
3011
|
}
|
|
2926
3012
|
);
|
|
@@ -2956,16 +3042,34 @@ var styles15 = StyleSheet.create({
|
|
|
2956
3042
|
wrap: {
|
|
2957
3043
|
marginBottom: 2
|
|
2958
3044
|
},
|
|
2959
|
-
bubble: {
|
|
2960
|
-
position: "relative"
|
|
2961
|
-
},
|
|
2962
3045
|
senderName: {
|
|
2963
3046
|
fontSize: 12,
|
|
2964
|
-
fontWeight: "
|
|
2965
|
-
|
|
3047
|
+
fontWeight: "700",
|
|
3048
|
+
paddingTop: 7,
|
|
3049
|
+
paddingHorizontal: 12
|
|
2966
3050
|
},
|
|
2967
|
-
|
|
2968
|
-
|
|
3051
|
+
mediaFrame: {
|
|
3052
|
+
margin: 3
|
|
3053
|
+
},
|
|
3054
|
+
filesBlock: {
|
|
3055
|
+
paddingHorizontal: 6,
|
|
3056
|
+
paddingTop: 6,
|
|
3057
|
+
gap: 4
|
|
3058
|
+
},
|
|
3059
|
+
textBlock: {
|
|
3060
|
+
paddingHorizontal: 12,
|
|
3061
|
+
paddingVertical: 7
|
|
3062
|
+
},
|
|
3063
|
+
// A hair less air when media / files / a quote already sit above.
|
|
3064
|
+
textBlockAfter: {
|
|
3065
|
+
paddingTop: 6
|
|
3066
|
+
},
|
|
3067
|
+
jumboBlock: {
|
|
3068
|
+
paddingVertical: 2
|
|
3069
|
+
},
|
|
3070
|
+
ghost: {
|
|
3071
|
+
color: "transparent",
|
|
3072
|
+
fontSize: 11
|
|
2969
3073
|
},
|
|
2970
3074
|
readMore: {
|
|
2971
3075
|
fontSize: 12,
|
|
@@ -2975,10 +3079,36 @@ var styles15 = StyleSheet.create({
|
|
|
2975
3079
|
metaRow: {
|
|
2976
3080
|
flexDirection: "row",
|
|
2977
3081
|
alignItems: "center",
|
|
3082
|
+
gap: 4
|
|
3083
|
+
},
|
|
3084
|
+
metaInline: {
|
|
3085
|
+
position: "absolute",
|
|
3086
|
+
right: 12,
|
|
3087
|
+
// Optically centers the meta against the body's last line (22px
|
|
3088
|
+
// line over the 7px bottom padding): 7 + (22 - 14) / 2. At 8 it
|
|
3089
|
+
// sat visibly low beside a one-line message.
|
|
3090
|
+
bottom: 11
|
|
3091
|
+
},
|
|
3092
|
+
metaOverlay: {
|
|
3093
|
+
position: "absolute",
|
|
3094
|
+
right: 6,
|
|
3095
|
+
bottom: 6,
|
|
3096
|
+
paddingHorizontal: 8,
|
|
3097
|
+
paddingVertical: 3,
|
|
3098
|
+
borderRadius: 999,
|
|
3099
|
+
backgroundColor: "rgba(0,0,0,0.42)"
|
|
3100
|
+
},
|
|
3101
|
+
metaBlock: {
|
|
2978
3102
|
justifyContent: "flex-end",
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
3103
|
+
paddingHorizontal: 12,
|
|
3104
|
+
paddingBottom: 6,
|
|
3105
|
+
marginTop: -2
|
|
3106
|
+
},
|
|
3107
|
+
metaBlockAfterFiles: {
|
|
3108
|
+
marginTop: 6
|
|
3109
|
+
},
|
|
3110
|
+
metaJumbo: {
|
|
3111
|
+
paddingTop: 2
|
|
2982
3112
|
},
|
|
2983
3113
|
meta: {
|
|
2984
3114
|
fontSize: 11,
|
|
@@ -2991,7 +3121,7 @@ var styles15 = StyleSheet.create({
|
|
|
2991
3121
|
letterSpacing: 0.1
|
|
2992
3122
|
},
|
|
2993
3123
|
readTick: {
|
|
2994
|
-
marginLeft:
|
|
3124
|
+
marginLeft: 1,
|
|
2995
3125
|
marginTop: 1
|
|
2996
3126
|
},
|
|
2997
3127
|
actionsSlot: {
|
|
@@ -3001,20 +3131,21 @@ var styles15 = StyleSheet.create({
|
|
|
3001
3131
|
},
|
|
3002
3132
|
quoted: {
|
|
3003
3133
|
borderLeftWidth: 3,
|
|
3004
|
-
paddingLeft:
|
|
3005
|
-
paddingVertical:
|
|
3006
|
-
paddingRight:
|
|
3007
|
-
|
|
3008
|
-
|
|
3134
|
+
paddingLeft: 9,
|
|
3135
|
+
paddingVertical: 5,
|
|
3136
|
+
paddingRight: 8,
|
|
3137
|
+
margin: 4,
|
|
3138
|
+
marginBottom: 0,
|
|
3139
|
+
borderRadius: 10
|
|
3009
3140
|
},
|
|
3010
3141
|
quotedSender: {
|
|
3011
3142
|
fontSize: 12,
|
|
3012
|
-
fontWeight: "
|
|
3013
|
-
marginBottom:
|
|
3143
|
+
fontWeight: "700",
|
|
3144
|
+
marginBottom: 1
|
|
3014
3145
|
},
|
|
3015
3146
|
quotedBody: {
|
|
3016
|
-
fontSize: 12,
|
|
3017
|
-
opacity: 0.
|
|
3147
|
+
fontSize: 12.5,
|
|
3148
|
+
opacity: 0.8
|
|
3018
3149
|
}
|
|
3019
3150
|
});
|
|
3020
3151
|
var DEFAULT_EMOJIS = ["\u{1F44D}", "\u2764\uFE0F", "\u{1F602}", "\u{1F389}", "\u{1F64F}", "\u{1F525}"];
|
|
@@ -3331,14 +3462,9 @@ function MessageRow({
|
|
|
3331
3462
|
showSenderName,
|
|
3332
3463
|
showAttachments: attachments,
|
|
3333
3464
|
markdown,
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
name: "chevron-down",
|
|
3338
|
-
size: 14,
|
|
3339
|
-
color: isSelf ? theme.colors.onBrand : theme.colors.ink3
|
|
3340
|
-
}
|
|
3341
|
-
) }) : null
|
|
3465
|
+
onLongPress: () => {
|
|
3466
|
+
if (actions) setActionsOpen(true);
|
|
3467
|
+
}
|
|
3342
3468
|
}
|
|
3343
3469
|
)
|
|
3344
3470
|
}
|